lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260209-stm32_risab-v1-2-ef0b2b6a7e0a@foss.st.com>
Date: Mon, 9 Feb 2026 15:59:32 +0100
From: Gatien Chevallier <gatien.chevallier@...s.st.com>
To: Rob Herring <robh@...nel.org>, Krzysztof Kozlowski <krzk+dt@...nel.org>,
	Conor Dooley <conor+dt@...nel.org>, Maxime Coquelin
	<mcoquelin.stm32@...il.com>, Alexandre Torgue <alexandre.torgue@...s.st.com>
CC: <devicetree@...r.kernel.org>, <linux-stm32@...md-mailman.stormreply.com>,
	<linux-arm-kernel@...ts.infradead.org>, <linux-kernel@...r.kernel.org>,
	Gatien Chevallier <gatien.chevallier@...s.st.com>, Theo GOUREAU
	<theo.goureau-ext@...com>
Subject: [PATCH 2/7] soc: st: add RISAB dump debug driver

This driver creates an entry in the debugfs to dump RISAB memory
regions configurations.

Signed-off-by: Theo GOUREAU <theo.goureau-ext@...com>
Signed-off-by: Gatien Chevallier <gatien.chevallier@...s.st.com>
---
 MAINTAINERS                  |   1 +
 drivers/soc/Kconfig          |   1 +
 drivers/soc/Makefile         |   1 +
 drivers/soc/st/Kconfig       |  11 ++
 drivers/soc/st/Makefile      |   1 +
 drivers/soc/st/stm32_risab.c | 329 +++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 344 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index b9a1276e94a9..64a5b894c6b8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -25096,6 +25096,7 @@ STM32 SoC FIREWALL DRIVERS
 M:	Gatien Chevallier <gatien.chevallier@...s.st.com>
 S:	Maintained
 F:	Documentation/devicetree/bindings/soc/st/*risa*
+F:	drivers/soc/st/*risa*
 
 STM32 TIMER/LPTIMER DRIVERS
 M:	Fabrice Gasnier <fabrice.gasnier@...s.st.com>
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index a2d65adffb80..dfe5cec59262 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -24,6 +24,7 @@ source "drivers/soc/renesas/Kconfig"
 source "drivers/soc/rockchip/Kconfig"
 source "drivers/soc/samsung/Kconfig"
 source "drivers/soc/sophgo/Kconfig"
+source "drivers/soc/st/Kconfig"
 source "drivers/soc/sunxi/Kconfig"
 source "drivers/soc/tegra/Kconfig"
 source "drivers/soc/ti/Kconfig"
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index c9e689080ceb..894bd6ebaaa4 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -30,6 +30,7 @@ obj-y				+= renesas/
 obj-y				+= rockchip/
 obj-$(CONFIG_SOC_SAMSUNG)	+= samsung/
 obj-y				+= sophgo/
+obj-y				+= st/
 obj-y				+= sunxi/
 obj-$(CONFIG_ARCH_TEGRA)	+= tegra/
 obj-y				+= ti/
diff --git a/drivers/soc/st/Kconfig b/drivers/soc/st/Kconfig
new file mode 100644
index 000000000000..6c293af58f2a
--- /dev/null
+++ b/drivers/soc/st/Kconfig
@@ -0,0 +1,11 @@
+if ARCH_STM32 || COMPILE_TEST
+
+config STM32_RISAB
+	tristate "STM32 RISAB"
+	depends on (ARM64  || COMPILE_TEST) && DEBUG_FS
+	default y
+	help
+	  Say y to enable RISAB dump debug helper driver. This creates an entry
+	  in the debugfs to dump RISAB pages and blocks RIF configurations.
+
+endif # ARCH_STM32 || COMPILE_TEST
diff --git a/drivers/soc/st/Makefile b/drivers/soc/st/Makefile
new file mode 100644
index 000000000000..6b53f3eda801
--- /dev/null
+++ b/drivers/soc/st/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_STM32_RISAB) += stm32_risab.o
diff --git a/drivers/soc/st/stm32_risab.c b/drivers/soc/st/stm32_risab.c
new file mode 100644
index 000000000000..f1f0300817e2
--- /dev/null
+++ b/drivers/soc/st/stm32_risab.c
@@ -0,0 +1,329 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026, STMicroelectronics - All Rights Reserved
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+/*
+ * RISAB constants
+ */
+#define RISAB_NUMBER_OF_PAGES_MAX	32
+#define RISAB_BLOCKS_PER_PAGES		8
+#define RISAB_NUMBER_OF_CID		7
+#define RISAB_PAGE_SIZE			0x1000
+
+/*
+ * RISAB configuration register
+ */
+#define RISAB_CR	0x000
+#define RISAB_CR_SRWIAD	BIT(31)
+#define RISAB_CR_GLOCK	BIT(0)
+
+/*
+ * RISAB configuration lock register
+ */
+#define RISAB_RCFGLOCKR	0x010
+
+/*
+ * RISAB page y=0..31 security and privileged configuration registers
+ */
+#define RISAB_PG_SECCFGR(y)	(0x100 + 0x4 * (y))
+#define RISAB_PG_PRIVCFGR(y)	(0x200 + 0x4 * (y))
+#define RISAB_PG_C2PRIVCFGR(y)	(0x600 + 0x4 * (y))
+
+/*
+ * RISAB compartment x=0..6 privilege, read and write configuration registers
+ */
+#define RISAB_CIDPRIVCFGR(x)	(0x800 + 0x20 * (x))
+#define RISAB_CIDRDCFGR(x)	(0x808 + 0x20 * (x))
+#define RISAB_CIDWRCFGR(x)	(0x810 + 0x20 * (x))
+
+/*
+ * RISAB page y=0..31 CID configuration registers
+ */
+#define RISAB_PG_CIDCFGR(y)		(0xA00 + 0x4 * (y))
+#define RISAB_PG_CIDCFGR_DCCID_MASK	GENMASK(6, 4)
+#define RISAB_PG_CIDCFGR_DCEN		BIT(2)
+#define RISAB_PG_CIDCFGR_CFEN		BIT(0)
+
+/*
+ * RISAB hardware configuration registers
+ */
+#define RISAB_HWCFGR1				0xFF0
+#define RISAB_HWCFGR1_LOG_NUM_PAGE_MASK		GENMASK(27, 24)
+#define RISAB_HWCFGR1_LOG_NUM_PAGE_SHIFT	24
+
+struct risab_debug_data {
+	bool sec[RISAB_BLOCKS_PER_PAGES];
+	bool priv[RISAB_BLOCKS_PER_PAGES];
+	bool c2priv[RISAB_BLOCKS_PER_PAGES];
+	u8 dccid;
+	bool dcen;
+	bool cfen;
+};
+
+struct risab_generic_debug_data {
+	bool srwiad;
+	bool glock;
+	bool rlock[RISAB_NUMBER_OF_PAGES_MAX];
+	bool ppriv[RISAB_NUMBER_OF_CID][RISAB_NUMBER_OF_PAGES_MAX];
+	bool prden[RISAB_NUMBER_OF_CID][RISAB_NUMBER_OF_PAGES_MAX];
+	bool pwren[RISAB_NUMBER_OF_CID][RISAB_NUMBER_OF_PAGES_MAX];
+};
+
+struct risab_pdata {
+	void __iomem *base;
+	struct device *dev;
+	struct dentry *dbg_entry;
+	u32 risab_map_base;
+	struct clk *clk;
+	u32 nb_pages;
+};
+
+static void stm32_risab_fill_dev_dbg_entry(struct risab_pdata *pdata,
+					   struct risab_debug_data *dbg_entry, int page)
+{
+	u32 risab_pg_c2privcfgr = readl_relaxed(pdata->base + RISAB_PG_C2PRIVCFGR(page));
+	u32 risab_pg_privcfgr = readl_relaxed(pdata->base + RISAB_PG_PRIVCFGR(page));
+	u32 risab_pg_seccfgr = readl_relaxed(pdata->base + RISAB_PG_SECCFGR(page));
+	u32 risab_pg_cidcfgr = readl_relaxed(pdata->base + RISAB_PG_CIDCFGR(page));
+	int block;
+
+	for (block = 0; block < RISAB_BLOCKS_PER_PAGES; block++) {
+		dbg_entry->sec[block] = risab_pg_seccfgr & BIT(block);
+		dbg_entry->priv[block] = risab_pg_privcfgr & BIT(block);
+		dbg_entry->c2priv[block] = risab_pg_c2privcfgr & BIT(block);
+	}
+
+	dbg_entry->dccid = FIELD_GET(RISAB_PG_CIDCFGR_DCCID_MASK, risab_pg_cidcfgr);
+	dbg_entry->dcen = risab_pg_cidcfgr & RISAB_PG_CIDCFGR_DCEN;
+	dbg_entry->cfen = risab_pg_cidcfgr & RISAB_PG_CIDCFGR_CFEN;
+}
+
+static void stm32_risab_fill_dev_generic_dbg_entry(struct risab_pdata *pdata,
+						   struct risab_generic_debug_data *dbg_entry)
+{
+	u32 risab_rcfglockr = readl_relaxed(pdata->base + RISAB_RCFGLOCKR);
+	u32 risab_cr = readl_relaxed(pdata->base + RISAB_CR);
+	int page, compartment;
+
+	dbg_entry->srwiad = risab_cr & RISAB_CR_SRWIAD;
+	dbg_entry->glock = risab_cr & RISAB_CR_GLOCK;
+
+	for (page = 0; page < pdata->nb_pages; page++)
+		dbg_entry->rlock[page] = risab_rcfglockr & BIT(page);
+
+	for (compartment = 0; compartment < RISAB_NUMBER_OF_CID; compartment++) {
+		u32 risab_cidprivcfgr = readl_relaxed(pdata->base + RISAB_CIDPRIVCFGR(compartment));
+		u32 risab_cidrdcfgr = readl_relaxed(pdata->base + RISAB_CIDRDCFGR(compartment));
+		u32 risab_cidwrcfgr = readl_relaxed(pdata->base + RISAB_CIDWRCFGR(compartment));
+
+		for (page = 0; page < pdata->nb_pages; page++) {
+			dbg_entry->ppriv[compartment][page] = risab_cidprivcfgr & BIT(page);
+			dbg_entry->prden[compartment][page] = risab_cidrdcfgr & BIT(page);
+			dbg_entry->pwren[compartment][page] = risab_cidwrcfgr & BIT(page);
+		}
+	}
+}
+
+static int stm32_risab_conf_dump_show(struct seq_file *s, void *data)
+{
+	struct risab_pdata *pdata = (struct risab_pdata *)s->private;
+	struct risab_generic_debug_data generic_dbg_entry;
+	struct risab_debug_data dbg_entry;
+	int ret, page, compartment, block;
+
+	ret = clk_prepare_enable(pdata->clk);
+	if (ret) {
+		dev_err(pdata->dev, "Couldn't enable RISAB clock");
+		return ret;
+	}
+
+	stm32_risab_fill_dev_generic_dbg_entry(pdata, &generic_dbg_entry);
+
+	seq_puts(s, "=============================================\n");
+	seq_printf(s, "        RISAB dump (%s)\n", pdata->dev->of_node->full_name);
+	seq_puts(s, "=============================================\n");
+
+	seq_printf(s, "Secure read/write illegal access disable (SRWIAD): %d.\n",
+		   generic_dbg_entry.srwiad);
+	seq_printf(s, "Global lock (GLOCK): %d.\n", generic_dbg_entry.glock);
+
+	seq_puts(s, "| Page                       |");
+	seq_puts(s, "| Res. |");
+	seq_puts(s, "|     priv. (p) read (r) write (w) per compartment      |");
+	seq_puts(s, "| Delegated |");
+	seq_puts(s, "|    CID    |");
+	seq_puts(s, "| secure (s) default priv. (p) compartment2 priv. (P) per block |\n");
+
+	seq_puts(s, "|     start add.  end add.   |");
+	seq_puts(s, "| lock |");
+	seq_puts(s, "| CID0  | CID1  | CID2  | CID3  | CID4  | CID5  | CID6  |");
+	seq_puts(s, "| conf. CID |");
+	seq_puts(s, "| filtering |");
+	seq_puts(s, "| blck0 | blck1 | blck2 | blck3 | blck4 | blck5 | blck6 | blck7 |\n");
+
+	for (page = 0; page < pdata->nb_pages; page++) {
+		stm32_risab_fill_dev_dbg_entry(pdata, &dbg_entry, page);
+		seq_printf(s, "| %2d  0x%08x  0x%08x |",
+			   page,
+			   pdata->risab_map_base + page * RISAB_PAGE_SIZE,
+			   pdata->risab_map_base + (page + 1) * RISAB_PAGE_SIZE - 1
+		);
+		seq_printf(s, "| %3s  |", generic_dbg_entry.rlock[page] ? "Yes" : "No");
+		for (compartment = 0; compartment < RISAB_NUMBER_OF_CID; compartment++) {
+			seq_printf(s, "| %1s %1s %1s ",
+				   generic_dbg_entry.ppriv[compartment][page] ? "p" : " ",
+				   generic_dbg_entry.prden[compartment][page] ? "r" : " ",
+				   generic_dbg_entry.pwren[compartment][page] ? "w" : " "
+			);
+		}
+
+		if (dbg_entry.dcen)
+			seq_printf(s, "||  0x%04x   |", dbg_entry.dccid);
+		else
+			seq_puts(s, "|| disabled  |");
+
+		seq_printf(s, "| %-9s |", dbg_entry.cfen ? "enabled" : "disabled");
+		for (block = 0; block < RISAB_BLOCKS_PER_PAGES; block++) {
+			seq_printf(s, "| %1s %1s %1s ",
+				   dbg_entry.sec[block] ? "s" : " ",
+				   dbg_entry.priv[block] && !dbg_entry.cfen ? "p" : " ",
+				   dbg_entry.c2priv[block] ? "P" : " "
+			);
+		}
+		seq_puts(s, "|\n");
+	}
+
+	clk_disable_unprepare(pdata->clk);
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(stm32_risab_conf_dump);
+
+static int stm32_risab_register_debugfs(struct risab_pdata *pdata)
+{
+	struct dentry *root = NULL;
+
+	root = debugfs_lookup("stm32_firewall", NULL);
+	if (!root)
+		root = debugfs_create_dir("stm32_firewall", NULL);
+
+	if (IS_ERR(root))
+		return PTR_ERR(root);
+
+	pdata->dbg_entry = debugfs_create_file(dev_name(pdata->dev), 0444,
+					       root, pdata, &stm32_risab_conf_dump_fops);
+
+	return 0;
+}
+
+static int stm32_risab_get_nb_pages(struct risab_pdata *pdata)
+{
+	u32 risab_hwcfgr1, nb_pages_shift;
+	int ret, nb_page;
+
+	ret = clk_prepare_enable(pdata->clk);
+	if (ret) {
+		dev_err(pdata->dev, "Failed to enable clk: %d\n", ret);
+		return ret;
+	}
+
+	risab_hwcfgr1 = readl_relaxed(pdata->base + RISAB_HWCFGR1);
+	nb_pages_shift = FIELD_GET(RISAB_HWCFGR1_LOG_NUM_PAGE_MASK,
+				   risab_hwcfgr1);
+	nb_page = BIT(nb_pages_shift);
+
+	if (nb_page > RISAB_NUMBER_OF_PAGES_MAX) {
+		dev_err(pdata->dev, "RISAB number of pages is greater than %d",
+			RISAB_NUMBER_OF_PAGES_MAX);
+		ret = -EINVAL;
+		goto err_clk_disable;
+	}
+
+	ret = nb_page;
+
+err_clk_disable:
+	clk_disable_unprepare(pdata->clk);
+
+	return ret;
+}
+
+static int stm32_risab_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct risab_pdata *pdata;
+	void __iomem *mmio;
+	int err, nb_pages;
+	struct clk *clk;
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	mmio =  devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(mmio))
+		return PTR_ERR(mmio);
+
+	clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(clk))
+		return dev_err_probe(&pdev->dev, PTR_ERR(clk), "Failed to get clk\n");
+
+	pdata->base = mmio;
+	pdata->clk = clk;
+	pdata->dev = &pdev->dev;
+
+	err = of_property_read_u32(np, "st,mem-map", &pdata->risab_map_base);
+	if (err) {
+		return dev_err_probe(&pdev->dev, err,
+				     "Couldn't read the memory range covered by the RISAB\n");
+	}
+
+	nb_pages = stm32_risab_get_nb_pages(pdata);
+	if (nb_pages < 0)
+		return dev_err_probe(&pdev->dev, nb_pages, "Couldn't read RISAB number of pages\n");
+
+	pdata->nb_pages = nb_pages;
+
+	platform_set_drvdata(pdev, pdata);
+
+	return stm32_risab_register_debugfs(pdata);
+}
+
+static void stm32_risab_remove(struct platform_device *pdev)
+{
+	struct risab_pdata *pdata = platform_get_drvdata(pdev);
+
+	debugfs_remove(pdata->dbg_entry);
+}
+
+static const struct of_device_id stm32_risab_match[] = {
+	{ .compatible = "st,stm32mp25-risab", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, stm32_risab_match);
+
+static struct platform_driver stm32_risab_driver = {
+	.probe  = stm32_risab_probe,
+	.remove = stm32_risab_remove,
+	.driver = {
+		.name = "stm32-risab",
+		.of_match_table = stm32_risab_match,
+	},
+};
+module_platform_driver(stm32_risab_driver);
+
+MODULE_AUTHOR("Gatien Chevallier <gatien.chevallier@...s.st.com>");
+MODULE_LICENSE("GPL");

-- 
2.43.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ