Merge branch 'issue/15-safety-controller-hardening' into issue/18-Backup-RAM

This commit is contained in:
Mario Hüttel 2020-09-06 21:10:30 +02:00
commit c7ebe441c7
4 changed files with 123 additions and 37 deletions

View File

@ -30,6 +30,7 @@
#define CONCAT(x,y) x##y #define CONCAT(x,y) x##y
#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) #define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
#define wordsize_of(x) ((sizeof(x) / 4U) / ((sizeof(x) % 4U) ? 0U : 1U))
#define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define MIN(a,b) (((a) < (b)) ? (a) : (b))
#define MAX(a,b) (((a) > (b)) ? (a) : (b)) #define MAX(a,b) (((a) > (b)) ? (a) : (b))

View File

@ -124,10 +124,10 @@ enum config_override_entry_type {
/** /**
* @brief Weights of error flags. * @brief Weights of error flags.
*/ */
enum config_override_weight { enum config_weight {
SAFETY_MEMORY_CONFIG_WEIGTH_NONE = 0, /**< @brief This flag has no global error consequence, but might be respected by certain software modules. */ SAFETY_FLAG_CONFIG_WEIGHT_NONE = 0, /**< @brief This flag has no global error consequence, but might be respected by certain software modules. */
SAFETY_MEMORY_CONFIG_WEIGTH_PID = 1, /**< @brief This flag will force a stop of the temperature PID controller */ SAFETY_FLAG_CONFIG_WEIGHT_PID = 1, /**< @brief This flag will force a stop of the temperature PID controller */
SAFETY_MEMORY_CONFIG_WEIGTH_PANIC = 2, /**< @brief This flag will trigger the panic mode */ SAFETY_FLAG_CONFIG_WEIGHT_PANIC = 2, /**< @brief This flag will trigger the panic mode */
}; };
/** /**
@ -138,7 +138,7 @@ struct config_override {
union { union {
struct { struct {
uint8_t flag; uint8_t flag;
enum config_override_weight weight; enum config_weight weight;
} weight_override; } weight_override;
struct { struct {
uint8_t flag; uint8_t flag;

View File

@ -29,6 +29,7 @@
#include <reflow-controller/safety/safety-adc.h> #include <reflow-controller/safety/safety-adc.h>
#include <reflow-controller/stack-check.h> #include <reflow-controller/stack-check.h>
#include <helper-macros/helper-macros.h> #include <helper-macros/helper-macros.h>
#include <stm-periph/crc-unit.h>
#include <reflow-controller/systick.h> #include <reflow-controller/systick.h>
#include <reflow-controller/safety/fault.h> #include <reflow-controller/safety/fault.h>
#include <stm32/stm32f4xx.h> #include <stm32/stm32f4xx.h>
@ -69,15 +70,18 @@ struct analog_mon {
uint64_t timestamp; uint64_t timestamp;
}; };
#ifdef COUNT_OF struct safety_weight {
#undef COUNT_OF uint32_t start_dummy;
#endif enum config_weight weight;
enum safety_flag flag;
#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) volatile struct error_flag *flag_ptr;
uint32_t end_dummy;
};
#define ERR_FLAG_ENTRY(errflag, persistency) {.name=#errflag, .flag = (errflag), .error_state = false, .error_state_inv = true, .persistent = (persistency), .key = 0UL} #define ERR_FLAG_ENTRY(errflag, persistency) {.name=#errflag, .flag = (errflag), .error_state = false, .error_state_inv = true, .persistent = (persistency), .key = 0UL}
#define TIM_MON_ENTRY(mon, min, max, flag) {.name=#mon, .monitor = (mon), .associated_flag=(flag), .min_delta = (min), .max_delta = (max), .last = 0ULL, .enabled= false} #define TIM_MON_ENTRY(mon, min, max, flag) {.name=#mon, .monitor = (mon), .associated_flag=(flag), .min_delta = (min), .max_delta = (max), .last = 0ULL, .enabled= false}
#define ANA_MON_ENTRY(mon, min_value, max_value, flag) {.name=#mon, .monitor = (mon), .associated_flag=(flag), .min = (min_value), .max = (max_value), .value = 0.0f, .valid = false} #define ANA_MON_ENTRY(mon, min_value, max_value, flag) {.name=#mon, .monitor = (mon), .associated_flag=(flag), .min = (min_value), .max = (max_value), .value = 0.0f, .valid = false}
#define ERR_FLAG_WEIGHT_ENTRY(_flag, _weight) {.flag = (_flag), .flag_ptr = NULL, .weight = (_weight), .start_dummy = 0x11823344, .end_dummy = 0xAABBCCFD}
static volatile struct error_flag IN_SECTION(.ccm.data) flags[] = { static volatile struct error_flag IN_SECTION(.ccm.data) flags[] = {
ERR_FLAG_ENTRY(ERR_FLAG_MEAS_ADC_OFF, false), ERR_FLAG_ENTRY(ERR_FLAG_MEAS_ADC_OFF, false),
@ -112,6 +116,75 @@ static volatile struct analog_mon IN_SECTION(.ccm.data) analog_mons[] = {
ERR_FLAG_AMON_UC_TEMP), ERR_FLAG_AMON_UC_TEMP),
}; };
static const struct safety_weight default_flag_weights[] = {
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_OFF, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_WATCHDOG, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_UNSTABLE, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_OVERFLOW, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_TIMING_MEAS_ADC, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_TIMING_PID, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_AMON_UC_TEMP, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_AMON_VREF, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_STACK, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_SAFETY_ADC, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_SYSTICK, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_WTCHDG_FIRED, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_UNCAL, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_DEBUG, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_TIMING_MAIN_LOOP, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_SAFETY_MEM_CORRUPT, SAFETY_FLAG_CONFIG_WEIGHT_NONE),
};
static volatile struct safety_weight IN_SECTION(.ccm.bss) flag_weights[COUNT_OF(default_flag_weights)];
static uint32_t IN_SECTION(.ccm.data) flag_weight_crc;
static int flag_weight_table_crc_check(void)
{
/* Check the flag weight table */
crc_unit_reset();
crc_unit_input_array((uint32_t *)flag_weights, wordsize_of(flag_weights));
if (crc_unit_get_crc() != flag_weight_crc)
return -1;
return 0;
}
static volatile struct error_flag *find_error_flag(enum safety_flag flag)
{
uint32_t i;
volatile struct error_flag *ret = NULL;
for (i = 0; i < COUNT_OF(flags); i++) {
if (flags[i].flag == flag)
ret = &flags[i];
}
return ret;
}
/**
* @brief This function copies the safety weigths from flash ro RAM and computes the CRC
*/
static void init_safety_flag_weight_table_from_default(void)
{
uint32_t index;
volatile struct safety_weight *current_weight;
/* Copy the table */
memcpy((void *)flag_weights, default_flag_weights, wordsize_of(flag_weights));
/* Fill in the flag pointers */
for (index = 0; index < COUNT_OF(flag_weights); index++) {
current_weight = &flag_weights[index];
current_weight->flag_ptr = find_error_flag(current_weight->flag);
}
crc_unit_reset();
crc_unit_input_array((uint32_t*)flag_weights, wordsize_of(flag_weights));
flag_weight_crc = crc_unit_get_crc();
}
static bool error_flag_get_status(const volatile struct error_flag *flag) static bool error_flag_get_status(const volatile struct error_flag *flag)
{ {
if (flag->error_state == flag->error_state_inv) { if (flag->error_state == flag->error_state_inv) {
@ -147,19 +220,6 @@ static volatile struct timing_mon *find_timing_mon(enum timing_monitor mon)
return ret; return ret;
} }
static volatile struct error_flag *find_error_flag(enum safety_flag flag)
{
uint32_t i;
volatile struct error_flag *ret = NULL;
for (i = 0; i < COUNT_OF(flags); i++) {
if (flags[i].flag == flag)
ret = &flags[i];
}
return ret;
}
static void safety_controller_process_active_timing_mons() static void safety_controller_process_active_timing_mons()
{ {
uint32_t i; uint32_t i;
@ -178,7 +238,7 @@ static void safety_controller_process_active_timing_mons()
} }
} }
static void safety_controller_process_checks() static void safety_controller_process_monitor_checks()
{ {
static bool startup_completed = false; static bool startup_completed = false;
enum analog_monitor_status amon_state; enum analog_monitor_status amon_state;
@ -283,6 +343,12 @@ void safety_controller_init()
/* Trigger panic mode! */ /* Trigger panic mode! */
panic_mode(); panic_mode();
} }
/* This is usually done by the safety memory already. But, since this module also uses the CRC... */
crc_unit_init();
init_safety_flag_weight_table_from_default();
if (found_memory_state == SAFETY_MEMORY_INIT_CORRUPTED) if (found_memory_state == SAFETY_MEMORY_INIT_CORRUPTED)
safety_controller_report_error(ERR_FLAG_SAFETY_MEM_CORRUPT); safety_controller_report_error(ERR_FLAG_SAFETY_MEM_CORRUPT);
@ -354,35 +420,39 @@ static void safety_controller_handle_safety_adc()
} }
} }
static void safety_controller_handle_safety_memory_check(void) /**
* @brief Check the memory structures.
* @return 0 if okay, != 0 when an error was detected. PANIC mode shall be entered in this case.
*/
static int safety_controller_handle_memory_checks(void)
{ {
static uint64_t ts = 0; static uint64_t ts = 0;
enum safety_memory_state found_state; enum safety_memory_state found_state;
int panic_request = 0;
if (systick_ticks_have_passed(ts, 5000)) { if (systick_ticks_have_passed(ts, 1000)) {
ts = systick_get_global_tick(); ts = systick_get_global_tick();
/* Check the safety memory */
if (safety_memory_check()) { if (safety_memory_check()) {
safety_memory_reinit(&found_state); (void)safety_memory_reinit(&found_state);
if (found_state != SAFETY_MEMORY_INIT_VALID_MEMORY) { if (found_state != SAFETY_MEMORY_INIT_VALID_MEMORY) {
safety_controller_report_error(ERR_FLAG_SAFETY_MEM_CORRUPT); safety_controller_report_error(ERR_FLAG_SAFETY_MEM_CORRUPT);
} }
} }
panic_request = flag_weight_table_crc_check();
} }
return panic_request;
} }
int safety_controller_handle() static void safety_controller_do_systick_checking()
{ {
static uint64_t last_systick; static uint64_t last_systick;
static uint32_t same_systick_cnt = 0UL; static uint32_t same_systick_cnt = 0UL;
uint64_t systick; uint64_t systick;
int ret = 0;
safety_controller_check_stack();
safety_controller_handle_safety_adc();
safety_controller_handle_safety_memory_check();
systick = systick_get_global_tick(); systick = systick_get_global_tick();
if (systick == last_systick) { if (systick == last_systick) {
same_systick_cnt++; same_systick_cnt++;
@ -392,8 +462,24 @@ int safety_controller_handle()
same_systick_cnt = 0UL; same_systick_cnt = 0UL;
} }
last_systick = systick; last_systick = systick;
}
safety_controller_process_checks(); int safety_controller_handle()
{
int panic_requested;
int ret = 0;
safety_controller_check_stack();
safety_controller_handle_safety_adc();
panic_requested = safety_controller_handle_memory_checks();
/* Panic here. If our internal structures are broken, we cannot be sure of anything anymore */
if (panic_requested)
panic_mode();
safety_controller_do_systick_checking();
safety_controller_process_monitor_checks();
/* TODO: Check flags for PID and HALT */ /* TODO: Check flags for PID and HALT */
ret |= watchdog_ack(WATCHDOG_MAGIC_KEY); ret |= watchdog_ack(WATCHDOG_MAGIC_KEY);

View File

@ -19,11 +19,10 @@
*/ */
#include <reflow-controller/safety/safety-memory.h> #include <reflow-controller/safety/safety-memory.h>
#include <helper-macros/helper-macros.h>
#include <stm-periph/crc-unit.h> #include <stm-periph/crc-unit.h>
#include <stm-periph/backup-ram.h> #include <stm-periph/backup-ram.h>
#define wordsize_of(x) ((sizeof(x) / 4U) / ((sizeof(x) % 4U) ? 0U : 1U))
static int word_to_error_memory_entry(uint32_t entry_data, struct error_memory_entry *out) static int word_to_error_memory_entry(uint32_t entry_data, struct error_memory_entry *out)
{ {
int ret = 0; int ret = 0;