Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2017 Linaro * Bryan O'Donoghue <bryan.odonoghue@linaro.org> */ #include <fdtdec.h> #include <image.h> #include <log.h> #include <malloc.h> #include <dm/ofnode.h> #include <linux/ioport.h> #include <linux/libfdt.h> #include <tee/optee.h> #define optee_hdr_err_msg \ "OPTEE verification error:" \ "\n\thdr=%p image=0x%08lx magic=0x%08x" \ "\n\theader lo=0x%08x hi=0x%08x size=0x%08lx arch=0x%08x" \ "\n\tuimage params 0x%08lx-0x%08lx\n" #if defined(CONFIG_OPTEE_IMAGE) static int optee_verify_image(struct optee_header *hdr, unsigned long image_len) { uint32_t tee_file_size; tee_file_size = hdr->init_size + hdr->paged_size + sizeof(struct optee_header); if (hdr->magic != OPTEE_MAGIC || hdr->version != OPTEE_VERSION || tee_file_size != image_len) { return -EINVAL; } return 0; } int optee_verify_bootm_image(unsigned long image_addr, unsigned long image_load_addr, unsigned long image_len) { struct optee_header *hdr = (struct optee_header *)image_addr; int ret; ret = optee_verify_image(hdr, image_len); if (ret) goto error; if (image_load_addr + sizeof(*hdr) != hdr->init_load_addr_lo) { ret = -EINVAL; goto error; } return ret; error: printf(optee_hdr_err_msg, hdr, image_addr, hdr->magic, hdr->init_load_addr_lo, hdr->init_load_addr_hi, image_len, hdr->arch, image_load_addr, image_load_addr + image_len); return ret; } #endif #if defined(CONFIG_OF_LIBFDT) static int optee_copy_firmware_node(ofnode node, void *fdt_blob) { int offs, ret, len; const void *prop; offs = fdt_path_offset(fdt_blob, "/firmware"); if (offs < 0) { offs = fdt_path_offset(fdt_blob, "/"); if (offs < 0) return offs; offs = fdt_add_subnode(fdt_blob, offs, "firmware"); if (offs < 0) return offs; } offs = fdt_add_subnode(fdt_blob, offs, "optee"); if (offs < 0) return offs; /* copy the compatible property */ prop = ofnode_get_property(node, "compatible", &len); if (!prop) { debug("missing OP-TEE compatible property\n"); return -EINVAL; } ret = fdt_setprop(fdt_blob, offs, "compatible", prop, len); if (ret < 0) return ret; /* copy the method property */ prop = ofnode_get_property(node, "method", &len); if (!prop) { debug("missing OP-TEE method property\n"); return -EINVAL; } ret = fdt_setprop(fdt_blob, offs, "method", prop, len); if (ret < 0) return ret; return 0; } int optee_copy_fdt_nodes(void *new_blob) { ofnode node, subnode; int ret; struct resource res; if (fdt_check_header(new_blob)) return -EINVAL; /* only proceed if there is an /firmware/optee node */ node = ofnode_path("/firmware/optee"); if (!ofnode_valid(node)) { debug("No OP-TEE firmware node in old fdt, nothing to do\n"); return 0; } /* * Do not proceed if the target dt already has an OP-TEE node. * In this case assume that the system knows better somehow, * so do not interfere. */ if (fdt_path_offset(new_blob, "/firmware/optee") >= 0) { debug("OP-TEE Device Tree node already exists in target\n"); return 0; } ret = optee_copy_firmware_node(node, new_blob); if (ret < 0) { printf("Failed to add OP-TEE firmware node\n"); return ret; } /* optee inserts its memory regions as reserved-memory nodes */ node = ofnode_path("/reserved-memory"); if (ofnode_valid(node)) { ofnode_for_each_subnode(subnode, node) { const char *name = ofnode_get_name(subnode); if (!name) return -EINVAL; /* only handle optee reservations */ if (strncmp(name, "optee", 5)) continue; /* check if this subnode has a reg property */ ret = ofnode_read_resource(subnode, 0, &res); if (!ret) { struct fdt_memory carveout = { .start = res.start, .end = res.end, }; unsigned long flags = FDTDEC_RESERVED_MEMORY_NO_MAP; char *oldname, *nodename, *tmp; oldname = strdup(name); if (!oldname) return -ENOMEM; tmp = oldname; nodename = strsep(&tmp, "@"); if (!nodename) { free(oldname); return -EINVAL; } ret = fdtdec_add_reserved_memory(new_blob, nodename, &carveout, NULL, 0, NULL, flags); free(oldname); if (ret < 0) return ret; } } } return 0; } #endif |