Introduce Exynos dtbtool to the Linux build system

This commit is contained in:
James Christopher Adduono 2018-07-17 14:03:19 +02:00 committed by BlackMesa123
parent 21acf76397
commit cdc35a950b
9 changed files with 518 additions and 1 deletions

View File

@ -220,6 +220,8 @@ source "kernel/Kconfig.freezer"
source "arch/arm64/Kconfig.platforms"
source "arch/arm64/mach-exynos/Kconfig"
menu "Bus support"
config PCI

View File

@ -87,6 +87,10 @@ endif
KBUILD_DTBS := dtbs
ifeq ($(CONFIG_EXYNOS_DTBTOOL),y)
KBUILD_DTBS += dtb.img
endif
all: $(KBUILD_IMAGE) $(KBUILD_DTBS)
boot := arch/arm64/boot
@ -103,7 +107,7 @@ zinstall install: vmlinux
%.dtb: scripts
$(Q)$(MAKE) $(build)=$(boot)/dts $(boot)/dts/$@
PHONY += dtbs dtbs_install
PHONY += dtbs dtbs_install dtb.img
dtbs: prepare scripts
$(Q)$(MAKE) $(build)=$(boot)/dts
@ -111,6 +115,9 @@ dtbs: prepare scripts
dtbs_install:
$(Q)$(MAKE) $(dtbinst)=$(boot)/dts
dtb.img: prepare scripts dtbs
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
Image-dtb Image.gz-dtb: vmlinux scripts dtbs
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
@ -126,6 +133,7 @@ archclean:
define archhelp
echo '* Image.gz - Compressed kernel image (arch/$(ARCH)/boot/Image.gz)'
echo ' Image - Uncompressed kernel image (arch/$(ARCH)/boot/Image)'
echo ' dtb.img - Build device tree image (arch/$(ARCH)/boot/dtb.img)'
echo '* dtbs - Build device tree blobs for enabled boards'
echo ' dtbs_install - Install dtbs to $(INSTALL_DTBS_PATH)'
echo ' install - Install uncompressed kernel'

View File

@ -26,6 +26,15 @@ DTB_LIST := $(dtb-y)
endif
DTB_OBJS := $(addprefix $(obj)/dts/,$(DTB_LIST))
ifeq ($(CONFIG_EXYNOS_DTBTOOL),y)
targets += dtb.img
DTB_OBJS += $(shell find -L $(obj)/dts/ -name \*.dtb)
$(obj)/dtb.img: $(DTB_OBJS) FORCE
$(call if_changed,dtbtool_exynos)
endif
$(obj)/Image: vmlinux FORCE
$(call if_changed,objcopy)

View File

@ -0,0 +1,55 @@
# arch/arm64/mach-exynos/Kconfig
#
# Copyright (c) 2016 Samsung Electronics Co., Ltd.
# http://www.samsung.com/
#
# Licensed under GPLv2
# Configuration options for the EXYNOS7
if ARCH_EXYNOS
menu "SAMSUNG EXYNOS SoCs Support"
menuconfig EXYNOS_DTBTOOL
bool "Build dtbtool for Exynos"
select DTC
default n
help
Say Y here to build the dtbtool for Exynos,
which is necessary to create DTB images for
use in Exynos boot images.
if EXYNOS_DTBTOOL
config EXYNOS_DTBH_PLATFORM_CODE
hex "Exynos DTBH hex platform code"
default 0x50a6
help
This value is verified by the bootloader
to determine if the DTB image is valid for
the device that the kernel is booting on.
config EXYNOS_DTBH_SUBTYPE_CODE
hex "Exynos DTBH hex subtype code"
default 0x217584da
help
This value is verified by the bootloader
to determine if the DTB image is valid for
the device that the kernel is booting on.
config EXYNOS_DTBH_PAGE_SIZE
int "Exynos DTBH page size"
range 2048 131072
default 2048
help
Page size used to pad the DTB image.
It should be equal to the page size of
the Exynos boot image.
Must be divisible by 2048.
endif
endmenu
endif

View File

@ -44,6 +44,7 @@ subdir-y += mod
subdir-$(CONFIG_SECURITY_SELINUX) += selinux
subdir-$(CONFIG_DTC) += dtc
subdir-$(CONFIG_GDB_SCRIPTS) += gdb
subdir-$(CONFIG_EXYNOS_DTBTOOL) += dtbtool_exynos
# Let clean descend into subdirs
subdir- += basic kconfig package

View File

@ -296,6 +296,16 @@ $(obj)/%.dtb: $(src)/%.dts FORCE
dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp)
# dtbtool (Exynos)
# ---------------------------------------------------------------------------
quiet_cmd_dtbtool_exynos = DTBTOOL $@
cmd_dtbtool_exynos = $(objtree)/scripts/dtbtool_exynos/dtbtool \
--pagesize $(CONFIG_EXYNOS_DTBH_PAGE_SIZE) \
--platform $(CONFIG_EXYNOS_DTBH_PLATFORM_CODE) \
--subtype $(CONFIG_EXYNOS_DTBH_SUBTYPE_CODE) \
-o $@ $(sort $(filter-out FORCE,$^))
# cat
# ---------------------------------------------------------------------------
# Concatentate multiple files together

1
scripts/dtbtool_exynos/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
dtbtool

View File

@ -0,0 +1,13 @@
# scripts/dtbtool_exynos makefile
hostprogs-y := dtbtool
always := $(hostprogs-y)
dtbtool-objs := dtbtool.o
dtbtool-objs += ../dtc/libfdt/fdt.o ../dtc/libfdt/fdt_ro.o
CFLAGS_LIBFDT := -I$(src)/../dtc/libfdt
HOSTCFLAGS_dtbtool.o := $(CFLAGS_LIBFDT)
HOSTCFLAGS_fdt.o := $(CFLAGS_LIBFDT)
HOSTCFLAGS_fdt_ro.o := $(CFLAGS_LIBFDT)

View File

@ -0,0 +1,418 @@
/*
* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of The Linux Foundation nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <assert.h>
#include <dirent.h>
#include <err.h>
#include <stdint.h>
#include "libfdt.h"
/* max amount of scanned dtb files */
#define DTB_MAX 100
/* defaults if not set by args */
#define DTBH_PAGE_SIZE_DEF 2048
#define DTBH_PLATFORM_CODE_DEF 0x50a6
#define DTBH_SUBTYPE_CODE_DEF 0x217584da
#define DTBH_MAGIC "DTBH"
#define DTBH_VERSION 2
struct dt_blob;
/* DTBH_MAGIC + DTBH_VERSION + DTB counts */
#define DT_HEADER_PHYS_SIZE 12
/*
* keep the eight uint32_t entries first in this struct so we can memcpy them to the file
*/
#define DT_ENTRY_PHYS_SIZE (sizeof(uint32_t) * 8)
struct dt_entry {
uint32_t chip;
uint32_t platform;
uint32_t subtype;
uint32_t hw_rev;
uint32_t hw_rev_end;
uint32_t offset;
uint32_t size; /* including padding */
uint32_t space;
struct dt_blob *blob;
};
/*
* In memory representation of a dtb blob
*/
struct dt_blob {
uint32_t size;
uint32_t offset;
void *payload;
struct dt_blob *next;
};
#define error(fmt, ...) fprintf(stderr, "error: " fmt "\n", ##__VA_ARGS__)
#define fail(fmt, ...) do { error(fmt, ##__VA_ARGS__); exit(1); } while (0)
static void *load_file(const char *fn, unsigned *_sz)
{
char *data = 0;
int sz;
int fd;
fd = open(fn, O_RDONLY);
if (fd < 0) return 0;
sz = lseek(fd, 0, SEEK_END);
if (sz < 0) goto oops;
if (lseek(fd, 0, SEEK_SET)) goto oops;
data = malloc(sz);
if (!data) goto oops;
if (read(fd, data, sz) != sz) goto oops;
close(fd);
*_sz = sz;
return data;
oops:
close(fd);
if (data) free(data);
return 0;
}
static void *scan_dtb_path(char **dtb_files, const char *dtb_path)
{
struct dirent **de;
int i, f, files, namlen;
const int dlen = strlen(dtb_path);
files = scandir(dtb_path, &de, NULL, alphasort);
if (files < 0)
error("failed to open '%s': %s", dtb_path, strerror(errno));
for (f = 0, i = 0; f < files; f++) {
namlen = strlen(de[f]->d_name);
if (namlen < 4 || strcmp(&de[f]->d_name[namlen - 4], ".dtb"))
goto next_f;
/* skip over already allocated file names */
for (; dtb_files[i]; i++)
if (i >= DTB_MAX)
fail("reached dtb file limit (%d)", DTB_MAX);
namlen += dlen + 2; /* / and NULL terminator */
dtb_files[i] = calloc(namlen, sizeof(char));
if (!dtb_files[i])
fail("failed to allocate memory");
snprintf(dtb_files[i], namlen, "%s/%s", dtb_path, de[f]->d_name);
next_f:
free(de[f]);
}
return 0;
}
static void *load_dtbh_block(char **dtb_files, unsigned pagesize,
uint32_t platform_code, uint32_t subtype_code,
unsigned *_sz)
{
const unsigned pagemask = pagesize - 1;
struct dt_entry *new_entries;
struct dt_entry *entries = NULL;
struct dt_entry *entry;
struct dt_blob *blob;
struct dt_blob *blob_list = NULL;
struct dt_blob *last_blob = NULL;
unsigned new_count;
unsigned entry_count = 0;
unsigned offset;
unsigned dtb_sz = 0;
unsigned hdr_sz = DT_HEADER_PHYS_SIZE;
uint32_t version = DTBH_VERSION;
unsigned blob_sz = 0;
const unsigned *prop_chip;
const unsigned *prop_hw_rev;
const unsigned *prop_hw_rev_end;
const unsigned *prop_compatible;
int len;
void *dtb;
char *dtbh;
char **fname;
unsigned c;
for (fname = dtb_files; *fname; fname++) {
dtb = load_file(*fname, &dtb_sz);
if (!dtb || !dtb_sz)
error("failed to read dtb '%s'", *fname);
if (fdt_check_header(dtb) != 0) {
warnx("'%s' is not a valid dtb, skipping", *fname);
free(dtb);
continue;
}
offset = fdt_path_offset(dtb, "/");
prop_chip = fdt_getprop(dtb, offset, "model_info-chip", &len);
if (len % (sizeof(uint32_t))) {
warnx("model_info-chip of %s is of invalid size, skipping", *fname);
free(dtb);
continue;
}
prop_hw_rev = fdt_getprop(dtb, offset, "model_info-hw_rev", &len);
if (len % (sizeof(uint32_t))) {
warnx("model_info-hw_rev of %s is of invalid size, skipping", *fname);
free(dtb);
continue;
}
prop_hw_rev_end = fdt_getprop(dtb, offset, "model_info-hw_rev_end", &len);
if (len % (sizeof(uint32_t))) {
warnx("model_info-hw_rev_end of %s is of invalid size, skipping", *fname);
free(dtb);
continue;
}
prop_compatible = fdt_getprop(dtb, offset, "compatible", 0);
if (!prop_compatible) {
warnx("compatible field of %s is missing, skipping", *fname);
free(dtb);
continue;
}
printf("=> Found compatible entry: %s\n"
" (chip: %u, hw_rev: %u, hw_rev_end: %u)\n",
(char *)&prop_compatible[0], ntohl(prop_chip[0]),
ntohl(prop_hw_rev[0]), ntohl(prop_hw_rev_end[0]));
blob = calloc(1, sizeof(struct dt_blob));
if (!blob)
error("failed to allocate memory");
blob->payload = dtb;
blob->size = dtb_sz;
if (!blob_list) {
blob_list = blob;
last_blob = blob;
} else {
last_blob->next = blob;
last_blob = blob;
}
blob_sz += (blob->size + pagemask) & ~pagemask;
new_count = entry_count + 1;
new_entries = realloc(entries, new_count * sizeof(struct dt_entry));
if (!new_entries)
error("failed to allocate memory");
entries = new_entries;
entry = &entries[entry_count];
memset(entry, 0, sizeof(*entry));
entry->chip = ntohl(prop_chip[0]);
entry->platform = platform_code;
entry->subtype = subtype_code;
entry->hw_rev = ntohl(prop_hw_rev[0]);
entry->hw_rev_end = ntohl(prop_hw_rev_end[0]);
entry->space = 0x20; /* space delimiter */
entry->blob = blob;
entry_count++;
hdr_sz += entry_count * DT_ENTRY_PHYS_SIZE;
}
if (!entry_count) {
warnx("unable to locate any dtbs in the given path");
return 0;
}
hdr_sz += sizeof(uint32_t); /* eot marker */
hdr_sz = (hdr_sz + pagemask) & ~pagemask;
/* The size of the dt header is now known, calculate the blob offsets... */
offset = hdr_sz;
for (blob = blob_list; blob; blob = blob->next) {
blob->offset = offset;
offset += (blob->size + pagemask) & ~pagemask;
}
/* ...and update the entries */
for (c = 0; c < entry_count; c++) {
entry = &entries[c];
entry->offset = entry->blob->offset;
entry->size = (entry->blob->size + pagemask) & ~pagemask;
}
/*
* All parts are now gathered, so build the dt block
*/
dtbh = calloc(hdr_sz + blob_sz, 1);
if (!dtbh)
fail("failed to allocate memory");
offset = 0;
memcpy(dtbh, DTBH_MAGIC, sizeof(uint32_t));
memcpy(dtbh + sizeof(uint32_t), &version, sizeof(uint32_t));
memcpy(dtbh + (sizeof(uint32_t) * 2), &entry_count, sizeof(uint32_t));
offset += DT_HEADER_PHYS_SIZE;
/* add dtbh entries */
for (c = 0; c < entry_count; c++) {
entry = &entries[c];
memcpy(dtbh + offset, entry, DT_ENTRY_PHYS_SIZE);
offset += DT_ENTRY_PHYS_SIZE;
}
/* add padding after dt header */
offset += pagesize - (offset & pagemask);
for (blob = blob_list; blob; blob = blob->next) {
memcpy(dtbh + offset, blob->payload, blob->size);
offset += (blob->size + pagemask) & ~pagemask;
}
*_sz = hdr_sz + blob_sz;
return dtbh;
}
static int usage(void)
{
fprintf(stderr, "usage: dtbtool\n"
" -o|--output <filename>\n"
" [ -s|--pagesize <pagesize> ]\n"
" [ --platform <hex platform code> ]\n"
" [ --subtype <hex subtype code> ]\n"
" [ -d|--dtb <dtb path> ]...\n"
" [ <dtb file> ]...\n"
);
exit(1);
}
#define read_val { if (argc < 2) return usage(); val = argv[1]; argc--; argv++; }
int main(int argc, char **argv)
{
char *arg, *val;
char *dt_img = 0;
void *dt_data = 0;
char **dtb_files = 0;
int fd, dt_count = 0;
unsigned pagesize = DTBH_PAGE_SIZE_DEF;
uint32_t dt_platform_code = DTBH_PLATFORM_CODE_DEF;
uint32_t dt_subtype_code = DTBH_SUBTYPE_CODE_DEF;
unsigned dt_size;
dtb_files = malloc(sizeof(char*) * DTB_MAX);
if (!dtb_files)
error("failed to allocate memory");
while (argc > 0) {
argc--;
argv++;
if (argc < 1)
break;
arg = argv[0];
val = 0;
if (!strcmp(arg,"--pagesize") || !strcmp(arg,"-s")) {
read_val;
pagesize = strtoul(val, 0, 10);
if ((pagesize != 2048) && (pagesize != 4096) && (pagesize != 8192) && (pagesize != 16384) && (pagesize != 32768) && (pagesize != 65536) && (pagesize != 131072))
fail("unsupported page size %d\n", pagesize);
} else if (!strcmp(arg, "--dtb") || !strcmp(arg, "-d")) {
read_val;
scan_dtb_path(dtb_files, val);
} else if (!strcmp(arg, "--output") || !strcmp(arg, "-o")) {
read_val;
dt_img = val;
} else if (!strcmp(arg, "--platform")) {
read_val;
dt_platform_code = strtoul(val, 0, 16);
} else if (!strcmp(arg, "--subtype")) {
read_val;
dt_subtype_code = strtoul(val, 0, 16);
} else if (*arg != '-') {
/* skip over already allocated file names */
for (; dtb_files[dt_count]; dt_count++)
if (dt_count >= DTB_MAX)
fail("reached dtb file limit (%d)", DTB_MAX);
dtb_files[dt_count] = strdup(arg);
if (!dtb_files[dt_count])
fail("failed to allocate memory");
} else
usage();
}
if (!dt_img) {
error("no output filename specified");
usage();
}
if (!dtb_files[0])
fail("no dtb files found");
dt_data = load_dtbh_block(dtb_files, pagesize, dt_platform_code, dt_subtype_code, &dt_size);
if (!dt_data)
fail("could not load device tree blobs");
fd = open(dt_img, O_CREAT | O_TRUNC | O_WRONLY, 0644);
if (fd < 0)
fail("could not create output file '%s': %s", dt_img, strerror(errno));
if (write(fd, dt_data, dt_size) != dt_size) goto fail;
close(fd);
return 0;
fail:
unlink(dt_img);
close(fd);
fail("failed writing '%s': %s", dt_img, strerror(errno));
}