SPM: Add support for using watermarks to determine stack usage
New config option CONFIG_TFM_STACK_WATERMARKS (defaulted to OFF).
If set, when SPM initialises a partition, it sets every dword of its
stack to a fixed value. As the stack is used, these values will get
overwritten.
Add a new SPM function dump_used_stacks() that examines every
partition's stack looking for the watermark, deduces how much stack
has been used, and prints the stack usages (note that this will be an
underestimate if the partition happens to write the watermark value
to the stack). Ideally this should be called after TF-M has been
thoroughly exercised.
Currently disabled for isolation level 3, which needs more
investigation.
Change-Id: I1592a383790da9d49fddac00407d7bceaf312d47
Signed-off-by: Chris Brand <chris.brand@cypress.com>
diff --git a/secure_fw/spm/ffm/backend_ipc.c b/secure_fw/spm/ffm/backend_ipc.c
index b5b99b6..597016d 100644
--- a/secure_fw/spm/ffm/backend_ipc.c
+++ b/secure_fw/spm/ffm/backend_ipc.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2021-2022, Arm Limited. All rights reserved.
- * Copyright (c) 2021, Cypress Semiconductor Corporation. All rights reserved.
+ * Copyright (c) 2021-2022, Cypress Semiconductor Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -10,6 +10,7 @@
#include "critical_section.h"
#include "compiler_ext_defs.h"
#include "runtime_defs.h"
+#include "ffm/stack_watermark.h"
#include "spm_ipc.h"
#include "tfm_hal_isolation.h"
#include "tfm_hal_platform.h"
@@ -166,6 +167,8 @@
LOAD_ALLOCED_STACK_ADDR(p_pldi),
p_pldi->stack_size);
+ watermark_stack(p_pt);
+
prv_process_metadata(p_pt);
THRD_INIT(&p_pt->thrd, &p_pt->ctx_ctrl,
diff --git a/secure_fw/spm/ffm/backend_sfn.c b/secure_fw/spm/ffm/backend_sfn.c
index ef8d5f7..9218afc 100644
--- a/secure_fw/spm/ffm/backend_sfn.c
+++ b/secure_fw/spm/ffm/backend_sfn.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ * Copyright (c) 2022, Cypress Semiconductor Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -11,6 +12,7 @@
#include "runtime_defs.h"
#include "tfm_hal_platform.h"
#include "ffm/backend.h"
+#include "ffm/stack_watermark.h"
#include "load/partition_defs.h"
#include "load/service_defs.h"
#include "load/spm_load_api.h"
@@ -123,6 +125,8 @@
LOAD_ALLOCED_STACK_ADDR(p_pldi),
p_pldi->stack_size);
+ watermark_stack(p_pt);
+
/*
* Built-in partitions still have thread instances: NS Agent (TZ) and
* IDLE partition, and NS Agent (TZ) needs to be specific cared here.
diff --git a/secure_fw/spm/ffm/stack_watermark.c b/secure_fw/spm/ffm/stack_watermark.c
new file mode 100644
index 0000000..cfcfa97
--- /dev/null
+++ b/secure_fw/spm/ffm/stack_watermark.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2022, Cypress Semiconductor Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdint.h>
+#include "ffm/backend.h"
+#include "ffm/stack_watermark.h"
+#include "lists.h"
+#include "load/spm_load_api.h"
+#include "spm_ipc.h"
+#include "tfm_spm_log.h"
+
+/* Always output, regardless of log level.
+ * If you don't want output, don't build this code
+ */
+#define SPMLOG(x) tfm_hal_output_spm_log((x), sizeof(x))
+#define SPMLOG_VAL(x, y) spm_log_msgval((x), sizeof(x), y)
+
+#define STACK_WATERMARK_VAL 0xdeadbeef
+
+void watermark_stack(struct partition_t *p_pt)
+{
+ const struct partition_load_info_t *p_pldi = p_pt->p_ldinf;
+
+ for (int i = 0; i < p_pldi->stack_size / 4; i++) {
+ *((uint32_t *)LOAD_ALLOCED_STACK_ADDR(p_pldi) + i) = STACK_WATERMARK_VAL;
+ }
+}
+
+/* Returns the number of bytes of stack that have been used by the specified partition */
+static uint32_t used_stack(struct partition_t *p_pt)
+{
+ const struct partition_load_info_t *p_pldi = p_pt->p_ldinf;
+ uint32_t unused_words = 0;
+
+ for (const uint32_t *p = (uint32_t *)LOAD_ALLOCED_STACK_ADDR(p_pldi);
+ p < (uint32_t *)(LOAD_ALLOCED_STACK_ADDR(p_pldi) + p_pldi->stack_size);
+ p++) {
+ if (*p != STACK_WATERMARK_VAL) {
+ break;
+ }
+ unused_words++;
+ }
+
+ return p_pldi->stack_size - (unused_words * 4);
+}
+
+void dump_used_stacks(void)
+{
+ struct partition_t *p_pt;
+
+ SPMLOG("Used stack sizes report\r\n");
+ UNI_LIST_FOREACH(p_pt, PARTITION_LIST_ADDR, next) {
+ SPMLOG_VAL(" Partition id: ", p_pt->p_ldinf->pid);
+ SPMLOG_VAL(" Stack bytes: ", p_pt->p_ldinf->stack_size);
+ SPMLOG_VAL(" Stack bytes used: ", used_stack(p_pt));
+ }
+}
diff --git a/secure_fw/spm/ffm/stack_watermark.h b/secure_fw/spm/ffm/stack_watermark.h
new file mode 100644
index 0000000..1af1094
--- /dev/null
+++ b/secure_fw/spm/ffm/stack_watermark.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2022, Cypress Semiconductor Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __STACK_WATERMARK_H__
+#define __STACK_WATERMARK_H__
+
+#include "spm_ipc.h"
+
+#ifdef CONFIG_TFM_STACK_WATERMARKS
+void watermark_stack(struct partition_t *p_pt);
+void dump_used_stacks(void);
+#else
+#define watermark_stack(p_pt)
+#define dump_used_stacks()
+#endif
+
+#endif /* __STACK_WATERMARK_H__ */