]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/boot/powerpc/ofw/ofwfdt.c
Re-sync loader.mk and ficl.mk to where they should be
[FreeBSD/FreeBSD.git] / sys / boot / powerpc / ofw / ofwfdt.c
1 /*-
2  * Copyright (C) 2014-2015 Nathan Whitehorn
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
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 /*
30  * Include stdlib.h because of DEBUG_MALLOC shenanigans in stand.h for now.
31  * This will be removed in the future, when libsa silently replaces stdlib.h.
32  */
33 #include <stdlib.h>
34 #include <stand.h>
35 #include <sys/param.h>
36 #include <fdt_platform.h>
37 #include <openfirm.h>
38 #include <libfdt.h>
39 #include "bootstrap.h"
40
41 extern int command_fdt_internal(int argc, char *argv[]);
42
43 static int
44 OF_hasprop(phandle_t node, const char *prop)
45 {
46         return (OF_getproplen(node, (char *)prop) > 0);
47 }
48
49 static void
50 add_node_to_fdt(void *buffer, phandle_t node, int fdt_offset)
51 {
52         int i, child_offset, error;
53         char name[255], *lastprop, *subname;
54         void *propbuf;
55         ssize_t proplen;
56
57         lastprop = NULL;
58         while (OF_nextprop(node, lastprop, name) > 0) {
59                 proplen = OF_getproplen(node, name);
60
61                 /* Detect and correct for errors and strangeness */
62                 if (proplen < 0)
63                         proplen = 0;
64                 if (proplen > 1024)
65                         proplen = 1024;
66
67                 propbuf = malloc(proplen);
68                 if (propbuf == NULL) {
69                         printf("Cannot allocate memory for prop %s\n", name);
70                         return;
71                 }
72                 OF_getprop(node, name, propbuf, proplen);
73                 error = fdt_setprop(buffer, fdt_offset, name, propbuf, proplen);
74                 free(propbuf);
75                 lastprop = name;
76                 if (error)
77                         printf("Error %d adding property %s to "
78                             "node %d\n", error, name, fdt_offset);
79         }
80
81         if (!OF_hasprop(node, "phandle") && !OF_hasprop(node, "linux,phandle")
82             && !OF_hasprop(node, "ibm,phandle"))
83                 fdt_setprop(buffer, fdt_offset, "phandle", &node, sizeof(node));
84
85         for (node = OF_child(node); node > 0; node = OF_peer(node)) {
86                 OF_package_to_path(node, name, sizeof(name));
87                 subname = strrchr(name, '/');
88                 subname++;
89                 child_offset = fdt_add_subnode(buffer, fdt_offset, subname);
90                 if (child_offset < 0) {
91                         printf("Error %d adding node %s (%s), skipping\n",
92                             child_offset, name, subname);
93                         continue;
94                 }
95         
96                 add_node_to_fdt(buffer, node, child_offset);
97         }
98 }
99
100 static void
101 ofwfdt_fixups(void *fdtp)
102 {
103         int offset, len, i;
104         phandle_t node;
105         ihandle_t rtas;
106         const void *prop;
107
108         /*
109          * Instantiate and add reservations for RTAS state if present
110          */
111
112         offset = fdt_path_offset(fdtp, "/rtas");
113         if (offset > 0) {
114                 uint32_t base;
115                 void *rtasmem;
116                 char path[255];
117
118                 node = OF_finddevice("/rtas");
119                 OF_package_to_path(node, path, sizeof(path));
120                 OF_getprop(node, "rtas-size", &len, sizeof(len));
121
122                 /* Allocate memory */
123                 rtasmem = OF_claim(0, len, 4096);
124
125                 /* Instantiate RTAS */
126                 rtas = OF_open(path);
127                 base = 0;
128                 OF_call_method("instantiate-rtas", rtas, 1, 1, (cell_t)rtas,
129                     &base);
130
131                 /* Store info to FDT using Linux convention */
132                 base = cpu_to_fdt32(base);
133                 fdt_setprop(fdtp, offset, "linux,rtas-entry", &base,
134                     sizeof(base));
135                 base = cpu_to_fdt32((uint32_t)rtasmem);
136                 offset = fdt_path_offset(fdtp, "/rtas");
137                 fdt_setprop(fdtp, offset, "linux,rtas-base", &base,
138                     sizeof(base));
139
140                 /* Mark RTAS private data area reserved */
141                 fdt_add_mem_rsv(fdtp, base, len);
142         } else {
143                 /*
144                  * Remove /memory/available properties, which reflect long-gone
145                  * OF state. Note that this doesn't work if we need RTAS still,
146                  * since that's part of the firmware.
147                  */
148                 offset = fdt_path_offset(fdtp, "/memory@0");
149                 if (offset > 0)
150                         fdt_delprop(fdtp, offset, "available");
151         }
152
153         
154         /*
155          * Convert stored ihandles under /chosen to xref phandles
156          */
157         offset = fdt_path_offset(fdtp, "/chosen");
158         if (offset > 0) {
159                 const char *chosenprops[] = {"stdout", "stdin", "mmu", "cpu",
160                     NULL};
161                 const uint32_t *ihand;
162                 for (i = 0; chosenprops[i] != NULL; i++) {
163                         ihand = fdt_getprop(fdtp, offset, chosenprops[i], &len);
164                         if (ihand != NULL && len == sizeof(*ihand)) {
165                                 node = OF_instance_to_package(
166                                     fdt32_to_cpu(*ihand));
167                                 if (OF_hasprop(node, "phandle"))
168                                         OF_getprop(node, "phandle", &node,
169                                             sizeof(node));
170                                 else if (OF_hasprop(node, "linux,phandle"))
171                                         OF_getprop(node, "linux,phandle", &node,
172                                             sizeof(node));
173                                 else if (OF_hasprop(node, "ibm,phandle"))
174                                         OF_getprop(node, "ibm,phandle", &node,
175                                             sizeof(node));
176                                 node = cpu_to_fdt32(node);
177                                 fdt_setprop(fdtp, offset, chosenprops[i], &node,
178                                     sizeof(node));
179                         }
180
181                         /* Refind node in case it moved */
182                         offset = fdt_path_offset(fdtp, "/chosen");
183                 }
184         }
185 }
186
187 int
188 fdt_platform_load_dtb(void)
189 {
190         void *buffer;
191         size_t buflen = 409600;
192
193         buffer = malloc(buflen);
194         fdt_create_empty_tree(buffer, buflen);
195         add_node_to_fdt(buffer, OF_peer(0), fdt_path_offset(buffer, "/"));
196         ofwfdt_fixups(buffer);
197         fdt_pack(buffer);
198
199         fdt_load_dtb_addr(buffer);
200         free(buffer);
201
202         return (0);
203 }
204
205 void
206 fdt_platform_fixups(void)
207 {
208
209 }
210
211 static int
212 command_fdt(int argc, char *argv[])
213 {
214  
215         return (command_fdt_internal(argc, argv));
216 }
217  
218 COMMAND_SET(fdt, "fdt", "flattened device tree handling", command_fdt);
219