nt9856x/code/hdal/samples/merge_fdtapp/merge_fdtapp.c
2023-03-28 15:07:53 +08:00

346 lines
7.2 KiB
C

/**
@brief merge fdt.app in mtd form a dtb file.\n
@author Niven Cho
@ingroup mhdal
@note Nothing.
Copyright Novatek Microelectronics Corp. 2018. All rights reserved.
*/
#include <stdio.h>
#include <stdlib.h>
#include <kwrap/cmdsys.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
#include <mtd/mtd-user.h>
#include <sys/ioctl.h>
#include "libfdt.h"
#define CFG_DEBUG_OUTPUT_FILE "/mnt/sd/output.dtb"
int chk_file_exist(const char *filename)
{
struct stat st;
if (stat(filename, &st) != 0) {
return -1;
} else {
return 0;
}
}
int remove_dummy(char *str, int len)
{
int i;
for (i = 0; i < len; i++) {
if (!isprint(str[i])) {
str[i] = 0;
return 0;
}
}
return 0;
}
int get_partition_phy_size(int fd)
{
mtd_info_t meminfo = {0};
if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
return -1;
}
return (int)meminfo.size;
}
int get_fdtapp_mtd_index(void)
{
int i;
char path[64] = {0};
char name[32] = {0};
// get mtd index of fdt.app
for (i = 0; i < 100; i++) {
sprintf(path, "/sys/class/mtd/mtd%d/name", i);
if (chk_file_exist(path) != 0) {
continue;
}
//check lable name
FILE *fptr = fopen(path, "rt");
if (fptr == NULL) {
fprintf(stderr, "unable to open %s.\n", path);
return -1;
}
if (fread(name, 1, sizeof(name), fptr) < 1) {
fprintf(stderr, "failed to read %s.\n", path);
fclose(fptr);
return -1;
}
fclose(fptr);
// because name include '\n'.
remove_dummy(name, sizeof(name));
if (strncmp(name, "fdt.app", 8) == 0) {
return i;
}
}
return -1;
}
int load_dtb_from_rootfs(unsigned char **pp_dtb, int *p_dtb_size, const char *path)
{
struct stat st;
unsigned char *p_dtb = NULL;
if (chk_file_exist(path) != 0) {
fprintf(stderr, "unable to open %s.\n", path);
return -1;
} else {
int fd = open(path, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "unable to open %s.\n", path);
return -1;
}
if (stat(path, &st) != 0) {
fprintf(stderr, "unable to stat %s\n", path);
close(fd);
return -1;
}
p_dtb = (unsigned char *)malloc(st.st_size);
if (p_dtb == NULL) {
fprintf(stderr, "failed to alloc memory %d bytes for %s\n", st.st_size, path);
close(fd);
return -1;
}
if (read(fd, p_dtb, st.st_size) != st.st_size) {
fprintf(stderr, "unable to read data from %s.\n", path);
free(p_dtb);
close(fd);
return -1;
}
close(fd);
if (fdt_check_full(p_dtb, st.st_size) != 0) {
fprintf(stderr, "invalid fdt on %s.\n", path);
free(p_dtb);
return -1;
}
}
*pp_dtb = p_dtb;
*p_dtb_size = (int)st.st_size;
return 0;
}
int load_fdt_from_mtd(unsigned char **pp_fdt, int *p_fdt_size, const char *path)
{
unsigned char *p_fdt = NULL;
if (chk_file_exist(path) != 0) {
fprintf(stderr, "unable to open %s.\n", path);
return -1;
}
int fd = open(path, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "unable to open %s.\n", path);
return -1;
}
//got mtd partition size
int partition_size = get_partition_phy_size(fd);
if (partition_size < 0) {
fprintf(stderr, "unable to get partition size from %s.\n", path);
close(fd);
return -1;
}
p_fdt = (unsigned char *)malloc(partition_size);
if (p_fdt == NULL) {
fprintf(stderr, "failed to alloc memory %d bytes for %s\n", partition_size, path);
close(fd);
return -1;
}
if (read(fd, p_fdt, partition_size) != partition_size) {
fprintf(stderr, "unable to read data from %s.\n", path);
free(p_fdt);
close(fd);
return -1;
}
close(fd);
//check fdt
int er = fdt_check_full(p_fdt, partition_size);
if (er != 0) {
fprintf(stderr, "invalid fdt on %s.\n", path);
free(p_fdt);
return -1;
}
// enlarge the size to write more nodes
fdt_set_totalsize(p_fdt, partition_size);
*pp_fdt = p_fdt;
*p_fdt_size = partition_size;
return 0;
}
static int fdt_find_or_add_subnode(void *fdt, int parentoffset, const char *name)
{
int offset;
offset = fdt_subnode_offset(fdt, parentoffset, name);
if (offset == -FDT_ERR_NOTFOUND) {
offset = fdt_add_subnode(fdt, parentoffset, name);
}
if (offset < 0) {
printf("%s: %s: %s\n", __func__, name, fdt_strerror(offset));
}
return offset;
}
static int merge_node(void *fdt_dst, void *fdt_src, const char *node_name)
{
int er;
int len;
int child;
char path[256] = { 0 };
if (fdt_dst == NULL || fdt_src == NULL) {
printf("merge_node: one of fdt is NULL\n");
return -1;
}
int src_parent = fdt_path_offset(fdt_src, node_name);
int dst_parent = fdt_path_offset(fdt_dst, node_name);
if (dst_parent <= 0) {
printf("unable to find %s on dst fdt.\n", node_name);
return -1;
}
if (src_parent <= 0) {
printf("unable to find %s on src fdt.\n", node_name);
return -1;
}
fdt_for_each_property_offset(child, fdt_src, src_parent) {
const struct fdt_property *fdt_prop = fdt_get_property_by_offset(fdt_src, child, &len);
const char *name = fdt_string(fdt_src, fdt32_to_cpu(fdt_prop->nameoff));
len = fdt32_to_cpu(fdt_prop->len);
const void *nodep = fdt_prop->data;
if ((er = fdt_setprop(fdt_dst, dst_parent, name, nodep, len)) != 0) {
printf("failed to fdt_setprop %s, er = %d\n", name, er);
return er;
}
}
fdt_for_each_subnode(child, fdt_src, src_parent) {
const char *name = fdt_get_name(fdt_src, child, &len);
sprintf(path, "%s/%s", node_name, name);
if (fdt_find_or_add_subnode(fdt_dst, dst_parent, name) <= 0) {
return -1;
}
if ((er = merge_node(fdt_dst, fdt_src, path)) != 0) {
return er;
}
}
return 0;
}
int erase_mtd(const char *path, int size)
{
int fd = open(path, O_RDWR);
if (fd < 0) {
fprintf(stderr, "unable to open %s.\n", path);
return -1;
}
erase_info_t erase;
erase.start = 0;
erase.length = size;
if (ioctl(fd, MEMERASE, &erase) < 0) {
fprintf(stderr, "erase failed\n");
close(fd);
return -1;
}
close(fd);
return 0;
}
int merge_fdtapp(const char *path_dtb)
{
unsigned char *p_dtb = NULL;
unsigned char *p_fdt = NULL;
int dtb_size = 0, fdt_size = 0;
// load source dtb
if (load_dtb_from_rootfs(&p_dtb, &dtb_size, path_dtb) != 0) {
return -1;
}
// get mtd index
int mtd_idx = get_fdtapp_mtd_index();
if (mtd_idx < 0) {
fprintf(stderr, "unable to find fdt.app from mtd.\n");
free(p_dtb);
return -1;
}
// load target fdt
char path_mtd[64] = {0};
sprintf(path_mtd, "/dev/mtd%d", mtd_idx);
if (load_fdt_from_mtd(&p_fdt, &fdt_size, path_mtd) != 0) {
free(p_dtb);
return -1;
}
// merge
if (merge_node(p_fdt, p_dtb, "/fastboot") != 0) {
fprintf(stderr, "failed to merge.\n");
free(p_fdt);
free(p_dtb);
return -1;
}
//make it real size
fdt_pack(p_fdt);
// erase mtd before written
if (erase_mtd(path_mtd, fdt_size) != 0) {
free(p_fdt);
free(p_dtb);
return -1;
}
// write mtd
int fd = open(path_mtd, O_RDWR);
int written = write(fd, p_fdt, fdt_size);
printf("merge_fdtapp wrote %d bytes into %s\n", written, path_mtd);
close(fd);
#if 0 //write to sd card
fd = open(CFG_DEBUG_OUTPUT_FILE, O_CREAT | O_WRONLY | O_SYNC);
write(fd, p_fdt, fdt_totalsize(p_fdt));
close(fd);
#endif
free(p_fdt);
free(p_dtb);
return 0;
}
MAINFUNC_ENTRY(merge_fdtapp, argc, argv)
{
#if 0
return merge_fdtapp("/etc/plugin_hdr.dtb");
#else
if (argc < 2) {
fprintf(stderr, "usage: merge_fdtapp [dtb]\n");
return -1;
}
return merge_fdtapp(argv[1]);
#endif
}