upload android base code part6

This commit is contained in:
August 2018-08-08 17:48:24 +08:00
parent 421e214c7d
commit 4e516ec6ed
35396 changed files with 9188716 additions and 0 deletions

View file

@ -0,0 +1,219 @@
libufdt `utils` folder
=====================
This folder contains utilities for device tree overlay.
mkdtimg
-------
If your DTB/DTBO is in an unique partition, e.g. `dtb` and `dtbo` partition.
`mkdtimg` is a tool for creating the `dtb`/`dtbo` image.
You can use `mkdtimg` to pack one or more DTB/DTBO files into an image.
### Image Format
This is the layout for `dtb`/`dtbo` image:
```txt
+---------------------------+ - - - -
| dt_table_header | ^ | v dt_entries_offset | header_size
+===========================+ | | - - -
| dt_table_entry #0 | | | ^ | dt_entry_size
+---------------------------+ | | | -
| dt_table_entry #1 | | | |
+---------------------------+ | | |
| ... | | | | dt_entry_size * dt_entry_count
+---------------------------+ | | |
| dt_table_entry #N | | | v
+===========================+ | | -
| +-----------------------+ | | |
| | fdt_header #0 | | | |
+ +-----------------------+ | | | dt_offset
| DTBO #0 | | v (dt_entry_entry #1)
+===========================+ | _
| +-----------------------+ | | ^
| | fdt_header #1 | | | |
+ +-----------------------+ | | | dt_size
| DTBO #1 | | v (dt_entry_entry #1)
+===========================+ | -
| ... | |
+===========================+ |
| +-----------------------+ | |
| | fdt_header #N | | | total_size
+ +-----------------------+ | |
| DTBO #N | v
+---------------------------+ -
```
You can find the data structure `dt_table_header` and `dt_table_entry`
in file `src/dt_table.h`
### Build `mkdtimg`
Assume that you are at the root directory of the Android source.
1. `source build/envsetup.sh`
2. `lunch`
3. `mmma system/libufdt/util/src`
### Using `mkdtimg`
`mkdtimg` supports several commands, including `create`, `cfg_create`,
and `dump`.
#### `create` Command
Use the `create` command to create a `dtb`/`dtbo` image:
```sh
$mkdtimg create <image_filename> (<global-option>...) \
<ftb1_filename> (<entry1_option>...) \
<ftb2_filename> (<entry2_option>...) \
...
```
Each dtb/dtbo `ftbX_filename` will generate a `dt_table_entry` in image.
`entryX_options` are the values to assign to `dt_table_entry`. These values
can be any of the following:
```sh
--id=<number|path>
--rev=<number|path>
--custom0=<number|path>
--custom1=<number|path>
--custom2=<number|path>
--custom3=<number|path>
```
Number values can be a 32-bit digit (such as `68000`) or a hex number
(such as `0x6800`). Alternatively, you can specify a path using the format:
```
<full_node_path>:<property_name>
```
For example, `/board/:id`. `mkdtimg` will read the value from the path in
the DTB/DTBO file and assign into relative property in `dt_table_entry`.
It should be a 32-bits value.
You can also give a `global_option` as a default option for all entries.
The default value of `page_size` in `dt_table_header` is `2048`. You can
use `global_option` `--page_size=<number>` to assign a different value.
Example:
```dts
[board1.dts]
/dts-v1/;
/plugin/;
/ {
compatible = "board_manufacturer,board_model";
board_id = <0x00010000>;
board_rev = <0x00010001>;
another_hw_information = "some_data";
...
};
&device@0 {
value = <0x1>;
status = "okay";
};
```
```sh
$mkdtimg create dtbo.img --id=/:board_id --rev=/:board_rev --custom0=0xabc \
board1.dtbo \
board2.dtbo --id=0x6800 \
board3.dtbo --id=0x6801 --custom0=0x123
```
* First `dt_table_entry` (`board1.dtbo`) `id` is `0x00010000` and `custom[0]`
is `0x00000abc.`
* Second `id` is `0x00006800` and `custom[0]` is `0x00000abc`.
* Third `id` is `0x00006801` and `custom[0]` is `0x00000123`.
* All others use the default value (0).
#### `cfg_create` Command
The `cfg_create` command creates an image with a config file in the following
format:
```sh
# global options
<global_option>
...
# entries
<ftb1_filename> # comment
<entry1_option> # comment
...
<ftb2_filename>
<entry2_option>
...
...
```
The `global_options` and `entryX_options` must start with one or more space
characters (these options are the same as create options, without the `--`
prefix). Empty lines or lines beginning with `#` are ignored.
Example:
```sh
[dtboimg.cfg]
# global options
id=/:board_id
rev=/:board_rev
custom0=0xabc
board1.dtbo
board2.dtbo
id=0x6800 # override the value of id in global options
board2.dtbo
```
```sh
$mkdtimg cfg_create dtbo.img dtboimg.cfg
```
#### `dump` Command
For `dtb`/`dtbo` images, use the `dump` command to print the information in
the image. Example:
```sh
$mkdtimg dump dtbo.img
dt_table_header:
magic = d7b7ab1e
total_size = 1300
header_size = 32
dt_entry_size = 32
dt_entry_count = 3
dt_entries_offset = 32
page_size = 2048
reserved[0] = 00000000
dt_table_entry[0]:
dt_size = 380
dt_offset = 128
id = 00010000
rev = 00010001
custom[0] = 00000abc
custom[1] = 00000000
custom[2] = 00000000
custom[3] = 00000000
(FDT)size = 380
(FDT)compatible = board_manufacturer,board_model
...
```
#### `help` Command
Use `help` command to get more detail options. Example:
```sh
$mkdtimg help cfg_create
```

View file

@ -0,0 +1,39 @@
# Copyright (C) 2017 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
LOCAL_PATH:= $(call my-dir)
###################################################
include $(CLEAR_VARS)
LOCAL_MODULE := mkdtimg
LOCAL_SRC_FILES := \
mkdtimg.c \
mkdtimg_cfg_create.c \
mkdtimg_core.c \
mkdtimg_create.c \
mkdtimg_dump.c \
dt_table.c
LOCAL_STATIC_LIBRARIES := \
libfdt \
libufdt_sysdeps
LOCAL_REQUIRED_MODULES := dtc
LOCAL_CXX_STL := none
include $(BUILD_HOST_EXECUTABLE)
###################################################
$(call dist-for-goals, dist_files, $(ALL_MODULES.mkdtimg.BUILT):libufdt/mkdtimg)

View file

@ -0,0 +1,36 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "dt_table.h"
#include <memory.h>
#include "libfdt.h"
#include "libufdt_sysdeps.h"
void dt_table_header_init(struct dt_table_header *header) {
const uint32_t header_size = sizeof(struct dt_table_header);
const uint32_t entry_size = sizeof(struct dt_table_entry);
dto_memset(header, 0, header_size);
header->magic = cpu_to_fdt32(DT_TABLE_MAGIC);
header->total_size = cpu_to_fdt32(header_size);
header->header_size = cpu_to_fdt32(header_size);
header->dt_entry_size = cpu_to_fdt32(entry_size);
header->dt_entries_offset = cpu_to_fdt32(header_size);
header->page_size = cpu_to_fdt32(DT_TABLE_DEFAULT_PAGE_SIZE);
}

View file

@ -0,0 +1,57 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DT_TABLE_H
#define DT_TABLE_H
#include <stdint.h>
/*
* For the image layout, refer README.md for the detail
*/
#define DT_TABLE_MAGIC 0xd7b7ab1e
#define DT_TABLE_DEFAULT_PAGE_SIZE 2048
struct dt_table_header {
uint32_t magic; /* DT_TABLE_MAGIC */
uint32_t total_size; /* includes dt_table_header + all dt_table_entry
and all dtb/dtbo */
uint32_t header_size; /* sizeof(dt_table_header) */
uint32_t dt_entry_size; /* sizeof(dt_table_entry) */
uint32_t dt_entry_count; /* number of dt_table_entry */
uint32_t dt_entries_offset; /* offset to the first dt_table_entry
from head of dt_table_header.
The value will be equal to header_size if
no padding is appended */
uint32_t page_size; /* flash page size we assume */
uint32_t reserved[1]; /* must be zero */
};
struct dt_table_entry {
uint32_t dt_size;
uint32_t dt_offset; /* offset from head of dt_table_header */
uint32_t id; /* optional, must be zero if unused */
uint32_t rev; /* optional, must be zero if unused */
uint32_t custom[4]; /* optional, must be zero if unused */
};
void dt_table_header_init(struct dt_table_header *header);
#endif

View file

@ -0,0 +1,130 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
extern void handle_usage_help(FILE *out_fp, const char *prog_name);
extern int handle_command_help(int argc, char *argv[], int arg_start);
extern void handle_usage_dump(FILE *out_fp, const char *prog_name);
extern int handle_command_dump(int argc, char *argv[], int arg_start);
extern void handle_usage_create(FILE *out_fp, const char *prog_name);
extern int handle_command_create(int argc, char *argv[], int arg_start);
extern void handle_usage_cfg_create(FILE *out_fp, const char *prog_name);
extern int handle_command_cfg_create(int argc, char *argv[], int arg_start);
struct command_info {
const char *command;
void (*usage)(FILE *out_fp, const char *prog_name);
int (*handler)(int argc, char *argv[], int arg_start);
};
static const struct command_info command_infos[] = {
{ "help", handle_usage_help, handle_command_help },
{ "dump", handle_usage_dump, handle_command_dump },
{ "create", handle_usage_create, handle_command_create },
{ "cfg_create", handle_usage_cfg_create, handle_command_cfg_create },
{ NULL, NULL, NULL }
};
static const struct command_info *search_command(const char *command) {
const struct command_info *info;
for (info = command_infos; info->command != NULL; info++) {
if (strcmp(command, info->command) == 0) {
break;
}
}
if (info->command == NULL) {
fprintf(stderr, "Unknown command: %s\n", command);
return NULL;
}
return info;
}
static void print_all_commands(FILE *out_fp) {
const struct command_info *info;
for (info = command_infos; info->command != NULL; info++) {
if (info != command_infos) {
fprintf(out_fp, ", ");
}
fprintf(out_fp, "%s", info->command);
}
fprintf(out_fp, "\n");
}
static void output_all_usage(FILE *out_fp, const char *prog_name) {
fprintf(out_fp, " %s <command>\n\n", prog_name);
fprintf(out_fp, " commands:\n ");
print_all_commands(out_fp);
fprintf(out_fp, "\n");
const struct command_info *info;
for (info = command_infos; info->command != NULL; info++) {
info->usage(out_fp, prog_name);
fprintf(out_fp, "\n");
}
}
void handle_usage_help(FILE *out_fp, const char *prog_name) {
fprintf(out_fp, " %s help all\n", prog_name);
fprintf(out_fp, " %s help <command>\n\n", prog_name);
fprintf(out_fp, " commands:\n ");
print_all_commands(out_fp);
}
int handle_command_help(int argc, char *argv[], int arg_start) {
const char *prog_name = argv[0];
if (argc - arg_start < 1) {
handle_usage_help(stderr, prog_name);
return 1;
}
if (strcmp(argv[arg_start], "all") == 0) {
output_all_usage(stdout, prog_name);
return 0;
}
const struct command_info *info = search_command(argv[arg_start]);
if (info == NULL) {
handle_usage_help(stderr, prog_name);
return 1;
}
info->usage(stdout, prog_name);
return 0;
}
int main(int argc, char *argv[]) {
if (argc <= 1) {
output_all_usage(stderr, argv[0]);
return 1;
}
const char *command = argv[1];
const struct command_info *info = search_command(argv[1]);
if (info == NULL) {
return 1;
}
/* skip 2 arguments, argv[0] and argv[1] */
return info->handler(argc, argv, 2);
}

View file

@ -0,0 +1,191 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <ctype.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "dt_table.h"
#include "mkdtimg_core.h"
struct cfg_create_params {
const char *img_filename;
const char *cfg_filename;
const char *dtb_dir;
};
static const char short_options[] = "d:";
static struct option options[] = {
{ "dtb-dir", required_argument, NULL, 'd' },
{ 0, 0, NULL, 0 }
};
static char *trim_line(char *line) {
/* Find the end of the string or the first of '#' */
char *end = line;
while (*end != '\0' && *end != '#') {
end++;
}
do {
end--;
} while (end >= line && isspace(*end));
*(end + 1) = '\0';
while (isspace(*line)) {
line++;
}
return line;
}
static int parse_config_entry_count(FILE *cfg_fp) {
int count = 0;
/* Any line without prefix spaces is entry filename */
char line[1024];
while (fgets(line, sizeof(line), cfg_fp) != NULL) {
char c = line[0];
if (c == '\0' || isspace(c) || c == '#') continue;
count++;
}
return count;
}
static int output_img_with_config(FILE *img_fp, FILE *cfg_fp) {
int entry_count = parse_config_entry_count(cfg_fp);
struct dt_image_writer *writer = dt_image_writer_start(img_fp, entry_count);
fseek(cfg_fp, 0, SEEK_SET); /* Reset the file pos to head */
int is_entry = 0;
char line[1024];
while (fgets(line, sizeof(line), cfg_fp) != NULL) {
char *trimmed = trim_line(line);
if (trimmed[0] == '\0') {
/* empty line, pass */
continue;
}
if (trimmed == line) {
/* This line is a file name,
because it start from the first char of the line */
if (dt_image_writer_add_entry(writer, trimmed) != 0) {
return -1;
}
is_entry = 1;
continue;
}
char *option, *value;
if (parse_option(&option, &value, trimmed) != 0) {
fprintf(stderr, "Wrong syntax: %s\n", trimmed);
return -1;
}
int ret = is_entry ?
set_entry_options(writer, option, value) :
set_global_options(writer, option, value);
if (ret != 0) {
fprintf(stderr, "Unknown option: %s\n", option);
return -1;
}
}
if (dt_image_writer_end(writer) != 0) {
return -1;
}
return 0;
}
static int process_command_cfg_create(const struct cfg_create_params *params) {
int ret = -1;
FILE *cfg_fp = NULL;
FILE *img_fp = NULL;
cfg_fp = fopen(params->cfg_filename, "r");
if (cfg_fp == NULL) {
fprintf(stderr, "Can not open config file: %s\n", params->cfg_filename);
goto end;
}
printf("create image file: %s...\n", params->img_filename);
img_fp = fopen(params->img_filename, "wb");
if (img_fp == NULL) {
fprintf(stderr, "Can not create file: %s\n", params->img_filename);
goto end;
}
if (params->dtb_dir != NULL) {
if (chdir(params->dtb_dir) != 0) {
fprintf(stderr, "Can not switch to directory: %s\n", params->dtb_dir);
goto end;
}
}
ret = output_img_with_config(img_fp, cfg_fp);
end:
if (img_fp) fclose(img_fp);
if (cfg_fp) fclose(cfg_fp);
return ret;
}
void handle_usage_cfg_create(FILE *out_fp, const char *prog_name) {
fprintf(out_fp, " %s cfg_create <image_file> <config_file> (<option>...)\n\n", prog_name);
fprintf(out_fp,
" options:\n"
" -d, --dtb-dir The path to load dtb files.\n"
" Default is load from the current path.\n");
}
int handle_command_cfg_create(int argc, char *argv[], int arg_start) {
if (argc - arg_start < 2) {
handle_usage_cfg_create(stderr, argv[0]);
return 1;
}
struct cfg_create_params params;
memset(&params, 0, sizeof(params));
params.img_filename = argv[arg_start];
params.cfg_filename = argv[arg_start + 1];
optind = arg_start + 2;
while (1) {
int c = getopt_long(argc, argv, short_options, options, NULL);
if (c == -1) {
break;
}
switch (c) {
case 'd':
params.dtb_dir = optarg;
break;
default:
/* Unknown option, return error */
return 1;
}
}
return process_command_cfg_create(&params);
}

View file

@ -0,0 +1,400 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mkdtimg_core.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include "libfdt.h"
#include "dt_table.h"
#define DEBUG 0
struct dt_options {
char id[OPTION_VALUE_SIZE_MAX];
char rev[OPTION_VALUE_SIZE_MAX];
char custom[4][OPTION_VALUE_SIZE_MAX];
};
struct dt_global_options {
struct dt_options default_options;
uint32_t page_size;
};
struct dt_image_writer_fdt_info {
char filename[1024];
uint32_t dt_offset;
};
struct dt_image_writer {
FILE *img_fp;
struct dt_global_options global_options;
struct dt_options entry_options;
char entry_filename[1024];
uint32_t entry_count;
uint32_t entry_offset;
uint32_t dt_offset;
struct dt_image_writer_fdt_info *fdt_infos;
uint32_t fdt_info_count;
};
static void init_dt_options(struct dt_options *options) {
memset(options, 0, sizeof(struct dt_options));
}
static void init_dt_global_options(struct dt_global_options *options) {
init_dt_options(&options->default_options);
options->page_size = DT_TABLE_DEFAULT_PAGE_SIZE;
}
static void copy_dt_options(struct dt_options *target, struct dt_options *options) {
memcpy(target, options, sizeof(struct dt_options));
}
static char *load_file_contents(FILE *fp, size_t *len_ptr) {
// Gets the file size.
fseek(fp, 0, SEEK_END);
size_t len = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *buf = malloc(len);
if (buf == NULL) {
return NULL;
}
if (fread(buf, len, 1, fp) != 1) {
free(buf);
return NULL;
}
if (len_ptr) {
*len_ptr = len;
}
return buf;
}
static char *load_file(const char *filename, size_t *len_ptr) {
FILE *fp = fopen(filename, "r");
if (!fp) {
return NULL;
}
char *buf = load_file_contents(fp, len_ptr);
fclose(fp);
return buf;
}
static int split_str(char **lhs_ptr, char **rhs_ptr, char *string, char c) {
char *middle_ptr = strchr(string, c);
if (middle_ptr == NULL) {
return -1;
}
*middle_ptr = '\0';
*lhs_ptr = string;
*rhs_ptr = middle_ptr + 1;
return 0;
}
int parse_option(char **option_ptr, char **value_ptr, char *line_str) {
return split_str(option_ptr, value_ptr, line_str, '=');
}
int parse_path(char **path_ptr, char **prop_ptr, char *value_str) {
return split_str(path_ptr, prop_ptr, value_str, ':');
}
static fdt32_t get_fdt32_from_prop(void *fdt, const char *path, const char *prop) {
int node_off = fdt_path_offset(fdt, path);
if (node_off < 0) {
fprintf(stderr, "Can not find node: %s\n", path);
return 0;
}
int len;
fdt32_t *prop_value_ptr = (fdt32_t *)fdt_getprop(fdt, node_off, prop, &len);
if (prop_value_ptr == NULL) {
fprintf(stderr, "Can not find property: %s:%s\n", path, prop);
return 0;
}
fdt32_t value = *prop_value_ptr;
/* TODO: check len */
if (DEBUG) printf("%s:%s => %08x\n", path, prop, fdt32_to_cpu(value));
return value;
}
static fdt32_t get_fdt32_from_number_or_prop(void *fdt, char *value_str) {
if (value_str[0] == '/') {
char *path, *prop;
if (parse_path(&path, &prop, value_str) != 0) {
fprintf(stderr, "Wrong syntax: %s\n", value_str);
return 0;
}
return get_fdt32_from_prop(fdt, path, prop);
}
/* It should be a number */
char *end;
uint32_t value = strtoul(value_str, &end, 0);
/* TODO: check end */
return cpu_to_fdt32(value);
}
static int output_img_header(FILE *img_fp,
uint32_t entry_count, uint32_t total_size,
struct dt_global_options *options) {
struct dt_table_header header;
dt_table_header_init(&header);
header.dt_entry_count = cpu_to_fdt32(entry_count);
header.total_size = cpu_to_fdt32(total_size);
header.page_size = cpu_to_fdt32(options->page_size);
fseek(img_fp, 0, SEEK_SET);
fwrite(&header, sizeof(header), 1, img_fp);
return 0;
}
static int32_t output_img_entry(FILE *img_fp, size_t entry_offset,
struct dt_image_writer_fdt_info *fdt_info,
struct dt_options *options, int output_fdt) {
int32_t ret = -1;
void *fdt = NULL;
size_t fdt_file_size;
fdt = load_file(fdt_info->filename, &fdt_file_size);
if (fdt == NULL) {
fprintf(stderr, "Can not read file: %s\n", fdt_info->filename);
goto end;
}
if (fdt_check_header(fdt) != 0) {
fprintf(stderr, "Bad FDT header: \n", fdt_info->filename);
goto end;
}
size_t fdt_size = fdt_totalsize(fdt);
if (fdt_size != fdt_file_size) {
fprintf(stderr, "The file size and FDT size are not matched: %s\n",
fdt_info->filename);
goto end;
}
/* Prepare dt_table_entry and output */
struct dt_table_entry entry;
entry.dt_size = cpu_to_fdt32(fdt_size);
entry.dt_offset = cpu_to_fdt32(fdt_info->dt_offset);
entry.id = get_fdt32_from_number_or_prop(fdt, options->id);
entry.rev = get_fdt32_from_number_or_prop(fdt, options->rev);
entry.custom[0] = get_fdt32_from_number_or_prop(fdt, options->custom[0]);
entry.custom[1] = get_fdt32_from_number_or_prop(fdt, options->custom[1]);
entry.custom[2] = get_fdt32_from_number_or_prop(fdt, options->custom[2]);
entry.custom[3] = get_fdt32_from_number_or_prop(fdt, options->custom[3]);
fseek(img_fp, entry_offset, SEEK_SET);
fwrite(&entry, sizeof(entry), 1, img_fp);
if (output_fdt) {
fseek(img_fp, fdt_info->dt_offset, SEEK_SET);
fwrite(fdt, fdt_file_size, 1, img_fp);
ret = fdt_file_size;
} else {
ret = 0;
}
end:
if (fdt) free(fdt);
return ret;
}
struct dt_image_writer *dt_image_writer_start(FILE *img_fp, uint32_t entry_count) {
struct dt_image_writer *writer = NULL;
struct dt_image_writer_fdt_info *fdt_infos = NULL;
writer = malloc(sizeof(struct dt_image_writer));
if (!writer) goto error;
fdt_infos = malloc(sizeof(struct dt_image_writer_fdt_info) * entry_count);
if (!fdt_infos) goto error;
writer->img_fp = img_fp;
init_dt_global_options(&writer->global_options);
init_dt_options(&writer->entry_options);
writer->entry_filename[0] = '\0';
writer->entry_count = entry_count;
writer->entry_offset = sizeof(struct dt_table_header);
writer->dt_offset =
writer->entry_offset + sizeof(struct dt_table_entry) * entry_count;
writer->fdt_infos = fdt_infos;
writer->fdt_info_count = 0;
return writer;
error:
fprintf(stderr, "Unable to start writer\n");
if (fdt_infos) free(fdt_infos);
if (writer) free(writer);
return NULL;
}
static int set_dt_options(struct dt_options *options,
const char *option, const char *value) {
if (strcmp(option, "id") == 0) {
strncpy(options->id, value, OPTION_VALUE_SIZE_MAX - 1);
} else if (strcmp(option, "rev") == 0) {
strncpy(options->rev, value, OPTION_VALUE_SIZE_MAX - 1);
} else if (strcmp(option, "custom0") == 0) {
strncpy(options->custom[0], value, OPTION_VALUE_SIZE_MAX - 1);
} else if (strcmp(option, "custom1") == 0) {
strncpy(options->custom[1], value, OPTION_VALUE_SIZE_MAX - 1);
} else if (strcmp(option, "custom2") == 0) {
strncpy(options->custom[2], value, OPTION_VALUE_SIZE_MAX - 1);
} else if (strcmp(option, "custom3") == 0) {
strncpy(options->custom[3], value, OPTION_VALUE_SIZE_MAX - 1);
} else {
return -1;
}
return 0;
}
int set_global_options(struct dt_image_writer *writer,
const char *option, const char *value) {
struct dt_global_options *global_options = &writer->global_options;
if (strcmp(option, "page_size") == 0) {
global_options->page_size = strtoul(value, NULL, 0);
} else {
return set_dt_options(&global_options->default_options, option, value);
}
return 0;
}
int set_entry_options(struct dt_image_writer *writer,
const char *option, const char *value) {
return set_dt_options(&writer->entry_options, option, value);
}
static struct dt_image_writer_fdt_info *search_fdt_info(
struct dt_image_writer *writer, const char *filename) {
for (uint32_t i = 0; i < writer->fdt_info_count; i++) {
struct dt_image_writer_fdt_info *fdt_info = &writer->fdt_infos[i];
if (strcmp(fdt_info->filename, filename) == 0) {
return fdt_info;
}
}
return NULL;
}
static struct dt_image_writer_fdt_info *add_fdt_info(
struct dt_image_writer *writer, const char *filename, uint32_t dt_offset) {
struct dt_image_writer_fdt_info *fdt_info =
&writer->fdt_infos[writer->fdt_info_count];
strncpy(fdt_info->filename, filename, sizeof(fdt_info->filename) - 1);
fdt_info->dt_offset = dt_offset;
writer->fdt_info_count++;
return fdt_info;
}
static int flush_entry_to_img(struct dt_image_writer *writer) {
if (writer->entry_filename[0] == '\0') {
return 0;
}
struct dt_image_writer_fdt_info *fdt_info =
search_fdt_info(writer, writer->entry_filename);
int output_fdt = (fdt_info == NULL);
if (fdt_info == NULL) {
fdt_info = add_fdt_info(writer, writer->entry_filename, writer->dt_offset);
}
int32_t dt_size =
output_img_entry(writer->img_fp, writer->entry_offset, fdt_info,
&writer->entry_options, output_fdt);
if (dt_size == -1) return -1;
writer->entry_offset += sizeof(struct dt_table_entry);
writer->dt_offset += dt_size;
return 0;
}
int dt_image_writer_add_entry(struct dt_image_writer *writer,
const char *fdt_filename) {
if (flush_entry_to_img(writer) != 0) {
return -1;
}
strncpy(
writer->entry_filename,
fdt_filename,
sizeof(writer->entry_filename) - 1);
/* Copy the default_options as default */
copy_dt_options(
&writer->entry_options,
&writer->global_options.default_options);
return 0;
}
int dt_image_writer_end(struct dt_image_writer *writer) {
int ret = -1;
if (flush_entry_to_img(writer) != 0) {
goto end;
}
if (output_img_header(
writer->img_fp,
writer->entry_count,
writer->dt_offset,
&writer->global_options) != 0) {
goto end;
}
printf("Total %d entries.\n", writer->entry_count);
ret = 0;
end:
free(writer->fdt_infos);
free(writer);
return ret;
}

View file

@ -0,0 +1,37 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MKDTIMG_CORE_H
#define MKDTIMG_CORE_H
#include <stdint.h>
#include <stdio.h>
#define OPTION_VALUE_SIZE_MAX 512
struct dt_image_writer;
int parse_option(char **option_ptr, char **value_ptr, char *line_str);
int parse_path(char **path_ptr, char **prop_ptr, char *value_str);
struct dt_image_writer *dt_image_writer_start(FILE *img_fp, uint32_t entry_count);
int set_global_options(struct dt_image_writer *writer, const char *option, const char *value);
int set_entry_options(struct dt_image_writer *writer, const char *option, const char *value);
int dt_image_writer_add_entry(struct dt_image_writer *writter, const char *fdt_filename);
int dt_image_writer_end(struct dt_image_writer *writter);
#endif

View file

@ -0,0 +1,137 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "dt_table.h"
#include "mkdtimg_core.h"
static int calculate_args_entry_count(int argc, char *argv[], int arg_start) {
int count = 0;
int i;
for (i = arg_start; i < argc; i++) {
const char *arg = argv[i];
char c = arg[0];
/* Skip options starting with -- */
if (c == '-') continue;
count++;
}
return count;
}
static int parse_arg(char **option, char **value, char *arg) {
if (arg[0] != '-') {
/* This is not a option */
*option = NULL;
return 0;
}
/* An option must start with -- */
if (arg[1] != '-') {
return -1;
}
return parse_option(option, value, arg + 2);
}
static int output_img_with_args(FILE *img_fp, int argc, char *argv[], int arg_start) {
int entry_count = calculate_args_entry_count(argc, argv, arg_start);
struct dt_image_writer *writer = dt_image_writer_start(img_fp, entry_count);
int is_entry = 0;
int i;
for (i = arg_start; i < argc; i++) {
char *arg = argv[i];
char *option, *value;
if (parse_arg(&option, &value, arg) != 0) {
fprintf(stderr, "Wrong syntax: %s\n", arg);
return -1;
}
if (option == NULL) {
/* This is a file name */
if (dt_image_writer_add_entry(writer, arg) != 0) {
return -1;
}
is_entry = 1;
continue;
}
int ret = is_entry ?
set_entry_options(writer, option, value) :
set_global_options(writer, option, value);
if (ret != 0) {
fprintf(stderr, "Unknown option: %s\n", option);
return -1;
}
} /* for all argv */
if (dt_image_writer_end(writer) != 0) {
return -1;
}
return 0;
}
void handle_usage_create(FILE *out_fp, const char *prog_name) {
fprintf(out_fp, " %s create <image_file> (<global_option>...) (<dtb_file> (<entry_option>...) ...)\n\n", prog_name);
fprintf(out_fp,
" global_options:\n"
" --page_size <number> Output file name. Default: 2048\n"
" --id=<number|path> The default value to set property id in dt_table_entry. Default: 0\n"
" --rev=<number|path>\n"
" --custom0=<number|path>\n"
" --custom1=<number|path>\n"
" --custom2=<number|path>\n"
" --custom3=<number|path>\n\n"
" The value could be a number or a DT node path.\n"
" <number> could be a 32-bits digit or hex value, ex. 68000, 0x6800.\n"
" <path> format is <full_node_path>:<property_name>, ex. /board/:id,\n"
" will read the value in given FTB file with the path.\n");
}
int handle_command_create(int argc, char *argv[], int arg_start) {
int ret = -1;
FILE *img_fp = NULL;
if (argc - arg_start < 1) {
handle_usage_create(stderr, argv[0]);
goto end;
}
const char *img_filename = argv[arg_start];
printf("create image file: %s...\n", img_filename);
img_fp = fopen(img_filename, "wb");
if (img_fp == NULL) {
fprintf(stderr, "Can not create file: %s\n", img_filename);
goto end;
}
ret = output_img_with_args(img_fp, argc, argv, arg_start + 1);
end:
if (img_fp) fclose(img_fp);
return ret;
}

View file

@ -0,0 +1,259 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "libfdt.h"
#include "dt_table.h"
struct dump_params {
const char *img_filename;
const char *out_filename;
const char *out_dtb_filename;
};
static const char short_options[] = "o:b:";
static struct option options[] = {
{ "output", required_argument, NULL, 'o' },
{ "dtb", required_argument, NULL, 'b' },
{ 0, 0, NULL, 0 }
};
static void *read_fdt_from_image(FILE *img_fp,
uint32_t dt_offset, uint32_t dt_size) {
void *fdt = NULL;
fdt = malloc(dt_size);
fseek(img_fp, dt_offset, SEEK_SET);
if (fread(fdt, dt_size, 1, img_fp) == 0) {
fprintf(stderr, "Read FDT data error.\n");
free(fdt);
return NULL;
}
return fdt;
}
static int write_fdt_to_file(const char *filename, const void *fdt) {
int ret = -1;
FILE *out_fp = NULL;
out_fp = fopen(filename, "wb");
if (!out_fp) {
fprintf(stderr, "Can not create file: %s\n", filename);
goto end;
}
size_t fdt_size = fdt_totalsize(fdt);
if (fwrite(fdt, fdt_size, 1, out_fp) < 1) {
fprintf(stderr, "Write FDT data error.\n");
goto end;
}
ret = 0;
end:
if (out_fp) fclose(out_fp);
return ret;
}
static void free_fdt(void *fdt) {
if (fdt == NULL) {
/* do nothing */
return;
}
free(fdt);
}
static void output_prop_int(FILE *out_fp, const char *name, uint32_t value) {
fprintf(out_fp, "%+20s = %d\n", name, fdt32_to_cpu(value));
}
static void output_prop_int_cpu(FILE *out_fp, const char *name, uint32_t value) {
fprintf(out_fp, "%+20s = %d\n", name, value);
}
static void output_prop_hex(FILE *out_fp, const char *name, uint32_t value) {
fprintf(out_fp, "%+20s = %08x\n", name, fdt32_to_cpu(value));
}
static void output_prop_str(FILE *out_fp, const char *name, const char *value) {
fprintf(out_fp, "%+20s = %s\n", name, value);
}
static void output_table_header(FILE *out_fp, const struct dt_table_header *header) {
fprintf(out_fp, "dt_table_header:\n");
output_prop_hex(out_fp, "magic", header->magic);
output_prop_int(out_fp, "total_size", header->total_size);
output_prop_int(out_fp, "header_size", header->header_size);
output_prop_int(out_fp, "dt_entry_size", header->dt_entry_size);
output_prop_int(out_fp, "dt_entry_count", header->dt_entry_count);
output_prop_int(out_fp, "dt_entries_offset", header->dt_entries_offset);
output_prop_int(out_fp, "page_size", header->page_size);
output_prop_hex(out_fp, "reserved[0]", header->reserved[0]);
}
static void output_table_entry(FILE *out_fp, int index, const struct dt_table_entry *entry) {
fprintf(out_fp, "dt_table_entry[%d]:\n", index);
output_prop_int(out_fp, "dt_size", entry->dt_size);
output_prop_int(out_fp, "dt_offset", entry->dt_offset);
output_prop_hex(out_fp, "id", entry->id);
output_prop_hex(out_fp, "rev", entry->rev);
output_prop_hex(out_fp, "custom[0]", entry->custom[0]);
output_prop_hex(out_fp, "custom[1]", entry->custom[1]);
output_prop_hex(out_fp, "custom[2]", entry->custom[2]);
output_prop_hex(out_fp, "custom[3]", entry->custom[3]);
}
static int output_fdt_info(FILE *out_fp, void *fdt) {
size_t fdt_size = fdt_totalsize(fdt);
output_prop_int_cpu(out_fp, "(FDT)size", fdt_size);
int root_node_off = fdt_path_offset(fdt, "/");
if (root_node_off < 0) {
fprintf(stderr, "Can not get the root node.\n");
return -1;
}
const char *compatible =
(const char *)fdt_getprop(fdt, root_node_off, "compatible", NULL);
output_prop_str(out_fp, "(FDT)compatible", compatible ? compatible : "(unknown)");
return 0;
}
static int dump_image_from_fp(FILE *out_fp, FILE *img_fp,
const struct dump_params *params) {
struct dt_table_header header;
if (fread(&header, sizeof(header), 1, img_fp) != 1) {
fprintf(stderr, "Read error.\n");
return -1;
}
/* TODO: check header */
output_table_header(out_fp, &header);
uint32_t entry_size = fdt32_to_cpu(header.dt_entry_size);
uint32_t entry_offset = fdt32_to_cpu(header.dt_entries_offset);
uint32_t entry_count = fdt32_to_cpu(header.dt_entry_count);
uint32_t i;
for (i = 0; i < entry_count; i++) {
struct dt_table_entry entry;
fseek(img_fp, entry_offset, SEEK_SET);
fread(&entry, sizeof(entry), 1, img_fp);
output_table_entry(out_fp, i, &entry);
uint32_t dt_size = fdt32_to_cpu(entry.dt_size);
uint32_t dt_offset = fdt32_to_cpu(entry.dt_offset);
if (dt_size > 0 && dt_offset > 0) {
void *fdt = read_fdt_from_image(img_fp, dt_offset, dt_size);
output_fdt_info(out_fp, fdt);
if (params->out_dtb_filename != NULL) {
char filename[256];
snprintf(filename, sizeof(filename), "%s.%d",
params->out_dtb_filename, i);
write_fdt_to_file(filename, fdt);
}
free_fdt(fdt);
}
entry_offset += entry_size;
}
return 0;
}
static int process_command_dump(const struct dump_params *params) {
int ret = -1;
FILE *out_fp = NULL;
FILE *img_fp = NULL;
img_fp = fopen(params->img_filename, "rb");
if (img_fp == NULL) {
fprintf(stderr, "Can not open image file: %s\n", params->img_filename);
goto end;
}
if (params->out_filename != NULL) {
out_fp = fopen(params->out_filename, "w");
if (out_fp == NULL) {
fprintf(stderr, "Can not create file: %s\n", params->out_filename);
goto end;
}
}
ret = dump_image_from_fp(out_fp ? out_fp : stdout, img_fp, params);
end:
if (img_fp) fclose(img_fp);
if (out_fp) fclose(out_fp);
return ret;
}
void handle_usage_dump(FILE *out_fp, const char *prog_name) {
fprintf(out_fp, " %s dump <image_file> (<option>...)\n\n", prog_name);
fprintf(out_fp,
" options:\n"
" -o, --output <filename> Output file name.\n"
" Default is output to stdout.\n"
" -b, --dtb <filename> Dump dtb/dtbo files from image.\n"
" Will output to <filename>.0, <filename>.1, etc.\n");
}
int handle_command_dump(int argc, char *argv[], int arg_start) {
if (argc - arg_start < 1) {
handle_usage_dump(stderr, argv[0]);
return 1;
}
struct dump_params params;
memset(&params, 0, sizeof(params));
params.img_filename = argv[arg_start];
optind = arg_start + 1;
while (1) {
int c = getopt_long(argc, argv, short_options, options, NULL);
if (c == -1) {
break;
}
switch (c) {
case 'o':
params.out_filename = optarg;
break;
case 'b':
params.out_dtb_filename = optarg;
break;
default:
/* Unknown option, return error */
return 1;
}
}
return process_command_dump(&params);
}

View file

@ -0,0 +1,15 @@
/dts-v1/;
/plugin/;
/ {
compatible = "board_manufacturer,board_model";
board_id = <0x00010000>;
board_rev = <0x00010000>;
/* optional, the soc used by the board */
soc_id = <0x00020000>;
};
&deviceB {
value = <0x1>;
status = "okay";
};

View file

@ -0,0 +1,16 @@
/dts-v1/;
/plugin/;
/ {
compatible = "board_manufacturer,board_model";
board_id = <0x00010000>;
board_rev = <0x00010001>;
another_board_id = <0xaabbccdd>;
/* optional, the soc used by the board */
soc_id = <0x00020000>;
};
&deviceB {
value = <0x2>;
status = "okay";
};

View file

@ -0,0 +1,15 @@
/dts-v1/;
/plugin/;
/ {
compatible = "board_manufacturer,board_model";
board_id = <0x00020000>;
board_rev = <0x00010000>;
/* optional, the soc used by the board */
soc_id = <0x00010000>;
};
&deviceA {
value = <0x1>;
status = "okay";
};

View file

@ -0,0 +1,16 @@
# Global options
page_size=4096
id=/:board_id # Read the value form the path in dtb
rev=/:board_rev # Read the value form the path in dtb
custom0=0xabc # default value
board1v1.dts.dtb
board1v1_1.dts.dtb
id=/:another_board_id # override with another path
board2v1.dts.dtb
rev=0x201 # override with another value
board1v1.dts.dtb
custom0=0xdef # override with another value

View file

@ -0,0 +1,12 @@
/dts-v1/;
/ {
compatible = "soc_manufacturer,soc_model";
soc_id = <0x0 0x0 0x0 0x1>;
soc_rev = <0x1 0x0>;
deviceA: deviceA {
compatible = "deviceA_manufacturer,deviceA_model";
status = "disabled";
};
};

View file

@ -0,0 +1,17 @@
/dts-v1/;
/ {
compatible = "soc_manufacturer,soc_model";
soc_id = <0x0 0x0 0x0 0x2>;
soc_rev = <0x1 0x0>;
deviceA: deviceA {
compatible = "deviceA_manufacturer,deviceA_model";
status = "disabled";
};
deviceB: deviceB {
compatible = "deviceB_manufacturer,deviceB_model";
status = "disabled";
};
};

View file

@ -0,0 +1,63 @@
#!/bin/bash
# Copyright (C) 2017 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
SRCDIR="data"
DTS_LIST="
board1v1.dts
board1v1_1.dts
board2v1.dts
"
DTB_LIST=(
"board1v1.dts.dtb"
"board1v1_1.dts.dtb"
"board2v1.dts.dtb"
"board1v1.dts.dtb"
)
CONFIG="${SRCDIR}/mkdtimg.cfg"
ALIGN=4
OUTDIR="out"
OUTDTB_CFG="${OUTDIR}/dump_cfg.dtb"
OUTDTB="${OUTDIR}/dump.dtb"
mkdir -p "$OUTDIR"
for dts in ${DTS_LIST}; do
echo "Building $dts..."
src_dts="${SRCDIR}/${dts}"
out_dtb="${OUTDIR}/${dts}.dtb"
dtc -O dtb -@ -qq -a "$ALIGN" -o "$out_dtb" "$src_dts"
done
IMG="${OUTDIR}/cfg_create.img"
mkdtimg cfg_create "$IMG" "${CONFIG}" --dtb-dir="$OUTDIR"
mkdtimg dump "$IMG" -b "$OUTDTB_CFG" | tee "${OUTDIR}/cfg_create.dump"
for index in ${!DTB_LIST[@]}; do
diff ${OUTDIR}/${DTB_LIST[$index]} ${OUTDTB_CFG}.$index
done
IMG="${OUTDIR}/create.img"
mkdtimg create "$IMG" \
--page_size=4096 --id=/:board_id --rev=/:board_rev --custom0=0xabc \
"${OUTDIR}/board1v1.dts.dtb" \
"${OUTDIR}/board1v1_1.dts.dtb" --id=/:another_board_id \
"${OUTDIR}/board2v1.dts.dtb" --rev=0x201 \
"${OUTDIR}/board1v1.dts.dtb" --custom0=0xdef
mkdtimg dump "$IMG" -b "$OUTDTB" | tee "${OUTDIR}/create.dump"
for index in ${!DTB_LIST[@]}; do
diff ${OUTDIR}/${DTB_LIST[$index]} ${OUTDTB}.$index
done
diff "${OUTDIR}/cfg_create.dump" "${OUTDIR}/create.dump"