scripts/dtc/libfdt/fdt_rw.c

Source file repositories/reference/linux-study-clean/scripts/dtc/libfdt/fdt_rw.c

File Facts

System
Linux kernel
Corpus path
scripts/dtc/libfdt/fdt_rw.c
Extension
.c
Size
12589 bytes
Lines
513
Domain
Support Tooling And Documentation
Bucket
scripts
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
 * libfdt - Flat Device Tree manipulation
 * Copyright (C) 2006 David Gibson, IBM Corporation.
 */
#include "libfdt_env.h"

#include <fdt.h>
#include <libfdt.h>

#include "libfdt_internal.h"

static int fdt_blocks_misordered_(const void *fdt,
				  int mem_rsv_size, int struct_size)
{
	return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
		|| (fdt_off_dt_struct(fdt) <
		    (fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
		|| (fdt_off_dt_strings(fdt) <
		    (fdt_off_dt_struct(fdt) + struct_size))
		|| (fdt_totalsize(fdt) <
		    (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
}

static void fdt_downgrade_version(void *fdt)
{
	if (!can_assume(LATEST) && fdt_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
		fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
}

static int fdt_rw_probe_(void *fdt)
{
	if (can_assume(VALID_DTB))
		return 0;
	FDT_RO_PROBE(fdt);

	if (!can_assume(LATEST) && fdt_version(fdt) < 17)
		return -FDT_ERR_BADVERSION;
	if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry),
				   fdt_size_dt_struct(fdt)))
		return -FDT_ERR_BADLAYOUT;

	fdt_downgrade_version(fdt);
	return 0;
}

#define FDT_RW_PROBE(fdt) \
	{ \
		int err_; \
		if ((err_ = fdt_rw_probe_(fdt)) != 0) \
			return err_; \
	}

static inline unsigned int fdt_data_size_(void *fdt)
{
	return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
}

static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen)
{
	char *p = splicepoint;
	unsigned int dsize = fdt_data_size_(fdt);
	size_t soff = p - (char *)fdt;

	if ((oldlen < 0) || (soff + oldlen < soff) || (soff + oldlen > dsize))
		return -FDT_ERR_BADOFFSET;
	if ((p < (char *)fdt) || (dsize + newlen < (unsigned)oldlen))
		return -FDT_ERR_BADOFFSET;
	if (dsize - oldlen + newlen > fdt_totalsize(fdt))
		return -FDT_ERR_NOSPACE;
	memmove(p + newlen, p + oldlen, ((char *)fdt + dsize) - (p + oldlen));
	return 0;
}

static int fdt_splice_mem_rsv_(void *fdt, struct fdt_reserve_entry *p,
			       int oldn, int newn)
{
	int delta = (newn - oldn) * sizeof(*p);
	int err;
	err = fdt_splice_(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
	if (err)
		return err;
	fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
	fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
	return 0;
}

static int fdt_splice_struct_(void *fdt, void *p,
			      int oldlen, int newlen)
{

Annotation

Implementation Notes