mkdtimg_core.c revision 780c3b0fba4bb4dbd39091ebbd1ddc3eacb2deb9
1#include "mkdtimg_core.h" 2 3#include <stdio.h> 4#include <stdlib.h> 5#include <string.h> 6#include <stdint.h> 7#include <unistd.h> 8 9#include "libfdt.h" 10 11#include "dt_table.h" 12 13#define DEBUG 0 14 15 16struct dt_options { 17 char id[OPTION_VALUE_SIZE_MAX]; 18 char rev[OPTION_VALUE_SIZE_MAX]; 19 char custom[4][OPTION_VALUE_SIZE_MAX]; 20}; 21 22struct dt_global_options { 23 struct dt_options default_options; 24 uint32_t page_size; 25}; 26 27struct dt_image_writer { 28 FILE *img_fp; 29 30 struct dt_global_options global_options; 31 struct dt_options entry_options; 32 33 char entry_filename[1024]; 34 uint32_t entry_count; 35 uint32_t entry_offset; 36 uint32_t dt_offset; 37}; 38 39 40static void init_dt_options(struct dt_options *options) { 41 memset(options, 0, sizeof(struct dt_options)); 42} 43 44static void init_dt_global_options(struct dt_global_options *options) { 45 init_dt_options(&options->default_options); 46 options->page_size = DT_TABLE_DEFAULT_PAGE_SIZE; 47} 48 49static void copy_dt_options(struct dt_options *target, struct dt_options *options) { 50 memcpy(target, options, sizeof(struct dt_options)); 51} 52 53static char *load_file_contents(FILE *fp, size_t *len_ptr) { 54 // Gets the file size. 55 fseek(fp, 0, SEEK_END); 56 size_t len = ftell(fp); 57 fseek(fp, 0, SEEK_SET); 58 59 char *buf = malloc(len); 60 if (buf == NULL) { 61 return NULL; 62 } 63 64 if (fread(buf, len, 1, fp) != 1) { 65 free(buf); 66 return NULL; 67 } 68 69 if (len_ptr) { 70 *len_ptr = len; 71 } 72 73 return buf; 74} 75 76static char *load_file(const char *filename, size_t *len_ptr) { 77 FILE *fp = fopen(filename, "r"); 78 if (!fp) { 79 return NULL; 80 } 81 82 char *buf = load_file_contents(fp, len_ptr); 83 84 fclose(fp); 85 86 return buf; 87} 88 89static int split_str(char **lhs_ptr, char **rhs_ptr, char *string, char c) { 90 char *middle_ptr = strchr(string, c); 91 if (middle_ptr == NULL) { 92 return -1; 93 } 94 95 *middle_ptr = '\0'; 96 97 *lhs_ptr = string; 98 *rhs_ptr = middle_ptr + 1; 99 100 return 0; 101} 102 103int parse_option(char **option_ptr, char **value_ptr, char *line_str) { 104 return split_str(option_ptr, value_ptr, line_str, '='); 105} 106 107int parse_path(char **path_ptr, char **prop_ptr, char *value_str) { 108 return split_str(path_ptr, prop_ptr, value_str, ':'); 109} 110 111static fdt32_t get_fdt32_from_prop(void *fdt, const char *path, const char *prop) { 112 int node_off = fdt_path_offset(fdt, path); 113 if (node_off < 0) { 114 fprintf(stderr, "Can not find node: %s\n", path); 115 return 0; 116 } 117 118 int len; 119 fdt32_t *prop_value_ptr = (fdt32_t *)fdt_getprop(fdt, node_off, prop, &len); 120 if (prop_value_ptr == NULL) { 121 fprintf(stderr, "Can not find property: %s:%s\n", path, prop); 122 return 0; 123 } 124 125 fdt32_t value = fdt32_to_cpu(*prop_value_ptr); 126 /* TODO: check len */ 127 if (DEBUG) printf("%s:%s => %08x\n", path, prop, fdt32_to_cpu(value)); 128 129 return value; 130} 131 132static fdt32_t get_fdt32_from_number_or_prop(void *fdt, char *value_str) { 133 if (value_str[0] == '/') { 134 char *path, *prop; 135 if (parse_path(&path, &prop, value_str) != 0) { 136 fprintf(stderr, "Wrong syntax: %s\n", value_str); 137 return 0; 138 } 139 return get_fdt32_from_prop(fdt, path, prop); 140 } 141 142 /* It should be a number */ 143 char *end; 144 uint32_t value = strtoul(value_str, &end, 0); 145 /* TODO: check end */ 146 return cpu_to_fdt32(value); 147} 148 149static int output_img_header(FILE *img_fp, 150 uint32_t entry_count, uint32_t total_size, 151 struct dt_global_options *options) { 152 struct dt_table_header header; 153 dt_table_header_init(&header); 154 header.dt_entry_count = cpu_to_fdt32(entry_count); 155 header.total_size = cpu_to_fdt32(total_size); 156 header.page_size = cpu_to_fdt32(options->page_size); 157 158 fseek(img_fp, 0, SEEK_SET); 159 fwrite(&header, sizeof(header), 1, img_fp); 160 161 return 0; 162} 163 164static size_t output_img_entry(FILE *img_fp, 165 size_t entry_offset, size_t dt_offset, 166 const char *fdt_filename, 167 struct dt_options *options) { 168 size_t ret = 0; 169 void *fdt = NULL; 170 171 size_t fdt_file_size; 172 fdt = load_file(fdt_filename, &fdt_file_size); 173 if (fdt == NULL) { 174 fprintf(stderr, "Can not read file: %s\n", fdt_filename); 175 goto end; 176 } 177 178 if (fdt_check_header(fdt) != 0) { 179 fprintf(stderr, "Bad FDT header: \n", fdt_filename); 180 goto end; 181 } 182 183 size_t fdt_size = fdt_totalsize(fdt); 184 if (fdt_size != fdt_file_size) { 185 fprintf(stderr, "The file size and FDT size are not matched: %s\n", fdt_filename); 186 goto end; 187 } 188 189 /* Prepare dt_table_entry and output */ 190 struct dt_table_entry entry; 191 entry.dt_size = cpu_to_fdt32(fdt_size); 192 entry.dt_offset = cpu_to_fdt32(dt_offset); 193 entry.id = get_fdt32_from_number_or_prop(fdt, options->id); 194 entry.rev = get_fdt32_from_number_or_prop(fdt, options->rev); 195 entry.custom[0] = get_fdt32_from_number_or_prop(fdt, options->custom[0]); 196 entry.custom[1] = get_fdt32_from_number_or_prop(fdt, options->custom[1]); 197 entry.custom[2] = get_fdt32_from_number_or_prop(fdt, options->custom[2]); 198 entry.custom[3] = get_fdt32_from_number_or_prop(fdt, options->custom[3]); 199 fseek(img_fp, entry_offset, SEEK_SET); 200 fwrite(&entry, sizeof(entry), 1, img_fp); 201 202 /* Output FDT */ 203 fseek(img_fp, dt_offset, SEEK_SET); 204 fwrite(fdt, fdt_file_size, 1, img_fp); 205 206 /* return the fdt_file_size */ 207 ret = fdt_file_size; 208 209end: 210 if (fdt) free(fdt); 211 212 return ret; 213} 214 215 216struct dt_image_writer *dt_image_writer_start(FILE *img_fp, uint32_t entry_count) { 217 struct dt_image_writer *writer = malloc(sizeof(struct dt_image_writer)); 218 writer->img_fp = img_fp; 219 init_dt_global_options(&writer->global_options); 220 init_dt_options(&writer->entry_options); 221 writer->entry_filename[0] = '\0'; 222 writer->entry_count = entry_count; 223 writer->entry_offset = sizeof(struct dt_table_header); 224 writer->dt_offset = 225 writer->entry_offset + sizeof(struct dt_table_entry) * entry_count; 226 return writer; 227} 228 229static int set_dt_options(struct dt_options *options, 230 const char *option, const char *value) { 231 if (strcmp(option, "id") == 0) { 232 strncpy(options->id, value, OPTION_VALUE_SIZE_MAX - 1); 233 } else if (strcmp(option, "rev") == 0) { 234 strncpy(options->rev, value, OPTION_VALUE_SIZE_MAX - 1); 235 } else if (strcmp(option, "custom0") == 0) { 236 strncpy(options->custom[0], value, OPTION_VALUE_SIZE_MAX - 1); 237 } else if (strcmp(option, "custom1") == 0) { 238 strncpy(options->custom[1], value, OPTION_VALUE_SIZE_MAX - 1); 239 } else if (strcmp(option, "custom2") == 0) { 240 strncpy(options->custom[2], value, OPTION_VALUE_SIZE_MAX - 1); 241 } else if (strcmp(option, "custom3") == 0) { 242 strncpy(options->custom[3], value, OPTION_VALUE_SIZE_MAX - 1); 243 } else { 244 return -1; 245 } 246 247 return 0; 248} 249 250int set_global_options(struct dt_image_writer *writer, 251 const char *option, const char *value) { 252 struct dt_global_options *global_options = &writer->global_options; 253 254 if (strcmp(option, "page_size") == 0) { 255 global_options->page_size = strtoul(value, NULL, 0); 256 } else { 257 return set_dt_options(&global_options->default_options, option, value); 258 } 259 260 return 0; 261} 262 263int set_entry_options(struct dt_image_writer *writer, 264 const char *option, const char *value) { 265 return set_dt_options(&writer->entry_options, option, value); 266} 267 268static int flush_entry_to_img(struct dt_image_writer *writer) { 269 if (writer->entry_filename[0] == '\0') { 270 return 0; 271 } 272 273 uint32_t dt_size = output_img_entry( 274 writer->img_fp, 275 writer->entry_offset, 276 writer->dt_offset, 277 writer->entry_filename, 278 &writer->entry_options); 279 if (dt_size == 0) { 280 return -1; 281 } 282 283 writer->entry_offset += sizeof(struct dt_table_entry); 284 writer->dt_offset += dt_size; 285 286 return 0; 287} 288 289int dt_image_writer_add_entry(struct dt_image_writer *writer, 290 const char *fdt_filename) { 291 if (flush_entry_to_img(writer) != 0) { 292 return -1; 293 } 294 295 strncpy( 296 writer->entry_filename, 297 fdt_filename, 298 sizeof(writer->entry_filename) - 1); 299 300 /* Copy the default_options as default */ 301 copy_dt_options( 302 &writer->entry_options, 303 &writer->global_options.default_options); 304 305 return 0; 306} 307 308int dt_image_writer_end(struct dt_image_writer *writer) { 309 int ret = -1; 310 311 if (flush_entry_to_img(writer) != 0) { 312 goto end; 313 } 314 315 if (output_img_header( 316 writer->img_fp, 317 writer->entry_count, 318 writer->dt_offset, 319 &writer->global_options) != 0) { 320 goto end; 321 } 322 323 printf("Total %d entries.\n", writer->entry_count); 324 ret = 0; 325 326end: 327 free(writer); 328 329 return ret; 330} 331