blob: 3fbde934fb16dc358c453018ae99373e5ecfbf73 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Bryan O'Donoghue4b0de7c2018-03-13 16:50:27 +00002/*
3 * Copyright (C) 2017 Linaro
4 * Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Bryan O'Donoghue4b0de7c2018-03-13 16:50:27 +00005 */
6
7#include <common.h>
Simon Glass3ba929a2020-10-30 21:38:53 -06008#include <fdtdec.h>
Simon Glass85f13782019-12-28 10:45:03 -07009#include <image.h>
Simon Glass0f2af882020-05-10 11:40:05 -060010#include <log.h>
Heiko Stuebnerb1a4fa02019-10-23 16:46:40 +020011#include <malloc.h>
Patrick Delaunay05381402021-02-08 13:54:31 +010012#include <dm/ofnode.h>
13#include <linux/ioport.h>
Heiko Stuebnerb1a4fa02019-10-23 16:46:40 +020014#include <linux/libfdt.h>
Bryan O'Donoghue4b0de7c2018-03-13 16:50:27 +000015#include <tee/optee.h>
16
Bryan O'Donoghue0eceed62018-03-13 16:50:34 +000017#define optee_hdr_err_msg \
18 "OPTEE verification error:" \
Alexandru Gagniucdccafba2021-09-07 12:07:06 -050019 "\n\thdr=%p image=0x%08lx magic=0x%08x" \
Bryan O'Donoghue0eceed62018-03-13 16:50:34 +000020 "\n\theader lo=0x%08x hi=0x%08x size=0x%08lx arch=0x%08x" \
21 "\n\tuimage params 0x%08lx-0x%08lx\n"
22
Patrick Delaunaya7ca4802021-09-02 11:56:16 +020023#if defined(CONFIG_OPTEE_IMAGE)
Alexandru Gagniucdccafba2021-09-07 12:07:06 -050024static int optee_verify_image(struct optee_header *hdr, unsigned long image_len)
Bryan O'Donoghue4b0de7c2018-03-13 16:50:27 +000025{
Bryan O'Donoghue4b0de7c2018-03-13 16:50:27 +000026 uint32_t tee_file_size;
27
28 tee_file_size = hdr->init_size + hdr->paged_size +
29 sizeof(struct optee_header);
30
31 if (hdr->magic != OPTEE_MAGIC ||
32 hdr->version != OPTEE_VERSION ||
Alexandru Gagniucdccafba2021-09-07 12:07:06 -050033 tee_file_size != image_len) {
Bryan O'Donoghue4b0de7c2018-03-13 16:50:27 +000034 return -EINVAL;
35 }
36
37 return 0;
38}
Bryan O'Donoghue4915f9b2018-03-13 16:50:33 +000039
40int optee_verify_bootm_image(unsigned long image_addr,
41 unsigned long image_load_addr,
42 unsigned long image_len)
43{
44 struct optee_header *hdr = (struct optee_header *)image_addr;
Bryan O'Donoghue4915f9b2018-03-13 16:50:33 +000045 int ret;
46
Alexandru Gagniucdccafba2021-09-07 12:07:06 -050047 ret = optee_verify_image(hdr, image_len);
Bryan O'Donoghue4915f9b2018-03-13 16:50:33 +000048 if (ret)
Bryan O'Donoghue0eceed62018-03-13 16:50:34 +000049 goto error;
Bryan O'Donoghue4915f9b2018-03-13 16:50:33 +000050
Bryan O'Donoghue0eceed62018-03-13 16:50:34 +000051 if (image_load_addr + sizeof(*hdr) != hdr->init_load_addr_lo) {
Bryan O'Donoghue4915f9b2018-03-13 16:50:33 +000052 ret = -EINVAL;
Bryan O'Donoghue0eceed62018-03-13 16:50:34 +000053 goto error;
54 }
55
56 return ret;
57error:
Alexandru Gagniucdccafba2021-09-07 12:07:06 -050058 printf(optee_hdr_err_msg, hdr, image_addr, hdr->magic,
59 hdr->init_load_addr_lo,
Bryan O'Donoghue0eceed62018-03-13 16:50:34 +000060 hdr->init_load_addr_hi, image_len, hdr->arch, image_load_addr,
61 image_load_addr + image_len);
Bryan O'Donoghue4915f9b2018-03-13 16:50:33 +000062
63 return ret;
64}
Patrick Delaunaya7ca4802021-09-02 11:56:16 +020065#endif
Heiko Stuebnerb1a4fa02019-10-23 16:46:40 +020066
67#if defined(CONFIG_OF_LIBFDT)
Patrick Delaunay05381402021-02-08 13:54:31 +010068static int optee_copy_firmware_node(ofnode node, void *fdt_blob)
Heiko Stuebnerb1a4fa02019-10-23 16:46:40 +020069{
Patrick Delaunay05381402021-02-08 13:54:31 +010070 int offs, ret, len;
Heiko Stuebnerb1a4fa02019-10-23 16:46:40 +020071 const void *prop;
72
Heiko Stuebnerb1a4fa02019-10-23 16:46:40 +020073 offs = fdt_path_offset(fdt_blob, "/firmware");
74 if (offs < 0) {
75 offs = fdt_path_offset(fdt_blob, "/");
76 if (offs < 0)
77 return offs;
78
79 offs = fdt_add_subnode(fdt_blob, offs, "firmware");
80 if (offs < 0)
81 return offs;
82 }
83
84 offs = fdt_add_subnode(fdt_blob, offs, "optee");
85 if (offs < 0)
Christoph Müllnercfb57672020-01-26 23:20:54 +010086 return offs;
Heiko Stuebnerb1a4fa02019-10-23 16:46:40 +020087
88 /* copy the compatible property */
Patrick Delaunay05381402021-02-08 13:54:31 +010089 prop = ofnode_get_property(node, "compatible", &len);
Heiko Stuebnerb1a4fa02019-10-23 16:46:40 +020090 if (!prop) {
91 debug("missing OP-TEE compatible property");
92 return -EINVAL;
93 }
94
95 ret = fdt_setprop(fdt_blob, offs, "compatible", prop, len);
96 if (ret < 0)
97 return ret;
98
99 /* copy the method property */
Patrick Delaunay05381402021-02-08 13:54:31 +0100100 prop = ofnode_get_property(node, "method", &len);
Heiko Stuebnerb1a4fa02019-10-23 16:46:40 +0200101 if (!prop) {
102 debug("missing OP-TEE method property");
103 return -EINVAL;
104 }
105
106 ret = fdt_setprop(fdt_blob, offs, "method", prop, len);
107 if (ret < 0)
108 return ret;
109
110 return 0;
111}
112
Patrick Delaunay05381402021-02-08 13:54:31 +0100113int optee_copy_fdt_nodes(void *new_blob)
Heiko Stuebnerb1a4fa02019-10-23 16:46:40 +0200114{
Patrick Delaunay05381402021-02-08 13:54:31 +0100115 ofnode node, subnode;
116 int ret;
117 struct resource res;
Heiko Stuebnerb1a4fa02019-10-23 16:46:40 +0200118
119 if (fdt_check_header(new_blob))
120 return -EINVAL;
121
122 /* only proceed if there is an /firmware/optee node */
Patrick Delaunay05381402021-02-08 13:54:31 +0100123 node = ofnode_path("/firmware/optee");
124 if (!ofnode_valid(node)) {
Heiko Stuebnerb1a4fa02019-10-23 16:46:40 +0200125 debug("No OP-TEE firmware node in old fdt, nothing to do");
126 return 0;
127 }
128
129 /*
130 * Do not proceed if the target dt already has an OP-TEE node.
131 * In this case assume that the system knows better somehow,
132 * so do not interfere.
133 */
134 if (fdt_path_offset(new_blob, "/firmware/optee") >= 0) {
135 debug("OP-TEE Device Tree node already exists in target");
136 return 0;
137 }
138
Patrick Delaunay05381402021-02-08 13:54:31 +0100139 ret = optee_copy_firmware_node(node, new_blob);
Heiko Stuebnerb1a4fa02019-10-23 16:46:40 +0200140 if (ret < 0) {
141 printf("Failed to add OP-TEE firmware node\n");
142 return ret;
143 }
144
145 /* optee inserts its memory regions as reserved-memory nodes */
Patrick Delaunay05381402021-02-08 13:54:31 +0100146 node = ofnode_path("/reserved-memory");
147 if (ofnode_valid(node)) {
148 ofnode_for_each_subnode(subnode, node) {
149 const char *name = ofnode_get_name(subnode);
Heiko Stuebnerb1a4fa02019-10-23 16:46:40 +0200150 if (!name)
151 return -EINVAL;
152
153 /* only handle optee reservations */
154 if (strncmp(name, "optee", 5))
155 continue;
156
157 /* check if this subnode has a reg property */
Patrick Delaunay05381402021-02-08 13:54:31 +0100158 ret = ofnode_read_resource(subnode, 0, &res);
Heiko Stuebnerb1a4fa02019-10-23 16:46:40 +0200159 if (!ret) {
160 struct fdt_memory carveout = {
161 .start = res.start,
162 .end = res.end,
163 };
164 char *oldname, *nodename, *tmp;
165
166 oldname = strdup(name);
167 if (!oldname)
168 return -ENOMEM;
169
170 tmp = oldname;
171 nodename = strsep(&tmp, "@");
172 if (!nodename) {
173 free(oldname);
174 return -EINVAL;
175 }
176
177 ret = fdtdec_add_reserved_memory(new_blob,
178 nodename,
179 &carveout,
Thierry Reding5e336912021-09-03 15:16:19 +0200180 NULL, 0,
Etienne Carriere141c2f72020-09-10 10:50:01 +0200181 NULL, true);
Heiko Stuebnerb1a4fa02019-10-23 16:46:40 +0200182 free(oldname);
183
184 if (ret < 0)
185 return ret;
186 }
Heiko Stuebnerb1a4fa02019-10-23 16:46:40 +0200187 }
188 }
189
190 return 0;
191}
192#endif