2 * libfdt - Flat Device Tree manipulation
3 * Copyright (C) 2006 David Gibson, IBM Corporation.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public License
7 * as published by the Free Software Foundation; either version 2.1 of
8 * the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 #include "libfdt_env.h"
24 #include "libfdt_internal.h"
26 static int check_header_sw(void *fdt
)
28 if (fdt_magic(fdt
) != SW_MAGIC
)
29 return -FDT_ERR_BADMAGIC
;
33 static void *grab_space(void *fdt
, int len
)
35 int offset
= fdt_size_dt_struct(fdt
);
38 spaceleft
= fdt_totalsize(fdt
) - fdt_off_dt_struct(fdt
)
39 - fdt_size_dt_strings(fdt
);
41 if ((offset
+ len
< offset
) || (offset
+ len
> spaceleft
))
44 fdt_set_header(fdt
, size_dt_struct
, offset
+ len
);
45 return fdt_offset_ptr(fdt
, offset
, len
);
48 int fdt_create(void *buf
, int bufsize
)
52 if (bufsize
< sizeof(struct fdt_header
))
53 return -FDT_ERR_NOSPACE
;
55 memset(buf
, 0, bufsize
);
57 fdt_set_header(fdt
, magic
, SW_MAGIC
);
58 fdt_set_header(fdt
, version
, FDT_LAST_SUPPORTED_VERSION
);
59 fdt_set_header(fdt
, last_comp_version
, FDT_FIRST_SUPPORTED_VERSION
);
60 fdt_set_header(fdt
, totalsize
, bufsize
);
62 fdt_set_header(fdt
, off_mem_rsvmap
, ALIGN(sizeof(struct fdt_header
),
63 sizeof(struct fdt_reserve_entry
)));
64 fdt_set_header(fdt
, off_dt_struct
, fdt_off_mem_rsvmap(fdt
));
65 fdt_set_header(fdt
, off_dt_strings
, bufsize
);
70 int fdt_add_reservemap_entry(void *fdt
, uint64_t addr
, uint64_t size
)
72 struct fdt_reserve_entry
*re
;
73 int err
= check_header_sw(fdt
);
78 if (fdt_size_dt_struct(fdt
))
79 return -FDT_ERR_BADSTATE
;
81 offset
= fdt_off_dt_struct(fdt
);
82 if ((offset
+ sizeof(*re
)) > fdt_totalsize(fdt
))
83 return -FDT_ERR_NOSPACE
;
85 re
= (struct fdt_reserve_entry
*)((void *)fdt
+ offset
);
86 re
->address
= cpu_to_fdt64(addr
);
87 re
->size
= cpu_to_fdt64(size
);
89 fdt_set_header(fdt
, off_dt_struct
, offset
+ sizeof(*re
));
94 int fdt_finish_reservemap(void *fdt
)
96 return fdt_add_reservemap_entry(fdt
, 0, 0);
99 int fdt_begin_node(void *fdt
, const char *name
)
101 struct fdt_node_header
*nh
;
102 int err
= check_header_sw(fdt
);
103 int namelen
= strlen(name
) + 1;
108 nh
= grab_space(fdt
, sizeof(*nh
) + ALIGN(namelen
, FDT_TAGSIZE
));
110 return -FDT_ERR_NOSPACE
;
112 nh
->tag
= cpu_to_fdt32(FDT_BEGIN_NODE
);
113 memcpy(nh
->name
, name
, namelen
);
117 int fdt_end_node(void *fdt
)
120 int err
= check_header_sw(fdt
);
125 en
= grab_space(fdt
, FDT_TAGSIZE
);
127 return -FDT_ERR_NOSPACE
;
129 *en
= cpu_to_fdt32(FDT_END_NODE
);
133 static int find_add_string(void *fdt
, const char *s
)
135 char *strtab
= (char *)fdt
+ fdt_totalsize(fdt
);
137 int strtabsize
= fdt_size_dt_strings(fdt
);
138 int len
= strlen(s
) + 1;
139 int struct_top
, offset
;
141 p
= _fdt_find_string(strtab
- strtabsize
, strtabsize
, s
);
146 offset
= -strtabsize
- len
;
147 struct_top
= fdt_off_dt_struct(fdt
) + fdt_size_dt_struct(fdt
);
148 if (fdt_totalsize(fdt
) + offset
< struct_top
)
149 return 0; /* no more room :( */
151 memcpy(strtab
+ offset
, s
, len
);
152 fdt_set_header(fdt
, size_dt_strings
, strtabsize
+ len
);
156 int fdt_property(void *fdt
, const char *name
, const void *val
, int len
)
158 struct fdt_property
*prop
;
159 int err
= check_header_sw(fdt
);
165 nameoff
= find_add_string(fdt
, name
);
167 return -FDT_ERR_NOSPACE
;
169 prop
= grab_space(fdt
, sizeof(*prop
) + ALIGN(len
, FDT_TAGSIZE
));
171 return -FDT_ERR_NOSPACE
;
173 prop
->tag
= cpu_to_fdt32(FDT_PROP
);
174 prop
->nameoff
= cpu_to_fdt32(nameoff
);
175 prop
->len
= cpu_to_fdt32(len
);
176 memcpy(prop
->data
, val
, len
);
180 int fdt_finish(void *fdt
)
182 int err
= check_header_sw(fdt
);
183 char *p
= (char *)fdt
;
185 int oldstroffset
, newstroffset
;
187 int offset
, nextoffset
;
193 end
= grab_space(fdt
, sizeof(*end
));
195 return -FDT_ERR_NOSPACE
;
196 *end
= cpu_to_fdt32(FDT_END
);
198 /* Relocate the string table */
199 oldstroffset
= fdt_totalsize(fdt
) - fdt_size_dt_strings(fdt
);
200 newstroffset
= fdt_off_dt_struct(fdt
) + fdt_size_dt_struct(fdt
);
201 memmove(p
+ newstroffset
, p
+ oldstroffset
, fdt_size_dt_strings(fdt
));
202 fdt_set_header(fdt
, off_dt_strings
, newstroffset
);
204 /* Walk the structure, correcting string offsets */
206 while ((tag
= fdt_next_tag(fdt
, offset
, &nextoffset
, NULL
)) != FDT_END
) {
207 if (tag
== FDT_PROP
) {
208 struct fdt_property
*prop
= fdt_offset_ptr(fdt
, offset
,
213 return -FDT_ERR_BADSTRUCTURE
;
215 nameoff
= fdt32_to_cpu(prop
->nameoff
);
216 nameoff
+= fdt_size_dt_strings(fdt
);
217 prop
->nameoff
= cpu_to_fdt32(nameoff
);
222 /* Finally, adjust the header */
223 fdt_set_header(fdt
, totalsize
, newstroffset
+ fdt_size_dt_strings(fdt
));
224 fdt_set_header(fdt
, magic
, FDT_MAGIC
);