3 * Written by: Pantelis Antoniou <pantelis.antoniou@gmail.com>
4 * Updated by: Matthew McClintock <msm@freescale.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of
9 * the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24 #include <environment.h>
26 #ifdef CONFIG_OF_FLAT_TREE
28 #include <asm/errno.h>
32 #include <linux/ctype.h>
36 /* align addr on a size boundary - adjust address up if needed -- Cort */
37 #define _ALIGN(addr,size) (((addr)+(size)-1)&(~((size)-1)))
38 #ifndef CONFIG_OF_BOOT_CPU
39 #define CONFIG_OF_BOOT_CPU 0
41 #define SIZE_OF_RSVMAP_ENTRY (2*sizeof(u64))
43 static void ft_put_word(struct ft_cxt
*cxt
, u32 v
)
45 memmove(cxt
->p
+ sizeof(u32
), cxt
->p
, cxt
->p_end
- cxt
->p
);
47 *(u32
*) cxt
->p
= cpu_to_be32(v
);
48 cxt
->p
+= sizeof(u32
);
49 cxt
->p_end
+= sizeof(u32
);
52 static inline void ft_put_bin(struct ft_cxt
*cxt
, const void *data
, int sz
)
54 int aligned_size
= ((u8
*)_ALIGN((unsigned long)cxt
->p
+ sz
,
55 sizeof(u32
))) - cxt
->p
;
57 memmove(cxt
->p
+ aligned_size
, cxt
->p
, cxt
->p_end
- cxt
->p
);
59 /* make sure the last bytes are zeroed */
60 memset(cxt
->p
+ aligned_size
- (aligned_size
% sizeof(u32
)), 0,
61 (aligned_size
% sizeof(u32
)));
63 memcpy(cxt
->p
, data
, sz
);
65 cxt
->p
+= aligned_size
;
66 cxt
->p_end
+= aligned_size
;
69 void ft_begin_node(struct ft_cxt
*cxt
, const char *name
)
71 ft_put_word(cxt
, OF_DT_BEGIN_NODE
);
72 ft_put_bin(cxt
, name
, strlen(name
) + 1);
75 void ft_end_node(struct ft_cxt
*cxt
)
77 ft_put_word(cxt
, OF_DT_END_NODE
);
80 void ft_nop(struct ft_cxt
*cxt
)
82 ft_put_word(cxt
, OF_DT_NOP
);
85 static int lookup_string(struct ft_cxt
*cxt
, const char *name
)
90 while (p
< cxt
->p_end
) {
91 if (strcmp((char *)p
, name
) == 0)
93 p
+= strlen((char *)p
) + 1;
99 void ft_prop(struct ft_cxt
*cxt
, const char *name
, const void *data
, int sz
)
103 off
= lookup_string(cxt
, name
);
105 memcpy(cxt
->p_end
, name
, strlen(name
) + 1);
106 off
= cxt
->p_end
- cxt
->p
;
107 cxt
->p_end
+= strlen(name
) + 1;
110 /* now put offset from beginning of *STRUCTURE* */
111 /* will be fixed up at the end */
112 ft_put_word(cxt
, OF_DT_PROP
);
113 ft_put_word(cxt
, sz
);
114 ft_put_word(cxt
, off
);
115 ft_put_bin(cxt
, data
, sz
);
118 void ft_prop_str(struct ft_cxt
*cxt
, const char *name
, const char *str
)
120 ft_prop(cxt
, name
, str
, strlen(str
) + 1);
123 void ft_prop_int(struct ft_cxt
*cxt
, const char *name
, int val
)
125 u32 v
= cpu_to_be32((u32
) val
);
127 ft_prop(cxt
, name
, &v
, sizeof(u32
));
130 /* pick up and start working on a tree in place */
131 void ft_init_cxt(struct ft_cxt
*cxt
, void *blob
)
133 struct boot_param_header
*bph
= blob
;
135 memset(cxt
, 0, sizeof(*cxt
));
138 bph
->boot_cpuid_phys
= CONFIG_OF_BOOT_CPU
;
140 /* find beginning and end of reserve map table (zeros in last entry) */
141 cxt
->p_rsvmap
= (u8
*)bph
+ bph
->off_mem_rsvmap
;
142 while ( ((uint64_t *)cxt
->p_rsvmap
)[0] != 0 &&
143 ((uint64_t *)cxt
->p_rsvmap
)[1] != 0 ) {
144 cxt
->p_rsvmap
+= SIZE_OF_RSVMAP_ENTRY
;
147 cxt
->p_start
= (u8
*)bph
+ bph
->off_dt_struct
;
148 cxt
->p_end
= (u8
*)bph
+ bph
->totalsize
;
149 cxt
->p
= (u8
*)bph
+ bph
->off_dt_strings
;
152 /* add a reserver physical area to the rsvmap */
153 void ft_add_rsvmap(struct ft_cxt
*cxt
, u64 physstart
, u64 physend
)
155 memmove(cxt
->p_rsvmap
+ SIZE_OF_RSVMAP_ENTRY
, cxt
->p_rsvmap
,
156 cxt
->p_end
- cxt
->p_rsvmap
);
158 ((u64
*)cxt
->p_rsvmap
)[0] = cpu_to_be64(physstart
);
159 ((u64
*)cxt
->p_rsvmap
)[1] = cpu_to_be64(physend
);
160 ((u64
*)cxt
->p_rsvmap
)[2] = 0;
161 ((u64
*)cxt
->p_rsvmap
)[3] = 0;
163 cxt
->p_rsvmap
+= SIZE_OF_RSVMAP_ENTRY
;
164 cxt
->p_start
+= SIZE_OF_RSVMAP_ENTRY
;
165 cxt
->p
+= SIZE_OF_RSVMAP_ENTRY
;
166 cxt
->p_end
+= SIZE_OF_RSVMAP_ENTRY
;
169 void ft_end_tree(struct ft_cxt
*cxt
)
171 ft_put_word(cxt
, OF_DT_END
);
174 /* update the boot param header with correct values */
175 void ft_finalize_tree(struct ft_cxt
*cxt
) {
176 struct boot_param_header
*bph
= cxt
->bph
;
178 bph
->totalsize
= cxt
->p_end
- (u8
*)bph
;
179 bph
->off_dt_struct
= cxt
->p_start
- (u8
*)bph
;
180 bph
->off_dt_strings
= cxt
->p
- (u8
*)bph
;
181 bph
->dt_strings_size
= cxt
->p_end
- cxt
->p
;
184 static int is_printable_string(const void *data
, int len
)
186 const char *s
= data
;
189 /* zero length is not */
193 /* must terminate with zero */
194 if (s
[len
- 1] != '\0')
198 while (*s
&& isprint(*s
))
201 /* not zero, or not done yet */
202 if (*s
!= '\0' || (s
+ 1 - ss
) < len
)
208 static void print_data(const void *data
, int len
)
213 /* no data, don't print */
217 if (is_printable_string(data
, len
)) {
226 printf(" = <%02x>", (*(u8
*) data
) & 0xff);
228 case 2: /* half-word */
229 printf(" = <%04x>", be16_to_cpu(*(u16
*) data
) & 0xffff);
232 printf(" = <%x>", be32_to_cpu(*(u32
*) data
) & 0xffffffffU
);
234 case 8: /* double-word */
235 printf(" = <%qx>", be64_to_cpu(*(uint64_t *) data
));
237 default: /* anything else... hexdump */
239 for (i
= 0, s
= data
; i
< len
; i
++)
240 printf("%02x%s", s
[i
], i
< len
- 1 ? " " : "");
247 void ft_dump_blob(const void *bphp
)
249 const struct boot_param_header
*bph
= bphp
;
250 const uint64_t *p_rsvmap
= (const uint64_t *)
251 ((const char *)bph
+ be32_to_cpu(bph
->off_mem_rsvmap
));
252 const u32
*p_struct
= (const u32
*)
253 ((const char *)bph
+ be32_to_cpu(bph
->off_dt_struct
));
254 const u32
*p_strings
= (const u32
*)
255 ((const char *)bph
+ be32_to_cpu(bph
->off_dt_strings
));
259 int depth
, sz
, shift
;
263 if (be32_to_cpu(bph
->magic
) != OF_DT_HEADER
) {
272 addr
= be64_to_cpu(p_rsvmap
[i
* 2]);
273 size
= be64_to_cpu(p_rsvmap
[i
* 2 + 1]);
274 if (addr
== 0 && size
== 0)
277 printf("/memreserve/ %qx %qx;\n", addr
, size
);
281 while ((tag
= be32_to_cpu(*p
++)) != OF_DT_END
) {
283 /* printf("tag: 0x%08x (%d)\n", tag, p - p_struct); */
285 if (tag
== OF_DT_BEGIN_NODE
) {
287 p
= (u32
*) _ALIGN((unsigned long)p
+ strlen(s
) + 1, 4);
289 printf("%*s%s {\n", depth
* shift
, "", s
);
295 if (tag
== OF_DT_END_NODE
) {
298 printf("%*s};\n", depth
* shift
, "");
302 if (tag
== OF_DT_NOP
) {
303 printf("%*s[NOP]\n", depth
* shift
, "");
307 if (tag
!= OF_DT_PROP
) {
308 fprintf(stderr
, "%*s ** Unknown tag 0x%08x at 0x%x\n",
309 depth
* shift
, "", tag
, --p
);
312 sz
= be32_to_cpu(*p
++);
313 s
= (const char *)p_strings
+ be32_to_cpu(*p
++);
315 p
= (const u32
*)_ALIGN((unsigned long)p
+ sz
, 4);
316 printf("%*s%s", depth
* shift
, "", s
);
322 void ft_backtrack_node(struct ft_cxt
*cxt
)
326 while (be32_to_cpu(*(u32
*) (cxt
->p
- i
)) != OF_DT_END_NODE
)
329 memmove (cxt
->p
- i
, cxt
->p
, cxt
->p_end
- cxt
->p
);
335 void *ft_get_prop(void *bphp
, const char *propname
, int *szp
)
337 struct boot_param_header
*bph
= bphp
;
339 (uint32_t *) ((char *)bph
+ be32_to_cpu(bph
->off_dt_struct
));
340 uint32_t *p_strings
=
341 (uint32_t *) ((char *)bph
+ be32_to_cpu(bph
->off_dt_strings
));
342 uint32_t version
= be32_to_cpu(bph
->version
);
348 static char path
[256], prop
[256];
353 while ((tag
= be32_to_cpu(*p
++)) != OF_DT_END
) {
355 if (tag
== OF_DT_BEGIN_NODE
) {
357 p
= (uint32_t *) _ALIGN((unsigned long)p
+ strlen(s
) +
364 if (tag
== OF_DT_END_NODE
) {
365 path
[strlen(path
) - 1] = '\0';
366 ss
= strrchr(path
, '/');
372 if (tag
== OF_DT_NOP
)
375 if (tag
!= OF_DT_PROP
)
378 sz
= be32_to_cpu(*p
++);
379 s
= (char *)p_strings
+ be32_to_cpu(*p
++);
380 if (version
< 0x10 && sz
>= 8)
381 p
= (uint32_t *) _ALIGN((unsigned long)p
, 8);
383 p
= (uint32_t *) _ALIGN((unsigned long)p
+ sz
, 4);
388 if (strcmp(prop
, propname
) == 0) {
397 /********************************************************************/
399 /* Function that returns a character from the environment */
400 extern uchar(*env_get_char
) (int);
402 void ft_setup(void *blob
, bd_t
* bd
, ulong initrd_start
, ulong initrd_end
)
409 /* disable OF tree; booting old kernel */
410 if (getenv("disable_of") != NULL
) {
411 memcpy(blob
, bd
, sizeof(*bd
));
416 printf ("recieved oftree\n");
420 ft_init_cxt(&cxt
, blob
);
422 if (initrd_start
&& initrd_end
)
423 ft_add_rsvmap(&cxt
, initrd_start
, initrd_end
- initrd_start
+ 1);
426 ft_backtrack_node(&cxt
);
428 ft_begin_node(&cxt
, "chosen");
429 ft_prop_str(&cxt
, "name", "chosen");
431 ft_prop_str(&cxt
, "bootargs", getenv("bootargs"));
432 ft_prop_int(&cxt
, "linux,platform", 0x600); /* what is this? */
433 if (initrd_start
&& initrd_end
) {
434 ft_prop_int(&cxt
, "linux,initrd-start", initrd_start
);
435 ft_prop_int(&cxt
, "linux,initrd-end", initrd_end
);
437 #ifdef OF_STDOUT_PATH
438 ft_prop_str(&cxt
, "linux,stdout-path", OF_STDOUT_PATH
);
443 ft_end_node(&cxt
); /* end root */
446 ft_finalize_tree(&cxt
);
449 clock
= bd
->bi_intfreq
;
450 p
= ft_get_prop(blob
, "/cpus/" OF_CPU
"/clock-frequency", &len
);
452 *p
= cpu_to_be32(clock
);
456 p
= ft_get_prop(blob
, "/cpus/" OF_CPU
"/timebase-frequency", &len
);
458 *p
= cpu_to_be32(clock
);
460 #endif /* __powerpc__ */
462 #ifdef CONFIG_OF_BOARD_SETUP
463 ft_board_setup(blob
, bd
);
466 /* in case the size changed in the platform code */
467 ft_finalize_tree(&cxt
);
470 printf("final OF-tree\n");