diff --git a/boards/nxp/mr-canhubk3/fmu.px4board b/boards/nxp/mr-canhubk3/fmu.px4board index 366bf7fa09..6d0a6d31d7 100644 --- a/boards/nxp/mr-canhubk3/fmu.px4board +++ b/boards/nxp/mr-canhubk3/fmu.px4board @@ -43,6 +43,7 @@ CONFIG_MODULES_VTOL_ATT_CONTROL=y CONFIG_SYSTEMCMDS_ACTUATOR_TEST=y CONFIG_SYSTEMCMDS_DMESG=y CONFIG_SYSTEMCMDS_DUMPFILE=y +CONFIG_SYSTEMCMDS_HARDFAULT_LOG=y CONFIG_SYSTEMCMDS_NETMAN=y CONFIG_SYSTEMCMDS_NSHTERM=y CONFIG_SYSTEMCMDS_PERF=y diff --git a/boards/nxp/mr-canhubk3/nuttx-config/nsh/defconfig b/boards/nxp/mr-canhubk3/nuttx-config/nsh/defconfig index 40350962c1..d2d4d7ea1d 100644 --- a/boards/nxp/mr-canhubk3/nuttx-config/nsh/defconfig +++ b/boards/nxp/mr-canhubk3/nuttx-config/nsh/defconfig @@ -71,6 +71,7 @@ CONFIG_ARMV7M_ICACHE=y CONFIG_ARMV7M_MEMCPY=y CONFIG_ARMV7M_USEBASEPRI=y CONFIG_BOARDCTL_RESET=y +CONFIG_BOARD_CRASHDUMP=y CONFIG_BOARD_LOOPSPERMSEC=14539 CONFIG_BUILTIN=y CONFIG_DEBUG_BUSFAULT=y @@ -247,6 +248,7 @@ CONFIG_S32K3XX_LPUART9=y CONFIG_S32K3XX_LPUART_INVERT=y CONFIG_S32K3XX_LPUART_SINGLEWIRE=y CONFIG_S32K3XX_PROGMEM=y +CONFIG_S32K3XX_PROGMEM_SIZE=120 CONFIG_S32K3XX_QSPI=y CONFIG_S32K3XX_WKPUINTS=y CONFIG_SCHED_HPWORK=y diff --git a/boards/nxp/mr-canhubk3/src/board_config.h b/boards/nxp/mr-canhubk3/src/board_config.h index fa6f66aa23..49a3162af6 100644 --- a/boards/nxp/mr-canhubk3/src/board_config.h +++ b/boards/nxp/mr-canhubk3/src/board_config.h @@ -38,6 +38,7 @@ __BEGIN_DECLS #include "hardware/s32k344_pinmux.h" #include "s32k3xx_periphclocks.h" #include "s32k3xx_pin.h" +#include "s32k3xx_progmem.h" #include /**************************************************************************** @@ -92,6 +93,23 @@ __BEGIN_DECLS #define BOARD_ENABLE_CONSOLE_BUFFER +/* + * Hardfault log to progmem + */ +#define PROGMEM_CRASHDUMP 1 +#define SAVE_CRASHDUMP 1 +#define PROGMEM_DUMP_BASE ((CONFIG_S32K3XX_PROGMEM_SIZE * 1024) + S32K3XX_PROGMEM_START_ADDR) +#define PROGMEM_DUMP_SIZE ((DFLASH_SIZE - CONFIG_S32K3XX_PROGMEM_SIZE) * 1024) +#define PROGMEM_DUMP_ALIGNMENT (S32K3XX_PROGMEM_WRITE_SIZE) +#define PROGMEM_DUMP_UNIT_SIZE (S32K3XX_PROGMEM_DFLASH_WRITE_UNIT_SIZE) +#define PROGMEM_DUMP_HEADER_PAD (108) +#define PROGMEM_DUMP_ERASE_VALUE (0xFF) +#define PROGMEM_DUMP_STACK_SIZE (6656) +#define BOARD_CRASHDUMP_BSS 1 + +/* Reboot and ulog we store on a wear-level filesystem */ +#define HARDFAULT_REBOOT_PATH "/mnt/progmem/reboot" + /**************************************************************************** * Public Data ****************************************************************************/ diff --git a/boards/nxp/mr-canhubk3/src/s32k3xx_bringup.c b/boards/nxp/mr-canhubk3/src/s32k3xx_bringup.c index ff00607b0d..529ed7ed9b 100644 --- a/boards/nxp/mr-canhubk3/src/s32k3xx_bringup.c +++ b/boards/nxp/mr-canhubk3/src/s32k3xx_bringup.c @@ -309,5 +309,7 @@ int s32k3xx_bringup(void) # endif /* CONFIG_S32K3XX_FLEXCAN5 */ #endif /* CONFIG_NETDEV_LATEINIT */ + board_hardfault_init(2, true); + return ret; } diff --git a/platforms/nuttx/NuttX/nuttx b/platforms/nuttx/NuttX/nuttx index e771ce8124..211dd7dc11 160000 --- a/platforms/nuttx/NuttX/nuttx +++ b/platforms/nuttx/NuttX/nuttx @@ -1 +1 @@ -Subproject commit e771ce812410eda35a1454548b5a694b57d811a5 +Subproject commit 211dd7dc110dcaaa2eb9d414d5d4e5a9a7ae5f43 diff --git a/platforms/nuttx/src/px4/common/CMakeLists.txt b/platforms/nuttx/src/px4/common/CMakeLists.txt index fbccd77a0f..ab16e77a0e 100644 --- a/platforms/nuttx/src/px4/common/CMakeLists.txt +++ b/platforms/nuttx/src/px4/common/CMakeLists.txt @@ -50,6 +50,7 @@ if(NOT PX4_BOARD MATCHES "io-v2") px4_mtd.cpp px4_24xxxx_mtd.c px4_crypto.cpp + progmem_dump.c ) # Kernel side & nuttx flat build common libraries diff --git a/platforms/nuttx/src/px4/common/board_crashdump.c b/platforms/nuttx/src/px4/common/board_crashdump.c index 90e541ae0e..42216c5122 100644 --- a/platforms/nuttx/src/px4/common/board_crashdump.c +++ b/platforms/nuttx/src/px4/common/board_crashdump.c @@ -56,18 +56,14 @@ #include "nvic.h" #include -#if defined(CONFIG_STM32F7_BBSRAM) && defined(CONFIG_STM32F7_SAVE_CRASHDUMP) -# define HAS_BBSRAM CONFIG_STM32F7_BBSRAM -# define BBSRAM_FILE_COUNT CONFIG_STM32F7_BBSRAM_FILES -# define SAVE_CRASHDUMP CONFIG_STM32F7_SAVE_CRASHDUMP -#elif defined(CONFIG_STM32H7_BBSRAM) && defined(CONFIG_STM32H7_SAVE_CRASHDUMP) -# define HAS_BBSRAM CONFIG_STM32H7_BBSRAM -# define BBSRAM_FILE_COUNT CONFIG_STM32H7_BBSRAM_FILES -# define SAVE_CRASHDUMP CONFIG_STM32H7_SAVE_CRASHDUMP -#elif defined(CONFIG_STM32_BBSRAM) && defined(CONFIG_STM32_SAVE_CRASHDUMP) -# define HAS_BBSRAM CONFIG_STM32_BBSRAM -# define BBSRAM_FILE_COUNT CONFIG_STM32_BBSRAM_FILES -# define SAVE_CRASHDUMP CONFIG_STM32_SAVE_CRASHDUMP +#ifdef HAS_PROGMEM +#include +#endif + +#ifdef HAS_BBSRAM +# define REBOOTS_COUNT 32000 +#elif defined(HAS_PROGMEM) +# define REBOOTS_COUNT 32 #endif int board_hardfault_init(int display_to_console, bool allow_prompt) @@ -86,7 +82,21 @@ int board_hardfault_init(int display_to_console, bool allow_prompt) stm32_bbsraminitialize(BBSRAM_PATH, filesizes); -#if defined(SAVE_CRASHDUMP) +#elif defined(HAS_PROGMEM) + + /* NB. the use of the console requires the hrt running + * to poll the DMA + */ + + /* Using progmem */ + + int filesizes[PROGMEM_FILE_COUNT + 1] = PROGMEM_FILE_SIZES; + + progmem_dump_initialize(PROGMEM_PATH, filesizes); + +#endif // HAS_PROGMEM + +#if defined(SAVE_CRASHDUMP) && (defined(HAS_BBSRAM) || defined(HAS_PROGMEM)) /* Panic Logging in Battery Backed Up Files */ @@ -124,7 +134,7 @@ int board_hardfault_init(int display_to_console, bool allow_prompt) return -EIO; } - if (reboots >= 32000) { + if (reboots >= REBOOTS_COUNT) { reboots = hardfault_increment_reboot("boot", true); return -ENOSPC; } @@ -219,7 +229,6 @@ read: } // outer if #endif // SAVE_CRASHDUMP -#endif // HAS_BBSRAM return hadCrash == OK ? 1 : 0; } @@ -230,11 +239,22 @@ static void copy_reverse(stack_word_t *dest, stack_word_t *src, int size) } } +#ifdef BOARD_CRASHDUMP_BSS + +static uint32_t *__attribute__((noinline)) __ebss_addr(void) +{ + return &_ebss; +} + +#else + static uint32_t *__attribute__((noinline)) __sdata_addr(void) { return &_sdata; } +#endif + __EXPORT void board_crashdump(uintptr_t currentsp, FAR void *tcb, FAR const char *filename, int lineno) { @@ -246,7 +266,11 @@ __EXPORT void board_crashdump(uintptr_t currentsp, FAR void *tcb, FAR const char * Unfortunately this is hard to test. See dead below */ +#ifdef BOARD_CRASHDUMP_BSS + fullcontext_s *pdump = (fullcontext_s *)(__ebss_addr() - sizeof(fullcontext_s)); +#else fullcontext_s *pdump = (fullcontext_s *)__sdata_addr(); +#endif (void)enter_critical_section(); @@ -378,14 +402,14 @@ __EXPORT void board_crashdump(uintptr_t currentsp, FAR void *tcb, FAR const char char *dead = "Memory wiped - dump not saved!"; while (*dead) { - arm_lowputc(*dead++); + up_putc(*dead++); } } else if (rv == -ENOSPC) { /* hard fault again */ - arm_lowputc('!'); + up_putc('!'); } #endif /* BOARD_CRASHDUMP_RESET_ONLY */ diff --git a/platforms/nuttx/src/px4/common/include/px4_platform/progmem_dump.h b/platforms/nuttx/src/px4/common/include/px4_platform/progmem_dump.h new file mode 100644 index 0000000000..0b11aeb374 --- /dev/null +++ b/platforms/nuttx/src/px4/common/include/px4_platform/progmem_dump.h @@ -0,0 +1,125 @@ +/**************************************************************************** + * + * Copyright (C) 2022 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#pragma once + +#define PROGMEM_DUMP_GETDESC_IOCTL _DIOC(0x0000) /* Returns a progmem_s */ +#define PROGMEM_DUMP_CLEAR_IOCTL _DIOC(0x0010) /* Erases flash sector */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +struct progmem_s { + struct timespec lastwrite; + int fileno; + int len; + int flags; +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +# define EXTERN extern "C" +extern "C" +{ +#else +# define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Function: progmem_dump_initialize + * + * Description: + * Initialize the Progmem dump driver + * + * Input Parameters: + * devpath - the path to instantiate the files. + * sizes - Pointer to a any array of file sizes to create + * the last entry should be 0 + * A size of -1 will use all the remaining spaces + * + * Returned Value: + * Number of files created on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +int progmem_dump_initialize(char *devpath, int *sizes); + +/**************************************************************************** + * Function: progmem_dump_savepanic + * + * Description: + * Saves the panic context in a previously allocated BBSRAM file + * + * Parameters: + * fileno - the value returned by the ioctl PROGMEM_DUMP_GETDESC_IOCTL + * context - Pointer to a any array of bytes to save + * length - The length of the data pointed to byt context + * + * Returned Value: + * Length saved or negated errno. + * + * Assumptions: + * + ****************************************************************************/ + +int progmem_dump_savepanic(int fileno, uint8_t *context, int length); + +#undef EXTERN +#ifdef __cplusplus +} +#endif +#endif /* __ASSEMBLY__ */ diff --git a/platforms/nuttx/src/px4/common/progmem_dump.c b/platforms/nuttx/src/px4/common/progmem_dump.c new file mode 100644 index 0000000000..e37a6dd697 --- /dev/null +++ b/platforms/nuttx/src/px4/common/progmem_dump.c @@ -0,0 +1,797 @@ +/**************************************************************************** + * + * Copyright (c) 2022 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef CONFIG_BOARD_CRASHDUMP + +#include +#include "chip.h" + +#ifdef HAS_PROGMEM + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define PROGMEM_DUMP_FILES 5 +#define MAX_OPENCNT (255) /* Limit of uint8_t */ +#define PROGMEM_HEADER_SIZE (sizeof(struct progmemfh_s)) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct progmemfh_s { + int32_t fileno; /* The minor number */ + uint32_t len; /* Total Bytes in this file */ + uint32_t clean; /* No data has been written to the file */ + struct timespec lastwrite; /* Last write time */ + uint8_t padding[PROGMEM_DUMP_HEADER_PAD]; /* Ensure padding for quick write of data */ + uint8_t data[]; /* Data in the file */ +}; + +static_assert(sizeof(struct progmemfh_s) == PROGMEM_DUMP_ALIGNMENT, "progmemfh_s doesn't match write alignment"); + +struct progmem_dump_s { + sem_t exclsem; /* For atomic accesses to this structure */ + uint8_t refs; /* Number of references */ + struct progmemfh_s *pf; /* File in progmem */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int progmem_dump_open(struct file *filep); +static int progmem_dump_close(struct file *filep); +static off_t progmem_dump_seek(struct file *filep, off_t offset, + int whence); +static ssize_t progmem_dump_read(struct file *filep, char *buffer, + size_t len); +static ssize_t progmem_dump_write(struct file *filep, + const char *buffer, size_t len); +static int progmem_dump_ioctl(struct file *filep, int cmd, + unsigned long arg); +static int progmem_dump_poll(struct file *filep, + struct pollfd *fds, bool setup); +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS +static int progmem_dump_unlink(struct inode *inode); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + + +static const struct file_operations progmem_dump_fops = { + .open = progmem_dump_open, + .close = progmem_dump_close, + .read = progmem_dump_read, + .write = progmem_dump_write, + .seek = progmem_dump_seek, + .ioctl = progmem_dump_ioctl, + .poll = progmem_dump_poll, +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS + .unlink = progmem_dump_unlink +#endif +}; + +/* Store ulog location in RAM to save on FLash wear */ +static char ulog_file_loc[HARDFAULT_MAX_ULOG_FILE_LEN] = {0}; + +static struct progmem_dump_s g_progmem[PROGMEM_DUMP_FILES]; + +/**************************************************************************** + * Name: progmem_check_erase + ****************************************************************************/ + +static int progmem_check_erase(char *buffer, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) { + if (buffer[i] != PROGMEM_DUMP_ERASE_VALUE) { + return 0; + } + } + + return 1; +} + +/**************************************************************************** + * Name: progmem_dump_semgive + ****************************************************************************/ + +static void progmem_dump_semgive(struct progmem_dump_s *priv) +{ + nxsem_post(&priv->exclsem); +} + +/**************************************************************************** + * Name: progmem_dump_semtake + * + * Description: + * Take a semaphore handling any exceptional conditions + * + * Input Parameters: + * priv - A reference to the CAN peripheral state + * + * Returned Value: + * None + * + ****************************************************************************/ + +static int progmem_dump_semtake(struct progmem_dump_s *priv) +{ + return nxsem_wait_uninterruptible(&priv->exclsem); +} + +/**************************************************************************** + * Name: progmem_dump_open + * + * Description: Open the device + * + ****************************************************************************/ + +static int progmem_dump_open(struct file *filep) +{ + struct inode *inode = filep->f_inode; + struct progmem_dump_s *pmf; + int ret; + + DEBUGASSERT(inode && inode->i_private); + pmf = (struct progmem_dump_s *)inode->i_private; + + /* Increment the reference count */ + + ret = progmem_dump_semtake(pmf); + + if (ret < 0) { + return ret; + } + + if (pmf->refs == MAX_OPENCNT) { + return -EMFILE; + + } else { + pmf->refs++; + } + + progmem_dump_semgive(pmf); + return OK; +} + +/**************************************************************************** + * Name: progmem_dump_internal_close + * + * Description: + * Close Progmem entry; Recalculate the time and crc + * + ****************************************************************************/ + +static int progmem_dump_internal_close(struct progmemfh_s *pf) +{ + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + up_progmem_write((size_t)pf + offsetof(struct progmemfh_s, lastwrite), + &ts, sizeof(ts)); + return pf->len; +} + +/**************************************************************************** + * Name: progmem_dump_close + * + * Description: close the device + * + ****************************************************************************/ + +static int progmem_dump_close(struct file *filep) +{ + struct inode *inode = filep->f_inode; + struct progmem_dump_s *pmf; + int ret = OK; + + DEBUGASSERT(inode && inode->i_private); + pmf = (struct progmem_dump_s *)inode->i_private; + + ret = progmem_dump_semtake(pmf); + + if (ret < 0) { + return ret; + } + + if (pmf->refs == 0) { + ret = -EIO; + + } else { + pmf->refs--; + + if (pmf->refs == 0) { + if (pmf->pf->clean == 0) { + progmem_dump_internal_close(pmf->pf); + } + } + } + + progmem_dump_semgive(pmf); + return ret; +} + +/**************************************************************************** + * Name: progmem_dump_seek + ****************************************************************************/ + +static off_t progmem_dump_seek(struct file *filep, off_t offset, + int whence) +{ + struct inode *inode = filep->f_inode; + struct progmem_dump_s *pmf; + off_t newpos; + int ret; + + DEBUGASSERT(inode && inode->i_private); + pmf = (struct progmem_dump_s *)inode->i_private; + + ret = progmem_dump_semtake(pmf); + + if (ret < 0) { + return (off_t)ret; + } + + /* Determine the new, requested file position */ + + switch (whence) { + case SEEK_CUR: + newpos = filep->f_pos + offset; + break; + + case SEEK_SET: + newpos = offset; + break; + + case SEEK_END: + newpos = pmf->pf->len + offset; + break; + + default: + + /* Return EINVAL if the whence argument is invalid */ + + progmem_dump_semgive(pmf); + return -EINVAL; + } + + /* Opengroup.org: + * + * "The lseek() function shall allow the file offset to be set beyond the + * end of the existing data in the file. If data is later written at this + * point, subsequent reads of data in the gap shall return bytes with the + * value 0 until data is actually written into the gap." + * + * We can conform to the first part, but not the second. But return EINVAL + * if "...the resulting file offset would be negative for a regular file, + * block special file, or directory." + */ + + if (newpos >= 0) { + filep->f_pos = newpos; + ret = newpos; + + } else { + ret = -EINVAL; + } + + progmem_dump_semgive(pmf); + return ret; +} + +/**************************************************************************** + * Name: progmem_dump_read + ****************************************************************************/ + +static ssize_t progmem_dump_read(struct file *filep, char *buffer, + size_t len) +{ + struct inode *inode = filep->f_inode; + struct progmem_dump_s *pmf; + int ret; + + DEBUGASSERT(inode && inode->i_private); + pmf = (struct progmem_dump_s *)inode->i_private; + + ret = progmem_dump_semtake(pmf); + + if (ret < 0) { + return (ssize_t)ret; + } + + /* Trim len if read would go beyond end of device */ + + if ((filep->f_pos + len) > pmf->pf->len) { + len = pmf->pf->len - filep->f_pos; + } + + memcpy(buffer, &pmf->pf->data[filep->f_pos], len); + filep->f_pos += len; + progmem_dump_semgive(pmf); + return len; +} + +/**************************************************************************** + * Name: progmem_dump_internal_write + ****************************************************************************/ + +static ssize_t progmem_dump_internal_write(struct progmemfh_s *pf, + const char *buffer, + off_t offset, size_t len) +{ + if (pf->clean) { + /* Update Header */ + uint32_t clean = 0; + up_progmem_write((size_t)pf + offsetof(struct progmemfh_s, clean), + &clean, sizeof(clean)); + + /* Write data */ + up_progmem_write((size_t)&pf->data[offset], buffer, len); + return len; + + } else { + /* It's dirty and since it's flash we can't write again */ + return 0; + } +} + +/**************************************************************************** + * Name: progmem_dump_write + ****************************************************************************/ + +static ssize_t progmem_dump_write(struct file *filep, + const char *buffer, size_t len) +{ + struct inode *inode = filep->f_inode; + struct progmem_dump_s *pmf; + int ret = -EFBIG; + + DEBUGASSERT(inode && inode->i_private); + pmf = (struct progmem_dump_s *)inode->i_private; + + /* Forbid writes past the end of the device */ + + if (filep->f_pos < (int)pmf->pf->len) { + /* Clamp len to avoid crossing the end of the memory */ + + if ((filep->f_pos + len) > pmf->pf->len) { + len = pmf->pf->len - filep->f_pos; + } + + ret = progmem_dump_semtake(pmf); + + if (ret < 0) { + return (ssize_t)ret; + } + + ret = len; /* save number of bytes written */ + + if (pmf->pf->fileno == HARDFAULT_ULOG_FILENO) { + /* Write ULOG location to ram to save on flash wear */ + strncpy(ulog_file_loc, buffer, HARDFAULT_MAX_ULOG_FILE_LEN); + + } else { + progmem_dump_internal_write(pmf->pf, buffer, filep->f_pos, len); + filep->f_pos += len; + } + + progmem_dump_semgive(pmf); + } + + return ret; +} + +/**************************************************************************** + * Name: progmem_dump_poll + ****************************************************************************/ + +static int progmem_dump_poll(struct file *filep, struct pollfd *fds, + bool setup) +{ + if (setup) { + fds->revents |= (fds->events & (POLLIN | POLLOUT)); + + if (fds->revents != 0) { + nxsem_post(fds->sem); + } + } + + return OK; +} + +/**************************************************************************** + * Name: progmem_dump_ioctl + * + * Description: Return device geometry + * + ****************************************************************************/ + +static int progmem_dump_ioctl(struct file *filep, int cmd, + unsigned long arg) +{ + struct inode *inode = filep->f_inode; + struct progmem_dump_s *pmf; + int ret = -ENOTTY; + + DEBUGASSERT(inode && inode->i_private); + pmf = (struct progmem_dump_s *)inode->i_private; + + if (cmd == PROGMEM_DUMP_GETDESC_IOCTL) { + struct progmem_s *desc = (struct progmem_s *)((uintptr_t)arg); + + ret = progmem_dump_semtake(pmf); + + if (ret < 0) { + return ret; + } + + if (!desc) { + ret = -EINVAL; + + } else { + desc->fileno = pmf->pf->fileno; + desc->len = pmf->pf->len; + desc->flags = ((pmf->pf->clean) ? 0 : 2); + + if (progmem_check_erase((char *)&pmf->pf->lastwrite, + sizeof(pmf->pf->lastwrite))) { + desc->lastwrite.tv_sec = 0; + desc->lastwrite.tv_nsec = 0; + + } else { + desc->lastwrite = pmf->pf->lastwrite; + } + + ret = OK; + } + + progmem_dump_semgive(pmf); + + } else if (cmd == PROGMEM_DUMP_CLEAR_IOCTL) { + ret = progmem_dump_semtake(pmf); + + if (ret < 0) { + return ret; + } + + /* Our dump data is beyond the progmem neraseblocks + * so we just start with that block + */ + int i; + size_t block = up_progmem_neraseblocks(); + size_t erase_size = up_progmem_erasesize(block); + size_t to_erase = PROGMEM_DUMP_SIZE; + uint32_t lens[PROGMEM_DUMP_FILES]; + + for (i = 0; i < PROGMEM_DUMP_FILES; i++) { + lens[i] = g_progmem[i].pf->len; + } + + while (to_erase > 0) { + up_progmem_eraseblock(block); + block--; + to_erase = to_erase - erase_size; + } + + for (i = 0; i < PROGMEM_DUMP_FILES; i++) { + struct progmemfh_s progmem_header; + /* Make sure ERASE_VALUE is set so we can do back-to-back write */ + memset(&progmem_header, PROGMEM_DUMP_ERASE_VALUE, sizeof(struct progmemfh_s)); + progmem_header.fileno = i; + progmem_header.len = lens[i]; + up_progmem_write((size_t)g_progmem[i].pf, + (void *)&progmem_header, sizeof(struct progmemfh_s)); + } + + ret = OK; + + progmem_dump_semgive(pmf); + } + + return ret; +} + +/**************************************************************************** + * Name: progmem_dump_unlink + * + * Description: + * This function will remove the remove the file from the file system + * it will zero the contents and time stamp. It will leave the fileno + * and pointer to the Progmem intact. + * It should be called called on the file used for the crash dump + * to remove it from visibility in the file system after it is created or + * read thus arming it. + * + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS +static int progmem_dump_unlink(struct inode *inode) +{ + struct progmem_dump_s *pmf; + int ret; + + DEBUGASSERT(inode && inode->i_private); + pmf = (struct progmem_dump_s *)inode->i_private; + + ret = progmem_dump_semtake(pmf); + + if (ret < 0) { + return ret; + } + + progmem_dump_semgive(pmf); + nxsem_destroy(&pmf->exclsem); + return 0; +} +#endif + +/**************************************************************************** + * Name: progmem_dump_probe + * + * Description: Based on the number of files defined and their sizes + * Initializes the base pointers to the file entries. + * + ****************************************************************************/ + +static int progmem_dump_probe(int *ent, struct progmem_dump_s pdev[]) +{ + int i; + int alloc; + int size; + int avail; + struct progmemfh_s *pf = (struct progmemfh_s *) PROGMEM_DUMP_BASE; + int ret = -EFBIG; + + avail = PROGMEM_DUMP_SIZE; + + for (i = 0; (i < PROGMEM_DUMP_FILES) && ent[i] && (avail > 0); + i++) { + /* Validate the actual allocations against what is in the PROGMEM */ + + size = ent[i]; + + /* Use all that is left */ + + if (size == -1) { + size = (avail - (avail % PROGMEM_DUMP_ALIGNMENT)); + size -= PROGMEM_HEADER_SIZE; + } + + /* Add in header size and keep aligned */ + + alloc = (((size + PROGMEM_DUMP_ALIGNMENT) / PROGMEM_DUMP_ALIGNMENT) + 1) * PROGMEM_DUMP_ALIGNMENT; + + if (size % PROGMEM_DUMP_ALIGNMENT != 0) { + alloc = (2 * PROGMEM_DUMP_ALIGNMENT) + + ((size / PROGMEM_DUMP_ALIGNMENT) * PROGMEM_DUMP_ALIGNMENT); + + } else { + alloc = PROGMEM_DUMP_ALIGNMENT + + ((size / PROGMEM_DUMP_ALIGNMENT) * PROGMEM_DUMP_ALIGNMENT); + } + + /* Does it fit? */ + + if (alloc <= avail) { + ret = i + 1; + + if ((int)pf->len != size || pf->fileno != i) { + /* Not Valid so wipe the file in PROGMEM */ + struct progmemfh_s progmem_header; + /* Make sure ERASE_VALUE is set so we can do back-to-back write */ + memset(&progmem_header, PROGMEM_DUMP_ERASE_VALUE, sizeof(struct progmemfh_s)); + progmem_header.fileno = i; + progmem_header.len = size; + up_progmem_write((size_t)pf, (void *)&progmem_header, sizeof(struct progmemfh_s)); + } + + pdev[i].pf = pf; + pf = (struct progmemfh_s *)((uint32_t *)pf + (alloc / 4)); + nxsem_init(&g_progmem[i].exclsem, 0, 1); + } + + avail -= alloc; + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: progmem_dump_initialize + * + * Description: + * Initialize the Battery Backed up SRAM driver. + * + * Input Parameters: + * devpath - the path to instantiate the files. + * sizes - Pointer to a any array of file sizes to create + * the last entry should be 0 + * A size of -1 will use all the remaining spaces + * + * Returned Value: + * Number of files created on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +int progmem_dump_initialize(char *devpath, int *sizes) +{ + int i; + int fcnt; + char devname[32]; + + int ret = OK; + + if (devpath == NULL) { + return -EINVAL; + } + + i = strlen(devpath); + + if (i == 0 || i > (int)sizeof(devname) - 3) { + return -EINVAL; + } + + memset(g_progmem, 0, sizeof(g_progmem)); + + fcnt = progmem_dump_probe(sizes, g_progmem); + + for (i = 0; i < fcnt && ret >= OK; i++) { + snprintf(devname, sizeof(devname), "%s%d", devpath, i); + ret = register_driver(devname, &progmem_dump_fops, 0666, &g_progmem[i]); + } + + return ret < OK ? ret : fcnt; +} + +/**************************************************************************** + * Function: progmem_dump_savepanic + * + * Description: + * Saves the panic context in a previously allocated PROGMEM file + * + * Input Parameters: + * fileno - the value returned by the ioctl GETDESC_IOCTL + * context - Pointer to a any array of bytes to save + * length - The length of the data pointed to byt context + * + * Returned Value: + * Length saved or negated errno. + * + * Assumptions: + * + ****************************************************************************/ + + +int progmem_dump_savepanic(int fileno, uint8_t *context, int length) +{ + struct progmemfh_s *pf; + int ret = -ENOSPC; + + /* On a bad day we could panic while panicking, (and we debug assert) + * this is a potential feeble attempt at only writing the first + * panic's context to the file + */ + + static bool once = false; + + if (!once) { + once = true; + + DEBUGASSERT(fileno > 0 && fileno < PROGMEM_DUMP_FILES); + + pf = g_progmem[fileno].pf; + + /* If the g_progmem has been nulled out we return ENXIO. + * + * As once ensures we will keep the first dump. Checking the time for + * 0 protects from over writing a previous crash dump that has not + * been saved to long term storage and erased. The dreaded reboot + * loop. + */ + + if (pf == NULL) { + ret = -ENXIO; + + } else if (progmem_check_erase((char *)&pf->lastwrite, + sizeof(pf->lastwrite))) { + /* Clamp length if too big */ + + if (length > (int)pf->len) { + length = pf->len; + } + + progmem_dump_internal_write(pf, (char *) context, 0, length); + + /* Seal the file */ + + progmem_dump_internal_close(pf); + ret = length; + } + + /* Write ulog file location to flash */ + pf = g_progmem[HARDFAULT_ULOG_FILENO].pf; + + if (pf == NULL) { + ret = -ENXIO; + + } else if (progmem_check_erase((char *)&pf->lastwrite, + sizeof(pf->lastwrite))) { + + progmem_dump_internal_write(pf, ulog_file_loc, 0, HARDFAULT_MAX_ULOG_FILE_LEN); + + /* Seal the file */ + + progmem_dump_internal_close(pf); + } + } + + return ret; +} + +#endif /* HAS_PROGMEM */ +#endif /* SYSTEMCMDS_HARDFAULT_LOG */ diff --git a/platforms/nuttx/src/px4/nxp/k66/include/px4_arch/micro_hal.h b/platforms/nuttx/src/px4/nxp/k66/include/px4_arch/micro_hal.h index 58d4421ba6..0e42f9629e 100644 --- a/platforms/nuttx/src/px4/nxp/k66/include/px4_arch/micro_hal.h +++ b/platforms/nuttx/src/px4/nxp/k66/include/px4_arch/micro_hal.h @@ -41,7 +41,7 @@ __BEGIN_DECLS // Fixme: using ?? #define PX4_BBSRAM_SIZE 2048 -#define PX4_BBSRAM_GETDESC_IOCTL 0 +#define PX4_HF_GETDESC_IOCTL 0 #define PX4_NUMBER_I2C_BUSES KINETIS_NI2C #define GPIO_OUTPUT_SET GPIO_OUTPUT_ONE diff --git a/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/micro_hal.h b/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/micro_hal.h index bd2719405b..a4e75958c8 100644 --- a/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/micro_hal.h +++ b/platforms/nuttx/src/px4/nxp/rt106x/include/px4_arch/micro_hal.h @@ -40,7 +40,7 @@ __BEGIN_DECLS #// Fixme: using ?? #define PX4_BBSRAM_SIZE 2048 -#define PX4_BBSRAM_GETDESC_IOCTL 0 +#define PX4_HF_GETDESC_IOCTL 0 #define PX4_NUMBER_I2C_BUSES 4 #define GPIO_OUTPUT_SET GPIO_OUTPUT_ONE diff --git a/platforms/nuttx/src/px4/nxp/s32k14x/include/px4_arch/micro_hal.h b/platforms/nuttx/src/px4/nxp/s32k14x/include/px4_arch/micro_hal.h index 83afbd8cf2..b18ed36ebe 100644 --- a/platforms/nuttx/src/px4/nxp/s32k14x/include/px4_arch/micro_hal.h +++ b/platforms/nuttx/src/px4/nxp/s32k14x/include/px4_arch/micro_hal.h @@ -41,7 +41,7 @@ __BEGIN_DECLS // Fixme: using ?? #define PX4_BBSRAM_SIZE 2048 -#define PX4_BBSRAM_GETDESC_IOCTL 0 +#define PX4_HF_GETDESC_IOCTL 0 #define PX4_NUMBER_I2C_BUSES 2 #define GPIO_OUTPUT_SET GPIO_OUTPUT_ONE diff --git a/platforms/nuttx/src/px4/nxp/s32k34x/include/px4_arch/micro_hal.h b/platforms/nuttx/src/px4/nxp/s32k34x/include/px4_arch/micro_hal.h index 89309062c3..fb2a3bcaed 100644 --- a/platforms/nuttx/src/px4/nxp/s32k34x/include/px4_arch/micro_hal.h +++ b/platforms/nuttx/src/px4/nxp/s32k34x/include/px4_arch/micro_hal.h @@ -41,7 +41,7 @@ __BEGIN_DECLS // Fixme: using ?? #define PX4_BBSRAM_SIZE 2048 -#define PX4_BBSRAM_GETDESC_IOCTL 0 +#define PX4_HF_GETDESC_IOCTL PROGMEM_DUMP_GETDESC_IOCTL #define PX4_NUMBER_I2C_BUSES 2 #define GPIO_OUTPUT_SET GPIO_OUTPUT_ONE @@ -93,6 +93,12 @@ __BEGIN_DECLS #define PX4_BUS_OFFSET 1 /* s32k3xx buses are 0 based and adjustment is needed */ +#define px4_savepanic(fileno, context, length) progmem_dump_savepanic(fileno, context, length) + +#if defined(CONFIG_ARCH_HAVE_PROGMEM) && defined(CONFIG_BOARD_CRASHDUMP) +# define HAS_PROGMEM 1 +#endif + #define px4_spibus_initialize(bus_num_1based) s32k3xx_lpspibus_initialize(PX4_BUS_NUMBER_FROM_PX4(bus_num_1based)) #define px4_i2cbus_initialize(bus_num_1based) s32k3xx_i2cbus_initialize(PX4_BUS_NUMBER_FROM_PX4(bus_num_1based)) diff --git a/platforms/nuttx/src/px4/rpi/rpi_common/include/px4_arch/micro_hal.h b/platforms/nuttx/src/px4/rpi/rpi_common/include/px4_arch/micro_hal.h index 1188b0704e..55471723dc 100644 --- a/platforms/nuttx/src/px4/rpi/rpi_common/include/px4_arch/micro_hal.h +++ b/platforms/nuttx/src/px4/rpi/rpi_common/include/px4_arch/micro_hal.h @@ -12,7 +12,7 @@ __BEGIN_DECLS // This will remove the errors of undefined PX4_BBSRAM_SIZE when logger module is activated. // Fixme: using ?? #define PX4_BBSRAM_SIZE 2048 -#define PX4_BBSRAM_GETDESC_IOCTL 0 +#define PX4_HF_GETDESC_IOCTL 0 // RP2040 doesn't really have a cpu register with unique id. // However, there is a function in pico-sdk which can provide @@ -49,8 +49,6 @@ __BEGIN_DECLS #define PX4_CPU_UUID_WORD32_FORMAT_SIZE (PX4_CPU_UUID_WORD32_LENGTH-1+(2*PX4_CPU_UUID_BYTE_LENGTH)+1) #define PX4_CPU_MFGUID_FORMAT_SIZE ((2*PX4_CPU_MFGUID_BYTE_LENGTH)+1) -#define px4_savepanic(fileno, context, length) (0) // Turn off px4_savepanic for rp2040 as it is not implemented in nuttx - #define PX4_BUS_OFFSET 1 /* RP2040 buses are 0 based and adjustment is needed */ #define px4_spibus_initialize(bus_num_1based) rp2040_spibus_initialize(PX4_BUS_NUMBER_FROM_PX4(bus_num_1based)) diff --git a/platforms/nuttx/src/px4/stm/stm32f1/include/px4_arch/micro_hal.h b/platforms/nuttx/src/px4/stm/stm32f1/include/px4_arch/micro_hal.h index 96f1205b77..4ef37a9542 100644 --- a/platforms/nuttx/src/px4/stm/stm32f1/include/px4_arch/micro_hal.h +++ b/platforms/nuttx/src/px4/stm/stm32f1/include/px4_arch/micro_hal.h @@ -43,7 +43,10 @@ __BEGIN_DECLS #if defined(CONFIG_STM32_STM32F4XXX) # include # define PX4_BBSRAM_SIZE STM32_BBSRAM_SIZE -# define PX4_BBSRAM_GETDESC_IOCTL STM32_BBSRAM_GETDESC_IOCTL +# define PX4_HF_GETDESC_IOCTL STM32_BBSRAM_GETDESC_IOCTL +# define HAS_BBSRAM CONFIG_STM32_BBSRAM +# define BBSRAM_FILE_COUNT CONFIG_STM32_BBSRAM_FILES +# define SAVE_CRASHDUMP CONFIG_STM32_SAVE_CRASHDUMP #endif #define PX4_NUMBER_I2C_BUSES STM32_NI2C #define PX4_ADC_INTERNAL_TEMP_SENSOR_CHANNEL 16 diff --git a/platforms/nuttx/src/px4/stm/stm32f3/include/px4_arch/micro_hal.h b/platforms/nuttx/src/px4/stm/stm32f3/include/px4_arch/micro_hal.h index 5c394050df..e43fabc2e3 100644 --- a/platforms/nuttx/src/px4/stm/stm32f3/include/px4_arch/micro_hal.h +++ b/platforms/nuttx/src/px4/stm/stm32f3/include/px4_arch/micro_hal.h @@ -43,7 +43,10 @@ __BEGIN_DECLS #if defined(CONFIG_STM32_STM32F4XXX) # include # define PX4_BBSRAM_SIZE STM32_BBSRAM_SIZE -# define PX4_BBSRAM_GETDESC_IOCTL STM32_BBSRAM_GETDESC_IOCTL +# define PX4_HF_GETDESC_IOCTL STM32_BBSRAM_GETDESC_IOCTL +# define HAS_BBSRAM CONFIG_STM32_BBSRAM +# define BBSRAM_FILE_COUNT CONFIG_STM32_BBSRAM_FILES +# define SAVE_CRASHDUMP CONFIG_STM32_SAVE_CRASHDUMP #endif #define PX4_NUMBER_I2C_BUSES STM32_NI2C #define PX4_ADC_INTERNAL_TEMP_SENSOR_CHANNEL 16 diff --git a/platforms/nuttx/src/px4/stm/stm32f4/include/px4_arch/micro_hal.h b/platforms/nuttx/src/px4/stm/stm32f4/include/px4_arch/micro_hal.h index edf02df263..d45a3add2b 100644 --- a/platforms/nuttx/src/px4/stm/stm32f4/include/px4_arch/micro_hal.h +++ b/platforms/nuttx/src/px4/stm/stm32f4/include/px4_arch/micro_hal.h @@ -43,7 +43,10 @@ __BEGIN_DECLS #if defined(CONFIG_STM32_STM32F4XXX) # include # define PX4_BBSRAM_SIZE STM32_BBSRAM_SIZE -# define PX4_BBSRAM_GETDESC_IOCTL STM32_BBSRAM_GETDESC_IOCTL +# define PX4_HF_GETDESC_IOCTL STM32_BBSRAM_GETDESC_IOCTL +# define HAS_BBSRAM CONFIG_STM32_BBSRAM +# define BBSRAM_FILE_COUNT CONFIG_STM32_BBSRAM_FILES +# define SAVE_CRASHDUMP CONFIG_STM32_SAVE_CRASHDUMP #endif #define PX4_NUMBER_I2C_BUSES STM32_NI2C #define PX4_ADC_INTERNAL_TEMP_SENSOR_CHANNEL 18 diff --git a/platforms/nuttx/src/px4/stm/stm32f7/include/px4_arch/micro_hal.h b/platforms/nuttx/src/px4/stm/stm32f7/include/px4_arch/micro_hal.h index 540c09a646..82ce68f8a5 100644 --- a/platforms/nuttx/src/px4/stm/stm32f7/include/px4_arch/micro_hal.h +++ b/platforms/nuttx/src/px4/stm/stm32f7/include/px4_arch/micro_hal.h @@ -46,7 +46,10 @@ __BEGIN_DECLS #if defined(CONFIG_STM32F7_BKPSRAM) # include # define PX4_BBSRAM_SIZE STM32F7_BBSRAM_SIZE -# define PX4_BBSRAM_GETDESC_IOCTL STM32F7_BBSRAM_GETDESC_IOCTL +# define PX4_HF_GETDESC_IOCTL STM32F7_BBSRAM_GETDESC_IOCTL +# define HAS_BBSRAM CONFIG_STM32F7_BBSRAM +# define BBSRAM_FILE_COUNT CONFIG_STM32F7_BBSRAM_FILES +# define SAVE_CRASHDUMP CONFIG_STM32F7_SAVE_CRASHDUMP #endif // CONFIG_STM32F7_BKPSRAM #define PX4_FLASH_BASE 0x08000000 #define PX4_NUMBER_I2C_BUSES STM32F7_NI2C diff --git a/platforms/nuttx/src/px4/stm/stm32h7/include/px4_arch/micro_hal.h b/platforms/nuttx/src/px4/stm/stm32h7/include/px4_arch/micro_hal.h index 93e80aaa49..9da7566a3a 100644 --- a/platforms/nuttx/src/px4/stm/stm32h7/include/px4_arch/micro_hal.h +++ b/platforms/nuttx/src/px4/stm/stm32h7/include/px4_arch/micro_hal.h @@ -55,9 +55,12 @@ __BEGIN_DECLS #include //include up_systemreset() which is included on stm32.h #include #define PX4_BBSRAM_SIZE STM32H7_BBSRAM_SIZE -#define PX4_BBSRAM_GETDESC_IOCTL STM32H7_BBSRAM_GETDESC_IOCTL +#define PX4_HF_GETDESC_IOCTL STM32H7_BBSRAM_GETDESC_IOCTL #define PX4_FLASH_BASE 0x08000000 #define PX4_NUMBER_I2C_BUSES STM32H7_NI2C +#define HAS_BBSRAM CONFIG_STM32H7_BBSRAM +#define BBSRAM_FILE_COUNT CONFIG_STM32H7_BBSRAM_FILES +#define SAVE_CRASHDUMP CONFIG_STM32H7_SAVE_CRASHDUMP int stm32h7_flash_lock(size_t addr); int stm32h7_flash_unlock(size_t addr); diff --git a/src/lib/systemlib/hardfault_log.h b/src/lib/systemlib/hardfault_log.h index 380732b498..574a2628ca 100644 --- a/src/lib/systemlib/hardfault_log.h +++ b/src/lib/systemlib/hardfault_log.h @@ -36,11 +36,18 @@ * Included Files ****************************************************************************/ #include +#include #include /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ + +#if defined(HAS_BBSRAM) + +#include +typedef struct bbsramd_s dump_s; + #define HARDFAULT_REBOOT_FILENO 0 #define HARDFAULT_REBOOT_PATH BBSRAM_PATH "" STRINGIFY(HARDFAULT_REBOOT_FILENO) #define HARDFAULT_ULOG_FILENO 3 @@ -86,6 +93,66 @@ BBSRAM_SIZE_FN4, /* For the Panic Log use rest of space */ \ 0 /* End of table marker */ \ } +#elif defined(HAS_PROGMEM) + +typedef struct progmem_s dump_s; + +#if CONFIG_ARCH_INTERRUPTSTACK <= 3 +# define PROGMEM_NUMBER_STACKS 1 +#else +# define PROGMEM_NUMBER_STACKS 2 +#endif +#define PROGMEM_DUMP_FIXED_ELEMENTS_SIZE (sizeof(info_s)) +#define PROGMEM_DUMP_LEFTOVER (PROGMEM_DUMP_STACK_SIZE-PROGMEM_DUMP_FIXED_ELEMENTS_SIZE) + +#define CONFIG_ISTACK_SIZE (PROGMEM_DUMP_LEFTOVER/PROGMEM_NUMBER_STACKS/sizeof(stack_word_t)) +#define CONFIG_USTACK_SIZE (PROGMEM_DUMP_LEFTOVER/PROGMEM_NUMBER_STACKS/sizeof(stack_word_t)) + +#define HARDFAULT_ULOG_FILENO 2 +#define HARDFAULT_ULOG_PATH PROGMEM_PATH "" STRINGIFY(HARDFAULT_ULOG_FILENO) +#define HARDFAULT_FILENO 3 +#define HARDFAULT_PATH PROGMEM_PATH "" STRINGIFY(HARDFAULT_FILENO) + +#define HARDFAULT_MAX_ULOG_FILE_LEN 64 /* must be large enough to store the full path to the log file */ + +#define PROGMEM_SIZE_FN0 384 /* greater then 2.5 times the size of vehicle_status_s */ +#define PROGMEM_SIZE_FN1 384 /* greater then 2.5 times the size of vehicle_status_s */ +#define PROGMEM_SIZE_FN2 HARDFAULT_MAX_ULOG_FILE_LEN +#define PROGMEM_SIZE_FN3 -1 + +/* The following guides in the amount of the user and interrupt stack + * data we can save. The amount of storage left will dictate the actual + * number of entries of the user stack data saved. If it is too big + * It will be truncated by the call to stm32_bbsram_savepanic + */ + +#define PROGMEM_USED ((5*PROGMEM_HEADER_SIZE)+(PROGMEM_SIZE_FN0+PROGMEM_SIZE_FN1+PROGMEM_SIZE_FN2+PROGMEM_SIZE_FN3)) +#define PROGMEM_REAMINING (PX4_PROGMEM_SIZE-PROGMEM_USED) +#if CONFIG_ARCH_INTERRUPTSTACK <= 3 +# define PROGMEM_NUMBER_STACKS 1 +#else +# define PROGMEM_NUMBER_STACKS 2 +#endif +#define PROGMEM_FIXED_ELEMENTS_SIZE (sizeof(info_s)) +#define PROGMEM_LEFTOVER (PROGMEM_REAMINING-PROGMEM_FIXED_ELEMENTS_SIZE) + +#define PROGMEM_FILE_COUNT 4 +/* The path to the Battery Backed up SRAM */ +#define PROGMEM_PATH "/mnt/hardfault" +/* The sizes of the files to create (-1) use rest of BBSRAM memory */ +#define PROGMEM_FILE_SIZES { \ + PROGMEM_SIZE_FN0, /* For Current Flight Parameters Copy A */ \ + PROGMEM_SIZE_FN1, /* For Current Flight Parameters Copy B */ \ + PROGMEM_SIZE_FN2, /* For the latest ULog file path */ \ + PROGMEM_SIZE_FN3, /* For the Panic Log use rest of space */ \ + 0 /* End of table marker */ \ + } +#else /* HAS_PROGMEM */ + +#define CONFIG_ISTACK_SIZE 0 +#define CONFIG_USTACK_SIZE 0 + +#endif /* For Assert keep this much of the file name*/ #define MAX_FILE_PATH_LENGTH 40 diff --git a/src/systemcmds/hardfault_log/hardfault_log.c b/src/systemcmds/hardfault_log/hardfault_log.c index 3f0b9ca8fe..d4e9ef09f5 100644 --- a/src/systemcmds/hardfault_log/hardfault_log.c +++ b/src/systemcmds/hardfault_log/hardfault_log.c @@ -54,12 +54,18 @@ #include #include +#ifdef HAS_BBSRAM #include +#endif #include #include #include +#ifdef HAS_PROGMEM +#include +#endif + #include "chip.h" #if defined(CONSTRAINED_FLASH_NO_HELP) @@ -224,7 +230,7 @@ static void identify(const char *caller) /**************************************************************************** * hardfault_get_desc ****************************************************************************/ -static int hardfault_get_desc(char *caller, struct bbsramd_s *desc, bool silent) +static int hardfault_get_desc(char *caller, dump_s *desc, bool silent) { int ret = -ENOENT; int fd = open(HARDFAULT_PATH, O_RDONLY); @@ -237,7 +243,7 @@ static int hardfault_get_desc(char *caller, struct bbsramd_s *desc, bool silent) } else { ret = -EIO; - int rv = ioctl(fd, PX4_BBSRAM_GETDESC_IOCTL, (unsigned long)((uintptr_t)desc)); + int rv = ioctl(fd, PX4_HF_GETDESC_IOCTL, (unsigned long)((uintptr_t)desc)); if (rv >= 0) { ret = fd; @@ -251,6 +257,39 @@ static int hardfault_get_desc(char *caller, struct bbsramd_s *desc, bool silent) return ret; } +#if HAS_PROGMEM +/**************************************************************************** + * hardfault_clear + ****************************************************************************/ +static int hardfault_clear(char *caller, bool silent) +{ + int ret = -ENOENT; + int fd = open(HARDFAULT_PATH, O_RDONLY); + int value = 1; + + if (fd < 0) { + if (!silent) { + identify(caller); + hfsyslog(LOG_INFO, "Failed to open Fault Log file to clear [%s] (%d)\n", HARDFAULT_PATH, fd); + } + + } else { + ret = -EIO; + int rv = ioctl(fd, PROGMEM_DUMP_CLEAR_IOCTL, (unsigned long)((uintptr_t)&value)); + + if (rv >= 0) { + ret = fd; + + } else { + identify(caller); + hfsyslog(LOG_INFO, "Failed to clear progmem sector (%d)\n", rv); + } + } + + return ret; +} +#endif + /**************************************************************************** * write_stack_detail ****************************************************************************/ @@ -518,7 +557,7 @@ static int write_user_stack_info(int fdout, info_s *pi, char *buffer, /**************************************************************************** * write_dump_info ****************************************************************************/ -static int write_dump_info(int fdout, info_s *info, struct bbsramd_s *desc, +static int write_dump_info(int fdout, info_s *info, dump_s *desc, char *buffer, unsigned int sz) { char fmtbuff[ TIME_FMT_LEN + 1]; @@ -859,7 +898,7 @@ static int hardfault_commit(char *caller) { int ret = -ENOENT; int state = -1; - struct bbsramd_s desc; + dump_s desc; char path[LOG_PATH_LEN + 1]; ret = hardfault_get_desc(caller, &desc, false); @@ -889,7 +928,7 @@ static int hardfault_commit(char *caller) if (fdout >= 0) { identify(caller); syslog(LOG_INFO, "Saving Fault Log file %s\n", path); - ret = hardfault_write(caller, fdout, HARDFAULT_FILE_FORMAT, true); + ret = hardfault_write(caller, fdout, HARDFAULT_FILE_FORMAT, false); identify(caller); hfsyslog(LOG_INFO, "Done saving Fault Log file\n"); @@ -916,6 +955,12 @@ static int hardfault_commit(char *caller) } } +#ifdef HAS_PROGMEM + // Clear flash sector to write new hardfault + hardfault_clear(caller, false); +#endif + ret = hardfault_rearm(caller); + close(fdout); } } @@ -931,7 +976,7 @@ static int hardfault_commit(char *caller) * hardfault_dowrite ****************************************************************************/ static int hardfault_dowrite(char *caller, int infd, int outfd, - struct bbsramd_s *desc, int format) + dump_s *desc, int format) { int ret = -ENOMEM; char *line = zalloc(OUT_BUFFER_LEN); @@ -1056,7 +1101,7 @@ __EXPORT int hardfault_rearm(char *caller) __EXPORT int hardfault_check_status(char *caller) { int state = -1; - struct bbsramd_s desc; + dump_s desc; int ret = hardfault_get_desc(caller, &desc, true); if (ret < 0) { @@ -1122,8 +1167,11 @@ __EXPORT int hardfault_increment_reboot(char *caller, bool reset) if (!reset) { if (read(fd, &count, sizeof(count)) != sizeof(count)) { + //Progmem could have an empty file hence we ignore this error +#ifndef HAS_PROGMEM ret = -EIO; close(fd); +#endif } else { lseek(fd, 0, SEEK_SET); @@ -1155,7 +1203,7 @@ __EXPORT int hardfault_increment_reboot(char *caller, bool reset) __EXPORT int hardfault_write(char *caller, int fd, int format, bool rearm) { - struct bbsramd_s desc; + dump_s desc; switch (format) {