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