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