14f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin/*
24f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin * Copyright (C) 2017 The Android Open Source Project
34f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin *
44f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin * Licensed under the Apache License, Version 2.0 (the "License");
54f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin * you may not use this file except in compliance with the License.
64f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin * You may obtain a copy of the License at
74f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin *
84f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin *      http://www.apache.org/licenses/LICENSE-2.0
94f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin *
104f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin * Unless required by applicable law or agreed to in writing, software
114f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin * distributed under the License is distributed on an "AS IS" BASIS,
124f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin * See the License for the specific language governing permissions and
144f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin * limitations under the License.
154f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin */
164f00eda9fa05364edd719b05b88e4445682eeee5SzuWei Lin
17780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin#include "mkdtimg_core.h"
18780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
19780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin#include <stdio.h>
20780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin#include <stdlib.h>
21780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin#include <string.h>
22780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin#include <stdint.h>
23780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin#include <unistd.h>
24780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
25780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin#include "libfdt.h"
26780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
27780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin#include "dt_table.h"
28780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
29780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin#define DEBUG 0
30780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
31780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
32780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linstruct dt_options {
33780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  char id[OPTION_VALUE_SIZE_MAX];
34780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  char rev[OPTION_VALUE_SIZE_MAX];
35780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  char custom[4][OPTION_VALUE_SIZE_MAX];
36780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin};
37780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
38780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linstruct dt_global_options {
39780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  struct dt_options default_options;
40780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  uint32_t page_size;
41780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin};
42780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
43780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linstruct dt_image_writer {
44780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  FILE *img_fp;
45780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
46780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  struct dt_global_options global_options;
47780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  struct dt_options entry_options;
48780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
49780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  char entry_filename[1024];
50780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  uint32_t entry_count;
51780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  uint32_t entry_offset;
52780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  uint32_t dt_offset;
5397a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu
5497a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  char (*past_filenames)[1024];
5597a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  uint32_t *past_dt_offsets;
56780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin};
57780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
58780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
59780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linstatic void init_dt_options(struct dt_options *options) {
60780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  memset(options, 0, sizeof(struct dt_options));
61780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin}
62780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
63780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linstatic void init_dt_global_options(struct dt_global_options *options) {
64780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  init_dt_options(&options->default_options);
65780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  options->page_size = DT_TABLE_DEFAULT_PAGE_SIZE;
66780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin}
67780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
68780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linstatic void copy_dt_options(struct dt_options *target, struct dt_options *options) {
69780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  memcpy(target, options, sizeof(struct dt_options));
70780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin}
71780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
72780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linstatic char *load_file_contents(FILE *fp, size_t *len_ptr) {
73780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  // Gets the file size.
74780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  fseek(fp, 0, SEEK_END);
75780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  size_t len = ftell(fp);
76780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  fseek(fp, 0, SEEK_SET);
77780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
78780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  char *buf = malloc(len);
79780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  if (buf == NULL) {
80780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    return NULL;
81780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
82780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
83780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  if (fread(buf, len, 1, fp) != 1) {
84780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    free(buf);
85780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    return NULL;
86780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
87780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
88780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  if (len_ptr) {
89780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    *len_ptr = len;
90780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
91780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
92780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  return buf;
93780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin}
94780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
95780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linstatic char *load_file(const char *filename, size_t *len_ptr) {
96780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  FILE *fp = fopen(filename, "r");
97780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  if (!fp) {
98780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    return NULL;
99780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
100780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
101780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  char *buf = load_file_contents(fp, len_ptr);
102780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
103780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  fclose(fp);
104780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
105780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  return buf;
106780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin}
107780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
108780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linstatic int split_str(char **lhs_ptr, char **rhs_ptr, char *string, char c) {
109780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  char *middle_ptr = strchr(string, c);
110780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  if (middle_ptr == NULL) {
111780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    return -1;
112780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
113780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
114780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  *middle_ptr = '\0';
115780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
116780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  *lhs_ptr = string;
117780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  *rhs_ptr = middle_ptr + 1;
118780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
119780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  return 0;
120780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin}
121780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
122780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linint parse_option(char **option_ptr, char **value_ptr, char *line_str) {
123780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  return split_str(option_ptr, value_ptr, line_str, '=');
124780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin}
125780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
126780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linint parse_path(char **path_ptr, char **prop_ptr, char *value_str) {
127780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  return split_str(path_ptr, prop_ptr, value_str, ':');
128780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin}
129780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
130780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linstatic fdt32_t get_fdt32_from_prop(void *fdt, const char *path, const char *prop) {
131780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  int node_off = fdt_path_offset(fdt, path);
132780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  if (node_off < 0) {
133780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    fprintf(stderr, "Can not find node: %s\n", path);
134780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    return 0;
135780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
136780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
137780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  int len;
138780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  fdt32_t *prop_value_ptr = (fdt32_t *)fdt_getprop(fdt, node_off, prop, &len);
139780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  if (prop_value_ptr == NULL) {
140780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    fprintf(stderr, "Can not find property: %s:%s\n", path, prop);
141780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    return 0;
142780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
143780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
1447b226bf72a0fd3fefcf7daca4991818187e338f8SzuWei Lin  fdt32_t value = *prop_value_ptr;
145780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  /* TODO: check len */
146780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  if (DEBUG) printf("%s:%s => %08x\n", path, prop, fdt32_to_cpu(value));
147780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
148780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  return value;
149780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin}
150780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
151780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linstatic fdt32_t get_fdt32_from_number_or_prop(void *fdt, char *value_str) {
152780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  if (value_str[0] == '/') {
153780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    char *path, *prop;
154780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    if (parse_path(&path, &prop, value_str) != 0) {
155780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      fprintf(stderr, "Wrong syntax: %s\n", value_str);
156780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      return 0;
157780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    }
158780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    return get_fdt32_from_prop(fdt, path, prop);
159780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
160780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
161780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  /* It should be a number */
162780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  char *end;
163780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  uint32_t value = strtoul(value_str, &end, 0);
164780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  /* TODO: check end */
165780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  return cpu_to_fdt32(value);
166780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin}
167780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
168780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linstatic int output_img_header(FILE *img_fp,
169780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin                             uint32_t entry_count, uint32_t total_size,
170780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin                             struct dt_global_options *options) {
171780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  struct dt_table_header header;
172780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  dt_table_header_init(&header);
173780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  header.dt_entry_count = cpu_to_fdt32(entry_count);
174780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  header.total_size = cpu_to_fdt32(total_size);
175780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  header.page_size = cpu_to_fdt32(options->page_size);
176780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
177780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  fseek(img_fp, 0, SEEK_SET);
178780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  fwrite(&header, sizeof(header), 1, img_fp);
179780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
180780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  return 0;
181780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin}
182780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
18397a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhustatic int32_t output_img_entry(FILE *img_fp, size_t entry_offset,
18497a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu                                size_t dt_offset, const char *fdt_filename,
18597a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu                                struct dt_options *options, int reuse_fdt) {
18697a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  int32_t ret = -1;
187780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  void *fdt = NULL;
188780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
189780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  size_t fdt_file_size;
190780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  fdt = load_file(fdt_filename, &fdt_file_size);
191780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  if (fdt == NULL) {
192780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    fprintf(stderr, "Can not read file: %s\n", fdt_filename);
193780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    goto end;
194780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
195780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
196780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  if (fdt_check_header(fdt) != 0) {
197780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    fprintf(stderr, "Bad FDT header: \n", fdt_filename);
198780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    goto end;
199780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
200780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
201780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  size_t fdt_size = fdt_totalsize(fdt);
202780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  if (fdt_size != fdt_file_size) {
203780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    fprintf(stderr, "The file size and FDT size are not matched: %s\n", fdt_filename);
204780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    goto end;
205780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
206780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
207780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  /* Prepare dt_table_entry and output */
208780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  struct dt_table_entry entry;
209780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  entry.dt_size = cpu_to_fdt32(fdt_size);
210780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  entry.dt_offset = cpu_to_fdt32(dt_offset);
211780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  entry.id = get_fdt32_from_number_or_prop(fdt, options->id);
212780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  entry.rev = get_fdt32_from_number_or_prop(fdt, options->rev);
213780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  entry.custom[0] = get_fdt32_from_number_or_prop(fdt, options->custom[0]);
214780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  entry.custom[1] = get_fdt32_from_number_or_prop(fdt, options->custom[1]);
215780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  entry.custom[2] = get_fdt32_from_number_or_prop(fdt, options->custom[2]);
216780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  entry.custom[3] = get_fdt32_from_number_or_prop(fdt, options->custom[3]);
217780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  fseek(img_fp, entry_offset, SEEK_SET);
218780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  fwrite(&entry, sizeof(entry), 1, img_fp);
219780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
220780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  /* Output FDT */
22197a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  if (!reuse_fdt) {
22297a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu    fseek(img_fp, dt_offset, SEEK_SET);
22397a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu    fwrite(fdt, fdt_file_size, 1, img_fp);
22497a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu    ret = fdt_file_size;
22597a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  } else {
22697a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu    ret = 0;
22797a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  }
228780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
229780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linend:
230780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  if (fdt) free(fdt);
231780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
232780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  return ret;
233780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin}
234780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
235780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
236780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linstruct dt_image_writer *dt_image_writer_start(FILE *img_fp, uint32_t entry_count) {
237780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  struct dt_image_writer *writer = malloc(sizeof(struct dt_image_writer));
23897a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  if (!writer) goto error;
23997a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  writer->past_filenames = calloc(entry_count, sizeof(*writer->past_filenames));
24097a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  if (!writer->past_filenames) goto error;
24197a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  writer->past_dt_offsets =
24297a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu      calloc(entry_count, sizeof(*writer->past_dt_offsets));
24397a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  if (!writer->past_dt_offsets) goto error;
244780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  writer->img_fp = img_fp;
245780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  init_dt_global_options(&writer->global_options);
246780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  init_dt_options(&writer->entry_options);
247780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  writer->entry_filename[0] = '\0';
248780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  writer->entry_count = entry_count;
249780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  writer->entry_offset = sizeof(struct dt_table_header);
250780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  writer->dt_offset =
251780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      writer->entry_offset + sizeof(struct dt_table_entry) * entry_count;
252780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  return writer;
25397a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu
25497a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhuerror:
25597a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  fprintf(stderr, "Unable to start writer\n");
25697a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  if (!writer) return NULL;
25797a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  if (writer->past_filenames) free(writer->past_filenames);
25897a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  if (writer->past_dt_offsets) free(writer->past_dt_offsets);
25997a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  free(writer);
26097a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  return NULL;
261780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin}
262780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
263780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linstatic int set_dt_options(struct dt_options *options,
264780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin                          const char *option, const char *value) {
265780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  if (strcmp(option, "id") == 0) {
266780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    strncpy(options->id, value, OPTION_VALUE_SIZE_MAX - 1);
267780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  } else if (strcmp(option, "rev") == 0) {
268780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    strncpy(options->rev, value, OPTION_VALUE_SIZE_MAX - 1);
269780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  } else if (strcmp(option, "custom0") == 0) {
270780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    strncpy(options->custom[0], value, OPTION_VALUE_SIZE_MAX - 1);
271780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  } else if (strcmp(option, "custom1") == 0) {
272780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    strncpy(options->custom[1], value, OPTION_VALUE_SIZE_MAX - 1);
273780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  } else if (strcmp(option, "custom2") == 0) {
274780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    strncpy(options->custom[2], value, OPTION_VALUE_SIZE_MAX - 1);
275780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  } else if (strcmp(option, "custom3") == 0) {
276780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    strncpy(options->custom[3], value, OPTION_VALUE_SIZE_MAX - 1);
277780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  } else {
278780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    return -1;
279780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
280780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
281780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  return 0;
282780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin}
283780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
284780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linint set_global_options(struct dt_image_writer *writer,
285780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin                       const char *option, const char *value) {
286780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  struct dt_global_options *global_options = &writer->global_options;
287780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
288780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  if (strcmp(option, "page_size") == 0) {
289780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    global_options->page_size = strtoul(value, NULL, 0);
290780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  } else {
291780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    return set_dt_options(&global_options->default_options, option, value);
292780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
293780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
294780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  return 0;
295780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin}
296780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
297780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linint set_entry_options(struct dt_image_writer *writer,
298780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin                      const char *option, const char *value) {
299780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  return set_dt_options(&writer->entry_options, option, value);
300780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin}
301780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
302780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linstatic int flush_entry_to_img(struct dt_image_writer *writer) {
303780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  if (writer->entry_filename[0] == '\0') {
304780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    return 0;
305780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
306780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
30797a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  int reuse_fdt;
30897a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  int fdt_idx;
30997a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  uint32_t dt_offset;
31097a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu
31197a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  for (fdt_idx = 0; writer->past_filenames[fdt_idx][0] != '\0'; fdt_idx++) {
31297a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu    if (strcmp(writer->past_filenames[fdt_idx], writer->entry_filename) == 0)
31397a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu      break;
31497a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  }
31597a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu
31697a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  if (writer->past_filenames[fdt_idx][0] != '\0') {
31797a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu    reuse_fdt = 1;
31897a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu    dt_offset = writer->past_dt_offsets[fdt_idx];
31997a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  } else {
32097a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu    reuse_fdt = 0;
32197a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu    dt_offset = writer->dt_offset;
32297a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  }
32397a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  int32_t dt_size = output_img_entry(writer->img_fp, writer->entry_offset,
32497a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu                                     dt_offset, writer->entry_filename,
32597a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu                                     &writer->entry_options, reuse_fdt);
32697a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  if (dt_size == -1) return -1;
32797a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu
32897a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  if (!reuse_fdt) {
32997a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu    strncpy(writer->past_filenames[fdt_idx], writer->entry_filename,
33097a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu            sizeof(writer->past_filenames[fdt_idx]) - 1);
33197a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu    writer->past_dt_offsets[fdt_idx] = dt_offset;
332780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
333780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
334780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  writer->entry_offset += sizeof(struct dt_table_entry);
335780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  writer->dt_offset += dt_size;
336780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
337780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  return 0;
338780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin}
339780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
340780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linint dt_image_writer_add_entry(struct dt_image_writer *writer,
341780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin                              const char *fdt_filename) {
342780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  if (flush_entry_to_img(writer) != 0) {
343780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    return -1;
344780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
345780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
346780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  strncpy(
347780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      writer->entry_filename,
348780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      fdt_filename,
349780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      sizeof(writer->entry_filename) - 1);
350780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
351780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  /* Copy the default_options as default */
352780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  copy_dt_options(
353780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      &writer->entry_options,
354780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      &writer->global_options.default_options);
355780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
356780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  return 0;
357780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin}
358780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
359780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linint dt_image_writer_end(struct dt_image_writer *writer) {
360780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  int ret = -1;
361780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
362780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  if (flush_entry_to_img(writer) != 0) {
363780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    goto end;
364780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
365780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
366780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  if (output_img_header(
367780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      writer->img_fp,
368780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      writer->entry_count,
369780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      writer->dt_offset,
370780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin      &writer->global_options) != 0) {
371780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin    goto end;
372780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  }
373780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
374780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  printf("Total %d entries.\n", writer->entry_count);
375780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  ret = 0;
376780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
377780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Linend:
37897a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  free(writer->past_filenames);
37997a832f2a345b6bb090dd4adc9f6e8b50e11b3daYueyao Zhu  free(writer->past_dt_offsets);
380780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  free(writer);
381780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin
382780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin  return ret;
383780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9SzuWei Lin}
384