]>
git.proxmox.com Git - mirror_edk2.git/blob - EmbeddedPkg/Library/FdtLib/fdt_rw.c
2 * libfdt - Flat Device Tree manipulation
3 * Copyright (C) 2006 David Gibson, IBM Corporation.
5 * libfdt is dual licensed: you can use it either under the terms of
6 * the GPL, or the BSD license, at your option.
8 * a) This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public
19 * License along with this library; if not, write to the Free
20 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
25 * b) Redistribution and use in source and binary forms, with or
26 * without modification, are permitted provided that the following
29 * 1. Redistributions of source code must retain the above
30 * copyright notice, this list of conditions and the following
32 * 2. Redistributions in binary form must reproduce the above
33 * copyright notice, this list of conditions and the following
34 * disclaimer in the documentation and/or other materials
35 * provided with the distribution.
37 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
38 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
39 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
40 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
41 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
42 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
48 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
49 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51 #include "libfdt_env.h"
56 #include "libfdt_internal.h"
59 _fdt_blocks_misordered (
65 return (fdt_off_mem_rsvmap (fdt
) < FDT_ALIGN (sizeof (struct fdt_header
), 8))
66 || (fdt_off_dt_struct (fdt
) <
67 (fdt_off_mem_rsvmap (fdt
) + mem_rsv_size
))
68 || (fdt_off_dt_strings (fdt
) <
69 (fdt_off_dt_struct (fdt
) + struct_size
))
70 || (fdt_totalsize (fdt
) <
71 (fdt_off_dt_strings (fdt
) + fdt_size_dt_strings (fdt
)));
75 _fdt_rw_check_header (
79 FDT_CHECK_HEADER (fdt
);
81 if (fdt_version (fdt
) < 17) {
82 return -FDT_ERR_BADVERSION
;
85 if (_fdt_blocks_misordered (
87 sizeof (struct fdt_reserve_entry
),
88 fdt_size_dt_struct (fdt
)
91 return -FDT_ERR_BADLAYOUT
;
94 if (fdt_version (fdt
) > 17) {
95 fdt_set_version (fdt
, 17);
101 #define FDT_RW_CHECK_HEADER(fdt) \
104 if ((__err = _fdt_rw_check_header(fdt)) != 0) \
113 return fdt_off_dt_strings (fdt
) + fdt_size_dt_strings (fdt
);
124 char *p
= splicepoint
;
125 char *end
= (char *)fdt
+ _fdt_data_size (fdt
);
127 if (((p
+ oldlen
) < p
) || ((p
+ oldlen
) > end
)) {
128 return -FDT_ERR_BADOFFSET
;
131 if ((p
< (char *)fdt
) || ((end
- oldlen
+ newlen
) < (char *)fdt
)) {
132 return -FDT_ERR_BADOFFSET
;
135 if ((end
- oldlen
+ newlen
) > ((char *)fdt
+ fdt_totalsize (fdt
))) {
136 return -FDT_ERR_NOSPACE
;
139 memmove (p
+ newlen
, p
+ oldlen
, end
- p
- oldlen
);
144 _fdt_splice_mem_rsv (
146 struct fdt_reserve_entry
*p
,
151 int delta
= (newn
- oldn
) * sizeof (*p
);
154 err
= _fdt_splice (fdt
, p
, oldn
* sizeof (*p
), newn
* sizeof (*p
));
159 fdt_set_off_dt_struct (fdt
, fdt_off_dt_struct (fdt
) + delta
);
160 fdt_set_off_dt_strings (fdt
, fdt_off_dt_strings (fdt
) + delta
);
172 int delta
= newlen
- oldlen
;
175 if ((err
= _fdt_splice (fdt
, p
, oldlen
, newlen
))) {
179 fdt_set_size_dt_struct (fdt
, fdt_size_dt_struct (fdt
) + delta
);
180 fdt_set_off_dt_strings (fdt
, fdt_off_dt_strings (fdt
) + delta
);
190 void *p
= (char *)fdt
191 + fdt_off_dt_strings (fdt
) + fdt_size_dt_strings (fdt
);
194 if ((err
= _fdt_splice (fdt
, p
, 0, newlen
))) {
198 fdt_set_size_dt_strings (fdt
, fdt_size_dt_strings (fdt
) + newlen
);
203 _fdt_find_add_string (
208 char *strtab
= (char *)fdt
+ fdt_off_dt_strings (fdt
);
211 int len
= strlen (s
) + 1;
214 p
= _fdt_find_string (strtab
, fdt_size_dt_strings (fdt
), s
);
220 new = strtab
+ fdt_size_dt_strings (fdt
);
221 err
= _fdt_splice_string (fdt
, len
);
226 memcpy (new, s
, len
);
227 return (new - strtab
);
237 struct fdt_reserve_entry
*re
;
240 FDT_RW_CHECK_HEADER (fdt
);
242 re
= _fdt_mem_rsv_w (fdt
, fdt_num_mem_rsv (fdt
));
243 err
= _fdt_splice_mem_rsv (fdt
, re
, 0, 1);
248 re
->address
= cpu_to_fdt64 (address
);
249 re
->size
= cpu_to_fdt64 (size
);
259 struct fdt_reserve_entry
*re
= _fdt_mem_rsv_w (fdt
, n
);
261 FDT_RW_CHECK_HEADER (fdt
);
263 if (n
>= fdt_num_mem_rsv (fdt
)) {
264 return -FDT_ERR_NOTFOUND
;
267 return _fdt_splice_mem_rsv (fdt
, re
, 1, 0);
271 _fdt_resize_property (
276 struct fdt_property
**prop
282 *prop
= fdt_get_property_w (fdt
, nodeoffset
, name
, &oldlen
);
287 if ((err
= _fdt_splice_struct (
290 FDT_TAGALIGN (oldlen
),
297 (*prop
)->len
= cpu_to_fdt32 (len
);
307 struct fdt_property
**prop
315 if ((nextoffset
= _fdt_check_node_offset (fdt
, nodeoffset
)) < 0) {
319 namestroff
= _fdt_find_add_string (fdt
, name
);
320 if (namestroff
< 0) {
324 *prop
= _fdt_offset_ptr_w (fdt
, nextoffset
);
325 proplen
= sizeof (**prop
) + FDT_TAGALIGN (len
);
327 err
= _fdt_splice_struct (fdt
, *prop
, 0, proplen
);
332 (*prop
)->tag
= cpu_to_fdt32 (FDT_PROP
);
333 (*prop
)->nameoff
= cpu_to_fdt32 (namestroff
);
334 (*prop
)->len
= cpu_to_fdt32 (len
);
349 FDT_RW_CHECK_HEADER (fdt
);
351 namep
= (char *)(uintptr_t)fdt_get_name (fdt
, nodeoffset
, &oldlen
);
356 newlen
= strlen (name
);
358 err
= _fdt_splice_struct (
361 FDT_TAGALIGN (oldlen
+1),
362 FDT_TAGALIGN (newlen
+1)
368 memcpy (namep
, name
, newlen
+1);
373 fdt_setprop_placeholder (
381 struct fdt_property
*prop
;
384 FDT_RW_CHECK_HEADER (fdt
);
386 err
= _fdt_resize_property (fdt
, nodeoffset
, name
, len
, &prop
);
387 if (err
== -FDT_ERR_NOTFOUND
) {
388 err
= _fdt_add_property (fdt
, nodeoffset
, name
, len
, &prop
);
395 *prop_data
= prop
->data
;
411 err
= fdt_setprop_placeholder (fdt
, nodeoffset
, name
, len
, &prop_data
);
417 memcpy (prop_data
, val
, len
);
432 struct fdt_property
*prop
;
433 int err
, oldlen
, newlen
;
435 FDT_RW_CHECK_HEADER (fdt
);
437 prop
= fdt_get_property_w (fdt
, nodeoffset
, name
, &oldlen
);
439 newlen
= len
+ oldlen
;
440 err
= _fdt_splice_struct (
443 FDT_TAGALIGN (oldlen
),
444 FDT_TAGALIGN (newlen
)
450 prop
->len
= cpu_to_fdt32 (newlen
);
451 memcpy (prop
->data
+ oldlen
, val
, len
);
453 err
= _fdt_add_property (fdt
, nodeoffset
, name
, len
, &prop
);
458 memcpy (prop
->data
, val
, len
);
471 struct fdt_property
*prop
;
474 FDT_RW_CHECK_HEADER (fdt
);
476 prop
= fdt_get_property_w (fdt
, nodeoffset
, name
, &len
);
481 proplen
= sizeof (*prop
) + FDT_TAGALIGN (len
);
482 return _fdt_splice_struct (fdt
, prop
, proplen
, 0);
486 fdt_add_subnode_namelen (
493 struct fdt_node_header
*nh
;
494 int offset
, nextoffset
;
500 FDT_RW_CHECK_HEADER (fdt
);
502 offset
= fdt_subnode_offset_namelen (fdt
, parentoffset
, name
, namelen
);
504 return -FDT_ERR_EXISTS
;
505 } else if (offset
!= -FDT_ERR_NOTFOUND
) {
509 /* Try to place the new node after the parent's properties */
510 fdt_next_tag (fdt
, parentoffset
, &nextoffset
); /* skip the BEGIN_NODE */
513 tag
= fdt_next_tag (fdt
, offset
, &nextoffset
);
514 } while ((tag
== FDT_PROP
) || (tag
== FDT_NOP
));
516 nh
= _fdt_offset_ptr_w (fdt
, offset
);
517 nodelen
= sizeof (*nh
) + FDT_TAGALIGN (namelen
+1) + FDT_TAGSIZE
;
519 err
= _fdt_splice_struct (fdt
, nh
, 0, nodelen
);
524 nh
->tag
= cpu_to_fdt32 (FDT_BEGIN_NODE
);
525 memset (nh
->name
, 0, FDT_TAGALIGN (namelen
+1));
526 memcpy (nh
->name
, name
, namelen
);
527 endtag
= (fdt32_t
*)((char *)nh
+ nodelen
- FDT_TAGSIZE
);
528 *endtag
= cpu_to_fdt32 (FDT_END_NODE
);
540 return fdt_add_subnode_namelen (fdt
, parentoffset
, name
, strlen (name
));
551 FDT_RW_CHECK_HEADER (fdt
);
553 endoffset
= _fdt_node_end_offset (fdt
, nodeoffset
);
558 return _fdt_splice_struct (
560 _fdt_offset_ptr_w (fdt
, nodeoffset
),
561 endoffset
- nodeoffset
,
574 int mem_rsv_off
, struct_off
, strings_off
;
576 mem_rsv_off
= FDT_ALIGN (sizeof (struct fdt_header
), 8);
577 struct_off
= mem_rsv_off
+ mem_rsv_size
;
578 strings_off
= struct_off
+ struct_size
;
580 memmove (new + mem_rsv_off
, old
+ fdt_off_mem_rsvmap (old
), mem_rsv_size
);
581 fdt_set_off_mem_rsvmap (new, mem_rsv_off
);
583 memmove (new + struct_off
, old
+ fdt_off_dt_struct (old
), struct_size
);
584 fdt_set_off_dt_struct (new, struct_off
);
585 fdt_set_size_dt_struct (new, struct_size
);
589 old
+ fdt_off_dt_strings (old
),
590 fdt_size_dt_strings (old
)
592 fdt_set_off_dt_strings (new, strings_off
);
593 fdt_set_size_dt_strings (new, fdt_size_dt_strings (old
));
604 int mem_rsv_size
, struct_size
;
606 const char *fdtstart
= fdt
;
607 const char *fdtend
= fdtstart
+ fdt_totalsize (fdt
);
610 FDT_CHECK_HEADER (fdt
);
612 mem_rsv_size
= (fdt_num_mem_rsv (fdt
)+1)
613 * sizeof (struct fdt_reserve_entry
);
615 if (fdt_version (fdt
) >= 17) {
616 struct_size
= fdt_size_dt_struct (fdt
);
619 while (fdt_next_tag (fdt
, struct_size
, &struct_size
) != FDT_END
) {
622 if (struct_size
< 0) {
627 if (!_fdt_blocks_misordered (fdt
, mem_rsv_size
, struct_size
)) {
628 /* no further work necessary */
629 err
= fdt_move (fdt
, buf
, bufsize
);
634 fdt_set_version (buf
, 17);
635 fdt_set_size_dt_struct (buf
, struct_size
);
636 fdt_set_totalsize (buf
, bufsize
);
640 /* Need to reorder */
641 newsize
= FDT_ALIGN (sizeof (struct fdt_header
), 8) + mem_rsv_size
642 + struct_size
+ fdt_size_dt_strings (fdt
);
644 if (bufsize
< newsize
) {
645 return -FDT_ERR_NOSPACE
;
648 /* First attempt to build converted tree at beginning of buffer */
650 /* But if that overlaps with the old tree... */
651 if (((tmp
+ newsize
) > fdtstart
) && (tmp
< fdtend
)) {
652 /* Try right after the old tree instead */
653 tmp
= (char *)(uintptr_t)fdtend
;
654 if ((tmp
+ newsize
) > ((char *)buf
+ bufsize
)) {
655 return -FDT_ERR_NOSPACE
;
659 _fdt_packblocks (fdt
, tmp
, mem_rsv_size
, struct_size
);
660 memmove (buf
, tmp
, newsize
);
662 fdt_set_magic (buf
, FDT_MAGIC
);
663 fdt_set_totalsize (buf
, bufsize
);
664 fdt_set_version (buf
, 17);
665 fdt_set_last_comp_version (buf
, 16);
666 fdt_set_boot_cpuid_phys (buf
, fdt_boot_cpuid_phys (fdt
));
678 FDT_RW_CHECK_HEADER (fdt
);
680 mem_rsv_size
= (fdt_num_mem_rsv (fdt
)+1)
681 * sizeof (struct fdt_reserve_entry
);
682 _fdt_packblocks (fdt
, fdt
, mem_rsv_size
, fdt_size_dt_struct (fdt
));
683 fdt_set_totalsize (fdt
, _fdt_data_size (fdt
));