1 /*
2 * Early Device Tree
3 *
4 * Copyright (C) 2012-2014 Citrix Systems, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10 #include <xen/types.h>
11 #include <xen/lib.h>
12 #include <xen/kernel.h>
13 #include <xen/init.h>
14 #include <xen/device_tree.h>
15 #include <xen/libfdt/libfdt.h>
16 #include <xsm/xsm.h>
17 #include <asm/setup.h>
18
device_tree_node_matches(const void * fdt,int node,const char * match)19 static bool __init device_tree_node_matches(const void *fdt, int node,
20 const char *match)
21 {
22 const char *name;
23 size_t match_len;
24
25 name = fdt_get_name(fdt, node, NULL);
26 match_len = strlen(match);
27
28 /* Match both "match" and "match@..." patterns but not
29 "match-foo". */
30 return strncmp(name, match, match_len) == 0
31 && (name[match_len] == '@' || name[match_len] == '\0');
32 }
33
device_tree_node_compatible(const void * fdt,int node,const char * match)34 static bool __init device_tree_node_compatible(const void *fdt, int node,
35 const char *match)
36 {
37 int len, l;
38 int mlen;
39 const void *prop;
40
41 mlen = strlen(match);
42
43 prop = fdt_getprop(fdt, node, "compatible", &len);
44 if ( prop == NULL )
45 return false;
46
47 while ( len > 0 ) {
48 if ( !dt_compat_cmp(prop, match) )
49 return true;
50 l = strlen(prop) + 1;
51 prop += l;
52 len -= l;
53 }
54
55 return false;
56 }
57
device_tree_get_reg(const __be32 ** cell,u32 address_cells,u32 size_cells,u64 * start,u64 * size)58 void __init device_tree_get_reg(const __be32 **cell, u32 address_cells,
59 u32 size_cells, u64 *start, u64 *size)
60 {
61 *start = dt_next_cell(address_cells, cell);
62 *size = dt_next_cell(size_cells, cell);
63 }
64
device_tree_get_u32(const void * fdt,int node,const char * prop_name,u32 dflt)65 u32 __init device_tree_get_u32(const void *fdt, int node,
66 const char *prop_name, u32 dflt)
67 {
68 const struct fdt_property *prop;
69
70 prop = fdt_get_property(fdt, node, prop_name, NULL);
71 if ( !prop || prop->len < sizeof(u32) )
72 return dflt;
73
74 return fdt32_to_cpu(*(uint32_t*)prop->data);
75 }
76
77 /**
78 * device_tree_for_each_node - iterate over all device tree sub-nodes
79 * @fdt: flat device tree.
80 * @node: parent node to start the search from
81 * @func: function to call for each sub-node.
82 * @data: data to pass to @func.
83 *
84 * Any nodes nested at DEVICE_TREE_MAX_DEPTH or deeper are ignored.
85 *
86 * Returns 0 if all nodes were iterated over successfully. If @func
87 * returns a value different from 0, that value is returned immediately.
88 */
device_tree_for_each_node(const void * fdt,int node,device_tree_node_func func,void * data)89 int __init device_tree_for_each_node(const void *fdt, int node,
90 device_tree_node_func func,
91 void *data)
92 {
93 /*
94 * We only care about relative depth increments, assume depth of
95 * node is 0 for simplicity.
96 */
97 int depth = 0;
98 const int first_node = node;
99 u32 address_cells[DEVICE_TREE_MAX_DEPTH];
100 u32 size_cells[DEVICE_TREE_MAX_DEPTH];
101 int ret;
102
103 do {
104 const char *name = fdt_get_name(fdt, node, NULL);
105 u32 as, ss;
106
107 if ( depth >= DEVICE_TREE_MAX_DEPTH )
108 {
109 printk("Warning: device tree node `%s' is nested too deep\n",
110 name);
111 continue;
112 }
113
114 as = depth > 0 ? address_cells[depth-1] : DT_ROOT_NODE_ADDR_CELLS_DEFAULT;
115 ss = depth > 0 ? size_cells[depth-1] : DT_ROOT_NODE_SIZE_CELLS_DEFAULT;
116
117 address_cells[depth] = device_tree_get_u32(fdt, node,
118 "#address-cells", as);
119 size_cells[depth] = device_tree_get_u32(fdt, node,
120 "#size-cells", ss);
121
122 /* skip the first node */
123 if ( node != first_node )
124 {
125 ret = func(fdt, node, name, depth, as, ss, data);
126 if ( ret != 0 )
127 return ret;
128 }
129
130 node = fdt_next_node(fdt, node, &depth);
131 } while ( node >= 0 && depth > 0 );
132
133 return 0;
134 }
135
process_memory_node(const void * fdt,int node,const char * name,int depth,u32 address_cells,u32 size_cells,void * data)136 static int __init process_memory_node(const void *fdt, int node,
137 const char *name, int depth,
138 u32 address_cells, u32 size_cells,
139 void *data)
140 {
141 const struct fdt_property *prop;
142 int i;
143 int banks;
144 const __be32 *cell;
145 paddr_t start, size;
146 u32 reg_cells = address_cells + size_cells;
147 struct meminfo *mem = data;
148
149 if ( address_cells < 1 || size_cells < 1 )
150 {
151 printk("fdt: node `%s': invalid #address-cells or #size-cells",
152 name);
153 return -EINVAL;
154 }
155
156 prop = fdt_get_property(fdt, node, "reg", NULL);
157 if ( !prop )
158 return -ENOENT;
159
160 cell = (const __be32 *)prop->data;
161 banks = fdt32_to_cpu(prop->len) / (reg_cells * sizeof (u32));
162
163 for ( i = 0; i < banks && mem->nr_banks < NR_MEM_BANKS; i++ )
164 {
165 device_tree_get_reg(&cell, address_cells, size_cells, &start, &size);
166 /* Some DT may describe empty bank, ignore them */
167 if ( !size )
168 continue;
169 mem->bank[mem->nr_banks].start = start;
170 mem->bank[mem->nr_banks].size = size;
171 mem->nr_banks++;
172 }
173
174 if ( i < banks )
175 return -ENOSPC;
176 return 0;
177 }
178
process_reserved_memory_node(const void * fdt,int node,const char * name,int depth,u32 address_cells,u32 size_cells,void * data)179 static int __init process_reserved_memory_node(const void *fdt, int node,
180 const char *name, int depth,
181 u32 address_cells,
182 u32 size_cells,
183 void *data)
184 {
185 int rc = process_memory_node(fdt, node, name, depth, address_cells,
186 size_cells, data);
187
188 if ( rc == -ENOSPC )
189 panic("Max number of supported reserved-memory regions reached.");
190 else if ( rc != -ENOENT )
191 return rc;
192 return 0;
193 }
194
process_reserved_memory(const void * fdt,int node,const char * name,int depth,u32 address_cells,u32 size_cells)195 static int __init process_reserved_memory(const void *fdt, int node,
196 const char *name, int depth,
197 u32 address_cells, u32 size_cells)
198 {
199 return device_tree_for_each_node(fdt, node,
200 process_reserved_memory_node,
201 &bootinfo.reserved_mem);
202 }
203
process_multiboot_node(const void * fdt,int node,const char * name,u32 address_cells,u32 size_cells)204 static void __init process_multiboot_node(const void *fdt, int node,
205 const char *name,
206 u32 address_cells, u32 size_cells)
207 {
208 static int __initdata kind_guess = 0;
209 const struct fdt_property *prop;
210 const __be32 *cell;
211 bootmodule_kind kind;
212 paddr_t start, size;
213 int len;
214 /* sizeof("/chosen/") + DT_MAX_NAME + '/' + DT_MAX_NAME + '/0' => 92 */
215 char path[92];
216 int parent_node, ret;
217 bool domU;
218
219 parent_node = fdt_parent_offset(fdt, node);
220 ASSERT(parent_node >= 0);
221
222 /* Check that the node is under "/chosen" (first 7 chars of path) */
223 ret = fdt_get_path(fdt, node, path, sizeof (path));
224 if ( ret != 0 || strncmp(path, "/chosen", 7) )
225 return;
226
227 prop = fdt_get_property(fdt, node, "reg", &len);
228 if ( !prop )
229 panic("node %s missing `reg' property\n", name);
230
231 if ( len < dt_cells_to_size(address_cells + size_cells) )
232 panic("fdt: node `%s': `reg` property length is too short\n",
233 name);
234
235 cell = (const __be32 *)prop->data;
236 device_tree_get_reg(&cell, address_cells, size_cells, &start, &size);
237
238 if ( fdt_node_check_compatible(fdt, node, "xen,linux-zimage") == 0 ||
239 fdt_node_check_compatible(fdt, node, "multiboot,kernel") == 0 )
240 kind = BOOTMOD_KERNEL;
241 else if ( fdt_node_check_compatible(fdt, node, "xen,linux-initrd") == 0 ||
242 fdt_node_check_compatible(fdt, node, "multiboot,ramdisk") == 0 )
243 kind = BOOTMOD_RAMDISK;
244 else if ( fdt_node_check_compatible(fdt, node, "xen,xsm-policy") == 0 )
245 kind = BOOTMOD_XSM;
246 else if ( fdt_node_check_compatible(fdt, node, "multiboot,device-tree") == 0 )
247 kind = BOOTMOD_GUEST_DTB;
248 else
249 kind = BOOTMOD_UNKNOWN;
250
251 /**
252 * Guess the kind of these first two unknowns respectively:
253 * (1) The first unknown must be kernel.
254 * (2) Detect the XSM Magic from the 2nd unknown:
255 * a. If it's XSM, set the kind as XSM, and that also means we
256 * won't load ramdisk;
257 * b. if it's not XSM, set the kind as ramdisk.
258 * So if user want to load ramdisk, it must be the 2nd unknown.
259 * We also detect the XSM Magic for the following unknowns,
260 * then set its kind according to the return value of has_xsm_magic.
261 */
262 if ( kind == BOOTMOD_UNKNOWN )
263 {
264 switch ( kind_guess++ )
265 {
266 case 0: kind = BOOTMOD_KERNEL; break;
267 case 1: kind = BOOTMOD_RAMDISK; break;
268 default: break;
269 }
270 if ( kind_guess > 1 && has_xsm_magic(start) )
271 kind = BOOTMOD_XSM;
272 }
273
274 domU = fdt_node_check_compatible(fdt, parent_node, "xen,domain") == 0;
275 add_boot_module(kind, start, size, domU);
276
277 prop = fdt_get_property(fdt, node, "bootargs", &len);
278 if ( !prop )
279 return;
280 add_boot_cmdline(fdt_get_name(fdt, parent_node, &len), prop->data,
281 kind, start, domU);
282 }
283
process_chosen_node(const void * fdt,int node,const char * name,u32 address_cells,u32 size_cells)284 static void __init process_chosen_node(const void *fdt, int node,
285 const char *name,
286 u32 address_cells, u32 size_cells)
287 {
288 const struct fdt_property *prop;
289 paddr_t start, end;
290 int len;
291
292 printk("Checking for initrd in /chosen\n");
293
294 prop = fdt_get_property(fdt, node, "linux,initrd-start", &len);
295 if ( !prop )
296 /* No initrd present. */
297 return;
298 if ( len != sizeof(u32) && len != sizeof(u64) )
299 {
300 printk("linux,initrd-start property has invalid length %d\n", len);
301 return;
302 }
303 start = dt_read_number((void *)&prop->data, dt_size_to_cells(len));
304
305 prop = fdt_get_property(fdt, node, "linux,initrd-end", &len);
306 if ( !prop )
307 {
308 printk("linux,initrd-end not present but -start was\n");
309 return;
310 }
311 if ( len != sizeof(u32) && len != sizeof(u64) )
312 {
313 printk("linux,initrd-end property has invalid length %d\n", len);
314 return;
315 }
316 end = dt_read_number((void *)&prop->data, dt_size_to_cells(len));
317
318 if ( start >= end )
319 {
320 printk("linux,initrd limits invalid: %"PRIpaddr" >= %"PRIpaddr"\n",
321 start, end);
322 return;
323 }
324
325 printk("Initrd %"PRIpaddr"-%"PRIpaddr"\n", start, end);
326
327 add_boot_module(BOOTMOD_RAMDISK, start, end-start, false);
328 }
329
early_scan_node(const void * fdt,int node,const char * name,int depth,u32 address_cells,u32 size_cells,void * data)330 static int __init early_scan_node(const void *fdt,
331 int node, const char *name, int depth,
332 u32 address_cells, u32 size_cells,
333 void *data)
334 {
335 int rc = 0;
336
337 if ( device_tree_node_matches(fdt, node, "memory") )
338 rc = process_memory_node(fdt, node, name, depth,
339 address_cells, size_cells, &bootinfo.mem);
340 else if ( depth == 1 && !dt_node_cmp(name, "reserved-memory") )
341 rc = process_reserved_memory(fdt, node, name, depth,
342 address_cells, size_cells);
343 else if ( depth <= 3 && (device_tree_node_compatible(fdt, node, "xen,multiboot-module" ) ||
344 device_tree_node_compatible(fdt, node, "multiboot,module" )))
345 process_multiboot_node(fdt, node, name, address_cells, size_cells);
346 else if ( depth == 1 && device_tree_node_matches(fdt, node, "chosen") )
347 process_chosen_node(fdt, node, name, address_cells, size_cells);
348
349 if ( rc < 0 )
350 printk("fdt: node `%s': parsing failed\n", name);
351 return rc;
352 }
353
early_print_info(void)354 static void __init early_print_info(void)
355 {
356 struct meminfo *mi = &bootinfo.mem;
357 struct meminfo *mem_resv = &bootinfo.reserved_mem;
358 struct bootmodules *mods = &bootinfo.modules;
359 struct bootcmdlines *cmds = &bootinfo.cmdlines;
360 unsigned int i, j, nr_rsvd;
361
362 for ( i = 0; i < mi->nr_banks; i++ )
363 printk("RAM: %"PRIpaddr" - %"PRIpaddr"\n",
364 mi->bank[i].start,
365 mi->bank[i].start + mi->bank[i].size - 1);
366 printk("\n");
367 for ( i = 0 ; i < mods->nr_mods; i++ )
368 printk("MODULE[%d]: %"PRIpaddr" - %"PRIpaddr" %-12s\n",
369 i,
370 mods->module[i].start,
371 mods->module[i].start + mods->module[i].size,
372 boot_module_kind_as_string(mods->module[i].kind));
373
374 nr_rsvd = fdt_num_mem_rsv(device_tree_flattened);
375 for ( i = 0; i < nr_rsvd; i++ )
376 {
377 paddr_t s, e;
378 if ( fdt_get_mem_rsv(device_tree_flattened, i, &s, &e) < 0 )
379 continue;
380 /* fdt_get_mem_rsv returns length */
381 e += s;
382 printk(" RESVD[%u]: %"PRIpaddr" - %"PRIpaddr"\n", i, s, e);
383 }
384 for ( j = 0; j < mem_resv->nr_banks; j++, i++ )
385 {
386 printk(" RESVD[%u]: %"PRIpaddr" - %"PRIpaddr"\n", i,
387 mem_resv->bank[j].start,
388 mem_resv->bank[j].start + mem_resv->bank[j].size - 1);
389 }
390 printk("\n");
391 for ( i = 0 ; i < cmds->nr_mods; i++ )
392 printk("CMDLINE[%"PRIpaddr"]:%s %s\n", cmds->cmdline[i].start,
393 cmds->cmdline[i].dt_name,
394 &cmds->cmdline[i].cmdline[0]);
395 printk("\n");
396 }
397
398 /**
399 * boot_fdt_info - initialize bootinfo from a DTB
400 * @fdt: flattened device tree binary
401 *
402 * Returns the size of the DTB.
403 */
boot_fdt_info(const void * fdt,paddr_t paddr)404 size_t __init boot_fdt_info(const void *fdt, paddr_t paddr)
405 {
406 int ret;
407
408 ret = fdt_check_header(fdt);
409 if ( ret < 0 )
410 panic("No valid device tree\n");
411
412 add_boot_module(BOOTMOD_FDT, paddr, fdt_totalsize(fdt), false);
413
414 device_tree_for_each_node((void *)fdt, 0, early_scan_node, NULL);
415 early_print_info();
416
417 return fdt_totalsize(fdt);
418 }
419
boot_fdt_cmdline(const void * fdt)420 const __init char *boot_fdt_cmdline(const void *fdt)
421 {
422 int node;
423 const struct fdt_property *prop;
424
425 node = fdt_path_offset(fdt, "/chosen");
426 if ( node < 0 )
427 return NULL;
428
429 prop = fdt_get_property(fdt, node, "xen,xen-bootargs", NULL);
430 if ( prop == NULL )
431 {
432 struct bootcmdline *dom0_cmdline =
433 boot_cmdline_find_by_kind(BOOTMOD_KERNEL);
434
435 if (fdt_get_property(fdt, node, "xen,dom0-bootargs", NULL) ||
436 ( dom0_cmdline && dom0_cmdline->cmdline[0] ) )
437 prop = fdt_get_property(fdt, node, "bootargs", NULL);
438 }
439 if ( prop == NULL )
440 return NULL;
441
442 return prop->data;
443 }
444
445 /*
446 * Local variables:
447 * mode: C
448 * c-file-style: "BSD"
449 * c-basic-offset: 4
450 * indent-tabs-mode: nil
451 * End:
452 */
453