]>
git.ipfire.org Git - people/ms/u-boot.git/blob - common/ft_build.c
7 #include <environment.h>
9 #ifdef CONFIG_OF_FLAT_TREE
11 #include <asm/errno.h>
16 /* align addr on a size boundary - adjust address up if needed -- Cort */
17 #define _ALIGN(addr,size) (((addr)+(size)-1)&(~((size)-1)))
19 static void ft_put_word(struct ft_cxt
*cxt
, u32 v
)
21 if (cxt
->overflow
) /* do nothing */
24 /* check for overflow */
25 if (cxt
->p
+ 4 > cxt
->pstr
) {
30 *(u32
*) cxt
->p
= cpu_to_be32(v
);
34 static inline void ft_put_bin(struct ft_cxt
*cxt
, const void *data
, int sz
)
38 if (cxt
->overflow
) /* do nothing */
41 /* next pointer pos */
42 p
= (u8
*) _ALIGN((unsigned long)cxt
->p
+ sz
, 4);
44 /* check for overflow */
50 memcpy(cxt
->p
, data
, sz
);
52 memset(cxt
->p
+ sz
, 0, 4 - (sz
& 3));
56 void ft_begin_node(struct ft_cxt
*cxt
, const char *name
)
58 ft_put_word(cxt
, OF_DT_BEGIN_NODE
);
59 ft_put_bin(cxt
, name
, strlen(name
) + 1);
62 void ft_end_node(struct ft_cxt
*cxt
)
64 ft_put_word(cxt
, OF_DT_END_NODE
);
67 void ft_nop(struct ft_cxt
*cxt
)
69 ft_put_word(cxt
, OF_DT_NOP
);
72 static int lookup_string(struct ft_cxt
*cxt
, const char *name
)
77 while (p
< cxt
->pstr_begin
) {
78 if (strcmp(p
, name
) == 0)
79 return p
- cxt
->p_begin
;
86 void ft_prop(struct ft_cxt
*cxt
, const char *name
, const void *data
, int sz
)
93 len
= strlen(name
) + 1;
95 off
= lookup_string(cxt
, name
);
97 /* check if we have space */
98 if (cxt
->p
+ 12 + sz
+ len
> cxt
->pstr
) {
104 memcpy(cxt
->pstr
, name
, len
);
105 off
= cxt
->pstr
- cxt
->p_begin
;
108 /* now put offset from beginning of *STRUCTURE* */
109 /* will be fixed up at the end */
110 ft_put_word(cxt
, OF_DT_PROP
);
111 ft_put_word(cxt
, sz
);
112 ft_put_word(cxt
, off
);
113 ft_put_bin(cxt
, data
, sz
);
116 void ft_prop_str(struct ft_cxt
*cxt
, const char *name
, const char *str
)
118 ft_prop(cxt
, name
, str
, strlen(str
) + 1);
121 void ft_prop_int(struct ft_cxt
*cxt
, const char *name
, int val
)
123 u32 v
= cpu_to_be32((u32
) val
);
125 ft_prop(cxt
, name
, &v
, 4);
128 /* start construction of the flat OF tree */
129 void ft_begin(struct ft_cxt
*cxt
, void *blob
, int max_size
)
131 struct boot_param_header
*bph
= blob
;
135 memset(cxt
, 0, sizeof(*cxt
));
138 cxt
->max_size
= max_size
;
140 /* zero everything in the header area */
141 memset(bph
, 0, sizeof(*bph
));
143 bph
->magic
= cpu_to_be32(OF_DT_HEADER
);
144 bph
->version
= cpu_to_be32(0x10);
145 bph
->last_comp_version
= cpu_to_be32(0x10);
148 cxt
->pres_begin
= (u8
*) _ALIGN((unsigned long)(bph
+ 1), 8);
149 cxt
->pres
= cxt
->pres_begin
;
151 off
= (unsigned long)cxt
->pres_begin
- (unsigned long)bph
;
152 bph
->off_mem_rsvmap
= cpu_to_be32(off
);
154 ((u64
*) cxt
->pres
)[0] = 0; /* phys = 0, size = 0, terminate */
155 ((u64
*) cxt
->pres
)[1] = 0;
157 cxt
->p_anchor
= cxt
->pres
+ 16; /* over the terminator */
160 /* add a reserver physical area to the rsvmap */
161 void ft_add_rsvmap(struct ft_cxt
*cxt
, u64 physaddr
, u64 size
)
163 ((u64
*) cxt
->pres
)[0] = cpu_to_be64(physaddr
); /* phys = 0, size = 0, terminate */
164 ((u64
*) cxt
->pres
)[1] = cpu_to_be64(size
);
166 cxt
->pres
+= 16; /* advance */
168 ((u64
*) cxt
->pres
)[0] = 0; /* phys = 0, size = 0, terminate */
169 ((u64
*) cxt
->pres
)[1] = 0;
171 /* keep track of size */
172 cxt
->res_size
= cxt
->pres
+ 16 - cxt
->pres_begin
;
174 cxt
->p_anchor
= cxt
->pres
+ 16; /* over the terminator */
177 void ft_begin_tree(struct ft_cxt
*cxt
)
179 cxt
->p_begin
= cxt
->p_anchor
;
180 cxt
->pstr_begin
= (char *)cxt
->bph
+ cxt
->max_size
; /* point at the end */
182 cxt
->p
= cxt
->p_begin
;
183 cxt
->pstr
= cxt
->pstr_begin
;
186 int ft_end_tree(struct ft_cxt
*cxt
)
188 struct boot_param_header
*bph
= cxt
->bph
;
193 ft_put_word(cxt
, OF_DT_END
);
198 /* size of the areas */
199 cxt
->struct_size
= cxt
->p
- cxt
->p_begin
;
200 cxt
->strings_size
= cxt
->pstr_begin
- cxt
->pstr
;
202 /* the offset we must move */
203 off
= (cxt
->pstr_begin
- cxt
->p_begin
) - cxt
->strings_size
;
205 /* the new strings start */
206 cxt
->pstr_begin
= cxt
->p_begin
+ cxt
->struct_size
;
208 /* move the whole string area */
209 memmove(cxt
->pstr_begin
, cxt
->pstr
, cxt
->strings_size
);
211 /* now perform the fixup of the strings */
213 while ((tag
= be32_to_cpu(*(u32
*) p
)) != OF_DT_END
) {
216 if (tag
== OF_DT_BEGIN_NODE
) {
217 p
= (u8
*) _ALIGN((unsigned long)p
+ strlen(p
) + 1, 4);
221 if (tag
== OF_DT_END_NODE
|| tag
== OF_DT_NOP
)
224 if (tag
!= OF_DT_PROP
)
227 sz
= be32_to_cpu(*(u32
*) p
);
230 v
= be32_to_cpu(*(u32
*) p
);
232 *(u32
*) p
= cpu_to_be32(v
); /* move down */
235 p
= (u8
*) _ALIGN((unsigned long)p
+ sz
, 4);
239 p
= (char *)cxt
->bph
;
240 sz
= (cxt
->pstr_begin
+ cxt
->strings_size
) - p
;
241 sz1
= _ALIGN(sz
, 16); /* align at 16 bytes */
243 memset(p
+ sz
, 0, sz1
- sz
);
244 bph
->totalsize
= cpu_to_be32(sz1
);
245 bph
->off_dt_struct
= cpu_to_be32(cxt
->p_begin
- p
);
246 bph
->off_dt_strings
= cpu_to_be32(cxt
->pstr_begin
- p
);
248 /* the new strings start */
249 cxt
->pstr_begin
= cxt
->p_begin
+ cxt
->struct_size
;
250 cxt
->pstr
= cxt
->pstr_begin
+ cxt
->strings_size
;
255 /**********************************************************************/
257 static inline int isprint(int c
)
259 return c
>= 0x20 && c
<= 0x7e;
262 static int is_printable_string(const void *data
, int len
)
264 const char *s
= data
;
267 /* zero length is not */
271 /* must terminate with zero */
272 if (s
[len
- 1] != '\0')
276 while (*s
&& isprint(*s
))
279 /* not zero, or not done yet */
280 if (*s
!= '\0' || (s
+ 1 - ss
) < len
)
286 static void print_data(const void *data
, int len
)
291 /* no data, don't print */
295 if (is_printable_string(data
, len
)) {
296 printf(" = \"%s\"", (char *)data
);
302 printf(" = <0x%02x>", (*(u8
*) data
) & 0xff);
304 case 2: /* half-word */
305 printf(" = <0x%04x>", be16_to_cpu(*(u16
*) data
) & 0xffff);
308 printf(" = <0x%08x>", be32_to_cpu(*(u32
*) data
) & 0xffffffffU
);
310 case 8: /* double-word */
311 printf(" = <0x%16llx>", be64_to_cpu(*(uint64_t *) data
));
313 default: /* anything else... hexdump */
315 for (i
= 0, s
= data
; i
< len
; i
++)
316 printf("%02x%s", s
[i
], i
< len
- 1 ? " " : "");
323 void ft_dump_blob(const void *bphp
)
325 const struct boot_param_header
*bph
= bphp
;
326 const uint64_t *p_rsvmap
= (const uint64_t *)
327 ((const char *)bph
+ be32_to_cpu(bph
->off_mem_rsvmap
));
328 const u32
*p_struct
= (const u32
*)
329 ((const char *)bph
+ be32_to_cpu(bph
->off_dt_struct
));
330 const u32
*p_strings
= (const u32
*)
331 ((const char *)bph
+ be32_to_cpu(bph
->off_dt_strings
));
335 int depth
, sz
, shift
;
339 if (be32_to_cpu(bph
->magic
) != OF_DT_HEADER
) {
348 addr
= be64_to_cpu(p_rsvmap
[i
* 2]);
349 size
= be64_to_cpu(p_rsvmap
[i
* 2 + 1]);
350 if (addr
== 0 && size
== 0)
353 printf("/memreserve/ 0x%llx 0x%llx;\n", addr
, size
);
357 while ((tag
= be32_to_cpu(*p
++)) != OF_DT_END
) {
359 /* printf("tag: 0x%08x (%d)\n", tag, p - p_struct); */
361 if (tag
== OF_DT_BEGIN_NODE
) {
363 p
= (u32
*) _ALIGN((unsigned long)p
+ strlen(s
) + 1, 4);
365 printf("%*s%s {\n", depth
* shift
, "", s
);
371 if (tag
== OF_DT_END_NODE
) {
374 printf("%*s};\n", depth
* shift
, "");
378 if (tag
== OF_DT_NOP
) {
379 printf("%*s[NOP]\n", depth
* shift
, "");
383 if (tag
!= OF_DT_PROP
) {
384 fprintf(stderr
, "%*s ** Unknown tag 0x%08x\n",
385 depth
* shift
, "", tag
);
388 sz
= be32_to_cpu(*p
++);
389 s
= (const char *)p_strings
+ be32_to_cpu(*p
++);
391 p
= (const u32
*)_ALIGN((unsigned long)p
+ sz
, 4);
392 printf("%*s%s", depth
* shift
, "", s
);
398 void ft_backtrack_node(struct ft_cxt
*cxt
)
400 if (be32_to_cpu(*(u32
*) (cxt
->p
- 4)) != OF_DT_END_NODE
)
401 return; /* XXX only for node */
406 /* note that the root node of the blob is "peeled" off */
407 void ft_merge_blob(struct ft_cxt
*cxt
, void *blob
)
409 struct boot_param_header
*bph
= (struct boot_param_header
*)blob
;
410 u32
*p_struct
= (u32
*) ((char *)bph
+ be32_to_cpu(bph
->off_dt_struct
));
412 (u32
*) ((char *)bph
+ be32_to_cpu(bph
->off_dt_strings
));
417 if (be32_to_cpu(*(u32
*) (cxt
->p
- 4)) != OF_DT_END_NODE
)
418 return; /* XXX only for node */
424 while ((tag
= be32_to_cpu(*p
++)) != OF_DT_END
) {
426 /* printf("tag: 0x%08x (%d) - %d\n", tag, p - p_struct, depth); */
428 if (tag
== OF_DT_BEGIN_NODE
) {
430 p
= (u32
*) _ALIGN((unsigned long)p
+ strlen(s
) + 1, 4);
433 ft_begin_node(cxt
, s
);
438 if (tag
== OF_DT_END_NODE
) {
445 if (tag
== OF_DT_NOP
)
448 if (tag
!= OF_DT_PROP
)
451 sz
= be32_to_cpu(*p
++);
452 s
= (char *)p_strings
+ be32_to_cpu(*p
++);
454 p
= (u32
*) _ALIGN((unsigned long)p
+ sz
, 4);
456 ft_prop(cxt
, s
, t
, sz
);
460 void *ft_get_prop(void *bphp
, const char *propname
, int *szp
)
462 struct boot_param_header
*bph
= bphp
;
464 (uint32_t *) ((char *)bph
+ be32_to_cpu(bph
->off_dt_struct
));
465 uint32_t *p_strings
=
466 (uint32_t *) ((char *)bph
+ be32_to_cpu(bph
->off_dt_strings
));
467 uint32_t version
= be32_to_cpu(bph
->version
);
473 static char path
[256], prop
[256];
478 while ((tag
= be32_to_cpu(*p
++)) != OF_DT_END
) {
480 if (tag
== OF_DT_BEGIN_NODE
) {
482 p
= (uint32_t *) _ALIGN((unsigned long)p
+ strlen(s
) +
489 if (tag
== OF_DT_END_NODE
) {
490 path
[strlen(path
) - 1] = '\0';
491 ss
= strrchr(path
, '/');
497 if (tag
== OF_DT_NOP
)
500 if (tag
!= OF_DT_PROP
)
503 sz
= be32_to_cpu(*p
++);
504 s
= (char *)p_strings
+ be32_to_cpu(*p
++);
505 if (version
< 0x10 && sz
>= 8)
506 p
= (uint32_t *) _ALIGN((unsigned long)p
, 8);
508 p
= (uint32_t *) _ALIGN((unsigned long)p
+ sz
, 4);
513 if (strcmp(prop
, propname
) == 0) {
522 /********************************************************************/
524 extern unsigned char oftree_dtb
[];
525 extern unsigned int oftree_dtb_len
;
527 /* Function that returns a character from the environment */
528 extern uchar(*env_get_char
) (int);
530 #define BDM(x) { .name = #x, .offset = offsetof(bd_t, bi_ ##x ) }
532 #ifdef CONFIG_OF_HAS_BD_T
533 static const struct {
544 #if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260) \
545 || defined(CONFIG_E500)
548 #if defined(CONFIG_MPC5xxx)
551 #if defined(CONFIG_MPC83XX)
554 #if defined(CONFIG_MPC8220)
572 #if defined(CONFIG_MPC5xxx)
580 void ft_setup(void *blob
, int size
, bd_t
* bd
, ulong initrd_start
, ulong initrd_end
)
586 #if defined(CONFIG_OF_HAS_UBOOT_ENV)
589 #if defined(CONFIG_OF_HAS_BD_T)
592 #if defined(CONFIG_OF_HAS_UBOOT_ENV) || defined(CONFIG_OF_HAS_BD_T)
594 static char tmpenv
[256];
597 /* disable OF tree; booting old kernel */
598 if (getenv("disable_of") != NULL
) {
599 memcpy(blob
, bd
, sizeof(*bd
));
603 ft_begin(&cxt
, blob
, size
);
605 if (initrd_start
&& initrd_end
)
606 ft_add_rsvmap(&cxt
, initrd_start
, initrd_end
- initrd_start
+ 1);
610 ft_begin_node(&cxt
, "");
615 ft_merge_blob(&cxt
, oftree_dtb
);
618 ft_backtrack_node(&cxt
);
620 #ifdef CONFIG_OF_HAS_UBOOT_ENV
621 ft_begin_node(&cxt
, "u-boot-env");
623 for (i
= 0; env_get_char(i
) != '\0'; i
= nxt
+ 1) {
624 char *s
, *lval
, *rval
;
626 for (nxt
= i
; env_get_char(nxt
) != '\0'; ++nxt
) ;
628 for (k
= i
; k
< nxt
&& s
< &tmpenv
[sizeof(tmpenv
) - 1]; ++k
)
629 *s
++ = env_get_char(k
);
632 s
= strchr(tmpenv
, '=');
638 ft_prop_str(&cxt
, lval
, rval
);
644 ft_begin_node(&cxt
, "chosen");
646 ft_prop_str(&cxt
, "name", "chosen");
647 ft_prop_str(&cxt
, "bootargs", getenv("bootargs"));
648 ft_prop_int(&cxt
, "linux,platform", 0x600); /* what is this? */
649 if (initrd_start
&& initrd_end
) {
650 ft_prop_int(&cxt
, "linux,initrd-start", initrd_start
);
651 ft_prop_int(&cxt
, "linux,initrd-end", initrd_end
);
653 #ifdef OF_STDOUT_PATH
654 ft_prop_str(&cxt
, "linux,stdout-path", OF_STDOUT_PATH
);
659 ft_end_node(&cxt
); /* end root */
664 printf("merged OF-tree\n");
668 #ifdef CONFIG_OF_HAS_BD_T
669 /* paste the bd_t at the end of the flat tree */
671 be32_to_cpu(((struct boot_param_header
*)blob
)->totalsize
);
672 memcpy(end
, bd
, sizeof(*bd
));
677 #ifdef CONFIG_OF_HAS_BD_T
678 for (i
= 0; i
< sizeof(bd_map
)/sizeof(bd_map
[0]); i
++) {
681 sprintf(tmpenv
, "/bd_t/%s", bd_map
[i
].name
);
682 v
= *(uint32_t *)((char *)bd
+ bd_map
[i
].offset
);
684 p
= ft_get_prop(blob
, tmpenv
, &len
);
689 p
= ft_get_prop(blob
, "/bd_t/enetaddr", &len
);
691 memcpy(p
, bd
->bi_enetaddr
, 6);
693 p
= ft_get_prop(blob
, "/bd_t/ethspeed", &len
);
695 *p
= cpu_to_be32((uint32_t) bd
->bi_ethspeed
);
698 clock
= bd
->bi_intfreq
;
699 p
= ft_get_prop(blob
, "/cpus/" OF_CPU
"/clock-frequency", &len
);
701 *p
= cpu_to_be32(clock
);
705 p
= ft_get_prop(blob
, "/cpus/" OF_CPU
"/timebase-frequency", &len
);
707 *p
= cpu_to_be32(clock
);
709 #endif /* __powerpc__ */
711 #ifdef CONFIG_OF_BOARD_SETUP
712 ft_board_setup(blob
, bd
);
716 printf("final OF-tree\n");