diff --git a/include/nuttx/mm/mm.h b/include/nuttx/mm/mm.h index 2024ea8830caf..e8e978f65ad1f 100644 --- a/include/nuttx/mm/mm.h +++ b/include/nuttx/mm/mm.h @@ -312,6 +312,12 @@ struct mallinfo_task kmm_mallinfo_task(pid_t pid); # endif #endif +/* Functions contained in mm_check.c ****************************************/ + +#ifdef CONFIG_MM_HEALTH_CHECK +void mm_check_init(void); +#endif + /* Functions contained in mm_memdump.c **************************************/ void mm_memdump(FAR struct mm_heap_s *heap, pid_t pid); diff --git a/mm/Kconfig b/mm/Kconfig index d49409611ba02..0dcee2b546b5a 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -207,3 +207,34 @@ config MM_PANIC_ON_FAILURE depends on DEBUG_MM source "mm/iob/Kconfig" + +config MM_HEALTH_CHECK + bool "Memory health checks" + default n + ---help--- + If enabled, a worker will be used to perform + various health checks on the system memories. + + The checks include: + * Check all stacks for overflow. + * The the heap for any corruption. + +config MM_CHECK_PERIOD + int "Health check period" + default 1 + depends on MM_HEALTH_CHECK + ---help--- + The time period that the health checks will + be executed. In seconds. + +config MM_STACK_USAGE_SAFE_PERCENT + int "Safe stack usage" + default 90 + depends on MM_HEALTH_CHECK + ---help--- + The stack usage that is considered safe. In + percent. + + If the stack usage goes beyond this percentage, + the memory checks will assume that an overflow + has occured. diff --git a/mm/Makefile b/mm/Makefile index c34f5e1ba69b2..762206364861a 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -30,6 +30,7 @@ include shm/Make.defs include iob/Make.defs include circbuf/Make.defs include kasan/Make.defs +include mm_check/Make.defs BINDIR ?= bin diff --git a/mm/mm_check/Make.defs b/mm/mm_check/Make.defs new file mode 100644 index 0000000000000..c6f234f01ce4e --- /dev/null +++ b/mm/mm_check/Make.defs @@ -0,0 +1,30 @@ +############################################################################ +# mm/mm_check/Make.defs +# +# 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. +# +############################################################################ + +# Memory health checks. + +ifeq ($(CONFIG_MM_HEALTH_CHECK),y) +CSRCS += mm_check.c + +# Add the health checks to the build. + +DEPPATH += --dep-path mm_check +VPATH += :mm_check +endif diff --git a/mm/mm_check/mm_check.c b/mm/mm_check/mm_check.c new file mode 100644 index 0000000000000..ed78907e17a4d --- /dev/null +++ b/mm/mm_check/mm_check.c @@ -0,0 +1,94 @@ +/**************************************************************************** + * mm/mm_check/mm_check.c + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_SCHED_LPWORK +#error "Low priority work queue is required for the memory health checks." +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +static struct work_s work_q; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void mm_check_worker(FAR void * arg) +{ + UNUSED(arg); + + int i; + FAR struct tcb_s *tcb; + irqstate_t flags; + extern FAR struct tcb_s **g_pidhash; + extern volatile int g_npidhash; + + for (i = 0; i < g_npidhash; i++) + { + flags = enter_critical_section(); + + tcb = g_pidhash[i]; + + if (tcb && ((up_check_tcbstack(tcb) * 100 / tcb->adj_stack_size) + > CONFIG_MM_STACK_USAGE_SAFE_PERCENT)) + { + PANIC(); + } + + leave_critical_section(flags); + } + + kmm_checkcorruption(); + + work_queue(LPWORK, &work_q, mm_check_worker, NULL, + (CONFIG_MM_CHECK_PERIOD * CLOCKS_PER_SEC)); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void mm_check_init() +{ + work_queue(LPWORK, &work_q, mm_check_worker, NULL, + (CONFIG_MM_CHECK_PERIOD * CLOCKS_PER_SEC)); +} diff --git a/sched/init/nx_start.c b/sched/init/nx_start.c index 497bf298acfe9..38240075891c6 100644 --- a/sched/init/nx_start.c +++ b/sched/init/nx_start.c @@ -502,6 +502,12 @@ void nx_start(void) iob_initialize(); #endif +#ifdef CONFIG_MM_HEALTH_CHECK + /* Initialize the memory health checks. */ + + mm_check_init(); +#endif + /* Initialize the logic that determine unique process IDs. */ g_npidhash = 4;