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 171 firewall_dt_probe_bus(const void *fdt, int node, 172 struct firewall_controller *ctrl __maybe_unused) 173 { 174 TEE_Result res = TEE_ERROR_GENERIC; 175 struct firewall_query *fw = NULL; 176 int subnode = 0; 177 178 DMSG("Populating %s firewall bus", ctrl->name); 179 180 fdt_for_each_subnode(subnode, fdt, node) { 181 unsigned int i = 0; 182 183 if (fdt_get_status(fdt, subnode) == DT_STATUS_DISABLED) 184 continue; 185 186 DMSG("Acquiring firewall access for %s when probing bus", 187 fdt_get_name(fdt, subnode, NULL)); 188 189 do { 190 /* 191 * The access-controllers property is mandatory for 192 * firewall bus devices 193 */ 194 res = firewall_dt_get_by_index(fdt, subnode, i, &fw); 195 if (res == TEE_ERROR_ITEM_NOT_FOUND) { 196 /* Stop when nothing more to parse */ 197 break; 198 } else if (res) { 199 EMSG("%s: Error on node %s: %#"PRIx32, 200 ctrl->name, 201 fdt_get_name(fdt, subnode, NULL), res); 202 panic(); 203 } 204 205 res = firewall_acquire_access(fw); 206 if (res) { 207 EMSG("%s: %s not accessible: %#"PRIx32, 208 ctrl->name, 209 fdt_get_name(fdt, subnode, NULL), res); 210 panic(); 211 } 212 213 firewall_put(fw); 214 i++; 215 } while (true); 216 217 res = dt_driver_maybe_add_probe_node(fdt, subnode); 218 if (res) { 219 EMSG("Failed on node %s with %#"PRIx32, 220 fdt_get_name(fdt, subnode, NULL), res); 221 panic(); 222 } 223 } 224 225 return TEE_SUCCESS; 226 } 227