upload android base code part6
This commit is contained in:
parent
421e214c7d
commit
4e516ec6ed
35396 changed files with 9188716 additions and 0 deletions
219
android/system/libufdt/utils/README.md
Normal file
219
android/system/libufdt/utils/README.md
Normal 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
|
||||
```
|
39
android/system/libufdt/utils/src/Android.mk
Normal file
39
android/system/libufdt/utils/src/Android.mk
Normal 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)
|
36
android/system/libufdt/utils/src/dt_table.c
Normal file
36
android/system/libufdt/utils/src/dt_table.c
Normal 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);
|
||||
}
|
57
android/system/libufdt/utils/src/dt_table.h
Normal file
57
android/system/libufdt/utils/src/dt_table.h
Normal 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
|
130
android/system/libufdt/utils/src/mkdtimg.c
Normal file
130
android/system/libufdt/utils/src/mkdtimg.c
Normal 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);
|
||||
}
|
191
android/system/libufdt/utils/src/mkdtimg_cfg_create.c
Normal file
191
android/system/libufdt/utils/src/mkdtimg_cfg_create.c
Normal 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(¶ms, 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(¶ms);
|
||||
}
|
400
android/system/libufdt/utils/src/mkdtimg_core.c
Normal file
400
android/system/libufdt/utils/src/mkdtimg_core.c
Normal 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;
|
||||
}
|
37
android/system/libufdt/utils/src/mkdtimg_core.h
Normal file
37
android/system/libufdt/utils/src/mkdtimg_core.h
Normal 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
|
137
android/system/libufdt/utils/src/mkdtimg_create.c
Normal file
137
android/system/libufdt/utils/src/mkdtimg_create.c
Normal 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;
|
||||
}
|
259
android/system/libufdt/utils/src/mkdtimg_dump.c
Normal file
259
android/system/libufdt/utils/src/mkdtimg_dump.c
Normal 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(¶ms, 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(¶ms);
|
||||
}
|
15
android/system/libufdt/utils/tests/data/board1v1.dts
Normal file
15
android/system/libufdt/utils/tests/data/board1v1.dts
Normal 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";
|
||||
};
|
16
android/system/libufdt/utils/tests/data/board1v1_1.dts
Normal file
16
android/system/libufdt/utils/tests/data/board1v1_1.dts
Normal 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";
|
||||
};
|
15
android/system/libufdt/utils/tests/data/board2v1.dts
Normal file
15
android/system/libufdt/utils/tests/data/board2v1.dts
Normal 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";
|
||||
};
|
16
android/system/libufdt/utils/tests/data/mkdtimg.cfg
Normal file
16
android/system/libufdt/utils/tests/data/mkdtimg.cfg
Normal 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
|
12
android/system/libufdt/utils/tests/data/soc1v1.dts
Normal file
12
android/system/libufdt/utils/tests/data/soc1v1.dts
Normal 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";
|
||||
};
|
||||
};
|
17
android/system/libufdt/utils/tests/data/soc2v1.dts
Normal file
17
android/system/libufdt/utils/tests/data/soc2v1.dts
Normal 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";
|
||||
};
|
||||
};
|
63
android/system/libufdt/utils/tests/mkdtimg_testdata.sh
Executable file
63
android/system/libufdt/utils/tests/mkdtimg_testdata.sh
Executable 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"
|
Loading…
Add table
Add a link
Reference in a new issue