Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <gatien.chevallier@foss.st.com>
Signed-off-by: Alexandre Torgue <alexandre.torgue@foss.st.com>

authored by

Gatien Chevallier and committed by
Alexandre Torgue
5c9668cf c1c67654

+537
+5
MAINTAINERS
··· 20811 20811 F: Documentation/devicetree/bindings/media/i2c/st,st-mipid02.yaml 20812 20812 F: drivers/media/i2c/st-mipid02.c 20813 20813 20814 + ST STM32 FIREWALL 20815 + M: Gatien Chevallier <gatien.chevallier@foss.st.com> 20816 + S: Maintained 20817 + F: drivers/bus/stm32_firewall.c 20818 + 20814 20819 ST STM32 I2C/SMBUS DRIVER 20815 20820 M: Pierre-Yves MORDRET <pierre-yves.mordret@foss.st.com> 20816 20821 M: Alain Volmat <alain.volmat@foss.st.com>
+1
arch/arm/mach-stm32/Kconfig
··· 12 12 select PINCTRL 13 13 select RESET_CONTROLLER 14 14 select STM32_EXTI 15 + select STM32_FIREWALL 15 16 help 16 17 Support for STMicroelectronics STM32 processors. 17 18
+1
arch/arm64/Kconfig.platforms
··· 305 305 select ARM_SMC_MBOX 306 306 select ARM_SCMI_PROTOCOL 307 307 select COMMON_CLK_SCMI 308 + select STM32_FIREWALL 308 309 help 309 310 This enables support for ARMv8 based STMicroelectronics 310 311 STM32 family, including:
+10
drivers/bus/Kconfig
··· 163 163 i2c/spi/uart controllers, a hexagon core, and a clock controller 164 164 which provides clocks for the above. 165 165 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 + 166 176 config SUN50I_DE2_BUS 167 177 bool "Allwinner A64 DE2 Bus Driver" 168 178 default ARM64
+1
drivers/bus/Makefile
··· 26 26 obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o 27 27 obj-$(CONFIG_QCOM_EBI2) += qcom-ebi2.o 28 28 obj-$(CONFIG_QCOM_SSC_BLOCK_BUS) += qcom-ssc-block-bus.o 29 + obj-$(CONFIG_STM32_FIREWALL) += stm32_firewall.o 29 30 obj-$(CONFIG_SUN50I_DE2_BUS) += sun50i-de2.o 30 31 obj-$(CONFIG_SUNXI_RSB) += sunxi-rsb.o 31 32 obj-$(CONFIG_OF) += simple-pm-bus.o
+294
drivers/bus/stm32_firewall.c
··· 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);
+83
drivers/bus/stm32_firewall.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright (C) 2023, STMicroelectronics - All Rights Reserved 4 + */ 5 + 6 + #ifndef _STM32_FIREWALL_H 7 + #define _STM32_FIREWALL_H 8 + 9 + #include <linux/kernel.h> 10 + #include <linux/list.h> 11 + #include <linux/of.h> 12 + #include <linux/platform_device.h> 13 + #include <linux/types.h> 14 + 15 + /** 16 + * STM32_PERIPHERAL_FIREWALL: This type of firewall protects peripherals 17 + * STM32_MEMORY_FIREWALL: This type of firewall protects memories/subsets of memory 18 + * zones 19 + * STM32_NOTYPE_FIREWALL: Undefined firewall type 20 + */ 21 + 22 + #define STM32_PERIPHERAL_FIREWALL BIT(1) 23 + #define STM32_MEMORY_FIREWALL BIT(2) 24 + #define STM32_NOTYPE_FIREWALL BIT(3) 25 + 26 + /** 27 + * struct stm32_firewall_controller - Information on firewall controller supplying services 28 + * 29 + * @name: Name of the firewall controller 30 + * @dev: Device reference of the firewall controller 31 + * @mmio: Base address of the firewall controller 32 + * @entry: List entry of the firewall controller list 33 + * @type: Type of firewall 34 + * @max_entries: Number of entries covered by the firewall 35 + * @grant_access: Callback used to grant access for a device access against a 36 + * firewall controller 37 + * @release_access: Callback used to release resources taken by a device when access was 38 + * granted 39 + * @grant_memory_range_access: Callback used to grant access for a device to a given memory region 40 + */ 41 + struct stm32_firewall_controller { 42 + const char *name; 43 + struct device *dev; 44 + void __iomem *mmio; 45 + struct list_head entry; 46 + unsigned int type; 47 + unsigned int max_entries; 48 + 49 + int (*grant_access)(struct stm32_firewall_controller *ctrl, u32 id); 50 + void (*release_access)(struct stm32_firewall_controller *ctrl, u32 id); 51 + int (*grant_memory_range_access)(struct stm32_firewall_controller *ctrl, phys_addr_t paddr, 52 + size_t size); 53 + }; 54 + 55 + /** 56 + * stm32_firewall_controller_register - Register a firewall controller to the STM32 firewall 57 + * framework 58 + * @firewall_controller: Firewall controller to register 59 + * 60 + * Returns 0 in case of success or -ENODEV if no controller was given. 61 + */ 62 + int stm32_firewall_controller_register(struct stm32_firewall_controller *firewall_controller); 63 + 64 + /** 65 + * stm32_firewall_controller_unregister - Unregister a firewall controller from the STM32 66 + * firewall framework 67 + * @firewall_controller: Firewall controller to unregister 68 + */ 69 + void stm32_firewall_controller_unregister(struct stm32_firewall_controller *firewall_controller); 70 + 71 + /** 72 + * stm32_firewall_populate_bus - Populate device tree nodes that have a correct firewall 73 + * configuration. This is used at boot-time only, as a sanity check 74 + * between device tree and firewalls hardware configurations to 75 + * prevent a kernel crash when a device driver is not granted access 76 + * 77 + * @firewall_controller: Firewall controller which nodes will be populated or not 78 + * 79 + * Returns 0 in case of success or appropriate errno code if error occurred. 80 + */ 81 + int stm32_firewall_populate_bus(struct stm32_firewall_controller *firewall_controller); 82 + 83 + #endif /* _STM32_FIREWALL_H */
+142
include/linux/bus/stm32_firewall_device.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright (C) 2023, STMicroelectronics - All Rights Reserved 4 + */ 5 + 6 + #ifndef STM32_FIREWALL_DEVICE_H 7 + #define STM32_FIREWALL_DEVICE_H 8 + 9 + #include <linux/of.h> 10 + #include <linux/platform_device.h> 11 + #include <linux/types.h> 12 + 13 + #define STM32_FIREWALL_MAX_EXTRA_ARGS 5 14 + 15 + /* Opaque reference to stm32_firewall_controller */ 16 + struct stm32_firewall_controller; 17 + 18 + /** 19 + * struct stm32_firewall - Information on a device's firewall. Each device can have more than one 20 + * firewall. 21 + * 22 + * @firewall_ctrl: Pointer referencing a firewall controller of the device. It is 23 + * opaque so a device cannot manipulate the controller's ops or access 24 + * the controller's data 25 + * @extra_args: Extra arguments that are implementation dependent 26 + * @entry: Name of the firewall entry 27 + * @extra_args_size: Number of extra arguments 28 + * @firewall_id: Firewall ID associated the device for this firewall controller 29 + */ 30 + struct stm32_firewall { 31 + struct stm32_firewall_controller *firewall_ctrl; 32 + u32 extra_args[STM32_FIREWALL_MAX_EXTRA_ARGS]; 33 + const char *entry; 34 + size_t extra_args_size; 35 + u32 firewall_id; 36 + }; 37 + 38 + #if IS_ENABLED(CONFIG_STM32_FIREWALL) 39 + /** 40 + * stm32_firewall_get_firewall - Get the firewall(s) associated to given device. 41 + * The firewall controller reference is always the first argument 42 + * of each of the access-controller property entries. 43 + * The firewall ID is always the second argument of each of the 44 + * access-controller property entries. 45 + * If there's no argument linked to the phandle, then the firewall ID 46 + * field is set to U32_MAX, which is an invalid ID. 47 + * 48 + * @np: Device node to parse 49 + * @firewall: Array of firewall references 50 + * @nb_firewall: Number of firewall references to get. Must be at least 1. 51 + * 52 + * Returns 0 on success, -ENODEV if there's no match with a firewall controller or appropriate errno 53 + * code if error occurred. 54 + */ 55 + int stm32_firewall_get_firewall(struct device_node *np, struct stm32_firewall *firewall, 56 + unsigned int nb_firewall); 57 + 58 + /** 59 + * stm32_firewall_grant_access - Request firewall access rights and grant access. 60 + * 61 + * @firewall: Firewall reference containing the ID to check against its firewall 62 + * controller 63 + * 64 + * Returns 0 if access is granted, -EACCES if access is denied, -ENODEV if firewall is null or 65 + * appropriate errno code if error occurred 66 + */ 67 + int stm32_firewall_grant_access(struct stm32_firewall *firewall); 68 + 69 + /** 70 + * stm32_firewall_release_access - Release access granted from a call to 71 + * stm32_firewall_grant_access(). 72 + * 73 + * @firewall: Firewall reference containing the ID to check against its firewall 74 + * controller 75 + */ 76 + void stm32_firewall_release_access(struct stm32_firewall *firewall); 77 + 78 + /** 79 + * stm32_firewall_grant_access_by_id - Request firewall access rights of a given device 80 + * based on a specific firewall ID 81 + * 82 + * Warnings: 83 + * There is no way to ensure that the given ID will correspond to the firewall referenced in the 84 + * device node if the ID did not come from stm32_firewall_get_firewall(). In that case, this 85 + * function must be used with caution. 86 + * This function should be used for subsystem resources that do not have the same firewall ID 87 + * as their parent. 88 + * U32_MAX is an invalid ID. 89 + * 90 + * @firewall: Firewall reference containing the firewall controller 91 + * @subsystem_id: Firewall ID of the subsystem resource 92 + * 93 + * Returns 0 if access is granted, -EACCES if access is denied, -ENODEV if firewall is null or 94 + * appropriate errno code if error occurred 95 + */ 96 + int stm32_firewall_grant_access_by_id(struct stm32_firewall *firewall, u32 subsystem_id); 97 + 98 + /** 99 + * stm32_firewall_release_access_by_id - Release access granted from a call to 100 + * stm32_firewall_grant_access_by_id(). 101 + * 102 + * Warnings: 103 + * There is no way to ensure that the given ID will correspond to the firewall referenced in the 104 + * device node if the ID did not come from stm32_firewall_get_firewall(). In that case, this 105 + * function must be used with caution. 106 + * This function should be used for subsystem resources that do not have the same firewall ID 107 + * as their parent. 108 + * U32_MAX is an invalid ID. 109 + * 110 + * @firewall: Firewall reference containing the firewall controller 111 + * @subsystem_id: Firewall ID of the subsystem resource 112 + */ 113 + void stm32_firewall_release_access_by_id(struct stm32_firewall *firewall, u32 subsystem_id); 114 + 115 + #else /* CONFIG_STM32_FIREWALL */ 116 + 117 + int stm32_firewall_get_firewall(struct device_node *np, struct stm32_firewall *firewall, 118 + unsigned int nb_firewall); 119 + { 120 + return -ENODEV; 121 + } 122 + 123 + int stm32_firewall_grant_access(struct stm32_firewall *firewall) 124 + { 125 + return -ENODEV; 126 + } 127 + 128 + void stm32_firewall_release_access(struct stm32_firewall *firewall) 129 + { 130 + } 131 + 132 + int stm32_firewall_grant_access_by_id(struct stm32_firewall *firewall, u32 subsystem_id) 133 + { 134 + return -ENODEV; 135 + } 136 + 137 + void stm32_firewall_release_access_by_id(struct stm32_firewall *firewall, u32 subsystem_id) 138 + { 139 + } 140 + 141 + #endif /* CONFIG_STM32_FIREWALL */ 142 + #endif /* STM32_FIREWALL_DEVICE_H */