• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "mkdtimg_core.h"
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <stdint.h>
23 #include <unistd.h>
24 
25 #include "libfdt.h"
26 
27 #include "dt_table.h"
28 
29 #define DEBUG 0
30 
31 
32 struct dt_options {
33   char id[OPTION_VALUE_SIZE_MAX];
34   char rev[OPTION_VALUE_SIZE_MAX];
35   char custom[4][OPTION_VALUE_SIZE_MAX];
36 };
37 
38 struct dt_global_options {
39   struct dt_options default_options;
40   uint32_t page_size;
41 };
42 
43 struct dt_image_writer {
44   FILE *img_fp;
45 
46   struct dt_global_options global_options;
47   struct dt_options entry_options;
48 
49   char entry_filename[1024];
50   uint32_t entry_count;
51   uint32_t entry_offset;
52   uint32_t dt_offset;
53 
54   char (*past_filenames)[1024];
55   uint32_t *past_dt_offsets;
56 };
57 
58 
init_dt_options(struct dt_options * options)59 static void init_dt_options(struct dt_options *options) {
60   memset(options, 0, sizeof(struct dt_options));
61 }
62 
init_dt_global_options(struct dt_global_options * options)63 static void init_dt_global_options(struct dt_global_options *options) {
64   init_dt_options(&options->default_options);
65   options->page_size = DT_TABLE_DEFAULT_PAGE_SIZE;
66 }
67 
copy_dt_options(struct dt_options * target,struct dt_options * options)68 static void copy_dt_options(struct dt_options *target, struct dt_options *options) {
69   memcpy(target, options, sizeof(struct dt_options));
70 }
71 
load_file_contents(FILE * fp,size_t * len_ptr)72 static char *load_file_contents(FILE *fp, size_t *len_ptr) {
73   // Gets the file size.
74   fseek(fp, 0, SEEK_END);
75   size_t len = ftell(fp);
76   fseek(fp, 0, SEEK_SET);
77 
78   char *buf = malloc(len);
79   if (buf == NULL) {
80     return NULL;
81   }
82 
83   if (fread(buf, len, 1, fp) != 1) {
84     free(buf);
85     return NULL;
86   }
87 
88   if (len_ptr) {
89     *len_ptr = len;
90   }
91 
92   return buf;
93 }
94 
load_file(const char * filename,size_t * len_ptr)95 static char *load_file(const char *filename, size_t *len_ptr) {
96   FILE *fp = fopen(filename, "r");
97   if (!fp) {
98     return NULL;
99   }
100 
101   char *buf = load_file_contents(fp, len_ptr);
102 
103   fclose(fp);
104 
105   return buf;
106 }
107 
split_str(char ** lhs_ptr,char ** rhs_ptr,char * string,char c)108 static int split_str(char **lhs_ptr, char **rhs_ptr, char *string, char c) {
109   char *middle_ptr = strchr(string, c);
110   if (middle_ptr == NULL) {
111     return -1;
112   }
113 
114   *middle_ptr = '\0';
115 
116   *lhs_ptr = string;
117   *rhs_ptr = middle_ptr + 1;
118 
119   return 0;
120 }
121 
parse_option(char ** option_ptr,char ** value_ptr,char * line_str)122 int parse_option(char **option_ptr, char **value_ptr, char *line_str) {
123   return split_str(option_ptr, value_ptr, line_str, '=');
124 }
125 
parse_path(char ** path_ptr,char ** prop_ptr,char * value_str)126 int parse_path(char **path_ptr, char **prop_ptr, char *value_str) {
127   return split_str(path_ptr, prop_ptr, value_str, ':');
128 }
129 
get_fdt32_from_prop(void * fdt,const char * path,const char * prop)130 static fdt32_t get_fdt32_from_prop(void *fdt, const char *path, const char *prop) {
131   int node_off = fdt_path_offset(fdt, path);
132   if (node_off < 0) {
133     fprintf(stderr, "Can not find node: %s\n", path);
134     return 0;
135   }
136 
137   int len;
138   fdt32_t *prop_value_ptr = (fdt32_t *)fdt_getprop(fdt, node_off, prop, &len);
139   if (prop_value_ptr == NULL) {
140     fprintf(stderr, "Can not find property: %s:%s\n", path, prop);
141     return 0;
142   }
143 
144   fdt32_t value = *prop_value_ptr;
145   /* TODO: check len */
146   if (DEBUG) printf("%s:%s => %08x\n", path, prop, fdt32_to_cpu(value));
147 
148   return value;
149 }
150 
get_fdt32_from_number_or_prop(void * fdt,char * value_str)151 static fdt32_t get_fdt32_from_number_or_prop(void *fdt, char *value_str) {
152   if (value_str[0] == '/') {
153     char *path, *prop;
154     if (parse_path(&path, &prop, value_str) != 0) {
155       fprintf(stderr, "Wrong syntax: %s\n", value_str);
156       return 0;
157     }
158     return get_fdt32_from_prop(fdt, path, prop);
159   }
160 
161   /* It should be a number */
162   char *end;
163   uint32_t value = strtoul(value_str, &end, 0);
164   /* TODO: check end */
165   return cpu_to_fdt32(value);
166 }
167 
output_img_header(FILE * img_fp,uint32_t entry_count,uint32_t total_size,struct dt_global_options * options)168 static int output_img_header(FILE *img_fp,
169                              uint32_t entry_count, uint32_t total_size,
170                              struct dt_global_options *options) {
171   struct dt_table_header header;
172   dt_table_header_init(&header);
173   header.dt_entry_count = cpu_to_fdt32(entry_count);
174   header.total_size = cpu_to_fdt32(total_size);
175   header.page_size = cpu_to_fdt32(options->page_size);
176 
177   fseek(img_fp, 0, SEEK_SET);
178   fwrite(&header, sizeof(header), 1, img_fp);
179 
180   return 0;
181 }
182 
output_img_entry(FILE * img_fp,size_t entry_offset,size_t dt_offset,const char * fdt_filename,struct dt_options * options,int reuse_fdt)183 static int32_t output_img_entry(FILE *img_fp, size_t entry_offset,
184                                 size_t dt_offset, const char *fdt_filename,
185                                 struct dt_options *options, int reuse_fdt) {
186   int32_t ret = -1;
187   void *fdt = NULL;
188 
189   size_t fdt_file_size;
190   fdt = load_file(fdt_filename, &fdt_file_size);
191   if (fdt == NULL) {
192     fprintf(stderr, "Can not read file: %s\n", fdt_filename);
193     goto end;
194   }
195 
196   if (fdt_check_header(fdt) != 0) {
197     fprintf(stderr, "Bad FDT header: \n", fdt_filename);
198     goto end;
199   }
200 
201   size_t fdt_size = fdt_totalsize(fdt);
202   if (fdt_size != fdt_file_size) {
203     fprintf(stderr, "The file size and FDT size are not matched: %s\n", fdt_filename);
204     goto end;
205   }
206 
207   /* Prepare dt_table_entry and output */
208   struct dt_table_entry entry;
209   entry.dt_size = cpu_to_fdt32(fdt_size);
210   entry.dt_offset = cpu_to_fdt32(dt_offset);
211   entry.id = get_fdt32_from_number_or_prop(fdt, options->id);
212   entry.rev = get_fdt32_from_number_or_prop(fdt, options->rev);
213   entry.custom[0] = get_fdt32_from_number_or_prop(fdt, options->custom[0]);
214   entry.custom[1] = get_fdt32_from_number_or_prop(fdt, options->custom[1]);
215   entry.custom[2] = get_fdt32_from_number_or_prop(fdt, options->custom[2]);
216   entry.custom[3] = get_fdt32_from_number_or_prop(fdt, options->custom[3]);
217   fseek(img_fp, entry_offset, SEEK_SET);
218   fwrite(&entry, sizeof(entry), 1, img_fp);
219 
220   /* Output FDT */
221   if (!reuse_fdt) {
222     fseek(img_fp, dt_offset, SEEK_SET);
223     fwrite(fdt, fdt_file_size, 1, img_fp);
224     ret = fdt_file_size;
225   } else {
226     ret = 0;
227   }
228 
229 end:
230   if (fdt) free(fdt);
231 
232   return ret;
233 }
234 
235 
dt_image_writer_start(FILE * img_fp,uint32_t entry_count)236 struct dt_image_writer *dt_image_writer_start(FILE *img_fp, uint32_t entry_count) {
237   struct dt_image_writer *writer = malloc(sizeof(struct dt_image_writer));
238   if (!writer) goto error;
239   writer->past_filenames = calloc(entry_count, sizeof(*writer->past_filenames));
240   if (!writer->past_filenames) goto error;
241   writer->past_dt_offsets =
242       calloc(entry_count, sizeof(*writer->past_dt_offsets));
243   if (!writer->past_dt_offsets) goto error;
244   writer->img_fp = img_fp;
245   init_dt_global_options(&writer->global_options);
246   init_dt_options(&writer->entry_options);
247   writer->entry_filename[0] = '\0';
248   writer->entry_count = entry_count;
249   writer->entry_offset = sizeof(struct dt_table_header);
250   writer->dt_offset =
251       writer->entry_offset + sizeof(struct dt_table_entry) * entry_count;
252   return writer;
253 
254 error:
255   fprintf(stderr, "Unable to start writer\n");
256   if (!writer) return NULL;
257   if (writer->past_filenames) free(writer->past_filenames);
258   if (writer->past_dt_offsets) free(writer->past_dt_offsets);
259   free(writer);
260   return NULL;
261 }
262 
set_dt_options(struct dt_options * options,const char * option,const char * value)263 static int set_dt_options(struct dt_options *options,
264                           const char *option, const char *value) {
265   if (strcmp(option, "id") == 0) {
266     strncpy(options->id, value, OPTION_VALUE_SIZE_MAX - 1);
267   } else if (strcmp(option, "rev") == 0) {
268     strncpy(options->rev, value, OPTION_VALUE_SIZE_MAX - 1);
269   } else if (strcmp(option, "custom0") == 0) {
270     strncpy(options->custom[0], value, OPTION_VALUE_SIZE_MAX - 1);
271   } else if (strcmp(option, "custom1") == 0) {
272     strncpy(options->custom[1], value, OPTION_VALUE_SIZE_MAX - 1);
273   } else if (strcmp(option, "custom2") == 0) {
274     strncpy(options->custom[2], value, OPTION_VALUE_SIZE_MAX - 1);
275   } else if (strcmp(option, "custom3") == 0) {
276     strncpy(options->custom[3], value, OPTION_VALUE_SIZE_MAX - 1);
277   } else {
278     return -1;
279   }
280 
281   return 0;
282 }
283 
set_global_options(struct dt_image_writer * writer,const char * option,const char * value)284 int set_global_options(struct dt_image_writer *writer,
285                        const char *option, const char *value) {
286   struct dt_global_options *global_options = &writer->global_options;
287 
288   if (strcmp(option, "page_size") == 0) {
289     global_options->page_size = strtoul(value, NULL, 0);
290   } else {
291     return set_dt_options(&global_options->default_options, option, value);
292   }
293 
294   return 0;
295 }
296 
set_entry_options(struct dt_image_writer * writer,const char * option,const char * value)297 int set_entry_options(struct dt_image_writer *writer,
298                       const char *option, const char *value) {
299   return set_dt_options(&writer->entry_options, option, value);
300 }
301 
flush_entry_to_img(struct dt_image_writer * writer)302 static int flush_entry_to_img(struct dt_image_writer *writer) {
303   if (writer->entry_filename[0] == '\0') {
304     return 0;
305   }
306 
307   int reuse_fdt;
308   int fdt_idx;
309   uint32_t dt_offset;
310 
311   for (fdt_idx = 0; writer->past_filenames[fdt_idx][0] != '\0'; fdt_idx++) {
312     if (strcmp(writer->past_filenames[fdt_idx], writer->entry_filename) == 0)
313       break;
314   }
315 
316   if (writer->past_filenames[fdt_idx][0] != '\0') {
317     reuse_fdt = 1;
318     dt_offset = writer->past_dt_offsets[fdt_idx];
319   } else {
320     reuse_fdt = 0;
321     dt_offset = writer->dt_offset;
322   }
323   int32_t dt_size = output_img_entry(writer->img_fp, writer->entry_offset,
324                                      dt_offset, writer->entry_filename,
325                                      &writer->entry_options, reuse_fdt);
326   if (dt_size == -1) return -1;
327 
328   if (!reuse_fdt) {
329     strncpy(writer->past_filenames[fdt_idx], writer->entry_filename,
330             sizeof(writer->past_filenames[fdt_idx]) - 1);
331     writer->past_dt_offsets[fdt_idx] = dt_offset;
332   }
333 
334   writer->entry_offset += sizeof(struct dt_table_entry);
335   writer->dt_offset += dt_size;
336 
337   return 0;
338 }
339 
dt_image_writer_add_entry(struct dt_image_writer * writer,const char * fdt_filename)340 int dt_image_writer_add_entry(struct dt_image_writer *writer,
341                               const char *fdt_filename) {
342   if (flush_entry_to_img(writer) != 0) {
343     return -1;
344   }
345 
346   strncpy(
347       writer->entry_filename,
348       fdt_filename,
349       sizeof(writer->entry_filename) - 1);
350 
351   /* Copy the default_options as default */
352   copy_dt_options(
353       &writer->entry_options,
354       &writer->global_options.default_options);
355 
356   return 0;
357 }
358 
dt_image_writer_end(struct dt_image_writer * writer)359 int dt_image_writer_end(struct dt_image_writer *writer) {
360   int ret = -1;
361 
362   if (flush_entry_to_img(writer) != 0) {
363     goto end;
364   }
365 
366   if (output_img_header(
367       writer->img_fp,
368       writer->entry_count,
369       writer->dt_offset,
370       &writer->global_options) != 0) {
371     goto end;
372   }
373 
374   printf("Total %d entries.\n", writer->entry_count);
375   ret = 0;
376 
377 end:
378   free(writer->past_filenames);
379   free(writer->past_dt_offsets);
380   free(writer);
381 
382   return ret;
383 }
384