xref: /optee_os/core/kernel/dt.c (revision b1469ba0bfd0371eb52bd50f5c52eeda7a8f5f1e)
1 /*
2  * Copyright (c) 2016, Linaro Limited
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <assert.h>
29 #include <kernel/dt.h>
30 #include <kernel/linker.h>
31 #include <libfdt.h>
32 #include <mm/core_memprot.h>
33 #include <mm/core_mmu.h>
34 #include <string.h>
35 #include <trace.h>
36 
37 const struct dt_driver *dt_find_compatible_driver(const void *fdt, int offs)
38 {
39 	const struct dt_device_match *dm;
40 	const struct dt_driver *drv;
41 
42 	for_each_dt_driver(drv)
43 		for (dm = drv->match_table; dm; dm++)
44 			if (!fdt_node_check_compatible(fdt, offs,
45 						       dm->compatible))
46 				return drv;
47 
48 	return NULL;
49 }
50 
51 const struct dt_driver *__dt_driver_start(void)
52 {
53 	return &__rodata_dtdrv_start;
54 }
55 
56 const struct dt_driver *__dt_driver_end(void)
57 {
58 	return &__rodata_dtdrv_end;
59 }
60 
61 bool dt_have_prop(const void *fdt, int offs, const char *propname)
62 {
63 	const void *prop;
64 
65 	prop = fdt_getprop(fdt, offs, propname, NULL);
66 
67 	return prop;
68 }
69 
70 int dt_map_dev(const void *fdt, int offs, vaddr_t *base, size_t *size)
71 {
72 	enum teecore_memtypes mtype;
73 	paddr_t pbase;
74 	vaddr_t vbase;
75 	ssize_t sz;
76 	int st;
77 
78 	assert(cpu_mmu_enabled());
79 
80 	st = _fdt_get_status(fdt, offs);
81 	if (st == DT_STATUS_DISABLED)
82 		return -1;
83 
84 	pbase = _fdt_reg_base_address(fdt, offs);
85 	if (pbase == (paddr_t)-1)
86 		return -1;
87 	sz = _fdt_reg_size(fdt, offs);
88 	if (sz < 0)
89 		return -1;
90 
91 	if ((st & DT_STATUS_OK_SEC) && !(st & DT_STATUS_OK_NSEC))
92 		mtype = MEM_AREA_IO_SEC;
93 	else
94 		mtype = MEM_AREA_IO_NSEC;
95 
96 	/* Check if we have a mapping, create one if needed */
97 	if (!core_mmu_add_mapping(mtype, pbase, sz)) {
98 		EMSG("Failed to map %zu bytes at PA 0x%"PRIxPA,
99 		     (size_t)sz, pbase);
100 		return -1;
101 	}
102 	vbase = (vaddr_t)phys_to_virt(pbase, mtype);
103 	if (!vbase) {
104 		EMSG("Failed to get VA for PA 0x%"PRIxPA, pbase);
105 		return -1;
106 	}
107 
108 	*base = vbase;
109 	*size = sz;
110 	return 0;
111 }
112 
113 /* Read a physical address (n=1 or 2 cells) */
114 static paddr_t _fdt_read_paddr(const uint32_t *cell, int n)
115 {
116 	paddr_t addr;
117 
118 	if (n < 1 || n > 2)
119 		goto bad;
120 
121 	addr = fdt32_to_cpu(*cell);
122 	cell++;
123 	if (n == 2) {
124 #ifdef ARM32
125 		if (addr) {
126 			/* High order 32 bits can't be nonzero */
127 			goto bad;
128 		}
129 		addr = fdt32_to_cpu(*cell);
130 #else
131 		addr = (addr << 32) | fdt32_to_cpu(*cell);
132 #endif
133 	}
134 
135 	if (!addr)
136 		goto bad;
137 
138 	return addr;
139 bad:
140 	return (paddr_t)-1;
141 
142 }
143 
144 paddr_t _fdt_reg_base_address(const void *fdt, int offs)
145 {
146 	const void *reg;
147 	int ncells;
148 	int len;
149 	int parent;
150 
151 	parent = fdt_parent_offset(fdt, offs);
152 	if (parent < 0)
153 		return (paddr_t)-1;
154 
155 	reg = fdt_getprop(fdt, offs, "reg", &len);
156 	if (!reg)
157 		return (paddr_t)-1;
158 
159 	ncells = fdt_address_cells(fdt, parent);
160 	if (ncells < 0)
161 		return (paddr_t)-1;
162 
163 	return _fdt_read_paddr(reg, ncells);
164 }
165 
166 ssize_t _fdt_reg_size(const void *fdt, int offs)
167 {
168 	const uint32_t *reg;
169 	uint32_t sz;
170 	int n;
171 	int len;
172 	int parent;
173 
174 	parent = fdt_parent_offset(fdt, offs);
175 	if (parent < 0)
176 		return (paddr_t)-1;
177 
178 	reg = (const uint32_t *)fdt_getprop(fdt, offs, "reg", &len);
179 	if (!reg)
180 		return -1;
181 
182 	n = fdt_address_cells(fdt, parent);
183 	if (n < 1 || n > 2)
184 		return -1;
185 
186 	reg += n;
187 
188 	n = fdt_size_cells(fdt, parent);
189 	if (n < 1 || n > 2)
190 		return -1;
191 
192 	sz = fdt32_to_cpu(*reg);
193 	if (n == 2) {
194 		if (sz)
195 			return -1;
196 		reg++;
197 		sz = fdt32_to_cpu(*reg);
198 	}
199 
200 	return sz;
201 }
202 
203 static bool is_okay(const char *st, int len)
204 {
205 	return !strncmp(st, "ok", len) || !strncmp(st, "okay", len);
206 }
207 
208 int _fdt_get_status(const void *fdt, int offs)
209 {
210 	const char *prop;
211 	int st = 0;
212 	int len;
213 
214 	prop = fdt_getprop(fdt, offs, "status", &len);
215 	if (!prop || is_okay(prop, len)) {
216 		/* If status is not specified, it defaults to "okay" */
217 		st |= DT_STATUS_OK_NSEC;
218 	}
219 
220 	prop = fdt_getprop(fdt, offs, "secure-status", &len);
221 	if (!prop) {
222 		/*
223 		 * When secure-status is not specified it defaults to the same
224 		 * value as status
225 		 */
226 		if (st & DT_STATUS_OK_NSEC)
227 			st |= DT_STATUS_OK_SEC;
228 	} else {
229 		if (is_okay(prop, len))
230 			st |= DT_STATUS_OK_SEC;
231 	}
232 
233 	return st;
234 }
235