xref: /optee_os/core/kernel/dt.c (revision ba6d8df98e3cf376aab45d0d958204c498a94123)
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 <libfdt.h>
31 #include <mm/core_memprot.h>
32 #include <mm/core_mmu.h>
33 #include <string.h>
34 #include <trace.h>
35 
36 const struct dt_driver *dt_find_compatible_driver(const void *fdt, int offs)
37 {
38 	const struct dt_device_match *dm;
39 	const struct dt_driver *drv;
40 
41 	for_each_dt_driver(drv)
42 		for (dm = drv->match_table; dm; dm++)
43 			if (!fdt_node_check_compatible(fdt, offs,
44 						       dm->compatible))
45 				return drv;
46 
47 	return NULL;
48 }
49 
50 const struct dt_driver *__dt_driver_start(void)
51 {
52 	return &__rodata_dtdrv_start;
53 }
54 
55 const struct dt_driver *__dt_driver_end(void)
56 {
57 	return &__rodata_dtdrv_end;
58 }
59 
60 int dt_map_dev(const void *fdt, int offs, vaddr_t *base, size_t *size)
61 {
62 	enum teecore_memtypes mtype;
63 	paddr_t pbase;
64 	vaddr_t vbase;
65 	ssize_t sz;
66 	int st;
67 
68 	assert(cpu_mmu_enabled());
69 
70 	st = _fdt_get_status(fdt, offs);
71 	if (st == DT_STATUS_DISABLED)
72 		return -1;
73 
74 	pbase = _fdt_reg_base_address(fdt, offs);
75 	if (pbase == (paddr_t)-1)
76 		return -1;
77 	sz = _fdt_reg_size(fdt, offs);
78 	if (sz < 0)
79 		return -1;
80 
81 	if ((st & DT_STATUS_OK_SEC) && !(st & DT_STATUS_OK_NSEC))
82 		mtype = MEM_AREA_IO_SEC;
83 	else
84 		mtype = MEM_AREA_IO_NSEC;
85 
86 	/* Check if we have a mapping, create one if needed */
87 	if (!core_mmu_add_mapping(mtype, pbase, sz)) {
88 		EMSG("Failed to map %zu bytes at PA 0x%"PRIxPA,
89 		     (size_t)size, pbase);
90 		return -1;
91 	}
92 	vbase = (vaddr_t)phys_to_virt(pbase, mtype);
93 	if (!vbase) {
94 		EMSG("Failed to get VA for PA 0x%"PRIxPA, pbase);
95 		return -1;
96 	}
97 
98 	*base = vbase;
99 	*size = sz;
100 	return 0;
101 }
102 
103 /* Read a physical address (n=1 or 2 cells) */
104 static paddr_t _fdt_read_paddr(const uint32_t *cell, int n)
105 {
106 	paddr_t addr;
107 
108 	if (n < 1 || n > 2)
109 		goto bad;
110 
111 	addr = fdt32_to_cpu(*cell);
112 	cell++;
113 	if (n == 2) {
114 #ifdef ARM32
115 		if (addr) {
116 			/* High order 32 bits can't be nonzero */
117 			goto bad;
118 		}
119 		addr = fdt32_to_cpu(*cell);
120 #else
121 		addr = (addr << 32) | fdt32_to_cpu(*cell);
122 #endif
123 	}
124 
125 	if (!addr)
126 		goto bad;
127 
128 	return addr;
129 bad:
130 	return (paddr_t)-1;
131 
132 }
133 
134 paddr_t _fdt_reg_base_address(const void *fdt, int offs)
135 {
136 	const void *reg;
137 	int ncells;
138 	int len;
139 
140 	reg = fdt_getprop(fdt, offs, "reg", &len);
141 	if (!reg)
142 		return (paddr_t)-1;
143 
144 	ncells = fdt_address_cells(fdt, offs);
145 	if (ncells < 0)
146 		return (paddr_t)-1;
147 
148 	return _fdt_read_paddr(reg, ncells);
149 }
150 
151 ssize_t _fdt_reg_size(const void *fdt, int offs)
152 {
153 	const uint32_t *reg;
154 	uint32_t sz;
155 	int n;
156 	int len;
157 
158 	reg = (const uint32_t *)fdt_getprop(fdt, offs, "reg", &len);
159 	if (!reg)
160 		return -1;
161 
162 	n = fdt_address_cells(fdt, offs);
163 	if (n < 1 || n > 2)
164 		return -1;
165 
166 	reg += n;
167 
168 	n = fdt_size_cells(fdt, offs);
169 	if (n < 1 || n > 2)
170 		return -1;
171 
172 	sz = fdt32_to_cpu(*reg);
173 	if (n == 2) {
174 		if (sz)
175 			return -1;
176 		reg++;
177 		sz = fdt32_to_cpu(*reg);
178 	}
179 
180 	return sz;
181 }
182 
183 static bool is_okay(const char *st, int len)
184 {
185 	return !strncmp(st, "ok", len) || !strncmp(st, "okay", len);
186 }
187 
188 int _fdt_get_status(const void *fdt, int offs)
189 {
190 	const char *prop;
191 	int st = 0;
192 	int len;
193 
194 	prop = fdt_getprop(fdt, offs, "status", &len);
195 	if (!prop || is_okay(prop, len)) {
196 		/* If status is not specified, it defaults to "okay" */
197 		st |= DT_STATUS_OK_NSEC;
198 	}
199 
200 	prop = fdt_getprop(fdt, offs, "secure-status", &len);
201 	if (!prop) {
202 		/*
203 		 * When secure-status is not specified it defaults to the same
204 		 * value as status
205 		 */
206 		if (st & DT_STATUS_OK_NSEC)
207 			st |= DT_STATUS_OK_SEC;
208 	} else {
209 		if (is_okay(prop, len))
210 			st |= DT_STATUS_OK_SEC;
211 	}
212 
213 	return st;
214 }
215