xref: /optee_os/core/drivers/firewall/firewall.c (revision 48a1cce429b4a61f22c7f8ee892d51569d15c355)
1*48a1cce4SGatien Chevallier // SPDX-License-Identifier: BSD-2-Clause
2*48a1cce4SGatien Chevallier /*
3*48a1cce4SGatien Chevallier  * Copyright (C) 2024, STMicroelectronics
4*48a1cce4SGatien Chevallier  */
5*48a1cce4SGatien Chevallier 
6*48a1cce4SGatien Chevallier #include <assert.h>
7*48a1cce4SGatien Chevallier #include <config.h>
8*48a1cce4SGatien Chevallier #include <drivers/firewall.h>
9*48a1cce4SGatien Chevallier #include <kernel/dt_driver.h>
10*48a1cce4SGatien Chevallier #include <kernel/panic.h>
11*48a1cce4SGatien Chevallier #include <libfdt.h>
12*48a1cce4SGatien Chevallier #include <malloc.h>
13*48a1cce4SGatien Chevallier #include <trace.h>
14*48a1cce4SGatien Chevallier 
15*48a1cce4SGatien Chevallier /* The firewall framework requires device tree support */
16*48a1cce4SGatien Chevallier static_assert(IS_ENABLED(CFG_DT));
17*48a1cce4SGatien Chevallier 
18*48a1cce4SGatien Chevallier static TEE_Result firewall_get(struct dt_pargs *parg, void *data,
19*48a1cce4SGatien Chevallier 			       struct firewall_query **out_fw)
20*48a1cce4SGatien Chevallier {
21*48a1cce4SGatien Chevallier 	struct firewall_query *fw = NULL;
22*48a1cce4SGatien Chevallier 	unsigned int i = 0;
23*48a1cce4SGatien Chevallier 
24*48a1cce4SGatien Chevallier 	assert(parg->args_count >= 0);
25*48a1cce4SGatien Chevallier 
26*48a1cce4SGatien Chevallier 	fw = calloc(1, sizeof(*fw));
27*48a1cce4SGatien Chevallier 	if (!fw)
28*48a1cce4SGatien Chevallier 		return TEE_ERROR_OUT_OF_MEMORY;
29*48a1cce4SGatien Chevallier 
30*48a1cce4SGatien Chevallier 	fw->ctrl = (struct firewall_controller *)data;
31*48a1cce4SGatien Chevallier 	fw->arg_count = parg->args_count;
32*48a1cce4SGatien Chevallier 
33*48a1cce4SGatien Chevallier 	if (fw->arg_count) {
34*48a1cce4SGatien Chevallier 		fw->args = calloc(fw->arg_count, sizeof(*fw->args));
35*48a1cce4SGatien Chevallier 		if (!fw->args) {
36*48a1cce4SGatien Chevallier 			free(fw);
37*48a1cce4SGatien Chevallier 			return TEE_ERROR_OUT_OF_MEMORY;
38*48a1cce4SGatien Chevallier 		}
39*48a1cce4SGatien Chevallier 	}
40*48a1cce4SGatien Chevallier 
41*48a1cce4SGatien Chevallier 	for (i = 0; i < (unsigned int)parg->args_count; i++)
42*48a1cce4SGatien Chevallier 		fw->args[i] = parg->args[i];
43*48a1cce4SGatien Chevallier 
44*48a1cce4SGatien Chevallier 	*out_fw = fw;
45*48a1cce4SGatien Chevallier 
46*48a1cce4SGatien Chevallier 	return TEE_SUCCESS;
47*48a1cce4SGatien Chevallier }
48*48a1cce4SGatien Chevallier 
49*48a1cce4SGatien Chevallier /* Firewall device API */
50*48a1cce4SGatien Chevallier 
51*48a1cce4SGatien Chevallier void firewall_put(struct firewall_query *fw)
52*48a1cce4SGatien Chevallier {
53*48a1cce4SGatien Chevallier 	if (fw) {
54*48a1cce4SGatien Chevallier 		free(fw->args);
55*48a1cce4SGatien Chevallier 		free(fw);
56*48a1cce4SGatien Chevallier 	}
57*48a1cce4SGatien Chevallier }
58*48a1cce4SGatien Chevallier 
59*48a1cce4SGatien Chevallier TEE_Result firewall_dt_get_by_index(const void *fdt, int node, uint32_t index,
60*48a1cce4SGatien Chevallier 				    struct firewall_query **out_fw)
61*48a1cce4SGatien Chevallier {
62*48a1cce4SGatien Chevallier 	return dt_driver_device_from_node_idx_prop("access-controllers", fdt,
63*48a1cce4SGatien Chevallier 						   node, index,
64*48a1cce4SGatien Chevallier 						   DT_DRIVER_FIREWALL,
65*48a1cce4SGatien Chevallier 						   out_fw);
66*48a1cce4SGatien Chevallier }
67*48a1cce4SGatien Chevallier 
68*48a1cce4SGatien Chevallier TEE_Result firewall_dt_get_by_name(const void *fdt, int node, const char *name,
69*48a1cce4SGatien Chevallier 				   struct firewall_query **out_fw)
70*48a1cce4SGatien Chevallier {
71*48a1cce4SGatien Chevallier 	int index = 0;
72*48a1cce4SGatien Chevallier 
73*48a1cce4SGatien Chevallier 	index = fdt_stringlist_search(fdt, node, "access-controllers-names",
74*48a1cce4SGatien Chevallier 				      name);
75*48a1cce4SGatien Chevallier 	if (index == -FDT_ERR_NOTFOUND)
76*48a1cce4SGatien Chevallier 		return TEE_ERROR_ITEM_NOT_FOUND;
77*48a1cce4SGatien Chevallier 	else if (index < 0)
78*48a1cce4SGatien Chevallier 		return TEE_ERROR_GENERIC;
79*48a1cce4SGatien Chevallier 
80*48a1cce4SGatien Chevallier 	return firewall_dt_get_by_index(fdt, node, index, out_fw);
81*48a1cce4SGatien Chevallier }
82*48a1cce4SGatien Chevallier 
83*48a1cce4SGatien Chevallier TEE_Result firewall_set_configuration(struct firewall_query *fw)
84*48a1cce4SGatien Chevallier {
85*48a1cce4SGatien Chevallier 	assert(fw && fw->ctrl && fw->ctrl->ops);
86*48a1cce4SGatien Chevallier 
87*48a1cce4SGatien Chevallier 	if (!fw->ctrl->ops->set_conf)
88*48a1cce4SGatien Chevallier 		return TEE_ERROR_NOT_SUPPORTED;
89*48a1cce4SGatien Chevallier 
90*48a1cce4SGatien Chevallier 	return fw->ctrl->ops->set_conf(fw);
91*48a1cce4SGatien Chevallier }
92*48a1cce4SGatien Chevallier 
93*48a1cce4SGatien Chevallier TEE_Result firewall_check_access(struct firewall_query *fw)
94*48a1cce4SGatien Chevallier {
95*48a1cce4SGatien Chevallier 	assert(fw && fw->ctrl && fw->ctrl->ops);
96*48a1cce4SGatien Chevallier 
97*48a1cce4SGatien Chevallier 	if (!fw->ctrl->ops->check_access)
98*48a1cce4SGatien Chevallier 		return TEE_ERROR_NOT_SUPPORTED;
99*48a1cce4SGatien Chevallier 
100*48a1cce4SGatien Chevallier 	return fw->ctrl->ops->check_access(fw);
101*48a1cce4SGatien Chevallier }
102*48a1cce4SGatien Chevallier 
103*48a1cce4SGatien Chevallier TEE_Result firewall_acquire_access(struct firewall_query *fw)
104*48a1cce4SGatien Chevallier {
105*48a1cce4SGatien Chevallier 	assert(fw && fw->ctrl && fw->ctrl->ops);
106*48a1cce4SGatien Chevallier 
107*48a1cce4SGatien Chevallier 	if (!fw->ctrl->ops->acquire_access)
108*48a1cce4SGatien Chevallier 		return TEE_ERROR_NOT_SUPPORTED;
109*48a1cce4SGatien Chevallier 
110*48a1cce4SGatien Chevallier 	return fw->ctrl->ops->acquire_access(fw);
111*48a1cce4SGatien Chevallier }
112*48a1cce4SGatien Chevallier 
113*48a1cce4SGatien Chevallier TEE_Result firewall_check_memory_access(struct firewall_query *fw,
114*48a1cce4SGatien Chevallier 					paddr_t paddr, size_t size, bool read,
115*48a1cce4SGatien Chevallier 					bool write)
116*48a1cce4SGatien Chevallier {
117*48a1cce4SGatien Chevallier 	assert(fw && fw->ctrl && fw->ctrl->ops);
118*48a1cce4SGatien Chevallier 
119*48a1cce4SGatien Chevallier 	if (!fw->ctrl->ops->check_memory_access)
120*48a1cce4SGatien Chevallier 		return TEE_ERROR_NOT_SUPPORTED;
121*48a1cce4SGatien Chevallier 
122*48a1cce4SGatien Chevallier 	return fw->ctrl->ops->check_memory_access(fw, paddr, size, read, write);
123*48a1cce4SGatien Chevallier }
124*48a1cce4SGatien Chevallier 
125*48a1cce4SGatien Chevallier TEE_Result firewall_acquire_memory_access(struct firewall_query *fw,
126*48a1cce4SGatien Chevallier 					  paddr_t paddr, size_t size, bool read,
127*48a1cce4SGatien Chevallier 					  bool write)
128*48a1cce4SGatien Chevallier {
129*48a1cce4SGatien Chevallier 	assert(fw && fw->ctrl && fw->ctrl->ops);
130*48a1cce4SGatien Chevallier 
131*48a1cce4SGatien Chevallier 	if (!fw->ctrl->ops->acquire_memory_access)
132*48a1cce4SGatien Chevallier 		return TEE_ERROR_NOT_SUPPORTED;
133*48a1cce4SGatien Chevallier 
134*48a1cce4SGatien Chevallier 	return fw->ctrl->ops->acquire_memory_access(fw, paddr, size, read,
135*48a1cce4SGatien Chevallier 						    write);
136*48a1cce4SGatien Chevallier }
137*48a1cce4SGatien Chevallier 
138*48a1cce4SGatien Chevallier void firewall_release_access(struct firewall_query *fw)
139*48a1cce4SGatien Chevallier {
140*48a1cce4SGatien Chevallier 	assert(fw && fw->ctrl && fw->ctrl->ops);
141*48a1cce4SGatien Chevallier 
142*48a1cce4SGatien Chevallier 	if (fw->ctrl->ops->release_access)
143*48a1cce4SGatien Chevallier 		fw->ctrl->ops->release_access(fw);
144*48a1cce4SGatien Chevallier }
145*48a1cce4SGatien Chevallier 
146*48a1cce4SGatien Chevallier void firewall_release_memory_access(struct firewall_query *fw, paddr_t paddr,
147*48a1cce4SGatien Chevallier 				    size_t size, bool read, bool write)
148*48a1cce4SGatien Chevallier {
149*48a1cce4SGatien Chevallier 	assert(fw && fw->ctrl && fw->ctrl->ops);
150*48a1cce4SGatien Chevallier 
151*48a1cce4SGatien Chevallier 	if (fw->ctrl->ops->release_memory_access)
152*48a1cce4SGatien Chevallier 		fw->ctrl->ops->release_memory_access(fw, paddr, size, read,
153*48a1cce4SGatien Chevallier 						     write);
154*48a1cce4SGatien Chevallier }
155*48a1cce4SGatien Chevallier 
156*48a1cce4SGatien Chevallier /* Firewall controller API */
157*48a1cce4SGatien Chevallier 
158*48a1cce4SGatien Chevallier TEE_Result firewall_dt_controller_register(const void *fdt, int node,
159*48a1cce4SGatien Chevallier 					   struct firewall_controller *ctrl)
160*48a1cce4SGatien Chevallier {
161*48a1cce4SGatien Chevallier 	assert(ctrl);
162*48a1cce4SGatien Chevallier 
163*48a1cce4SGatien Chevallier 	DMSG("Registering %s firewall controller", ctrl->name);
164*48a1cce4SGatien Chevallier 
165*48a1cce4SGatien Chevallier 	return dt_driver_register_provider(fdt, node,
166*48a1cce4SGatien Chevallier 					   (get_of_device_func)firewall_get,
167*48a1cce4SGatien Chevallier 					   ctrl, DT_DRIVER_FIREWALL);
168*48a1cce4SGatien Chevallier }
169*48a1cce4SGatien Chevallier 
170*48a1cce4SGatien Chevallier TEE_Result firewall_dt_probe_bus(const void *fdt, int node,
171*48a1cce4SGatien Chevallier 				 struct firewall_controller *ctrl)
172*48a1cce4SGatien Chevallier {
173*48a1cce4SGatien Chevallier 	TEE_Result res = TEE_ERROR_GENERIC;
174*48a1cce4SGatien Chevallier 	struct firewall_query *fw = NULL;
175*48a1cce4SGatien Chevallier 	int subnode = 0;
176*48a1cce4SGatien Chevallier 
177*48a1cce4SGatien Chevallier 	DMSG("Populating %s firewall bus", ctrl->name);
178*48a1cce4SGatien Chevallier 
179*48a1cce4SGatien Chevallier 	fdt_for_each_subnode(subnode, fdt, node) {
180*48a1cce4SGatien Chevallier 		unsigned int i = 0;
181*48a1cce4SGatien Chevallier 
182*48a1cce4SGatien Chevallier 		if (fdt_get_status(fdt, subnode) == DT_STATUS_DISABLED)
183*48a1cce4SGatien Chevallier 			continue;
184*48a1cce4SGatien Chevallier 
185*48a1cce4SGatien Chevallier 		DMSG("Acquiring firewall access for %s when probing bus",
186*48a1cce4SGatien Chevallier 		     fdt_get_name(fdt, subnode, NULL));
187*48a1cce4SGatien Chevallier 
188*48a1cce4SGatien Chevallier 		do {
189*48a1cce4SGatien Chevallier 			/*
190*48a1cce4SGatien Chevallier 			 * The access-controllers property is mandatory for
191*48a1cce4SGatien Chevallier 			 * firewall bus devices
192*48a1cce4SGatien Chevallier 			 */
193*48a1cce4SGatien Chevallier 			res = firewall_dt_get_by_index(fdt, subnode, i, &fw);
194*48a1cce4SGatien Chevallier 			if (res == TEE_ERROR_ITEM_NOT_FOUND) {
195*48a1cce4SGatien Chevallier 				/* Stop when nothing more to parse */
196*48a1cce4SGatien Chevallier 				break;
197*48a1cce4SGatien Chevallier 			} else if (res) {
198*48a1cce4SGatien Chevallier 				EMSG("%s: Error on node %s: %#"PRIx32,
199*48a1cce4SGatien Chevallier 				     ctrl->name,
200*48a1cce4SGatien Chevallier 				     fdt_get_name(fdt, subnode, NULL), res);
201*48a1cce4SGatien Chevallier 				panic();
202*48a1cce4SGatien Chevallier 			}
203*48a1cce4SGatien Chevallier 
204*48a1cce4SGatien Chevallier 			res = firewall_acquire_access(fw);
205*48a1cce4SGatien Chevallier 			if (res) {
206*48a1cce4SGatien Chevallier 				EMSG("%s: %s not accessible: %#"PRIx32,
207*48a1cce4SGatien Chevallier 				     ctrl->name,
208*48a1cce4SGatien Chevallier 				     fdt_get_name(fdt, subnode, NULL), res);
209*48a1cce4SGatien Chevallier 				panic();
210*48a1cce4SGatien Chevallier 			}
211*48a1cce4SGatien Chevallier 
212*48a1cce4SGatien Chevallier 			firewall_put(fw);
213*48a1cce4SGatien Chevallier 			i++;
214*48a1cce4SGatien Chevallier 		} while (true);
215*48a1cce4SGatien Chevallier 
216*48a1cce4SGatien Chevallier 		res = dt_driver_maybe_add_probe_node(fdt, subnode);
217*48a1cce4SGatien Chevallier 		if (res) {
218*48a1cce4SGatien Chevallier 			EMSG("Failed on node %s with %#"PRIx32,
219*48a1cce4SGatien Chevallier 			     fdt_get_name(fdt, subnode, NULL), res);
220*48a1cce4SGatien Chevallier 			panic();
221*48a1cce4SGatien Chevallier 		}
222*48a1cce4SGatien Chevallier 	}
223*48a1cce4SGatien Chevallier 
224*48a1cce4SGatien Chevallier 	return TEE_SUCCESS;
225*48a1cce4SGatien Chevallier }
226