xref: /optee_os/core/kernel/dt.c (revision 50f3b32394ff871cbcee703a966445637f4dfeea)
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 
150 	reg = fdt_getprop(fdt, offs, "reg", &len);
151 	if (!reg)
152 		return (paddr_t)-1;
153 
154 	ncells = fdt_address_cells(fdt, offs);
155 	if (ncells < 0)
156 		return (paddr_t)-1;
157 
158 	return _fdt_read_paddr(reg, ncells);
159 }
160 
161 ssize_t _fdt_reg_size(const void *fdt, int offs)
162 {
163 	const uint32_t *reg;
164 	uint32_t sz;
165 	int n;
166 	int len;
167 
168 	reg = (const uint32_t *)fdt_getprop(fdt, offs, "reg", &len);
169 	if (!reg)
170 		return -1;
171 
172 	n = fdt_address_cells(fdt, offs);
173 	if (n < 1 || n > 2)
174 		return -1;
175 
176 	reg += n;
177 
178 	n = fdt_size_cells(fdt, offs);
179 	if (n < 1 || n > 2)
180 		return -1;
181 
182 	sz = fdt32_to_cpu(*reg);
183 	if (n == 2) {
184 		if (sz)
185 			return -1;
186 		reg++;
187 		sz = fdt32_to_cpu(*reg);
188 	}
189 
190 	return sz;
191 }
192 
193 static bool is_okay(const char *st, int len)
194 {
195 	return !strncmp(st, "ok", len) || !strncmp(st, "okay", len);
196 }
197 
198 int _fdt_get_status(const void *fdt, int offs)
199 {
200 	const char *prop;
201 	int st = 0;
202 	int len;
203 
204 	prop = fdt_getprop(fdt, offs, "status", &len);
205 	if (!prop || is_okay(prop, len)) {
206 		/* If status is not specified, it defaults to "okay" */
207 		st |= DT_STATUS_OK_NSEC;
208 	}
209 
210 	prop = fdt_getprop(fdt, offs, "secure-status", &len);
211 	if (!prop) {
212 		/*
213 		 * When secure-status is not specified it defaults to the same
214 		 * value as status
215 		 */
216 		if (st & DT_STATUS_OK_NSEC)
217 			st |= DT_STATUS_OK_SEC;
218 	} else {
219 		if (is_okay(prop, len))
220 			st |= DT_STATUS_OK_SEC;
221 	}
222 
223 	return st;
224 }
225