Skip to content

Commit 5c9668c

Browse files
GseoCAlexandre Torgue
authored andcommitted
firewall: introduce stm32_firewall framework
Introduce a STM32 firewall framework that offers to firewall consumers different firewall services such as the ability to check their access rights against their firewall controller(s). The STM32 firewall framework offers a generic API for STM32 firewall controllers that is defined in their drivers to best fit the specificity of each firewall. There are various types of firewalls: -Peripheral firewalls that filter accesses to peripherals -Memory firewalls that filter accesses to memories or memory regions -No type for undefined type of firewall Signed-off-by: Gatien Chevallier <[email protected]> Signed-off-by: Alexandre Torgue <[email protected]>
1 parent c1c6765 commit 5c9668c

File tree

8 files changed

+537
-0
lines changed

8 files changed

+537
-0
lines changed

MAINTAINERS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20811,6 +20811,11 @@ T: git git://linuxtv.org/media_tree.git
2081120811
F: Documentation/devicetree/bindings/media/i2c/st,st-mipid02.yaml
2081220812
F: drivers/media/i2c/st-mipid02.c
2081320813

20814+
ST STM32 FIREWALL
20815+
M: Gatien Chevallier <[email protected]>
20816+
S: Maintained
20817+
F: drivers/bus/stm32_firewall.c
20818+
2081420819
ST STM32 I2C/SMBUS DRIVER
2081520820
M: Pierre-Yves MORDRET <[email protected]>
2081620821
M: Alain Volmat <[email protected]>

arch/arm/mach-stm32/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ menuconfig ARCH_STM32
1212
select PINCTRL
1313
select RESET_CONTROLLER
1414
select STM32_EXTI
15+
select STM32_FIREWALL
1516
help
1617
Support for STMicroelectronics STM32 processors.
1718

arch/arm64/Kconfig.platforms

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ config ARCH_STM32
305305
select ARM_SMC_MBOX
306306
select ARM_SCMI_PROTOCOL
307307
select COMMON_CLK_SCMI
308+
select STM32_FIREWALL
308309
help
309310
This enables support for ARMv8 based STMicroelectronics
310311
STM32 family, including:

drivers/bus/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,16 @@ config QCOM_SSC_BLOCK_BUS
163163
i2c/spi/uart controllers, a hexagon core, and a clock controller
164164
which provides clocks for the above.
165165

166+
config STM32_FIREWALL
167+
bool "STM32 Firewall framework"
168+
depends on (ARCH_STM32 || COMPILE_TEST) && OF
169+
select OF_DYNAMIC
170+
help
171+
Say y to enable STM32 firewall framework and its services. Firewall
172+
controllers will be able to register to the framework. Access for
173+
hardware resources linked to a firewall controller can be requested
174+
through this STM32 framework.
175+
166176
config SUN50I_DE2_BUS
167177
bool "Allwinner A64 DE2 Bus Driver"
168178
default ARM64

drivers/bus/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ obj-$(CONFIG_OMAP_INTERCONNECT) += omap_l3_smx.o omap_l3_noc.o
2626
obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o
2727
obj-$(CONFIG_QCOM_EBI2) += qcom-ebi2.o
2828
obj-$(CONFIG_QCOM_SSC_BLOCK_BUS) += qcom-ssc-block-bus.o
29+
obj-$(CONFIG_STM32_FIREWALL) += stm32_firewall.o
2930
obj-$(CONFIG_SUN50I_DE2_BUS) += sun50i-de2.o
3031
obj-$(CONFIG_SUNXI_RSB) += sunxi-rsb.o
3132
obj-$(CONFIG_OF) += simple-pm-bus.o

drivers/bus/stm32_firewall.c

Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright (C) 2023, STMicroelectronics - All Rights Reserved
4+
*/
5+
6+
#include <linux/bitfield.h>
7+
#include <linux/bits.h>
8+
#include <linux/bus/stm32_firewall_device.h>
9+
#include <linux/device.h>
10+
#include <linux/err.h>
11+
#include <linux/init.h>
12+
#include <linux/io.h>
13+
#include <linux/kernel.h>
14+
#include <linux/module.h>
15+
#include <linux/of.h>
16+
#include <linux/of_platform.h>
17+
#include <linux/platform_device.h>
18+
#include <linux/types.h>
19+
#include <linux/slab.h>
20+
21+
#include "stm32_firewall.h"
22+
23+
/* Corresponds to STM32_FIREWALL_MAX_EXTRA_ARGS + firewall ID */
24+
#define STM32_FIREWALL_MAX_ARGS (STM32_FIREWALL_MAX_EXTRA_ARGS + 1)
25+
26+
static LIST_HEAD(firewall_controller_list);
27+
static DEFINE_MUTEX(firewall_controller_list_lock);
28+
29+
/* Firewall device API */
30+
31+
int stm32_firewall_get_firewall(struct device_node *np, struct stm32_firewall *firewall,
32+
unsigned int nb_firewall)
33+
{
34+
struct stm32_firewall_controller *ctrl;
35+
struct of_phandle_iterator it;
36+
unsigned int i, j = 0;
37+
int err;
38+
39+
if (!firewall || !nb_firewall)
40+
return -EINVAL;
41+
42+
/* Parse property with phandle parsed out */
43+
of_for_each_phandle(&it, err, np, "access-controllers", "#access-controller-cells", 0) {
44+
struct of_phandle_args provider_args;
45+
struct device_node *provider = it.node;
46+
const char *fw_entry;
47+
bool match = false;
48+
49+
if (err) {
50+
pr_err("Unable to get access-controllers property for node %s\n, err: %d",
51+
np->full_name, err);
52+
of_node_put(provider);
53+
return err;
54+
}
55+
56+
if (j > nb_firewall) {
57+
pr_err("Too many firewall controllers");
58+
of_node_put(provider);
59+
return -EINVAL;
60+
}
61+
62+
provider_args.args_count = of_phandle_iterator_args(&it, provider_args.args,
63+
STM32_FIREWALL_MAX_ARGS);
64+
65+
/* Check if the parsed phandle corresponds to a registered firewall controller */
66+
mutex_lock(&firewall_controller_list_lock);
67+
list_for_each_entry(ctrl, &firewall_controller_list, entry) {
68+
if (ctrl->dev->of_node->phandle == it.phandle) {
69+
match = true;
70+
firewall[j].firewall_ctrl = ctrl;
71+
break;
72+
}
73+
}
74+
mutex_unlock(&firewall_controller_list_lock);
75+
76+
if (!match) {
77+
firewall[j].firewall_ctrl = NULL;
78+
pr_err("No firewall controller registered for %s\n", np->full_name);
79+
of_node_put(provider);
80+
return -ENODEV;
81+
}
82+
83+
err = of_property_read_string_index(np, "access-controller-names", j, &fw_entry);
84+
if (err == 0)
85+
firewall[j].entry = fw_entry;
86+
87+
/* Handle the case when there are no arguments given along with the phandle */
88+
if (provider_args.args_count < 0 ||
89+
provider_args.args_count > STM32_FIREWALL_MAX_ARGS) {
90+
of_node_put(provider);
91+
return -EINVAL;
92+
} else if (provider_args.args_count == 0) {
93+
firewall[j].extra_args_size = 0;
94+
firewall[j].firewall_id = U32_MAX;
95+
j++;
96+
continue;
97+
}
98+
99+
/* The firewall ID is always the first argument */
100+
firewall[j].firewall_id = provider_args.args[0];
101+
102+
/* Extra args start at the second argument */
103+
for (i = 0; i < provider_args.args_count - 1; i++)
104+
firewall[j].extra_args[i] = provider_args.args[i + 1];
105+
106+
/* Remove the firewall ID arg that is not an extra argument */
107+
firewall[j].extra_args_size = provider_args.args_count - 1;
108+
109+
j++;
110+
}
111+
112+
return 0;
113+
}
114+
EXPORT_SYMBOL_GPL(stm32_firewall_get_firewall);
115+
116+
int stm32_firewall_grant_access(struct stm32_firewall *firewall)
117+
{
118+
struct stm32_firewall_controller *firewall_controller;
119+
120+
if (!firewall || firewall->firewall_id == U32_MAX)
121+
return -EINVAL;
122+
123+
firewall_controller = firewall->firewall_ctrl;
124+
125+
if (!firewall_controller)
126+
return -ENODEV;
127+
128+
return firewall_controller->grant_access(firewall_controller, firewall->firewall_id);
129+
}
130+
EXPORT_SYMBOL_GPL(stm32_firewall_grant_access);
131+
132+
int stm32_firewall_grant_access_by_id(struct stm32_firewall *firewall, u32 subsystem_id)
133+
{
134+
struct stm32_firewall_controller *firewall_controller;
135+
136+
if (!firewall || subsystem_id == U32_MAX || firewall->firewall_id == U32_MAX)
137+
return -EINVAL;
138+
139+
firewall_controller = firewall->firewall_ctrl;
140+
141+
if (!firewall_controller)
142+
return -ENODEV;
143+
144+
return firewall_controller->grant_access(firewall_controller, subsystem_id);
145+
}
146+
EXPORT_SYMBOL_GPL(stm32_firewall_grant_access_by_id);
147+
148+
void stm32_firewall_release_access(struct stm32_firewall *firewall)
149+
{
150+
struct stm32_firewall_controller *firewall_controller;
151+
152+
if (!firewall || firewall->firewall_id == U32_MAX) {
153+
pr_debug("Incorrect arguments when releasing a firewall access\n");
154+
return;
155+
}
156+
157+
firewall_controller = firewall->firewall_ctrl;
158+
159+
if (!firewall_controller) {
160+
pr_debug("No firewall controller to release\n");
161+
return;
162+
}
163+
164+
firewall_controller->release_access(firewall_controller, firewall->firewall_id);
165+
}
166+
EXPORT_SYMBOL_GPL(stm32_firewall_release_access);
167+
168+
void stm32_firewall_release_access_by_id(struct stm32_firewall *firewall, u32 subsystem_id)
169+
{
170+
struct stm32_firewall_controller *firewall_controller;
171+
172+
if (!firewall || subsystem_id == U32_MAX || firewall->firewall_id == U32_MAX) {
173+
pr_debug("Incorrect arguments when releasing a firewall access");
174+
return;
175+
}
176+
177+
firewall_controller = firewall->firewall_ctrl;
178+
179+
if (!firewall_controller) {
180+
pr_debug("No firewall controller to release");
181+
return;
182+
}
183+
184+
firewall_controller->release_access(firewall_controller, subsystem_id);
185+
}
186+
EXPORT_SYMBOL_GPL(stm32_firewall_release_access_by_id);
187+
188+
/* Firewall controller API */
189+
190+
int stm32_firewall_controller_register(struct stm32_firewall_controller *firewall_controller)
191+
{
192+
struct stm32_firewall_controller *ctrl;
193+
194+
if (!firewall_controller)
195+
return -ENODEV;
196+
197+
pr_info("Registering %s firewall controller\n", firewall_controller->name);
198+
199+
mutex_lock(&firewall_controller_list_lock);
200+
list_for_each_entry(ctrl, &firewall_controller_list, entry) {
201+
if (ctrl == firewall_controller) {
202+
pr_debug("%s firewall controller already registered\n",
203+
firewall_controller->name);
204+
mutex_unlock(&firewall_controller_list_lock);
205+
return 0;
206+
}
207+
}
208+
list_add_tail(&firewall_controller->entry, &firewall_controller_list);
209+
mutex_unlock(&firewall_controller_list_lock);
210+
211+
return 0;
212+
}
213+
EXPORT_SYMBOL_GPL(stm32_firewall_controller_register);
214+
215+
void stm32_firewall_controller_unregister(struct stm32_firewall_controller *firewall_controller)
216+
{
217+
struct stm32_firewall_controller *ctrl;
218+
bool controller_removed = false;
219+
220+
if (!firewall_controller) {
221+
pr_debug("Null reference while unregistering firewall controller\n");
222+
return;
223+
}
224+
225+
mutex_lock(&firewall_controller_list_lock);
226+
list_for_each_entry(ctrl, &firewall_controller_list, entry) {
227+
if (ctrl == firewall_controller) {
228+
controller_removed = true;
229+
list_del_init(&ctrl->entry);
230+
break;
231+
}
232+
}
233+
mutex_unlock(&firewall_controller_list_lock);
234+
235+
if (!controller_removed)
236+
pr_debug("There was no firewall controller named %s to unregister\n",
237+
firewall_controller->name);
238+
}
239+
EXPORT_SYMBOL_GPL(stm32_firewall_controller_unregister);
240+
241+
int stm32_firewall_populate_bus(struct stm32_firewall_controller *firewall_controller)
242+
{
243+
struct stm32_firewall *firewalls;
244+
struct device_node *child;
245+
struct device *parent;
246+
unsigned int i;
247+
int len;
248+
int err;
249+
250+
parent = firewall_controller->dev;
251+
252+
dev_dbg(parent, "Populating %s system bus\n", dev_name(firewall_controller->dev));
253+
254+
for_each_available_child_of_node(dev_of_node(parent), child) {
255+
/* The access-controllers property is mandatory for firewall bus devices */
256+
len = of_count_phandle_with_args(child, "access-controllers",
257+
"#access-controller-cells");
258+
if (len <= 0) {
259+
of_node_put(child);
260+
return -EINVAL;
261+
}
262+
263+
firewalls = kcalloc(len, sizeof(*firewalls), GFP_KERNEL);
264+
if (!firewalls) {
265+
of_node_put(child);
266+
return -ENOMEM;
267+
}
268+
269+
err = stm32_firewall_get_firewall(child, firewalls, (unsigned int)len);
270+
if (err) {
271+
kfree(firewalls);
272+
of_node_put(child);
273+
return err;
274+
}
275+
276+
for (i = 0; i < len; i++) {
277+
if (firewall_controller->grant_access(firewall_controller,
278+
firewalls[i].firewall_id)) {
279+
/*
280+
* Peripheral access not allowed or not defined.
281+
* Mark the node as populated so platform bus won't probe it
282+
*/
283+
of_detach_node(child);
284+
dev_err(parent, "%s: Device driver will not be probed\n",
285+
child->full_name);
286+
}
287+
}
288+
289+
kfree(firewalls);
290+
}
291+
292+
return 0;
293+
}
294+
EXPORT_SYMBOL_GPL(stm32_firewall_populate_bus);

0 commit comments

Comments
 (0)