1 /* SPDX-License-Identifier: GPL-2.0-only */
2 #include <xen/bootfdt.h>
3 #include <xen/bug.h>
4 #include <xen/lib.h>
5 #include <xen/libfdt/libfdt.h>
6 #include <xen/unaligned.h>
7 
fdt_node_to_kind(const void * fdt,int node)8 boot_module_kind __init fdt_node_to_kind(const void *fdt, int node)
9 {
10     if ( fdt_node_check_compatible(fdt, node, "xen,linux-zimage") == 0 ||
11          fdt_node_check_compatible(fdt, node, "multiboot,kernel") == 0 )
12         return BOOTMOD_KERNEL;
13     if ( fdt_node_check_compatible(fdt, node, "xen,linux-initrd") == 0 ||
14          fdt_node_check_compatible(fdt, node, "multiboot,ramdisk") == 0 )
15         return BOOTMOD_RAMDISK;
16     if ( fdt_node_check_compatible(fdt, node, "xen,xsm-policy") == 0 )
17         return BOOTMOD_XSM_POLICY;
18     if ( fdt_node_check_compatible(fdt, node, "multiboot,device-tree") == 0 )
19         return BOOTMOD_GUEST_DTB;
20     if ( fdt_node_check_compatible(fdt, node, "multiboot,microcode") == 0 )
21         return BOOTMOD_MICROCODE;
22 
23     return BOOTMOD_UNKNOWN;
24 }
25 
device_tree_get_reg(const __be32 ** cell,uint32_t address_cells,uint32_t size_cells,paddr_t * start,paddr_t * size)26 void __init device_tree_get_reg(const __be32 **cell, uint32_t address_cells,
27                                 uint32_t size_cells, paddr_t *start,
28                                 paddr_t *size)
29 {
30     uint64_t dt_start, dt_size;
31 
32     /*
33      * dt_next_cell will return uint64_t whereas paddr_t may not be 64-bit.
34      * Thus, there is an implicit cast from uint64_t to paddr_t.
35      */
36     dt_start = dt_next_cell(address_cells, cell);
37     dt_size = dt_next_cell(size_cells, cell);
38 
39     if ( dt_start != (paddr_t)dt_start )
40     {
41         printk("Physical address greater than max width supported\n");
42         WARN();
43     }
44 
45     if ( dt_size != (paddr_t)dt_size )
46     {
47         printk("Physical size greater than max width supported\n");
48         WARN();
49     }
50 
51     /*
52      * Xen will truncate the address/size if it is greater than the maximum
53      * supported width and it will give an appropriate warning.
54      */
55     *start = dt_start;
56     *size = dt_size;
57 }
58 
device_tree_get_u32(const void * fdt,int node,const char * prop_name,u32 dflt)59 u32 __init device_tree_get_u32(const void *fdt, int node,
60                                const char *prop_name, u32 dflt)
61 {
62     const struct fdt_property *prop;
63 
64     prop = fdt_get_property(fdt, node, prop_name, NULL);
65     if ( !prop || prop->len < sizeof(u32) )
66         return dflt;
67 
68     return fdt32_to_cpu(get_unaligned_t(uint32_t, prop->data));
69 }
70 
device_tree_for_each_node(const void * fdt,int node,device_tree_node_func func,void * data)71 int __init device_tree_for_each_node(const void *fdt, int node,
72                                      device_tree_node_func func,
73                                      void *data)
74 {
75     /*
76      * We only care about relative depth increments, assume depth of
77      * node is 0 for simplicity.
78      */
79     int depth = 0;
80     const int first_node = node;
81     u32 address_cells[DEVICE_TREE_MAX_DEPTH];
82     u32 size_cells[DEVICE_TREE_MAX_DEPTH];
83     int ret;
84 
85     do {
86         const char *name = fdt_get_name(fdt, node, NULL);
87         u32 as, ss;
88 
89         if ( depth >= DEVICE_TREE_MAX_DEPTH )
90         {
91             printk("Warning: device tree node `%s' is nested too deep\n",
92                    name);
93             continue;
94         }
95 
96         as = depth > 0 ? address_cells[depth-1] : DT_ROOT_NODE_ADDR_CELLS_DEFAULT;
97         ss = depth > 0 ? size_cells[depth-1] : DT_ROOT_NODE_SIZE_CELLS_DEFAULT;
98 
99         address_cells[depth] = device_tree_get_u32(fdt, node,
100                                                    "#address-cells", as);
101         size_cells[depth] = device_tree_get_u32(fdt, node,
102                                                 "#size-cells", ss);
103 
104         /* skip the first node */
105         if ( node != first_node )
106         {
107             ret = func(fdt, node, name, depth, as, ss, data);
108             if ( ret != 0 )
109                 return ret;
110         }
111 
112         node = fdt_next_node(fdt, node, &depth);
113     } while ( node >= 0 && depth > 0 );
114 
115     return 0;
116 }
117 
118