xref: /optee_os/core/drivers/firewall/firewall.c (revision d6b3f5f4a8e1f6aade6e5532076b23cc042f603f)
148a1cce4SGatien Chevallier // SPDX-License-Identifier: BSD-2-Clause
248a1cce4SGatien Chevallier /*
348a1cce4SGatien Chevallier  * Copyright (C) 2024, STMicroelectronics
448a1cce4SGatien Chevallier  */
548a1cce4SGatien Chevallier 
648a1cce4SGatien Chevallier #include <assert.h>
748a1cce4SGatien Chevallier #include <config.h>
848a1cce4SGatien Chevallier #include <drivers/firewall.h>
948a1cce4SGatien Chevallier #include <kernel/dt_driver.h>
1048a1cce4SGatien Chevallier #include <kernel/panic.h>
1148a1cce4SGatien Chevallier #include <libfdt.h>
1248a1cce4SGatien Chevallier #include <malloc.h>
1348a1cce4SGatien Chevallier #include <trace.h>
1448a1cce4SGatien Chevallier 
1548a1cce4SGatien Chevallier /* The firewall framework requires device tree support */
1648a1cce4SGatien Chevallier static_assert(IS_ENABLED(CFG_DT));
1748a1cce4SGatien Chevallier 
firewall_get(struct dt_pargs * parg,void * data,struct firewall_query ** out_fw)1848a1cce4SGatien Chevallier static TEE_Result firewall_get(struct dt_pargs *parg, void *data,
1948a1cce4SGatien Chevallier 			       struct firewall_query **out_fw)
2048a1cce4SGatien Chevallier {
2148a1cce4SGatien Chevallier 	struct firewall_query *fw = NULL;
2248a1cce4SGatien Chevallier 	unsigned int i = 0;
2348a1cce4SGatien Chevallier 
2448a1cce4SGatien Chevallier 	assert(parg->args_count >= 0);
2548a1cce4SGatien Chevallier 
2648a1cce4SGatien Chevallier 	fw = calloc(1, sizeof(*fw));
2748a1cce4SGatien Chevallier 	if (!fw)
2848a1cce4SGatien Chevallier 		return TEE_ERROR_OUT_OF_MEMORY;
2948a1cce4SGatien Chevallier 
3048a1cce4SGatien Chevallier 	fw->ctrl = (struct firewall_controller *)data;
3148a1cce4SGatien Chevallier 	fw->arg_count = parg->args_count;
3248a1cce4SGatien Chevallier 
3348a1cce4SGatien Chevallier 	if (fw->arg_count) {
3448a1cce4SGatien Chevallier 		fw->args = calloc(fw->arg_count, sizeof(*fw->args));
3548a1cce4SGatien Chevallier 		if (!fw->args) {
3648a1cce4SGatien Chevallier 			free(fw);
3748a1cce4SGatien Chevallier 			return TEE_ERROR_OUT_OF_MEMORY;
3848a1cce4SGatien Chevallier 		}
3948a1cce4SGatien Chevallier 	}
4048a1cce4SGatien Chevallier 
4148a1cce4SGatien Chevallier 	for (i = 0; i < (unsigned int)parg->args_count; i++)
4248a1cce4SGatien Chevallier 		fw->args[i] = parg->args[i];
4348a1cce4SGatien Chevallier 
4448a1cce4SGatien Chevallier 	*out_fw = fw;
4548a1cce4SGatien Chevallier 
4648a1cce4SGatien Chevallier 	return TEE_SUCCESS;
4748a1cce4SGatien Chevallier }
4848a1cce4SGatien Chevallier 
4948a1cce4SGatien Chevallier /* Firewall device API */
5048a1cce4SGatien Chevallier 
firewall_put(struct firewall_query * fw)5148a1cce4SGatien Chevallier void firewall_put(struct firewall_query *fw)
5248a1cce4SGatien Chevallier {
5348a1cce4SGatien Chevallier 	if (fw) {
5448a1cce4SGatien Chevallier 		free(fw->args);
5548a1cce4SGatien Chevallier 		free(fw);
5648a1cce4SGatien Chevallier 	}
5748a1cce4SGatien Chevallier }
5848a1cce4SGatien Chevallier 
firewall_dt_get_by_index(const void * fdt,int node,uint32_t index,struct firewall_query ** out_fw)5948a1cce4SGatien Chevallier TEE_Result firewall_dt_get_by_index(const void *fdt, int node, uint32_t index,
6048a1cce4SGatien Chevallier 				    struct firewall_query **out_fw)
6148a1cce4SGatien Chevallier {
6248a1cce4SGatien Chevallier 	return dt_driver_device_from_node_idx_prop("access-controllers", fdt,
6348a1cce4SGatien Chevallier 						   node, index,
6448a1cce4SGatien Chevallier 						   DT_DRIVER_FIREWALL,
6548a1cce4SGatien Chevallier 						   out_fw);
6648a1cce4SGatien Chevallier }
6748a1cce4SGatien Chevallier 
firewall_dt_get_by_name(const void * fdt,int node,const char * name,struct firewall_query ** out_fw)6848a1cce4SGatien Chevallier TEE_Result firewall_dt_get_by_name(const void *fdt, int node, const char *name,
6948a1cce4SGatien Chevallier 				   struct firewall_query **out_fw)
7048a1cce4SGatien Chevallier {
7148a1cce4SGatien Chevallier 	int index = 0;
7248a1cce4SGatien Chevallier 
7348a1cce4SGatien Chevallier 	index = fdt_stringlist_search(fdt, node, "access-controllers-names",
7448a1cce4SGatien Chevallier 				      name);
7548a1cce4SGatien Chevallier 	if (index == -FDT_ERR_NOTFOUND)
7648a1cce4SGatien Chevallier 		return TEE_ERROR_ITEM_NOT_FOUND;
7748a1cce4SGatien Chevallier 	else if (index < 0)
7848a1cce4SGatien Chevallier 		return TEE_ERROR_GENERIC;
7948a1cce4SGatien Chevallier 
8048a1cce4SGatien Chevallier 	return firewall_dt_get_by_index(fdt, node, index, out_fw);
8148a1cce4SGatien Chevallier }
8248a1cce4SGatien Chevallier 
firewall_set_configuration(struct firewall_query * fw)8348a1cce4SGatien Chevallier TEE_Result firewall_set_configuration(struct firewall_query *fw)
8448a1cce4SGatien Chevallier {
8548a1cce4SGatien Chevallier 	assert(fw && fw->ctrl && fw->ctrl->ops);
8648a1cce4SGatien Chevallier 
8748a1cce4SGatien Chevallier 	if (!fw->ctrl->ops->set_conf)
8848a1cce4SGatien Chevallier 		return TEE_ERROR_NOT_SUPPORTED;
8948a1cce4SGatien Chevallier 
9048a1cce4SGatien Chevallier 	return fw->ctrl->ops->set_conf(fw);
9148a1cce4SGatien Chevallier }
9248a1cce4SGatien Chevallier 
firewall_set_memory_configuration(struct firewall_query * fw,paddr_t paddr,size_t size)93*d6b3f5f4SGatien Chevallier TEE_Result firewall_set_memory_configuration(struct firewall_query *fw,
94*d6b3f5f4SGatien Chevallier 					     paddr_t paddr, size_t size)
95*d6b3f5f4SGatien Chevallier {
96*d6b3f5f4SGatien Chevallier 	assert(fw && fw->ctrl && fw->ctrl->ops);
97*d6b3f5f4SGatien Chevallier 
98*d6b3f5f4SGatien Chevallier 	if (!fw->ctrl->ops->set_memory_conf)
99*d6b3f5f4SGatien Chevallier 		return TEE_ERROR_NOT_SUPPORTED;
100*d6b3f5f4SGatien Chevallier 
101*d6b3f5f4SGatien Chevallier 	return fw->ctrl->ops->set_memory_conf(fw, paddr, size);
102*d6b3f5f4SGatien Chevallier }
103*d6b3f5f4SGatien Chevallier 
firewall_check_access(struct firewall_query * fw)10448a1cce4SGatien Chevallier TEE_Result firewall_check_access(struct firewall_query *fw)
10548a1cce4SGatien Chevallier {
10648a1cce4SGatien Chevallier 	assert(fw && fw->ctrl && fw->ctrl->ops);
10748a1cce4SGatien Chevallier 
10848a1cce4SGatien Chevallier 	if (!fw->ctrl->ops->check_access)
10948a1cce4SGatien Chevallier 		return TEE_ERROR_NOT_SUPPORTED;
11048a1cce4SGatien Chevallier 
11148a1cce4SGatien Chevallier 	return fw->ctrl->ops->check_access(fw);
11248a1cce4SGatien Chevallier }
11348a1cce4SGatien Chevallier 
firewall_acquire_access(struct firewall_query * fw)11448a1cce4SGatien Chevallier TEE_Result firewall_acquire_access(struct firewall_query *fw)
11548a1cce4SGatien Chevallier {
11648a1cce4SGatien Chevallier 	assert(fw && fw->ctrl && fw->ctrl->ops);
11748a1cce4SGatien Chevallier 
11848a1cce4SGatien Chevallier 	if (!fw->ctrl->ops->acquire_access)
11948a1cce4SGatien Chevallier 		return TEE_ERROR_NOT_SUPPORTED;
12048a1cce4SGatien Chevallier 
12148a1cce4SGatien Chevallier 	return fw->ctrl->ops->acquire_access(fw);
12248a1cce4SGatien Chevallier }
12348a1cce4SGatien Chevallier 
firewall_check_memory_access(struct firewall_query * fw,paddr_t paddr,size_t size,bool read,bool write)12448a1cce4SGatien Chevallier TEE_Result firewall_check_memory_access(struct firewall_query *fw,
12548a1cce4SGatien Chevallier 					paddr_t paddr, size_t size, bool read,
12648a1cce4SGatien Chevallier 					bool write)
12748a1cce4SGatien Chevallier {
12848a1cce4SGatien Chevallier 	assert(fw && fw->ctrl && fw->ctrl->ops);
12948a1cce4SGatien Chevallier 
13048a1cce4SGatien Chevallier 	if (!fw->ctrl->ops->check_memory_access)
13148a1cce4SGatien Chevallier 		return TEE_ERROR_NOT_SUPPORTED;
13248a1cce4SGatien Chevallier 
13348a1cce4SGatien Chevallier 	return fw->ctrl->ops->check_memory_access(fw, paddr, size, read, write);
13448a1cce4SGatien Chevallier }
13548a1cce4SGatien Chevallier 
firewall_acquire_memory_access(struct firewall_query * fw,paddr_t paddr,size_t size,bool read,bool write)13648a1cce4SGatien Chevallier TEE_Result firewall_acquire_memory_access(struct firewall_query *fw,
13748a1cce4SGatien Chevallier 					  paddr_t paddr, size_t size, bool read,
13848a1cce4SGatien Chevallier 					  bool write)
13948a1cce4SGatien Chevallier {
14048a1cce4SGatien Chevallier 	assert(fw && fw->ctrl && fw->ctrl->ops);
14148a1cce4SGatien Chevallier 
14248a1cce4SGatien Chevallier 	if (!fw->ctrl->ops->acquire_memory_access)
14348a1cce4SGatien Chevallier 		return TEE_ERROR_NOT_SUPPORTED;
14448a1cce4SGatien Chevallier 
14548a1cce4SGatien Chevallier 	return fw->ctrl->ops->acquire_memory_access(fw, paddr, size, read,
14648a1cce4SGatien Chevallier 						    write);
14748a1cce4SGatien Chevallier }
14848a1cce4SGatien Chevallier 
firewall_release_access(struct firewall_query * fw)14948a1cce4SGatien Chevallier void firewall_release_access(struct firewall_query *fw)
15048a1cce4SGatien Chevallier {
15148a1cce4SGatien Chevallier 	assert(fw && fw->ctrl && fw->ctrl->ops);
15248a1cce4SGatien Chevallier 
15348a1cce4SGatien Chevallier 	if (fw->ctrl->ops->release_access)
15448a1cce4SGatien Chevallier 		fw->ctrl->ops->release_access(fw);
15548a1cce4SGatien Chevallier }
15648a1cce4SGatien Chevallier 
firewall_release_memory_access(struct firewall_query * fw,paddr_t paddr,size_t size,bool read,bool write)15748a1cce4SGatien Chevallier void firewall_release_memory_access(struct firewall_query *fw, paddr_t paddr,
15848a1cce4SGatien Chevallier 				    size_t size, bool read, bool write)
15948a1cce4SGatien Chevallier {
16048a1cce4SGatien Chevallier 	assert(fw && fw->ctrl && fw->ctrl->ops);
16148a1cce4SGatien Chevallier 
16248a1cce4SGatien Chevallier 	if (fw->ctrl->ops->release_memory_access)
16348a1cce4SGatien Chevallier 		fw->ctrl->ops->release_memory_access(fw, paddr, size, read,
16448a1cce4SGatien Chevallier 						     write);
16548a1cce4SGatien Chevallier }
16648a1cce4SGatien Chevallier 
16748a1cce4SGatien Chevallier /* Firewall controller API */
16848a1cce4SGatien Chevallier 
firewall_dt_controller_register(const void * fdt,int node,struct firewall_controller * ctrl)16948a1cce4SGatien Chevallier TEE_Result firewall_dt_controller_register(const void *fdt, int node,
17048a1cce4SGatien Chevallier 					   struct firewall_controller *ctrl)
17148a1cce4SGatien Chevallier {
17248a1cce4SGatien Chevallier 	assert(ctrl);
17348a1cce4SGatien Chevallier 
17448a1cce4SGatien Chevallier 	DMSG("Registering %s firewall controller", ctrl->name);
17548a1cce4SGatien Chevallier 
17648a1cce4SGatien Chevallier 	return dt_driver_register_provider(fdt, node,
17748a1cce4SGatien Chevallier 					   (get_of_device_func)firewall_get,
17848a1cce4SGatien Chevallier 					   ctrl, DT_DRIVER_FIREWALL);
17948a1cce4SGatien Chevallier }
180