Skip to content

Commit a4711bc

Browse files
author
Memfault Inc
committed
Memfault Firmware SDK 1.10.0 (Build 8899)
1 parent 5cce7ee commit a4711bc

File tree

11 files changed

+182
-41
lines changed

11 files changed

+182
-41
lines changed

CHANGELOG.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,34 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to
77
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
88

9+
## [1.10.0] - 2024-07-12
10+
11+
### :chart_with_upwards_trend: Improvements
12+
13+
- Zephyr:
14+
15+
- Add support for Memfault Logging when `CONFIG_LOG_MODE_MINIMAL=y`, in
16+
addition to the previously supported `LOG_MODE_DEFERRED` (Zephyr default)
17+
and `LOG_MODE_IMMEDIATE`.
18+
[Zephyr minimal log mode](https://docs.zephyrproject.org/3.6.0/kconfig.html#CONFIG_LOG_MODE_MINIMAL)
19+
disables all backends- logs are simply sent to `printk`.
20+
21+
- For ESP32 chips, place the reboot reason tracking into a dedicated section,
22+
`.rtc_noinit`, to ensure the reboot reason is preserved across reboots. This
23+
was previously only supported on Zephyr ESP32-S3/S2 devices (all ESP32
24+
devices on ESP-IDF already support this).
25+
26+
- Fix a bug where the default `memfault_platform_get_device_info()`, which
27+
uses the hwinfo subsystem, when available, was incorrectly disabled when
28+
`CONFIG_MEMFAULT_REBOOT_REASON_GET_CUSTOM=y`.
29+
30+
- General:
31+
32+
- Improve the `memfault_demo_cli_cmd_busfault()` function (accessed via
33+
`test_busfault`/`mflt test busfault` demo CLI commands) to produce BusFaults
34+
on more devices. Previously, certain chips would either not produce a fault,
35+
or would produce a MemManage exception instead.
36+
937
## [1.9.4] - 2024-07-01
1038

1139
### :chart_with_upwards_trend: Improvements

VERSION

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
BUILD ID: 8676
2-
GIT COMMIT: 69ac2e1558
3-
VERSION: 1.9.4
1+
BUILD ID: 8899
2+
GIT COMMIT: 7e534eec9c
3+
VERSION: 1.10.0

components/demo/src/panics/memfault_demo_panics.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,13 @@ int memfault_demo_cli_cmd_memmanage(MEMFAULT_UNUSED int argc, MEMFAULT_UNUSED ch
172172
}
173173

174174
int memfault_demo_cli_cmd_busfault(MEMFAULT_UNUSED int argc, MEMFAULT_UNUSED char *argv[]) {
175-
void (*unaligned_func)(void) = (void (*)(void))0x50000001;
176-
unaligned_func();
175+
// Trigger a BusFault by attempting to load and jump to an address from the "RAM" (0x60000000 -
176+
// 0x7FFFFFFF) region, described as: "Memory with write-back, write allocate cache attribute for
177+
// L2/L3 cache support." in the ARMv7-M architecture reference manual. This is not guaranteed to
178+
// trigger a BusFault, if the address is both loadable and executable, but on many devices it
179+
// will.
180+
void (*busfault_func)(void) = (void (*)(void))0x60000001;
181+
busfault_func();
177182

178183
// We should never get here -- platforms BusFault or HardFault handler should be tripped
179184
// with a precise error due to unaligned execution

components/include/memfault/version.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ typedef struct {
1919
uint8_t patch;
2020
} sMfltSdkVersion;
2121

22-
#define MEMFAULT_SDK_VERSION { .major = 1, .minor = 9, .patch = 4 }
23-
#define MEMFAULT_SDK_VERSION_STR "1.9.4"
22+
#define MEMFAULT_SDK_VERSION { .major = 1, .minor = 10, .patch = 0 }
23+
#define MEMFAULT_SDK_VERSION_STR "1.10.0"
2424

2525
#ifdef __cplusplus
2626
}

examples/freertos/boards/qemu_mps2_an385/startup.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ __attribute__((noinline)) static void prv_cinit(void) {
102102
}
103103

104104
__attribute__((noreturn)) void Reset_Handler(void) {
105+
// enable mem/bus/usage faults
106+
#define SCBSHCSR_ (*(uint32_t *)0xE000ED24)
107+
SCBSHCSR_ |= (1UL << 16U) | (1UL << 17U) | (1UL << 18U);
108+
105109
prv_cinit();
106110

107111
uart_init();

examples/freertos/boards/qemu_mps2_an386/startup.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ __attribute__((noinline)) static void prv_cinit(void) {
102102
}
103103

104104
__attribute__((noreturn)) void Reset_Handler(void) {
105+
// enable mem/bus/usage faults
106+
#define SCBSHCSR_ (*(uint32_t *)0xE000ED24)
107+
SCBSHCSR_ |= (1UL << 16U) | (1UL << 17U) | (1UL << 18U);
108+
105109
prv_cinit();
106110

107111
uart_init();

ports/zephyr/common/CMakeLists.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@ if (CONFIG_MEMFAULT_LOGGING_ENABLE)
3636
# https://github.com/zephyrproject-rtos/zephyr/pull/31535
3737
# It fully replaced version 1 after the 3.1 release: https://github.com/zephyrproject-rtos/zephyr/issues/46500
3838
# and the option to enable logging v1 via CONFIG_LOG1 was entirely removed
39-
if(${KERNEL_VERSION_MAJOR}.${KERNEL_VERSION_MINOR}.${KERNEL_PATCHLEVEL} VERSION_GREATER_EQUAL "3.1.99" OR CONFIG_LOG2)
39+
if(CONFIG_LOG_MODE_MINIMAL)
40+
target_link_libraries(app INTERFACE "-Wl,--wrap=z_log_minimal_printk")
41+
zephyr_library_sources(memfault_logging_minimal.c)
42+
elseif(${KERNEL_VERSION_MAJOR}.${KERNEL_VERSION_MINOR}.${KERNEL_PATCHLEVEL} VERSION_GREATER_EQUAL "3.1.99" OR CONFIG_LOG2)
4043
zephyr_library_sources(memfault_logging.c)
4144
else()
4245
zephyr_library_sources(memfault_logging_legacy.c)
@@ -73,4 +76,8 @@ if(CONFIG_MEMFAULT_HEAP_STATS AND CONFIG_HEAP_MEM_POOL_SIZE GREATER 0)
7376
zephyr_ld_options(-Wl,--wrap=k_free)
7477
endif()
7578

79+
if(CONFIG_SOC_FAMILY_ESP32)
80+
zephyr_linker_sources(SECTIONS memfault-rtc-noinit-region.ld)
81+
endif()
82+
7683
zephyr_include_directories(.)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* For ESP32 variants other than ESP32-S3/S2, provide a region of noinit placed
3+
in * RTC memory, for holding reboot reason information through OTA updates. *
4+
The normal Zephyr noinit region is not suitable for this, because its offset *
5+
can change through an OTA update, invalidating the reboot reason data.
6+
*
7+
* Unfortunately this doesn't place the section in the same order in RTC as in
8+
* the ESP32-S3/S2, but it puts it in a usable location.
9+
*/
10+
#if !defined(CONFIG_SOC_SERIES_ESP32S3) && !defined(CONFIG_SOC_SERIES_ESP32S2)
11+
SECTION_PROLOGUE(.rtc_noinit,(NOLOAD),)
12+
{
13+
. = ALIGN(4);
14+
_rtc_noinit_start = ABSOLUTE(.);
15+
*(.rtc_noinit .rtc_noinit.*)
16+
. = ALIGN(4) ;
17+
_rtc_noinit_end = ABSOLUTE(.);
18+
} GROUP_LINK_IN(rtc_slow_seg)
19+
#endif
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//! @file
2+
//!
3+
//! Copyright (c) Memfault, Inc.
4+
//! See License.txt for details
5+
//!
6+
//! @brief
7+
//! Hooks the Memfault log collection to the Zephyr LOG_MODE_MINIMAL logging
8+
//! system.
9+
10+
// clang-format off
11+
#include MEMFAULT_ZEPHYR_INCLUDE(kernel.h)
12+
#include MEMFAULT_ZEPHYR_INCLUDE(sys/atomic.h)
13+
#include MEMFAULT_ZEPHYR_INCLUDE(logging/log.h)
14+
15+
#include <stdarg.h>
16+
17+
#include "memfault/components.h"
18+
// clang-format on
19+
20+
enum {
21+
MFLT_LOG_BUFFER_BUSY,
22+
};
23+
static atomic_t s_log_output_busy_flag;
24+
25+
static void prv_log_init(void) {
26+
// Static RAM storage where logs will be stored.
27+
static uint8_t s_mflt_log_buf_storage[CONFIG_MEMFAULT_LOGGING_RAM_SIZE];
28+
memfault_log_boot(s_mflt_log_buf_storage, sizeof(s_mflt_log_buf_storage));
29+
}
30+
31+
static void prv_memfault_log_vprintf(const char *fmt, va_list args) {
32+
// Force synchronization at this level.
33+
if (atomic_test_and_set_bit(&s_log_output_busy_flag, MFLT_LOG_BUFFER_BUSY)) {
34+
return;
35+
}
36+
37+
// This is idempotent; but sensitive to concurrent access. The atomic flag
38+
// that protects this function should be good enough, since it only has to
39+
// succeed once. The vulnerability is only if a user is accessing
40+
// memfault_log_save_preformatted_nolock() directly (should not be done).
41+
prv_log_init();
42+
43+
// Render the log message into a buffer. Static storage class, so it doesn't
44+
// contribute to stack usage which could be problematic in this call site.
45+
static uint8_t s_zephyr_render_buf[128];
46+
int save_length = vsnprintk(s_zephyr_render_buf, sizeof(s_zephyr_render_buf), fmt, args);
47+
if (save_length > 0) {
48+
// Always set to info, since we can't reliably determine the log level
49+
memfault_log_save_preformatted_nolock(kMemfaultPlatformLogLevel_Info, s_zephyr_render_buf,
50+
save_length);
51+
}
52+
53+
atomic_clear_bit(&s_log_output_busy_flag, MFLT_LOG_BUFFER_BUSY);
54+
}
55+
56+
void __wrap_z_log_minimal_printk(const char *fmt, ...) {
57+
va_list args;
58+
va_start(args, fmt);
59+
60+
prv_memfault_log_vprintf(fmt, args);
61+
62+
va_start(args, fmt);
63+
64+
// Now call zephyr printk
65+
z_log_minimal_vprintk(fmt, args);
66+
67+
va_end(args);
68+
}
69+
70+
// Ensure the substituted function signature matches the original function
71+
_Static_assert(__builtin_types_compatible_p(__typeof__(&z_log_minimal_printk),
72+
__typeof__(&__wrap_z_log_minimal_printk)),
73+
"Error: check z_log_minimal_printk function signature");

ports/zephyr/common/memfault_platform_core.c

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@ void __wrap_z_arm_fault(uint32_t msp, uint32_t psp, uint32_t exc_return,
6161
// register capture disable is a very small size optimization, and logs are
6262
// likely not used on devices with space constraints.
6363
LOG_PANIC();
64+
#if !defined(CONFIG_LOG_MODE_MINIMAL)
6465
memfault_zephyr_log_backend_disable();
66+
#endif
6567
#endif
6668

6769
memfault_coredump_cache_fault_regs();
@@ -149,26 +151,49 @@ static eMemfaultRebootReason prv_zephyr_to_memfault_reboot_reason(uint32_t reset
149151
}
150152
#endif // CONFIG_HWINFO
151153

154+
MEMFAULT_WEAK void memfault_reboot_reason_get(sResetBootupInfo *info) {
155+
eMemfaultRebootReason reset_reason = kMfltRebootReason_Unknown;
156+
uint32_t reset_reason_reg = 0;
157+
#if defined(CONFIG_HWINFO)
158+
int rv = hwinfo_get_reset_cause(&reset_reason_reg);
159+
160+
if (rv == 0) {
161+
reset_reason = prv_zephyr_to_memfault_reboot_reason(reset_reason_reg);
162+
}
163+
164+
#endif
165+
166+
*info = (sResetBootupInfo){
167+
.reset_reason = reset_reason,
168+
.reset_reason_reg = reset_reason_reg,
169+
};
170+
}
171+
#endif
172+
173+
void memfault_zephyr_collect_reset_info(void) {
174+
memfault_reboot_tracking_collect_reset_info(s_memfault_event_storage);
175+
}
176+
152177
// This can be overridden by the application to set a custom device ID
153178
MEMFAULT_WEAK const char *memfault_zephyr_get_device_id(void) {
154179
uint8_t dev_id[16] = { 0 };
155180
static char dev_id_str[sizeof(dev_id) * 2 + 1];
156181
static const char *dev_str = "UNKNOWN";
157182

158-
// Obtain the device id
159-
#if defined(CONFIG_HWINFO)
183+
// Obtain the device id
184+
#if defined(CONFIG_HWINFO)
160185
ssize_t length = hwinfo_get_device_id(dev_id, sizeof(dev_id));
161-
#else
186+
#else
162187
ssize_t length = 0;
163-
#endif
188+
#endif
164189

165190
// If hwinfo_get_device_id() fails or isn't enabled, use a fallback string
166191
if (length <= 0) {
167-
#if defined(CONFIG_SOC)
192+
#if defined(CONFIG_SOC)
168193
dev_str = CONFIG_SOC "-testserial";
169-
#else
194+
#else
170195
dev_str = "testserial";
171-
#endif
196+
#endif
172197
length = strlen(dev_str);
173198
} else {
174199
// Render the obtained serial number in hexadecimal representation
@@ -190,29 +215,6 @@ MEMFAULT_WEAK void memfault_platform_get_device_info(sMemfaultDeviceInfo *info)
190215
};
191216
}
192217

193-
MEMFAULT_WEAK void memfault_reboot_reason_get(sResetBootupInfo *info) {
194-
eMemfaultRebootReason reset_reason = kMfltRebootReason_Unknown;
195-
uint32_t reset_reason_reg = 0;
196-
#if defined(CONFIG_HWINFO)
197-
int rv = hwinfo_get_reset_cause(&reset_reason_reg);
198-
199-
if (rv == 0) {
200-
reset_reason = prv_zephyr_to_memfault_reboot_reason(reset_reason_reg);
201-
}
202-
203-
#endif
204-
205-
*info = (sResetBootupInfo){
206-
.reset_reason = reset_reason,
207-
.reset_reason_reg = reset_reason_reg,
208-
};
209-
}
210-
#endif
211-
212-
void memfault_zephyr_collect_reset_info(void) {
213-
memfault_reboot_tracking_collect_reset_info(s_memfault_event_storage);
214-
}
215-
216218
// Note: the function signature has changed here across zephyr releases
217219
// "struct device *dev" -> "const struct device *dev"
218220
//

0 commit comments

Comments
 (0)