import G965FXXU7DTAA OSRC

*First release for Android (Q).

Signed-off-by: FAROVITUS <farovitus@gmail.com>
This commit is contained in:
FAROVITUS 2020-02-04 13:44:48 +02:00
parent 856452b4f2
commit 2b92eefa41
7696 changed files with 3763754 additions and 92661 deletions

View file

@ -27,6 +27,7 @@ ifeq ("$(dtbinst-root)", "$(obj)")
endif
dtbinst-files := $(dtb-y)
dtboinst-files := $(dtbo-y)
dtbinst-dirs := $(dts-dirs)
# Helper targets for Installing DTBs into the boot directory
@ -35,15 +36,18 @@ quiet_cmd_dtb_install = INSTALL $<
install-dir = $(patsubst $(dtbinst-root)%,$(INSTALL_DTBS_PATH)%,$(obj))
$(dtbinst-files) $(dtbinst-dirs): | __dtbs_install_prep
$(dtbinst-files) $(dtboinst-files) $(dtbinst-dirs): | __dtbs_install_prep
$(dtbinst-files): %.dtb: $(obj)/%.dtb
$(call cmd,dtb_install,$(install-dir))
$(dtboinst-files): %.dtbo: $(obj)/%.dtbo
$(call cmd,dtb_install,$(install-dir))
$(dtbinst-dirs):
$(Q)$(MAKE) $(dtbinst)=$(obj)/$@
PHONY += $(dtbinst-files) $(dtbinst-dirs)
__dtbs_install: $(dtbinst-files) $(dtbinst-dirs)
PHONY += $(dtbinst-files) $(dtboinst-files) $(dtbinst-dirs)
__dtbs_install: $(dtbinst-files) $(dtboinst-files) $(dtbinst-dirs)
.PHONY: $(PHONY)

View file

@ -5,11 +5,14 @@ else
call_threshold := 0
endif
CC = $(srctree)/../../prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.2.1/bin/aarch64-linux-gnu-gcc
KASAN_SHADOW_OFFSET ?= $(CONFIG_KASAN_SHADOW_OFFSET)
CFLAGS_KASAN_MINIMAL := -fsanitize=kernel-address
cc-param = $(call cc-option, -mllvm -$(1), $(call cc-option, --param $(1)))
KBUILD_CFLAGS += $(call cc-option, -D__ANDROID__ -Wno-error)
ifeq ($(call cc-option, $(CFLAGS_KASAN_MINIMAL) -Werror),)
ifneq ($(CONFIG_COMPILE_TEST),y)

View file

@ -179,6 +179,10 @@ dtc_cpp_flags = -Wp,-MD,$(depfile).pre.tmp -nostdinc \
-I$(srctree)/drivers/of/testcase-data \
-undef -D__DTS__
ifeq ($(CONFIG_SEC_FACTORY),y)
dtc_cpp_flags += -DCONFIG_SEC_FACTORY
endif
# Finds the multi-part object the current object will be linked into
modname-multi = $(sort $(foreach m,$(multi-used),\
$(if $(filter $(subst $(obj)/,,$*.o), $($(m:.o=-objs)) $($(m:.o=-y))),$(m:.o=))))
@ -278,6 +282,9 @@ cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -n -f -9 > $@) || \
# ---------------------------------------------------------------------------
DTC ?= $(objtree)/scripts/dtc/dtc
# Overlay support
DTC_FLAGS += -@
# Disable noisy checks by default
ifeq ($(KBUILD_ENABLE_EXTRA_GCC_CHECKS),)
DTC_FLAGS += -Wno-unit_address_vs_reg
@ -304,14 +311,18 @@ $(obj)/%.dtb.S: $(obj)/%.dtb
quiet_cmd_dtc = DTC $@
cmd_dtc = mkdir -p $(dir ${dtc-tmp}) ; \
$(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \
$(DTC) -O dtb -o $@ -b 0 \
$(DTC) -O dtb -o $@ -b 0 -a 4\
-i $(dir $<) $(DTC_FLAGS) \
-d $(depfile).dtc.tmp $(dtc-tmp) ; \
cat $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile)
$(DTC) -O dts -I dtb -o $@.reverse.dts $@ ; \
cat $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile)
$(obj)/%.dtb: $(src)/%.dts FORCE
$(call if_changed_dep,dtc)
$(obj)/%.dtbo: $(src)/%.dts FORCE
$(call if_changed_dep,dtc)
dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp)
# cat

View file

@ -1,4 +1,6 @@
ifdef CONFIG_UBSAN
CC = $(srctree)/../../prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.2.1/bin/aarch64-linux-gnu-gcc
CFLAGS_UBSAN += $(call cc-option, -fsanitize=shift)
CFLAGS_UBSAN += $(call cc-option, -fsanitize=integer-divide-by-zero)
CFLAGS_UBSAN += $(call cc-option, -fsanitize=unreachable)
@ -21,4 +23,5 @@ endif
# -fsanitize=* options makes GCC less smart than usual and
# increase number of 'maybe-uninitialized false-positives
CFLAGS_UBSAN += $(call cc-option, -Wno-maybe-uninitialized)
CFLAGS_UBSAN += $(call cc-option, -D__ANDROID__ -Wno-error)
endif

View file

@ -0,0 +1,9 @@
#!/bin/sh
MAJOR=$(echo $1 | cut -d '.' -f 1)
if echo $MAJOR | egrep -q '^[0-9]+$'; then
let MAJOR=MAJOR+103
printf "%b" "$(printf '\%03o' $MAJOR)"
else
echo $MAJOR | tr '[A-Z]' '[a-z]'
fi

View file

@ -0,0 +1,2 @@
#!/bin/sh
echo $1 | awk -F. '{ printf "%d%02d%02d", $1, $2, $3 }'

View file

@ -1,4 +1,4 @@
#!/usr/bin/perl -w
#!/usr/bin/env perl
# (c) 2001, Dave Jones. (the file handling bit)
# (c) 2005, Joel Schopp <jschopp@austin.ibm.com> (the ugly bit)
# (c) 2007,2008, Andy Whitcroft <apw@uk.ibm.com> (new conditions, test suite)
@ -6,6 +6,7 @@
# Licensed under the terms of the GNU GPL License version 2
use strict;
use warnings;
use POSIX;
use File::Basename;
use Cwd 'abs_path';
@ -55,7 +56,8 @@ my $spelling_file = "$D/spelling.txt";
my $codespell = 0;
my $codespellfile = "/usr/share/codespell/dictionary.txt";
my $conststructsfile = "$D/const_structs.checkpatch";
my $color = 1;
my $typedefsfile = "";
my $color = "auto";
my $allow_c99_comments = 1;
sub help {
@ -113,7 +115,9 @@ Options:
--codespell Use the codespell dictionary for spelling/typos
(default:/usr/share/codespell/dictionary.txt)
--codespellfile Use this codespell dictionary
--color Use colors when output is STDOUT (default: on)
--typedefsfile Read additional types from this file
--color[=WHEN] Use colors 'always', 'never', or only when output
is a terminal ('auto'). Default is 'auto'.
-h, --help, --version display this help and exit
When FILE is - read standard input.
@ -179,6 +183,14 @@ if (-f $conf) {
unshift(@ARGV, @conf_args) if @conf_args;
}
# Perl's Getopt::Long allows options to take optional arguments after a space.
# Prevent --color by itself from consuming other arguments
foreach (@ARGV) {
if ($_ eq "--color" || $_ eq "-color") {
$_ = "--color=$color";
}
}
GetOptions(
'q|quiet+' => \$quiet,
'tree!' => \$tree,
@ -208,7 +220,10 @@ GetOptions(
'test-only=s' => \$tst_only,
'codespell!' => \$codespell,
'codespellfile=s' => \$codespellfile,
'color!' => \$color,
'typedefsfile=s' => \$typedefsfile,
'color=s' => \$color,
'no-color' => \$color, #keep old behaviors of -nocolor
'nocolor' => \$color, #keep old behaviors of -nocolor
'h|help' => \$help,
'version' => \$help
) or help(1);
@ -234,6 +249,18 @@ if ($#ARGV < 0) {
push(@ARGV, '-');
}
if ($color =~ /^[01]$/) {
$color = !$color;
} elsif ($color =~ /^always$/i) {
$color = 1;
} elsif ($color =~ /^never$/i) {
$color = 0;
} elsif ($color =~ /^auto$/i) {
$color = (-t STDOUT);
} else {
die "Invalid color mode: $color\n";
}
sub hash_save_array_words {
my ($hashRef, $arrayRef) = @_;
@ -335,7 +362,7 @@ our $Attribute = qr{
__percpu|
__nocast|
__safe|
__bitwise__|
__bitwise|
__packed__|
__packed2__|
__naked|
@ -424,7 +451,7 @@ our $typeTypedefs = qr{(?x:
our $zero_initializer = qr{(?:(?:0[xX])?0+$Int_type?|NULL|false)\b};
our $logFunctions = qr{(?x:
printk(?:_ratelimited|_once|)|
printk(?:_ratelimited|_once|_deferred_once|_deferred|)|
(?:[a-z0-9]+_){1,2}(?:printk|emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)(?:_ratelimited|_once|)|
WARN(?:_RATELIMIT|_ONCE|)|
panic|
@ -629,29 +656,44 @@ if ($codespell) {
$misspellings = join("|", sort keys %spelling_fix) if keys %spelling_fix;
my $const_structs = "";
if (open(my $conststructs, '<', $conststructsfile)) {
while (<$conststructs>) {
my $line = $_;
sub read_words {
my ($wordsRef, $file) = @_;
$line =~ s/\s*\n?$//g;
$line =~ s/^\s*//g;
if (open(my $words, '<', $file)) {
while (<$words>) {
my $line = $_;
next if ($line =~ m/^\s*#/);
next if ($line =~ m/^\s*$/);
if ($line =~ /\s/) {
print("$conststructsfile: '$line' invalid - ignored\n");
next;
$line =~ s/\s*\n?$//g;
$line =~ s/^\s*//g;
next if ($line =~ m/^\s*#/);
next if ($line =~ m/^\s*$/);
if ($line =~ /\s/) {
print("$file: '$line' invalid - ignored\n");
next;
}
$$wordsRef .= '|' if ($$wordsRef ne "");
$$wordsRef .= $line;
}
$const_structs .= '|' if ($const_structs ne "");
$const_structs .= $line;
close($file);
return 1;
}
close($conststructsfile);
} else {
warn "No structs that should be const will be found - file '$conststructsfile': $!\n";
return 0;
}
my $const_structs = "";
read_words(\$const_structs, $conststructsfile)
or warn "No structs that should be const will be found - file '$conststructsfile': $!\n";
my $typeOtherTypedefs = "";
if (length($typedefsfile)) {
read_words(\$typeOtherTypedefs, $typedefsfile)
or warn "No additional types will be considered - file '$typedefsfile': $!\n";
}
$typeTypedefs .= '|' . $typeOtherTypedefs if ($typeOtherTypedefs ne "");
sub build_types {
my $mods = "(?x: \n" . join("|\n ", (@modifierList, @modifierListFile)) . "\n)";
my $all = "(?x: \n" . join("|\n ", (@typeList, @typeListFile)) . "\n)";
@ -714,7 +756,7 @@ our $FuncArg = qr{$Typecast{0,1}($LvalOrFunc|$Constant|$String)};
our $declaration_macros = qr{(?x:
(?:$Storage\s+)?(?:[A-Z_][A-Z0-9]*_){0,2}(?:DEFINE|DECLARE)(?:_[A-Z0-9]+){1,6}\s*\(|
(?:$Storage\s+)?LIST_HEAD\s*\(|
(?:$Storage\s+)?[HLP]?LIST_HEAD\s*\(|
(?:$Storage\s+)?${Type}\s+uninitialized_var\s*\(
)};
@ -761,7 +803,7 @@ sub seed_camelcase_file {
sub is_maintained_obsolete {
my ($filename) = @_;
return 0 if (!(-e "$root/scripts/get_maintainer.pl"));
return 0 if (!$tree || !(-e "$root/scripts/get_maintainer.pl"));
my $status = `perl $root/scripts/get_maintainer.pl --status --nom --nol --nogit --nogit-fallback -f $filename 2>&1`;
@ -848,6 +890,7 @@ sub git_commit_info {
# echo "commit $(cut -c 1-12,41-)"
# done
} elsif ($lines[0] =~ /^fatal: ambiguous argument '$commit': unknown revision or path not in the working tree\./) {
$id = undef;
} else {
$id = substr($lines[0], 0, 12);
$desc = substr($lines[0], 41);
@ -1848,6 +1891,8 @@ my $prefix = '';
sub show_type {
my ($type) = @_;
$type =~ tr/[a-z]/[A-Z]/;
return defined $use_type{$type} if (scalar keys %use_type > 0);
return !defined $ignore_type{$type};
@ -1861,7 +1906,7 @@ sub report {
return 0;
}
my $output = '';
if (-t STDOUT && $color) {
if ($color) {
if ($level eq 'ERROR') {
$output .= RED;
} elsif ($level eq 'WARNING') {
@ -1872,10 +1917,10 @@ sub report {
}
$output .= $prefix . $level . ':';
if ($show_types) {
$output .= BLUE if (-t STDOUT && $color);
$output .= BLUE if ($color);
$output .= "$type:";
}
$output .= RESET if (-t STDOUT && $color);
$output .= RESET if ($color);
$output .= ' ' . $msg . "\n";
if ($showfile) {
@ -2134,7 +2179,7 @@ sub process {
my $in_header_lines = $file ? 0 : 1;
my $in_commit_log = 0; #Scanning lines before patch
my $has_commit_log = 0; #Encountered lines before patch
my $commit_log_possible_stack_dump = 0;
my $commit_log_possible_stack_dump = 0;
my $commit_log_long_line = 0;
my $commit_log_has_diff = 0;
my $reported_maintainer_file = 0;
@ -2154,6 +2199,7 @@ sub process {
my $realline = 0;
my $realcnt = 0;
my $here = '';
my $context_function; #undef'd unless there's a known function
my $in_comment = 0;
my $comment_edge = 0;
my $first_line = 0;
@ -2187,12 +2233,12 @@ sub process {
if ($rawline=~/^\+\+\+\s+(\S+)/) {
$setup_docs = 0;
if ($1 =~ m@Documentation/kernel-parameters.txt$@) {
if ($1 =~ m@Documentation/admin-guide/kernel-parameters.rst$@) {
$setup_docs = 1;
}
#next;
}
if ($rawline=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
if ($rawline =~ /^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
$realline=$1-1;
if (defined $2) {
$realcnt=$3+1;
@ -2271,7 +2317,8 @@ sub process {
#extract the line range in the file after the patch is applied
if (!$in_commit_log &&
$line =~ /^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
$line =~ /^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@(.*)/) {
my $context = $4;
$is_patch = 1;
$first_line = $linenr + 1;
$realline=$1-1;
@ -2287,6 +2334,11 @@ sub process {
%suppress_whiletrailers = ();
%suppress_export = ();
$suppress_statement = 0;
if ($context =~ /\b(\w+)\s*\(/) {
$context_function = $1;
} else {
undef $context_function;
}
next;
# track the line number as we move through the hunk, note that
@ -2578,7 +2630,8 @@ sub process {
($id, $description) = git_commit_info($orig_commit,
$id, $orig_desc);
if ($short || $long || $space || $case || ($orig_desc ne $description) || !$hasparens) {
if (defined($id) &&
($short || $long || $space || $case || ($orig_desc ne $description) || !$hasparens)) {
ERROR("GIT_COMMIT_ID",
"Please use git commit description style 'commit <12+ chars of sha1> (\"<title line>\")' - ie: '${init_char}ommit $id (\"$description\")'\n" . $herecurr);
}
@ -2590,6 +2643,7 @@ sub process {
$line =~ /^rename (?:from|to) [\w\/\.\-]+\s*$/ ||
($line =~ /\{\s*([\w\/\.\-]*)\s*\=\>\s*([\w\/\.\-]*)\s*\}/ &&
(defined($1) || defined($2))))) {
$is_patch = 1;
$reported_maintainer_file = 1;
WARN("FILE_PATH_CHANGES",
"added, moved or deleted file(s), does MAINTAINERS need updating?\n" . $herecurr);
@ -2602,20 +2656,6 @@ sub process {
$herecurr) if (!$emitted_corrupt++);
}
# Check for absolute kernel paths.
if ($tree) {
while ($line =~ m{(?:^|\s)(/\S*)}g) {
my $file = $1;
if ($file =~ m{^(.*?)(?::\d+)+:?$} &&
check_absolute_file($1, $herecurr)) {
#
} else {
check_absolute_file($file, $herecurr);
}
}
}
# UTF-8 regex found at http://www.w3.org/International/questions/qa-forms-utf-8.en.php
if (($realfile =~ /^$/ || $line =~ /^\+/) &&
$rawline !~ m/^$UTF8*$/) {
@ -2632,8 +2672,8 @@ sub process {
# Check if it's the start of a commit log
# (not a header line and we haven't seen the patch filename)
if ($in_header_lines && $realfile =~ /^$/ &&
!($rawline =~ /^\s+\S/ ||
$rawline =~ /^(commit\b|from\b|[\w-]+:).*$/i)) {
!($rawline =~ /^\s+(?:\S|$)/ ||
$rawline =~ /^(?:commit\b|from\b|[\w-]+:)/i)) {
$in_header_lines = 0;
$in_commit_log = 1;
$has_commit_log = 1;
@ -2653,6 +2693,20 @@ sub process {
"8-bit UTF-8 used in possible commit log\n" . $herecurr);
}
# Check for absolute kernel paths in commit message
if ($tree && $in_commit_log) {
while ($line =~ m{(?:^|\s)(/\S*)}g) {
my $file = $1;
if ($file =~ m{^(.*?)(?::\d+)+:?$} &&
check_absolute_file($1, $herecurr)) {
#
} else {
check_absolute_file($file, $herecurr);
}
}
}
# Check for various typo / spelling mistakes
if (defined($misspellings) &&
($in_commit_log || $line =~ /^(?:\+|Subject:)/i)) {
@ -2695,6 +2749,7 @@ sub process {
# Check for FSF mailing addresses.
if ($rawline =~ /\bwrite to the Free/i ||
$rawline =~ /\b675\s+Mass\s+Ave/i ||
$rawline =~ /\b59\s+Temple\s+Pl/i ||
$rawline =~ /\b51\s+Franklin\s+St/i) {
my $herevet = "$here\n" . cat_vet($rawline) . "\n";
@ -2746,11 +2801,15 @@ sub process {
#print "is_start<$is_start> is_end<$is_end> length<$length>\n";
}
# discourage the addition of CONFIG_EXPERIMENTAL in Kconfig.
if ($realfile =~ /Kconfig/ &&
$line =~ /.\s*depends on\s+.*\bEXPERIMENTAL\b/) {
WARN("CONFIG_EXPERIMENTAL",
"Use of CONFIG_EXPERIMENTAL is deprecated. For alternatives, see https://lkml.org/lkml/2012/10/23/580\n");
# check for MAINTAINERS entries that don't have the right form
if ($realfile =~ /^MAINTAINERS$/ &&
$rawline =~ /^\+[A-Z]:/ &&
$rawline !~ /^\+[A-Z]:\t\S/) {
if (WARN("MAINTAINERS_STYLE",
"MAINTAINERS entries use one tab after TYPE:\n" . $herecurr) &&
$fix) {
$fixed[$fixlinenr] =~ s/^(\+[A-Z]):\s*/$1:\t/;
}
}
# discourage the use of boolean for type definition attributes of Kconfig options
@ -2806,7 +2865,7 @@ sub process {
}
# check we are in a valid source file if not then ignore this hunk
next if ($realfile !~ /\.(h|c|s|S|pl|sh|dtsi|dts)$/);
next if ($realfile !~ /\.(h|c|s|S|sh|dtsi|dts)$/);
# line length limit (with some exclusions)
#
@ -2934,7 +2993,7 @@ sub process {
# check multi-line statement indentation matches previous line
if ($^V && $^V ge 5.10.0 &&
$prevline =~ /^\+([ \t]*)((?:$c90_Keywords(?:\s+if)\s*)|(?:$Declare\s*)?(?:$Ident|\(\s*\*\s*$Ident\s*\))\s*|$Ident\s*=\s*$Ident\s*)\(.*(\&\&|\|\||,)\s*$/) {
$prevline =~ /^\+([ \t]*)((?:$c90_Keywords(?:\s+if)\s*)|(?:$Declare\s*)?(?:$Ident|\(\s*\*\s*$Ident\s*\))\s*|(?:\*\s*)*$Lval\s*=\s*$Ident\s*)\(.*(\&\&|\|\||,)\s*$/) {
$prevline =~ /^\+(\t*)(.*)$/;
my $oldindent = $1;
my $rest = $2;
@ -3122,6 +3181,17 @@ sub process {
# check we are in a valid C source file if not then ignore this hunk
next if ($realfile !~ /\.(h|c)$/);
# check if this appears to be the start function declaration, save the name
if ($sline =~ /^\+\{\s*$/ &&
$prevline =~ /^\+(?:(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*)?($Ident)\(/) {
$context_function = $1;
}
# check if this appears to be the end of function declaration
if ($sline =~ /^\+\}\s*$/) {
undef $context_function;
}
# check indentation of any line with a bare else
# (but not if it is a multiple line "if (foo) return bar; else return baz;")
# if the previous line is a break or return and is indented 1 tab more...
@ -3146,12 +3216,6 @@ sub process {
}
}
# discourage the addition of CONFIG_EXPERIMENTAL in #if(def).
if ($line =~ /^\+\s*\#\s*if.*\bCONFIG_EXPERIMENTAL\b/) {
WARN("CONFIG_EXPERIMENTAL",
"Use of CONFIG_EXPERIMENTAL is deprecated. For alternatives, see https://lkml.org/lkml/2012/10/23/580\n");
}
# check for RCS/CVS revision markers
if ($rawline =~ /^\+.*\$(Revision|Log|Id)(?:\$|)/) {
WARN("CVS_KEYWORD",
@ -3180,7 +3244,7 @@ sub process {
my ($stat, $cond, $line_nr_next, $remain_next, $off_next,
$realline_next);
#print "LINE<$line>\n";
if ($linenr >= $suppress_statement &&
if ($linenr > $suppress_statement &&
$realcnt && $sline =~ /.\s*\S/) {
($stat, $cond, $line_nr_next, $remain_next, $off_next) =
ctx_statement_block($linenr, $realcnt, 0);
@ -3327,7 +3391,7 @@ sub process {
}
# Check relative indent for conditionals and blocks.
if ($line =~ /\b(?:(?:if|while|for|(?:[a-z_]+|)for_each[a-z_]+)\s*\(|do\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) {
if ($line =~ /\b(?:(?:if|while|for|(?:[a-z_]+|)for_each[a-z_]+)\s*\(|(?:do|else)\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) {
($stat, $cond, $line_nr_next, $remain_next, $off_next) =
ctx_statement_block($linenr, $realcnt, 0)
if (!defined $stat);
@ -3419,6 +3483,8 @@ sub process {
if ($check && $s ne '' &&
(($sindent % 8) != 0 ||
($sindent < $indent) ||
($sindent == $indent &&
($s !~ /^\s*(?:\}|\{|else\b)/)) ||
($sindent > $indent + 8))) {
WARN("SUSPECT_CODE_INDENT",
"suspect code indent for conditional statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n");
@ -3441,6 +3507,18 @@ sub process {
#ignore lines not being added
next if ($line =~ /^[^\+]/);
# check for dereferences that span multiple lines
if ($prevline =~ /^\+.*$Lval\s*(?:\.|->)\s*$/ &&
$line =~ /^\+\s*(?!\#\s*(?!define\s+|if))\s*$Lval/) {
$prevline =~ /($Lval\s*(?:\.|->))\s*$/;
my $ref = $1;
$line =~ /^.\s*($Lval)/;
$ref .= $1;
$ref =~ s/\s//g;
WARN("MULTILINE_DEREFERENCE",
"Avoid multiple line dereference - prefer '$ref'\n" . $hereprev);
}
# check for declarations of signed or unsigned without int
while ($line =~ m{\b($Declare)\s*(?!char\b|short\b|int\b|long\b)\s*($Ident)?\s*[=,;\[\)\(]}g) {
my $type = $1;
@ -3669,7 +3747,7 @@ sub process {
$line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ &&
$line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ &&
$line !~ /\b$typeTypedefs\b/ &&
$line !~ /\b__bitwise(?:__|)\b/) {
$line !~ /\b__bitwise\b/) {
WARN("NEW_TYPEDEFS",
"do not add new typedefs\n" . $herecurr);
}
@ -4828,8 +4906,10 @@ sub process {
$dstat !~ /^\(\{/ && # ({...
$ctx !~ /^.\s*#\s*define\s+TRACE_(?:SYSTEM|INCLUDE_FILE|INCLUDE_PATH)\b/)
{
if ($dstat =~ /;/) {
if ($dstat =~ /^\s*if\b/) {
ERROR("MULTISTATEMENT_MACRO_USE_DO_WHILE",
"Macros starting with if should be enclosed by a do - while loop to avoid possible if/else logic defects\n" . "$herectx");
} elsif ($dstat =~ /;/) {
ERROR("MULTISTATEMENT_MACRO_USE_DO_WHILE",
"Macros with multiple statements should be enclosed in a do - while loop\n" . "$herectx");
} else {
@ -4860,17 +4940,17 @@ sub process {
foreach my $arg (@def_args) {
next if ($arg =~ /\.\.\./);
next if ($arg =~ /^type$/i);
my $tmp = $define_stmt;
$tmp =~ s/\b(typeof|__typeof__|__builtin\w+|typecheck\s*\(\s*$Type\s*,|\#+)\s*\(*\s*$arg\s*\)*\b//g;
$tmp =~ s/\#+\s*$arg\b//g;
$tmp =~ s/\b$arg\s*\#\#//g;
my $use_cnt = $tmp =~ s/\b$arg\b//g;
my $tmp_stmt = $define_stmt;
$tmp_stmt =~ s/\b(typeof|__typeof__|__builtin\w+|typecheck\s*\(\s*$Type\s*,|\#+)\s*\(*\s*$arg\s*\)*\b//g;
$tmp_stmt =~ s/\#+\s*$arg\b//g;
$tmp_stmt =~ s/\b$arg\s*\#\#//g;
my $use_cnt = $tmp_stmt =~ s/\b$arg\b//g;
if ($use_cnt > 1) {
CHK("MACRO_ARG_REUSE",
"Macro argument reuse '$arg' - possible side-effects?\n" . "$herectx");
}
# check if any macro arguments may have other precedence issues
if ($define_stmt =~ m/($Operators)?\s*\b$arg\b\s*($Operators)?/m &&
if ($tmp_stmt =~ m/($Operators)?\s*\b$arg\b\s*($Operators)?/m &&
((defined($1) && $1 ne ',') ||
(defined($2) && $2 ne ','))) {
CHK("MACRO_ARG_PRECEDENCE",
@ -5083,6 +5163,12 @@ sub process {
}
}
# check for single line unbalanced braces
if ($sline =~ /^.\s*\}\s*else\s*$/ ||
$sline =~ /^.\s*else\s*\{\s*$/) {
CHK("BRACES", "Unbalanced braces around else statement\n" . $herecurr);
}
# check for unnecessary blank lines around braces
if (($line =~ /^.\s*}\s*$/ && $prevrawline =~ /^.\s*$/)) {
if (CHK("BRACES",
@ -5103,7 +5189,7 @@ sub process {
my $asm_volatile = qr{\b(__asm__|asm)\s+(__volatile__|volatile)\b};
if ($line =~ /\bvolatile\b/ && $line !~ /$asm_volatile/) {
WARN("VOLATILE",
"Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt\n" . $herecurr);
"Use of volatile is usually wrong: see Documentation/process/volatile-considered-harmful.rst\n" . $herecurr);
}
# Check for user-visible strings broken across lines, which breaks the ability
@ -5145,6 +5231,18 @@ sub process {
"break quoted strings at a space character\n" . $hereprev);
}
# check for an embedded function name in a string when the function is known
# This does not work very well for -f --file checking as it depends on patch
# context providing the function name or a single line form for in-file
# function declarations
if ($line =~ /^\+.*$String/ &&
defined($context_function) &&
get_quoted_string($line, $rawline) =~ /\b$context_function\b/ &&
length(get_quoted_string($line, $rawline)) != (length($context_function) + 2)) {
WARN("EMBEDDED_FUNCTION_NAME",
"Prefer using '\"%s...\", __func__' to using '$context_function', this function's name, in a string\n" . $herecurr);
}
# check for spaces before a quoted newline
if ($rawline =~ /^.*\".*\s\\n/) {
if (WARN("QUOTED_WHITESPACE_BEFORE_NEWLINE",
@ -5167,18 +5265,27 @@ sub process {
"Consecutive strings are generally better as a single string\n" . $herecurr);
}
# check for %L{u,d,i} and 0x%[udi] in strings
my $string;
# check for non-standard and hex prefixed decimal printf formats
my $show_L = 1; #don't show the same defect twice
my $show_Z = 1;
while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) {
$string = substr($rawline, $-[1], $+[1] - $-[1]);
my $string = substr($rawline, $-[1], $+[1] - $-[1]);
$string =~ s/%%/__/g;
if ($string =~ /(?<!%)%[\*\d\.\$]*L[udi]/) {
# check for %L
if ($show_L && $string =~ /%[\*\d\.\$]*L([diouxX])/) {
WARN("PRINTF_L",
"\%Ld/%Lu are not-standard C, use %lld/%llu\n" . $herecurr);
last;
"\%L$1 is non-standard C, use %ll$1\n" . $herecurr);
$show_L = 0;
}
if ($string =~ /0x%[\*\d\.\$\Llzth]*[udi]/) {
ERROR("PRINTF_0xDECIMAL",
# check for %Z
if ($show_Z && $string =~ /%[\*\d\.\$]*Z([diouxX])/) {
WARN("PRINTF_Z",
"%Z$1 is non-standard C, use %z$1\n" . $herecurr);
$show_Z = 0;
}
# check for 0x<decimal>
if ($string =~ /0x%[\*\d\.\$\Llzth]*[diou]/) {
ERROR("PRINTF_0XDECIMAL",
"Prefixing 0x with decimal output is defective\n" . $herecurr);
}
}
@ -5240,7 +5347,7 @@ sub process {
my ($s, $c) = ctx_statement_block($linenr - 3, $realcnt, 0);
# print("line: <$line>\nprevline: <$prevline>\ns: <$s>\nc: <$c>\n\n\n");
if ($c =~ /(?:^|\n)[ \+]\s*(?:$Type\s*)?\Q$testval\E\s*=\s*(?:\([^\)]*\)\s*)?\s*(?:devm_)?(?:[kv][czm]alloc(?:_node|_array)?\b|kstrdup|(?:dev_)?alloc_skb)/) {
if ($s =~ /(?:^|\n)[ \+]\s*(?:$Type\s*)?\Q$testval\E\s*=\s*(?:\([^\)]*\)\s*)?\s*(?:devm_)?(?:[kv][czm]alloc(?:_node|_array)?\b|kstrdup|kmemdup|(?:dev_)?alloc_skb)/) {
WARN("OOM_MESSAGE",
"Possible unnecessary 'out of memory' message\n" . $hereprev);
}
@ -5257,6 +5364,12 @@ sub process {
}
}
# check for logging continuations
if ($line =~ /\bprintk\s*\(\s*KERN_CONT\b|\bpr_cont\s*\(/) {
WARN("LOGGING_CONTINUATION",
"Avoid logging continuation uses where feasible\n" . $herecurr);
}
# check for mask then right shift without a parentheses
if ($^V && $^V ge 5.10.0 &&
$line =~ /$LvalOrFunc\s*\&\s*($LvalOrFunc)\s*>>/ &&
@ -5457,33 +5570,24 @@ sub process {
}
}
# Check for expedited grace periods that interrupt non-idle non-nohz
# online CPUs. These expedited can therefore degrade real-time response
# if used carelessly, and should be avoided where not absolutely
# needed. It is always OK to use synchronize_rcu_expedited() and
# synchronize_sched_expedited() at boot time (before real-time applications
# start) and in error situations where real-time response is compromised in
# any case. Note that synchronize_srcu_expedited() does -not- interrupt
# other CPUs, so don't warn on uses of synchronize_srcu_expedited().
# Of course, nothing comes for free, and srcu_read_lock() and
# srcu_read_unlock() do contain full memory barriers in payment for
# synchronize_srcu_expedited() non-interruption properties.
if ($line =~ /\b(synchronize_rcu_expedited|synchronize_sched_expedited)\(/) {
WARN("EXPEDITED_RCU_GRACE_PERIOD",
"expedited RCU grace periods should be avoided where they can degrade real-time response\n" . $herecurr);
}
# check of hardware specific defines
if ($line =~ m@^.\s*\#\s*if.*\b(__i386__|__powerpc64__|__sun__|__s390x__)\b@ && $realfile !~ m@include/asm-@) {
CHK("ARCH_DEFINES",
"architecture specific defines should be avoided\n" . $herecurr);
}
# Check that the storage class is at the beginning of a declaration
if ($line =~ /\b$Storage\b/ && $line !~ /^.\s*$Storage\b/) {
# check that the storage class is not after a type
if ($line =~ /\b($Type)\s+($Storage)\b/) {
WARN("STORAGE_CLASS",
"storage class should be at the beginning of the declaration\n" . $herecurr)
"storage class '$2' should be located before type '$1'\n" . $herecurr);
}
# Check that the storage class is at the beginning of a declaration
if ($line =~ /\b$Storage\b/ &&
$line !~ /^.\s*$Storage/ &&
$line =~ /^.\s*(.+?)\$Storage\s/ &&
$1 !~ /[\,\)]\s*$/) {
WARN("STORAGE_CLASS",
"storage class should be at the beginning of the declaration\n" . $herecurr);
}
# check the location of the inline attribute, that it is between
@ -5549,8 +5653,9 @@ sub process {
"Using weak declarations can have unintended link defects\n" . $herecurr);
}
# check for c99 types like uint8_t used outside of uapi/
# check for c99 types like uint8_t used outside of uapi/ and tools/
if ($realfile !~ m@\binclude/uapi/@ &&
$realfile !~ m@\btools/@ &&
$line =~ /\b($Declare)\s*$Ident\s*[=;,\[]/) {
my $type = $1;
if ($type =~ /\b($typeC99Typedefs)\b/) {
@ -5621,6 +5726,32 @@ sub process {
}
}
# check for vsprintf extension %p<foo> misuses
if ($^V && $^V ge 5.10.0 &&
defined $stat &&
$stat =~ /^\+(?![^\{]*\{\s*).*\b(\w+)\s*\(.*$String\s*,/s &&
$1 !~ /^_*volatile_*$/) {
my $bad_extension = "";
my $lc = $stat =~ tr@\n@@;
$lc = $lc + $linenr;
for (my $count = $linenr; $count <= $lc; $count++) {
my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0));
$fmt =~ s/%%//g;
if ($fmt =~ /(\%[\*\d\.]*p(?![\WFfSsBKRraEhMmIiUDdgVCbGNO]).)/) {
$bad_extension = $1;
last;
}
}
if ($bad_extension ne "") {
my $stat_real = raw_line($linenr, 0);
for (my $count = $linenr + 1; $count <= $lc; $count++) {
$stat_real = $stat_real . "\n" . raw_line($count, 0);
}
WARN("VSPRINTF_POINTER_EXTENSION",
"Invalid vsprintf pointer extension '$bad_extension'\n" . "$here\n$stat_real\n");
}
}
# Check for misused memsets
if ($^V && $^V ge 5.10.0 &&
defined $stat &&
@ -5799,7 +5930,8 @@ sub process {
"externs should be avoided in .c files\n" . $herecurr);
}
if ($realfile =~ /\.[ch]$/ && defined $stat &&
# check for function declarations that have arguments without identifier names
if (defined $stat &&
$stat =~ /^.\s*(?:extern\s+)?$Type\s*$Ident\s*\(\s*([^{]+)\s*\)\s*;/s &&
$1 ne "void") {
my $args = trim($1);
@ -5812,13 +5944,36 @@ sub process {
}
}
# check for function definitions
if ($^V && $^V ge 5.10.0 &&
defined $stat &&
$stat =~ /^.\s*(?:$Storage\s+)?$Type\s*($Ident)\s*$balanced_parens\s*{/s) {
$context_function = $1;
# check for multiline function definition with misplaced open brace
my $ok = 0;
my $cnt = statement_rawlines($stat);
my $herectx = $here . "\n";
for (my $n = 0; $n < $cnt; $n++) {
my $rl = raw_line($linenr, $n);
$herectx .= $rl . "\n";
$ok = 1 if ($rl =~ /^[ \+]\{/);
$ok = 1 if ($rl =~ /\{/ && $n == 0);
last if $rl =~ /^[ \+].*\{/;
}
if (!$ok) {
ERROR("OPEN_BRACE",
"open brace '{' following function definitions go on the next line\n" . $herectx);
}
}
# checks for new __setup's
if ($rawline =~ /\b__setup\("([^"]*)"/) {
my $name = $1;
if (!grep(/$name/, @setup_docs)) {
CHK("UNDOCUMENTED_SETUP",
"__setup appears un-documented -- check Documentation/kernel-parameters.txt\n" . $herecurr);
"__setup appears un-documented -- check Documentation/admin-guide/kernel-parameters.rst\n" . $herecurr);
}
}
@ -5838,7 +5993,8 @@ sub process {
# check for k[mz]alloc with multiplies that could be kmalloc_array/kcalloc
if ($^V && $^V ge 5.10.0 &&
$line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)\s*,/) {
defined $stat &&
$stat =~ /^\+\s*($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)\s*,/) {
my $oldfunc = $3;
my $a1 = $4;
my $a2 = $10;
@ -5852,11 +6008,17 @@ sub process {
}
if ($r1 !~ /^sizeof\b/ && $r2 =~ /^sizeof\s*\S/ &&
!($r1 =~ /^$Constant$/ || $r1 =~ /^[A-Z_][A-Z0-9_]*$/)) {
my $ctx = '';
my $herectx = $here . "\n";
my $cnt = statement_rawlines($stat);
for (my $n = 0; $n < $cnt; $n++) {
$herectx .= raw_line($linenr, $n) . "\n";
}
if (WARN("ALLOC_WITH_MULTIPLY",
"Prefer $newfunc over $oldfunc with multiply\n" . $herecurr) &&
"Prefer $newfunc over $oldfunc with multiply\n" . $herectx) &&
$cnt == 1 &&
$fix) {
$fixed[$fixlinenr] =~ s/\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)/$1 . ' = ' . "$newfunc(" . trim($r1) . ', ' . trim($r2)/e;
}
}
}
@ -5926,7 +6088,7 @@ sub process {
}
if (!$has_break && $has_statement) {
WARN("MISSING_BREAK",
"Possible switch case/default not preceeded by break or fallthrough comment\n" . $herecurr);
"Possible switch case/default not preceded by break or fallthrough comment\n" . $herecurr);
}
}
@ -6011,11 +6173,11 @@ sub process {
}
# check for various structs that are normally const (ops, kgdb, device_tree)
# and avoid what seem like struct definitions 'struct foo {'
if ($line !~ /\bconst\b/ &&
$line =~ /\bstruct\s+($const_structs)\b/) {
$line =~ /\bstruct\s+($const_structs)\b(?!\s*\{)/) {
WARN("CONST_STRUCT",
"struct $1 should normally be const\n" .
$herecurr);
"struct $1 should normally be const\n" . $herecurr);
}
# use of NR_CPUS is usually wrong
@ -6077,6 +6239,12 @@ sub process {
}
}
# check for mutex_trylock_recursive usage
if ($line =~ /mutex_trylock_recursive/) {
ERROR("LOCKING",
"recursive locking is bad, do not use this ever.\n" . $herecurr);
}
# check for lockdep_set_novalidate_class
if ($line =~ /^.\s*lockdep_set_novalidate_class\s*\(/ ||
$line =~ /__lockdep_no_validate__\s*\)/ ) {

255
scripts/crypto/ELF.py Normal file
View file

@ -0,0 +1,255 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Module ELF contains ELF, Symbol, Section classes for manipulation over ELF files.
It can parse, and change ELF file. This version works only with vmlinux and doesn't properly work with ELF that contains
UND symbols
"""
import subprocess
import re
import os
from Utils import Utils
from collections import OrderedDict
__author__ = "Vadym Stupakov"
__copyright__ = "Copyright (c) 2017 Samsung Electronics"
__credits__ = ["Vadym Stupakov"]
__version__ = "1.0"
__maintainer__ = "Vadym Stupakov"
__email__ = "v.stupakov@samsung.com"
__status__ = "Production"
class Symbol:
def __init__(self, name=str(), sym_type=str(), bind=str(), visibility=str(), addr=int(), size=int(), ndx=str()):
self.utils = Utils()
self.name = str(name)
self.type = str(sym_type)
self.bind = str(bind)
self.ndx = str(ndx)
self.visibility = str(visibility)
self.addr = self.utils.to_int(addr)
self.size = self.utils.to_int(size)
def __str__(self):
return "name: '{}', type: '{}', bind: '{}', ndx: '{}', visibility: '{}', address: '{}', size: '{}'".format(
self.name, self.type, self.bind, self.ndx, self.visibility, hex(self.addr), hex(self.size)
)
def __lt__(self, other):
return self.addr <= other.addr
class Section:
def __init__(self, name=str(), sec_type=str(), addr=int(), offset=int(), size=int()):
self.utils = Utils()
self.name = str(name)
self.type = str(sec_type)
self.addr = self.utils.to_int(addr)
self.offset = self.utils.to_int(offset)
self.size = self.utils.to_int(size)
def __str__(self):
return "name: '{}', type: '{}', address: '{}', offset: '{}', size: '{}'".format(
self.name, self.type, hex(self.addr), hex(self.offset), hex(self.size)
)
def __lt__(self, other):
return self.addr <= other.addr
class ELF:
"""
Utils for manipulating over ELF
"""
def __init__(self, elf_file, readelf_path="readelf"):
self.__elf_file = elf_file
self.utils = Utils()
self.__readelf_path = readelf_path
self.__sections = OrderedDict()
self.__symbols = OrderedDict()
self.__relocs = list()
self.__re_hexdecimal = "\s*[0-9A-Fa-f]+\s*"
self.__re_sec_name = "\s*[._a-zA-Z]+\s*"
self.__re_type = "\s*[A-Z]+\s*"
def __readelf_raw(self, options):
"""
Execute readelf with options and print raw output
:param options readelf options: ["opt1", "opt2", "opt3", ..., "optN"]
:returns raw output
"""
ret = subprocess.Popen(args=[self.__readelf_path] + options,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout, stderr = ret.communicate()
if "readelf: Error: the PHDR segment is not covered by a LOAD segment" in stderr.decode("utf-8").strip():
ret.returncode = 0
if ret.returncode != 0:
raise ChildProcessError(stderr.decode("utf-8") + stdout.decode("utf-8"))
return stdout.decode("utf-8")
def set_elf_file(self, elf_file):
if os.path.abspath(self.__elf_file) != os.path.abspath(elf_file):
self.__elf_file = os.path.abspath(elf_file)
self.__sections.clear()
self.__symbols.clear()
self.__relocs.clear()
def get_elf_file(self):
return os.path.abspath(self.__elf_file)
def get_sections(self):
""""
Execute -> parse -> transform to dict() readelf output
:returns dict: {sec_addr : Section()}
"""
if len(self.__sections) == 0:
sec_header = self.__readelf_raw(["-SW", self.__elf_file]).strip()
secs = re.compile("^.*\[.*\](" + self.__re_sec_name + self.__re_type + self.__re_hexdecimal +
self.__re_hexdecimal + self.__re_hexdecimal + ")", re.MULTILINE)
found = secs.findall(sec_header)
for line in found:
line = line.split()
if len(line) == 5:
self.__sections[int(line[2], 16)] = Section(name=line[0], sec_type=line[1], addr=int(line[2], 16),
offset=int(line[3], 16), size=int(line[4], 16))
self.__sections = OrderedDict(sorted(self.__sections.items()))
return self.__sections
def get_symbols(self):
""""
Execute -> parse -> transform to dict() readelf output
:returns dict: {sym_addr : Symbol()}
"""
if len(self.__symbols) == 0:
sym_tab = self.__readelf_raw(["-sW", self.__elf_file])
syms = re.compile(r"^.*\d+:\s(.*$)", re.MULTILINE)
found = syms.findall(sym_tab.strip())
for line in found:
line = line.split()
if len(line) == 7:
size = line[1]
# This needs, because readelf prints sizes in hex if size is large
if size[:2].upper() == "0X":
size = int(size, 16)
else:
size = int(size, 10)
self.__symbols[int(line[0], 16)] = Symbol(addr=int(line[0], 16), size=size, sym_type=line[2],
bind=line[3], visibility=line[4], ndx=line[5],
name=line[6])
self.__symbols = OrderedDict(sorted(self.__symbols.items()))
return self.__symbols
def get_relocs(self, start_addr=None, end_addr=None):
""""
:param start_addr: start address :int
:param end_addr: end address: int
:returns list: [reloc1, reloc2, reloc3, ..., relocN]
"""
if len(self.__relocs) == 0:
relocs = self.__readelf_raw(["-rW", self.__elf_file])
rel = re.compile(r"^(" + self.__re_hexdecimal + ")\s*", re.MULTILINE)
self.__relocs = [self.utils.to_int(el) for el in rel.findall(relocs.strip())]
if start_addr and end_addr is not None:
ranged_rela = list()
for el in self.__relocs:
if self.utils.to_int(start_addr) <= self.utils.to_int(el) <= self.utils.to_int(end_addr):
ranged_rela.append(el)
return ranged_rela
return self.__relocs
def get_symbol_by_name(self, sym_names):
"""
Get symbol by_name
:param sym_names: "sym_name" : str or list
:return: Symbol() or [Symbol()]
"""
if isinstance(sym_names, str):
for addr, symbol_obj in self.get_symbols().items():
if symbol_obj.name == sym_names:
return symbol_obj
elif isinstance(sym_names, list):
symbols = [self.get_symbol_by_name(sym_name) for sym_name in sym_names]
return symbols
else:
raise ValueError
return None
def get_symbol_by_vaddr(self, vaddrs=None):
"""
Get symbol by virtual address
:param vaddrs: vaddr : int or list
:return: Symbol() or [Symbol()]
"""
if isinstance(vaddrs, int):
if vaddrs in self.get_symbols():
return self.get_symbols()[vaddrs]
for addr, symbol_obj in self.get_symbols().items():
if (addr + symbol_obj.size) >= vaddrs >= addr:
return symbol_obj
elif isinstance(vaddrs, list):
symbol = [self.get_symbol_by_vaddr(vaddr) for vaddr in vaddrs]
return symbol
else:
raise ValueError
return None
def get_section_by_name(self, sec_names=None):
"""
Get section by_name
:param sec_names: "sec_name" : str or list
:return: Section() or [Section()]
"""
if isinstance(sec_names, str):
for addr, section_obj in self.get_sections().items():
if section_obj.name == sec_names:
return section_obj
elif isinstance(sec_names, list):
sections = [self.get_section_by_name(sec_name) for sec_name in sec_names]
return sections
else:
raise ValueError
return None
def get_section_by_vaddr(self, vaddrs=None):
"""
Get section by virtual address
:param vaddrs: vaddr : int or list
:return: Section() or [Section()]
"""
if isinstance(vaddrs, int):
if vaddrs in self.get_sections():
return self.get_sections()[vaddrs]
for addr, section_obj in self.get_sections().items():
if (addr + section_obj.size) >= vaddrs >= addr:
return section_obj
elif isinstance(vaddrs, list):
sections = [self.get_symbol_by_vaddr(vaddr) for vaddr in vaddrs]
return sections
else:
raise ValueError
return None
def vaddr_to_file_offset(self, vaddrs):
"""
Transform virtual address to file offset
:param vaddrs: addr string or int or list
:returns file offset or list
"""
if isinstance(vaddrs, str) or isinstance(vaddrs, int):
section = self.get_section_by_vaddr(vaddrs)
return self.utils.to_int(vaddrs, 16) - section.addr + section.offset
elif isinstance(vaddrs, list):
return [self.vaddr_to_file_offset(vaddr) for vaddr in vaddrs]
else:
raise ValueError
def read_data_from_vaddr(self, vaddr, size, out_file):
with open(self.__elf_file, "rb") as elf_fp:
elf_fp.seek(self.vaddr_to_file_offset(vaddr))
with open(out_file, "wb") as out_fp:
out_fp.write(elf_fp.read(size))

View file

@ -0,0 +1,305 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Module IntegrityRoutine Contains IntegrityRoutine class helps with FIPS 140-2 build time integrity routine.
This module is needed to calculate HMAC and embed other needed stuff.
"""
import hmac
import hashlib
import bisect
import itertools
import binascii
from ELF import *
__author__ = "Vadym Stupakov"
__copyright__ = "Copyright (c) 2017 Samsung Electronics"
__credits__ = ["Vadym Stupakov"]
__version__ = "1.0"
__maintainer__ = "Vadym Stupakov"
__email__ = "v.stupakov@samsung.com"
__status__ = "Production"
class IntegrityRoutine(ELF):
"""
Utils for fips-integrity process
"""
def __init__(self, elf_file, readelf_path="readelf"):
ELF.__init__(self, elf_file, readelf_path)
@staticmethod
def __remove_all_dublicates(lst):
"""
Removes all occurrences of tha same value. For instance: transforms [1, 2, 3, 1] -> [2, 3]
:param lst: input list
:return: lst w/o duplicates
"""
to_remove = list()
for i in range(len(lst)):
it = itertools.islice(lst, i + 1, len(lst) - 1, None)
for j, val in enumerate(it, start=i+1):
if val == lst[i]:
to_remove.extend([lst[i], lst[j]])
for el in to_remove:
lst.remove(el)
def get_reloc_gaps(self, start_addr, end_addr):
"""
:param start_addr: start address :int
:param end_addr: end address: int
:returns list of relocation gaps like [[gap_start, gap_end], [gap_start, gap_end], ...]
"""
all_relocs = self.get_relocs(start_addr, end_addr)
relocs_gaps = list()
for addr in all_relocs:
relocs_gaps.append(addr)
relocs_gaps.append(addr + 8)
self.__remove_all_dublicates(relocs_gaps)
relocs_gaps.sort()
relocs_gaps = [[addr1, addr2] for addr1, addr2 in self.utils.pairwise(relocs_gaps)]
return relocs_gaps
def get_addrs_for_hmac(self, sec_sym_sequence, relocs_gaps=None):
"""
Generate addresses for calculating HMAC
:param sec_sym_sequence: [addr_start1, addr_end1, ..., addr_startN, addr_endN],
:param relocs_gaps: [[start_gap_addr, end_gap_addr], [start_gap_addr, end_gap_addr]]
:return: addresses for calculating HMAC: [[addr_start, addr_end], [addr_start, addr_end], ...]
"""
addrs_for_hmac = list()
for section_name, sym_names in sec_sym_sequence.items():
if relocs_gaps is not None and section_name == ".rodata":
for symbol in self.get_symbol_by_name(sym_names):
addrs_for_hmac.append(symbol.addr)
else:
for symbol in self.get_symbol_by_name(sym_names):
addrs_for_hmac.append(symbol.addr)
addrs_for_hmac.extend(self.utils.flatten(relocs_gaps))
addrs_for_hmac.sort()
return [[item1, item2] for item1, item2 in self.utils.pairwise(addrs_for_hmac)]
def embed_bytes(self, vaddr, in_bytes):
"""
Write bytes to ELF file
:param vaddr: virtual address in ELF
:param in_bytes: byte array to write
"""
offset = self.vaddr_to_file_offset(vaddr)
with open(self.get_elf_file(), "rb+") as elf_file:
elf_file.seek(offset)
elf_file.write(in_bytes)
def __update_hmac(self, hmac_obj, file_obj, file_offset_start, file_offset_end):
"""
Update hmac from addrstart tp addr_end
FIXMI: it needs to implement this function via fixed block size
:param file_offset_start: could be string or int
:param file_offset_end: could be string or int
"""
file_offset_start = self.utils.to_int(file_offset_start)
file_offset_end = self.utils.to_int(file_offset_end)
file_obj.seek(self.vaddr_to_file_offset(file_offset_start))
block_size = file_offset_end - file_offset_start
msg = file_obj.read(block_size)
hmac_obj.update(msg)
def get_hmac(self, offset_sequence, key, output_type="byte"):
"""
Calculate HMAC
:param offset_sequence: start and end addresses sequence [addr_start, addr_end], [addr_start, addr_end], ...]
:param key HMAC key: string value
:param output_type string value. Could be "hex" or "byte"
:return: bytearray or hex string
"""
digest = hmac.new(bytearray(key.encode("utf-8")), digestmod=hashlib.sha256)
with open(self.get_elf_file(), "rb") as file:
for addr_start, addr_end in offset_sequence:
self.__update_hmac(digest, file, addr_start, addr_end)
if output_type == "byte":
return digest.digest()
if output_type == "hex":
return digest.hexdigest()
def __find_nearest_symbol_by_vaddr(self, vaddr, method):
"""
Find nearest symbol near vaddr
:param vaddr:
:return: idx of symbol from self.get_symbols()
"""
symbol = self.get_symbol_by_vaddr(vaddr)
if symbol is None:
raise ValueError("Can't find symbol by vaddr")
idx = method(list(self.get_symbols()), vaddr)
return idx
def find_rnearest_symbol_by_vaddr(self, vaddr):
"""
Find right nearest symbol near vaddr
:param vaddr:
:return: idx of symbol from self.get_symbols()
"""
return self.__find_nearest_symbol_by_vaddr(vaddr, bisect.bisect_right)
def find_lnearest_symbol_by_vaddr(self, vaddr):
"""
Find left nearest symbol near vaddr
:param vaddr:
:return: idx of symbol from self.get_symbols()
"""
return self.__find_nearest_symbol_by_vaddr(vaddr, bisect.bisect_left)
def find_symbols_between_vaddrs(self, vaddr_start, vaddr_end):
"""
Returns list of symbols between two virtual addresses
:param vaddr_start:
:param vaddr_end:
:return: [(Symbol(), Section)]
"""
symbol_start = self.get_symbol_by_vaddr(vaddr_start)
symbol_end = self.get_symbol_by_vaddr(vaddr_end)
if symbol_start is None or symbol_end is None:
raise ValueError("Error: Cannot find symbol by vaddr. vaddr should coincide with symbol address!")
idx_start = self.find_lnearest_symbol_by_vaddr(vaddr_start)
idx_end = self.find_lnearest_symbol_by_vaddr(vaddr_end)
sym_sec = list()
for idx in range(idx_start, idx_end):
symbol_addr = list(self.get_symbols())[idx]
symbol = self.get_symbol_by_vaddr(symbol_addr)
section = self.get_section_by_vaddr(symbol_addr)
sym_sec.append((symbol, section))
sym_sec.sort(key=lambda x: x[0])
return sym_sec
@staticmethod
def __get_skipped_bytes(symbol, relocs):
"""
:param symbol: Symbol()
:param relocs: [[start1, end1], [start2, end2]]
:return: Returns skipped bytes and [[start, end]] addresses that show which bytes were skipped
"""
symbol_start_addr = symbol.addr
symbol_end_addr = symbol.addr + symbol.size
skipped_bytes = 0
reloc_addrs = list()
for reloc_start, reloc_end in relocs:
if reloc_start >= symbol_start_addr and reloc_end <= symbol_end_addr:
skipped_bytes += reloc_end - reloc_start
reloc_addrs.append([reloc_start, reloc_end])
if reloc_start > symbol_end_addr:
break
return skipped_bytes, reloc_addrs
def print_covered_info(self, sec_sym, relocs, print_reloc_addrs=False, sort_by="address", reverse=False):
"""
Prints information about covered symbols in detailed table:
|N| symbol name | symbol address | symbol section | bytes skipped | skipped bytes address range |
|1| symbol | 0xXXXXXXXXXXXXXXXX | .rodata | 8 | [[addr1, addr2], [addr1, addr2]] |
:param sec_sym: {section_name : [sym_name1, sym_name2]}
:param relocs: [[start1, end1], [start2, end2]]
:param print_reloc_addrs: print or not skipped bytes address range
:param sort_by: method for sorting table. Could be: "address", "name", "section"
:param reverse: sort order
"""
if sort_by.lower() == "address":
def sort_method(x): return x[0].addr
elif sort_by.lower() == "name":
def sort_method(x): return x[0].name
elif sort_by.lower() == "section":
def sort_method(x): return x[1].name
else:
raise ValueError("Invalid sort type!")
table_format = "|{:4}| {:50} | {:18} | {:20} | {:15} |"
if print_reloc_addrs is True:
table_format += "{:32} |"
print(table_format.format("N", "symbol name", "symbol address", "symbol section", "bytes skipped",
"skipped bytes address range"))
data_to_print = list()
for sec_name, sym_names in sec_sym.items():
for symbol_start, symbol_end in self.utils.pairwise(self.get_symbol_by_name(sym_names)):
symbol_sec_in_range = self.find_symbols_between_vaddrs(symbol_start.addr, symbol_end.addr)
for symbol, section in symbol_sec_in_range:
skipped_bytes, reloc_addrs = self.__get_skipped_bytes(symbol, relocs)
reloc_addrs_str = "["
for start_addr, end_addr in reloc_addrs:
reloc_addrs_str += "[{}, {}], ".format(hex(start_addr), hex(end_addr))
reloc_addrs_str += "]"
if symbol.size > 0:
data_to_print.append((symbol, section, skipped_bytes, reloc_addrs_str))
skipped_bytes_size = 0
symbol_covered_size = 0
cnt = 0
data_to_print.sort(key=sort_method, reverse=reverse)
for symbol, section, skipped_bytes, reloc_addrs_str in data_to_print:
cnt += 1
symbol_covered_size += symbol.size
skipped_bytes_size += skipped_bytes
if print_reloc_addrs is True:
print(table_format.format(cnt, symbol.name, hex(symbol.addr), section.name,
self.utils.human_size(skipped_bytes), reloc_addrs_str))
else:
print(table_format.format(cnt, symbol.name, hex(symbol.addr), section.name,
self.utils.human_size(skipped_bytes)))
addrs_for_hmac = self.get_addrs_for_hmac(sec_sym, relocs)
all_covered_size = 0
for addr_start, addr_end in addrs_for_hmac:
all_covered_size += addr_end - addr_start
print("Symbol covered bytes len: {} ".format(self.utils.human_size(symbol_covered_size - skipped_bytes_size)))
print("All covered bytes len : {} ".format(self.utils.human_size(all_covered_size)))
print("Skipped bytes len : {} ".format(self.utils.human_size(skipped_bytes_size)))
def dump_covered_bytes(self, vaddr_seq, out_file):
"""
Dumps covered bytes
:param vaddr_seq: [[start1, end1], [start2, end2]] start - end sequence of covered bytes
:param out_file: file where will be stored dumped bytes
"""
with open(self.get_elf_file(), "rb") as elf_fp:
with open(out_file, "wb") as out_fp:
for vaddr_start, vaddr_end, in vaddr_seq:
elf_fp.seek(self.vaddr_to_file_offset(vaddr_start))
out_fp.write(elf_fp.read(vaddr_end - vaddr_start))
def make_integrity(self, sec_sym, module_name, debug=False, print_reloc_addrs=False, sort_by="address",
reverse=False):
"""
Calculate HMAC and embed needed info
:param sec_sym: {sec_name: [addr1, addr2, ..., addrN]}
:param module_name: module name that you want to make integrity. See Makefile targets
:param debug: If True prints debug information
:param print_reloc_addrs: If True, print relocation addresses that are skipped
:param sort_by: sort method
:param reverse: sort order
"""
rel_addr_start = self.get_symbol_by_name("first_" + module_name + "_rodata")
rel_addr_end = self.get_symbol_by_name("last_" + module_name + "_rodata")
reloc_gaps = self.get_reloc_gaps(rel_addr_start.addr, rel_addr_end.addr)
addrs_for_hmac = self.get_addrs_for_hmac(sec_sym, reloc_gaps)
digest = self.get_hmac(addrs_for_hmac, "The quick brown fox jumps over the lazy dog")
self.embed_bytes(self.get_symbol_by_name("builtime_" + module_name + "_hmac").addr,
self.utils.to_bytearray(digest))
self.embed_bytes(self.get_symbol_by_name("integrity_" + module_name + "_addrs").addr,
self.utils.to_bytearray(addrs_for_hmac))
self.embed_bytes(self.get_symbol_by_name(module_name + "_buildtime_address").addr,
self.utils.to_bytearray(self.get_symbol_by_name(module_name + "_buildtime_address").addr))
print("HMAC for \"{}\" module is: {}".format(module_name, binascii.hexlify(digest)))
if debug:
self.print_covered_info(sec_sym, reloc_gaps, print_reloc_addrs=print_reloc_addrs, sort_by=sort_by,
reverse=reverse)
self.dump_covered_bytes(addrs_for_hmac, "covered_dump_for_" + module_name + ".bin")
print("\nFIPS integrity procedure has been finished for {}\n".format(module_name))

100
scripts/crypto/Utils.py Normal file
View file

@ -0,0 +1,100 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Module Utils contains Utils class with general purpose helper functions.
"""
import struct
import os
from itertools import chain
__author__ = "Vadym Stupakov"
__copyright__ = "Copyright (c) 2017 Samsung Electronics"
__credits__ = ["Vadym Stupakov"]
__version__ = "1.0"
__maintainer__ = "Vadym Stupakov"
__email__ = "v.stupakov@samsung.com"
__status__ = "Production"
class Utils:
"""
Utils class with general purpose helper functions.
"""
@staticmethod
def flatten(alist):
"""
Make list from sub lists
:param alist: any list: [[item1, item2], [item3, item4], ..., [itemN, itemN+1]]
:return: [item1, item2, item3, item4, ..., itemN, itemN+1]
"""
if alist is []:
return []
elif type(alist) is not list:
return [alist]
else:
return [el for el in chain.from_iterable(alist)]
@staticmethod
def pairwise(iterable):
"""
Iter over two elements: [s0, s1, s2, s3, ..., sN] -> (s0, s1), (s2, s3), ..., (sN, sN+1)
:param iterable:
:return: (s0, s1), (s2, s3), ..., (sN, sN+1)
"""
a = iter(iterable)
return zip(a, a)
@staticmethod
def paths_exists(path_list):
"""
Check if path exist, otherwise raise FileNotFoundError exception
:param path_list: list of paths
"""
for path in path_list:
if not os.path.exists(path):
raise FileNotFoundError("File: \"" + path + "\" doesn't exist!\n")
@staticmethod
def to_int(value, base=16):
"""
Converts string to int
:param value: string or int
:param base: string base int
:return: integer value
"""
if isinstance(value, int):
return value
elif isinstance(value, str):
return int(value.strip(), base)
def to_bytearray(self, value):
"""
Converts list to bytearray with block size 8 byte
:param value: list of integers or bytearray or int
:return: bytes
"""
if isinstance(value, bytearray) or isinstance(value, bytes):
return value
elif isinstance(value, list):
value = self.flatten(value)
return struct.pack("%sQ" % len(value), *value)
elif isinstance(value, int):
return struct.pack("Q", value)
@staticmethod
def human_size(nbytes):
"""
Print in human readable
:param nbytes: number of bytes
:return: human readable string. For instance: 0x26a5d (154.6 K)
"""
raw = nbytes
suffixes = ("B", "K", "M")
i = 0
while nbytes >= 1024 and i < len(suffixes) - 1:
nbytes /= 1024.
i += 1
f = "{:.1f}".format(nbytes).rstrip("0").rstrip(".")
return "{} ({} {})".format(hex(raw), f, suffixes[i])

View file

@ -0,0 +1,48 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
This script is needed for buildtime integrity routine.
It calculates and embeds HMAC and other needed stuff for in terms of FIPS 140-2
"""
import os
import sys
from IntegrityRoutine import IntegrityRoutine
from Utils import Utils
__author__ = "Vadym Stupakov"
__copyright__ = "Copyright (c) 2017 Samsung Electronics"
__credits__ = ["Vadym Stupakov"]
__version__ = "1.0"
__maintainer__ = "Vadym Stupakov"
__email__ = "v.stupakov@samsung.com"
__status__ = "Production"
sec_sym = {".text": ["first_crypto_text", "last_crypto_text",
"first_crypto_asm_text", "last_crypto_asm_text"],
".rodata": ["first_crypto_rodata", "last_crypto_rodata",
"first_crypto_asm_rodata", "last_crypto_asm_rodata"],
"init.text": ["first_crypto_init", "last_crypto_init",
"first_crypto_asm_init", "last_crypto_asm_init"]
}
module_name = "crypto"
if __name__ == "__main__":
#print("python version:\n{}\n".format(sys.version))
if len(sys.argv) != 2:
print("Usage " + sys.argv[0] + " elf_file")
sys.exit(-1)
elf_file = os.path.abspath(sys.argv[1])
modules = sys.argv[2:]
utils = Utils()
utils.paths_exists([elf_file])
integrity = IntegrityRoutine(elf_file)
integrity.make_integrity(sec_sym=sec_sym, module_name=module_name, debug=False, print_reloc_addrs=False,
sort_by="address", reverse=False)

View file

@ -40,16 +40,11 @@ enum checkstatus {
struct check;
typedef void (*tree_check_fn)(struct check *c, struct node *dt);
typedef void (*node_check_fn)(struct check *c, struct node *dt, struct node *node);
typedef void (*prop_check_fn)(struct check *c, struct node *dt,
struct node *node, struct property *prop);
typedef void (*check_fn)(struct check *c, struct dt_info *dti, struct node *node);
struct check {
const char *name;
tree_check_fn tree_fn;
node_check_fn node_fn;
prop_check_fn prop_fn;
check_fn fn;
void *data;
bool warn, error;
enum checkstatus status;
@ -58,45 +53,24 @@ struct check {
struct check **prereq;
};
#define CHECK_ENTRY(nm, tfn, nfn, pfn, d, w, e, ...) \
static struct check *nm##_prereqs[] = { __VA_ARGS__ }; \
static struct check nm = { \
.name = #nm, \
.tree_fn = (tfn), \
.node_fn = (nfn), \
.prop_fn = (pfn), \
.data = (d), \
.warn = (w), \
.error = (e), \
#define CHECK_ENTRY(_nm, _fn, _d, _w, _e, ...) \
static struct check *_nm##_prereqs[] = { __VA_ARGS__ }; \
static struct check _nm = { \
.name = #_nm, \
.fn = (_fn), \
.data = (_d), \
.warn = (_w), \
.error = (_e), \
.status = UNCHECKED, \
.num_prereqs = ARRAY_SIZE(nm##_prereqs), \
.prereq = nm##_prereqs, \
.num_prereqs = ARRAY_SIZE(_nm##_prereqs), \
.prereq = _nm##_prereqs, \
};
#define WARNING(nm, tfn, nfn, pfn, d, ...) \
CHECK_ENTRY(nm, tfn, nfn, pfn, d, true, false, __VA_ARGS__)
#define ERROR(nm, tfn, nfn, pfn, d, ...) \
CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, true, __VA_ARGS__)
#define CHECK(nm, tfn, nfn, pfn, d, ...) \
CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, false, __VA_ARGS__)
#define TREE_WARNING(nm, d, ...) \
WARNING(nm, check_##nm, NULL, NULL, d, __VA_ARGS__)
#define TREE_ERROR(nm, d, ...) \
ERROR(nm, check_##nm, NULL, NULL, d, __VA_ARGS__)
#define TREE_CHECK(nm, d, ...) \
CHECK(nm, check_##nm, NULL, NULL, d, __VA_ARGS__)
#define NODE_WARNING(nm, d, ...) \
WARNING(nm, NULL, check_##nm, NULL, d, __VA_ARGS__)
#define NODE_ERROR(nm, d, ...) \
ERROR(nm, NULL, check_##nm, NULL, d, __VA_ARGS__)
#define NODE_CHECK(nm, d, ...) \
CHECK(nm, NULL, check_##nm, NULL, d, __VA_ARGS__)
#define PROP_WARNING(nm, d, ...) \
WARNING(nm, NULL, NULL, check_##nm, d, __VA_ARGS__)
#define PROP_ERROR(nm, d, ...) \
ERROR(nm, NULL, NULL, check_##nm, d, __VA_ARGS__)
#define PROP_CHECK(nm, d, ...) \
CHECK(nm, NULL, NULL, check_##nm, d, __VA_ARGS__)
#define WARNING(_nm, _fn, _d, ...) \
CHECK_ENTRY(_nm, _fn, _d, true, false, __VA_ARGS__)
#define ERROR(_nm, _fn, _d, ...) \
CHECK_ENTRY(_nm, _fn, _d, false, true, __VA_ARGS__)
#define CHECK(_nm, _fn, _d, ...) \
CHECK_ENTRY(_nm, _fn, _d, false, false, __VA_ARGS__)
#ifdef __GNUC__
static inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
@ -123,27 +97,21 @@ static inline void check_msg(struct check *c, const char *fmt, ...)
check_msg((c), __VA_ARGS__); \
} while (0)
static void check_nodes_props(struct check *c, struct node *dt, struct node *node)
static void check_nodes_props(struct check *c, struct dt_info *dti, struct node *node)
{
struct node *child;
struct property *prop;
TRACE(c, "%s", node->fullpath);
if (c->node_fn)
c->node_fn(c, dt, node);
if (c->prop_fn)
for_each_property(node, prop) {
TRACE(c, "%s\t'%s'", node->fullpath, prop->name);
c->prop_fn(c, dt, node, prop);
}
if (c->fn)
c->fn(c, dti, node);
for_each_child(node, child)
check_nodes_props(c, dt, child);
check_nodes_props(c, dti, child);
}
static bool run_check(struct check *c, struct node *dt)
static bool run_check(struct check *c, struct dt_info *dti)
{
struct node *dt = dti->dt;
bool error = false;
int i;
@ -156,7 +124,7 @@ static bool run_check(struct check *c, struct node *dt)
for (i = 0; i < c->num_prereqs; i++) {
struct check *prq = c->prereq[i];
error = error || run_check(prq, dt);
error = error || run_check(prq, dti);
if (prq->status != PASSED) {
c->status = PREREQ;
check_msg(c, "Failed prerequisite '%s'",
@ -167,11 +135,8 @@ static bool run_check(struct check *c, struct node *dt)
if (c->status != UNCHECKED)
goto out;
if (c->node_fn || c->prop_fn)
check_nodes_props(c, dt, dt);
check_nodes_props(c, dti, dt);
if (c->tree_fn)
c->tree_fn(c, dt);
if (c->status == UNCHECKED)
c->status = PASSED;
@ -189,13 +154,14 @@ out:
*/
/* A check which always fails, for testing purposes only */
static inline void check_always_fail(struct check *c, struct node *dt)
static inline void check_always_fail(struct check *c, struct dt_info *dti,
struct node *node)
{
FAIL(c, "always_fail check");
}
TREE_CHECK(always_fail, NULL);
CHECK(always_fail, check_always_fail, NULL);
static void check_is_string(struct check *c, struct node *root,
static void check_is_string(struct check *c, struct dt_info *dti,
struct node *node)
{
struct property *prop;
@ -210,11 +176,11 @@ static void check_is_string(struct check *c, struct node *root,
propname, node->fullpath);
}
#define WARNING_IF_NOT_STRING(nm, propname) \
WARNING(nm, NULL, check_is_string, NULL, (propname))
WARNING(nm, check_is_string, (propname))
#define ERROR_IF_NOT_STRING(nm, propname) \
ERROR(nm, NULL, check_is_string, NULL, (propname))
ERROR(nm, check_is_string, (propname))
static void check_is_cell(struct check *c, struct node *root,
static void check_is_cell(struct check *c, struct dt_info *dti,
struct node *node)
{
struct property *prop;
@ -229,15 +195,15 @@ static void check_is_cell(struct check *c, struct node *root,
propname, node->fullpath);
}
#define WARNING_IF_NOT_CELL(nm, propname) \
WARNING(nm, NULL, check_is_cell, NULL, (propname))
WARNING(nm, check_is_cell, (propname))
#define ERROR_IF_NOT_CELL(nm, propname) \
ERROR(nm, NULL, check_is_cell, NULL, (propname))
ERROR(nm, check_is_cell, (propname))
/*
* Structural check functions
*/
static void check_duplicate_node_names(struct check *c, struct node *dt,
static void check_duplicate_node_names(struct check *c, struct dt_info *dti,
struct node *node)
{
struct node *child, *child2;
@ -250,9 +216,9 @@ static void check_duplicate_node_names(struct check *c, struct node *dt,
FAIL(c, "Duplicate node name %s",
child->fullpath);
}
NODE_ERROR(duplicate_node_names, NULL);
ERROR(duplicate_node_names, check_duplicate_node_names, NULL);
static void check_duplicate_property_names(struct check *c, struct node *dt,
static void check_duplicate_property_names(struct check *c, struct dt_info *dti,
struct node *node)
{
struct property *prop, *prop2;
@ -267,14 +233,15 @@ static void check_duplicate_property_names(struct check *c, struct node *dt,
}
}
}
NODE_ERROR(duplicate_property_names, NULL);
ERROR(duplicate_property_names, check_duplicate_property_names, NULL);
#define LOWERCASE "abcdefghijklmnopqrstuvwxyz"
#define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define DIGITS "0123456789"
#define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-"
#define PROPNODECHARSSTRICT LOWERCASE UPPERCASE DIGITS ",-"
static void check_node_name_chars(struct check *c, struct node *dt,
static void check_node_name_chars(struct check *c, struct dt_info *dti,
struct node *node)
{
int n = strspn(node->name, c->data);
@ -283,19 +250,30 @@ static void check_node_name_chars(struct check *c, struct node *dt,
FAIL(c, "Bad character '%c' in node %s",
node->name[n], node->fullpath);
}
NODE_ERROR(node_name_chars, PROPNODECHARS "@");
ERROR(node_name_chars, check_node_name_chars, PROPNODECHARS "@");
static void check_node_name_format(struct check *c, struct node *dt,
static void check_node_name_chars_strict(struct check *c, struct dt_info *dti,
struct node *node)
{
int n = strspn(node->name, c->data);
if (n < node->basenamelen)
FAIL(c, "Character '%c' not recommended in node %s",
node->name[n], node->fullpath);
}
CHECK(node_name_chars_strict, check_node_name_chars_strict, PROPNODECHARSSTRICT);
static void check_node_name_format(struct check *c, struct dt_info *dti,
struct node *node)
{
if (strchr(get_unitname(node), '@'))
FAIL(c, "Node %s has multiple '@' characters in name",
node->fullpath);
}
NODE_ERROR(node_name_format, NULL, &node_name_chars);
ERROR(node_name_format, check_node_name_format, NULL, &node_name_chars);
static void check_unit_address_vs_reg(struct check *c, struct node *dt,
struct node *node)
static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti,
struct node *node)
{
const char *unitname = get_unitname(node);
struct property *prop = get_property(node, "reg");
@ -316,18 +294,54 @@ static void check_unit_address_vs_reg(struct check *c, struct node *dt,
node->fullpath);
}
}
NODE_WARNING(unit_address_vs_reg, NULL);
WARNING(unit_address_vs_reg, check_unit_address_vs_reg, NULL);
static void check_property_name_chars(struct check *c, struct node *dt,
struct node *node, struct property *prop)
static void check_property_name_chars(struct check *c, struct dt_info *dti,
struct node *node)
{
int n = strspn(prop->name, c->data);
struct property *prop;
if (n < strlen(prop->name))
FAIL(c, "Bad character '%c' in property name \"%s\", node %s",
prop->name[n], prop->name, node->fullpath);
for_each_property(node, prop) {
int n = strspn(prop->name, c->data);
if (n < strlen(prop->name))
FAIL(c, "Bad character '%c' in property name \"%s\", node %s",
prop->name[n], prop->name, node->fullpath);
}
}
PROP_ERROR(property_name_chars, PROPNODECHARS);
ERROR(property_name_chars, check_property_name_chars, PROPNODECHARS);
static void check_property_name_chars_strict(struct check *c,
struct dt_info *dti,
struct node *node)
{
struct property *prop;
for_each_property(node, prop) {
const char *name = prop->name;
int n = strspn(name, c->data);
if (n == strlen(prop->name))
continue;
/* Certain names are whitelisted */
if (streq(name, "device_type"))
continue;
/*
* # is only allowed at the beginning of property names not counting
* the vendor prefix.
*/
if (name[n] == '#' && ((n == 0) || (name[n-1] == ','))) {
name += n + 1;
n = strspn(name, c->data);
}
if (n < strlen(name))
FAIL(c, "Character '%c' not recommended in property name \"%s\", node %s",
name[n], prop->name, node->fullpath);
}
}
CHECK(property_name_chars_strict, check_property_name_chars_strict, PROPNODECHARSSTRICT);
#define DESCLABEL_FMT "%s%s%s%s%s"
#define DESCLABEL_ARGS(node,prop,mark) \
@ -336,10 +350,11 @@ PROP_ERROR(property_name_chars, PROPNODECHARS);
((prop) ? (prop)->name : ""), \
((prop) ? "' in " : ""), (node)->fullpath
static void check_duplicate_label(struct check *c, struct node *dt,
static void check_duplicate_label(struct check *c, struct dt_info *dti,
const char *label, struct node *node,
struct property *prop, struct marker *mark)
{
struct node *dt = dti->dt;
struct node *othernode = NULL;
struct property *otherprop = NULL;
struct marker *othermark = NULL;
@ -362,44 +377,43 @@ static void check_duplicate_label(struct check *c, struct node *dt,
DESCLABEL_ARGS(othernode, otherprop, othermark));
}
static void check_duplicate_label_node(struct check *c, struct node *dt,
static void check_duplicate_label_node(struct check *c, struct dt_info *dti,
struct node *node)
{
struct label *l;
struct property *prop;
for_each_label(node->labels, l)
check_duplicate_label(c, dt, l->label, node, NULL, NULL);
check_duplicate_label(c, dti, l->label, node, NULL, NULL);
for_each_property(node, prop) {
struct marker *m = prop->val.markers;
for_each_label(prop->labels, l)
check_duplicate_label(c, dti, l->label, node, prop, NULL);
for_each_marker_of_type(m, LABEL)
check_duplicate_label(c, dti, m->ref, node, prop, m);
}
}
static void check_duplicate_label_prop(struct check *c, struct node *dt,
struct node *node, struct property *prop)
{
struct marker *m = prop->val.markers;
struct label *l;
for_each_label(prop->labels, l)
check_duplicate_label(c, dt, l->label, node, prop, NULL);
for_each_marker_of_type(m, LABEL)
check_duplicate_label(c, dt, m->ref, node, prop, m);
}
ERROR(duplicate_label, NULL, check_duplicate_label_node,
check_duplicate_label_prop, NULL);
static void check_explicit_phandles(struct check *c, struct node *root,
struct node *node, struct property *prop)
ERROR(duplicate_label, check_duplicate_label_node, NULL);
static cell_t check_phandle_prop(struct check *c, struct dt_info *dti,
struct node *node, const char *propname)
{
struct node *root = dti->dt;
struct property *prop;
struct marker *m;
struct node *other;
cell_t phandle;
if (!streq(prop->name, "phandle")
&& !streq(prop->name, "linux,phandle"))
return;
prop = get_property(node, propname);
if (!prop)
return 0;
if (prop->val.len != sizeof(cell_t)) {
FAIL(c, "%s has bad length (%d) %s property",
node->fullpath, prop->val.len, prop->name);
return;
return 0;
}
m = prop->val.markers;
@ -411,14 +425,13 @@ static void check_explicit_phandles(struct check *c, struct node *root,
* by construction. */ {
FAIL(c, "%s in %s is a reference to another node",
prop->name, node->fullpath);
return;
}
/* But setting this node's phandle equal to its own
* phandle is allowed - that means allocate a unique
* phandle for this node, even if it's not otherwise
* referenced. The value will be filled in later, so
* no further checking for now. */
return;
* we treat it as having no phandle data for now. */
return 0;
}
phandle = propval_cell(prop);
@ -426,12 +439,36 @@ static void check_explicit_phandles(struct check *c, struct node *root,
if ((phandle == 0) || (phandle == -1)) {
FAIL(c, "%s has bad value (0x%x) in %s property",
node->fullpath, phandle, prop->name);
return;
return 0;
}
if (node->phandle && (node->phandle != phandle))
FAIL(c, "%s has %s property which replaces existing phandle information",
node->fullpath, prop->name);
return phandle;
}
static void check_explicit_phandles(struct check *c, struct dt_info *dti,
struct node *node)
{
struct node *root = dti->dt;
struct node *other;
cell_t phandle, linux_phandle;
/* Nothing should have assigned phandles yet */
assert(!node->phandle);
phandle = check_phandle_prop(c, dti, node, "phandle");
linux_phandle = check_phandle_prop(c, dti, node, "linux,phandle");
if (!phandle && !linux_phandle)
/* No valid phandles; nothing further to check */
return;
if (linux_phandle && phandle && (phandle != linux_phandle))
FAIL(c, "%s has mismatching 'phandle' and 'linux,phandle'"
" properties", node->fullpath);
if (linux_phandle && !phandle)
phandle = linux_phandle;
other = get_node_by_phandle(root, phandle);
if (other && (other != node)) {
@ -442,9 +479,9 @@ static void check_explicit_phandles(struct check *c, struct node *root,
node->phandle = phandle;
}
PROP_ERROR(explicit_phandles, NULL);
ERROR(explicit_phandles, check_explicit_phandles, NULL);
static void check_name_properties(struct check *c, struct node *root,
static void check_name_properties(struct check *c, struct dt_info *dti,
struct node *node)
{
struct property **pp, *prop = NULL;
@ -472,60 +509,73 @@ static void check_name_properties(struct check *c, struct node *root,
}
}
ERROR_IF_NOT_STRING(name_is_string, "name");
NODE_ERROR(name_properties, NULL, &name_is_string);
ERROR(name_properties, check_name_properties, NULL, &name_is_string);
/*
* Reference fixup functions
*/
static void fixup_phandle_references(struct check *c, struct node *dt,
struct node *node, struct property *prop)
static void fixup_phandle_references(struct check *c, struct dt_info *dti,
struct node *node)
{
struct marker *m = prop->val.markers;
struct node *refnode;
cell_t phandle;
struct node *dt = dti->dt;
struct property *prop;
for_each_marker_of_type(m, REF_PHANDLE) {
assert(m->offset + sizeof(cell_t) <= prop->val.len);
for_each_property(node, prop) {
struct marker *m = prop->val.markers;
struct node *refnode;
cell_t phandle;
refnode = get_node_by_ref(dt, m->ref);
if (! refnode) {
FAIL(c, "Reference to non-existent node or label \"%s\"\n",
m->ref);
continue;
for_each_marker_of_type(m, REF_PHANDLE) {
assert(m->offset + sizeof(cell_t) <= prop->val.len);
refnode = get_node_by_ref(dt, m->ref);
if (!refnode) {
if (!(dti->dtsflags & DTSF_PLUGIN))
FAIL(c, "Reference to non-existent node or "
"label \"%s\"\n", m->ref);
else /* mark the entry as unresolved */
*((cell_t *)(prop->val.val + m->offset)) =
cpu_to_fdt32(0xffffffff);
continue;
}
phandle = get_node_phandle(dt, refnode);
*((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
}
phandle = get_node_phandle(dt, refnode);
*((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
}
}
ERROR(phandle_references, NULL, NULL, fixup_phandle_references, NULL,
ERROR(phandle_references, fixup_phandle_references, NULL,
&duplicate_node_names, &explicit_phandles);
static void fixup_path_references(struct check *c, struct node *dt,
struct node *node, struct property *prop)
static void fixup_path_references(struct check *c, struct dt_info *dti,
struct node *node)
{
struct marker *m = prop->val.markers;
struct node *refnode;
char *path;
struct node *dt = dti->dt;
struct property *prop;
for_each_marker_of_type(m, REF_PATH) {
assert(m->offset <= prop->val.len);
for_each_property(node, prop) {
struct marker *m = prop->val.markers;
struct node *refnode;
char *path;
refnode = get_node_by_ref(dt, m->ref);
if (!refnode) {
FAIL(c, "Reference to non-existent node or label \"%s\"\n",
m->ref);
continue;
for_each_marker_of_type(m, REF_PATH) {
assert(m->offset <= prop->val.len);
refnode = get_node_by_ref(dt, m->ref);
if (!refnode) {
FAIL(c, "Reference to non-existent node or label \"%s\"\n",
m->ref);
continue;
}
path = refnode->fullpath;
prop->val = data_insert_at_marker(prop->val, m, path,
strlen(path) + 1);
}
path = refnode->fullpath;
prop->val = data_insert_at_marker(prop->val, m, path,
strlen(path) + 1);
}
}
ERROR(path_references, NULL, NULL, fixup_path_references, NULL,
&duplicate_node_names);
ERROR(path_references, fixup_path_references, NULL, &duplicate_node_names);
/*
* Semantic checks
@ -538,7 +588,7 @@ WARNING_IF_NOT_STRING(device_type_is_string, "device_type");
WARNING_IF_NOT_STRING(model_is_string, "model");
WARNING_IF_NOT_STRING(status_is_string, "status");
static void fixup_addr_size_cells(struct check *c, struct node *dt,
static void fixup_addr_size_cells(struct check *c, struct dt_info *dti,
struct node *node)
{
struct property *prop;
@ -554,7 +604,7 @@ static void fixup_addr_size_cells(struct check *c, struct node *dt,
if (prop)
node->size_cells = propval_cell(prop);
}
WARNING(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL,
WARNING(addr_size_cells, fixup_addr_size_cells, NULL,
&address_cells_is_cell, &size_cells_is_cell);
#define node_addr_cells(n) \
@ -562,7 +612,7 @@ WARNING(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL,
#define node_size_cells(n) \
(((n)->size_cells == -1) ? 1 : (n)->size_cells)
static void check_reg_format(struct check *c, struct node *dt,
static void check_reg_format(struct check *c, struct dt_info *dti,
struct node *node)
{
struct property *prop;
@ -589,9 +639,9 @@ static void check_reg_format(struct check *c, struct node *dt,
"(#address-cells == %d, #size-cells == %d)",
node->fullpath, prop->val.len, addr_cells, size_cells);
}
NODE_WARNING(reg_format, NULL, &addr_size_cells);
WARNING(reg_format, check_reg_format, NULL, &addr_size_cells);
static void check_ranges_format(struct check *c, struct node *dt,
static void check_ranges_format(struct check *c, struct dt_info *dti,
struct node *node)
{
struct property *prop;
@ -630,12 +680,12 @@ static void check_ranges_format(struct check *c, struct node *dt,
p_addr_cells, c_addr_cells, c_size_cells);
}
}
NODE_WARNING(ranges_format, NULL, &addr_size_cells);
WARNING(ranges_format, check_ranges_format, NULL, &addr_size_cells);
/*
* Style checks
*/
static void check_avoid_default_addr_size(struct check *c, struct node *dt,
static void check_avoid_default_addr_size(struct check *c, struct dt_info *dti,
struct node *node)
{
struct property *reg, *ranges;
@ -657,14 +707,21 @@ static void check_avoid_default_addr_size(struct check *c, struct node *dt,
FAIL(c, "Relying on default #size-cells value for %s",
node->fullpath);
}
NODE_WARNING(avoid_default_addr_size, NULL, &addr_size_cells);
WARNING(avoid_default_addr_size, check_avoid_default_addr_size, NULL,
&addr_size_cells);
static void check_obsolete_chosen_interrupt_controller(struct check *c,
struct node *dt)
struct dt_info *dti,
struct node *node)
{
struct node *dt = dti->dt;
struct node *chosen;
struct property *prop;
if (node != dt)
return;
chosen = get_node_by_path(dt, "/chosen");
if (!chosen)
return;
@ -674,7 +731,8 @@ static void check_obsolete_chosen_interrupt_controller(struct check *c,
FAIL(c, "/chosen has obsolete \"interrupt-controller\" "
"property");
}
TREE_WARNING(obsolete_chosen_interrupt_controller, NULL);
WARNING(obsolete_chosen_interrupt_controller,
check_obsolete_chosen_interrupt_controller, NULL);
static struct check *check_table[] = {
&duplicate_node_names, &duplicate_property_names,
@ -689,6 +747,9 @@ static struct check *check_table[] = {
&address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell,
&device_type_is_string, &model_is_string, &status_is_string,
&property_name_chars_strict,
&node_name_chars_strict,
&addr_size_cells, &reg_format, &ranges_format,
&unit_address_vs_reg,
@ -760,9 +821,8 @@ void parse_checks_option(bool warn, bool error, const char *arg)
die("Unrecognized check name \"%s\"\n", name);
}
void process_checks(bool force, struct boot_info *bi)
void process_checks(bool force, struct dt_info *dti)
{
struct node *dt = bi->dt;
int i;
int error = 0;
@ -770,7 +830,7 @@ void process_checks(bool force, struct boot_info *bi)
struct check *c = check_table[i];
if (c->warn || c->error)
error = error || run_check(c, dt);
error = error || run_check(c, dti);
}
if (error) {

View file

@ -121,6 +121,11 @@ static void lexical_error(const char *fmt, ...);
return DT_V1;
}
<*>"/plugin/" {
DPRINT("Keyword: /plugin/\n");
return DT_PLUGIN;
}
<*>"/memreserve/" {
DPRINT("Keyword: /memreserve/\n");
BEGIN_DEFAULT();
@ -184,16 +189,16 @@ static void lexical_error(const char *fmt, ...);
if (d.len == 1) {
lexical_error("Empty character literal");
yylval.integer = 0;
return DT_CHAR_LITERAL;
} else {
yylval.integer = (unsigned char)d.val[0];
if (d.len > 2)
lexical_error("Character literal has %d"
" characters instead of 1",
d.len - 1);
}
yylval.integer = (unsigned char)d.val[0];
if (d.len > 2)
lexical_error("Character literal has %d"
" characters instead of 1",
d.len - 1);
data_free(d);
return DT_CHAR_LITERAL;
}

View file

@ -8,8 +8,8 @@
#define FLEX_SCANNER
#define YY_FLEX_MAJOR_VERSION 2
#define YY_FLEX_MINOR_VERSION 5
#define YY_FLEX_SUBMINOR_VERSION 39
#define YY_FLEX_MINOR_VERSION 6
#define YY_FLEX_SUBMINOR_VERSION 0
#if YY_FLEX_SUBMINOR_VERSION > 0
#define FLEX_BETA
#endif
@ -211,7 +211,7 @@ struct yy_buffer_state
/* Number of characters read into yy_ch_buf, not including EOB
* characters.
*/
yy_size_t yy_n_chars;
int yy_n_chars;
/* Whether we "own" the buffer - i.e., we know we created it,
* and can realloc() it to grow it, and should free() it to
@ -281,7 +281,7 @@ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
/* yy_hold_char holds the character lost when yytext is formed. */
static char yy_hold_char;
static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */
static int yy_n_chars; /* number of characters read into yy_ch_buf */
yy_size_t yyleng;
/* Points to current character in buffer. */
@ -342,7 +342,7 @@ void yyfree (void * );
/* Begin user sect3 */
#define yywrap() 1
#define yywrap() (/*CONSTCOND*/1)
#define YY_SKIP_YYWRAP
typedef unsigned char YY_CHAR;
@ -356,11 +356,17 @@ extern int yylineno;
int yylineno = 1;
extern char *yytext;
#ifdef yytext_ptr
#undef yytext_ptr
#endif
#define yytext_ptr yytext
static yy_state_type yy_get_previous_state (void );
static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
static int yy_get_next_buffer (void );
#if defined(__GNUC__) && __GNUC__ >= 3
__attribute__((__noreturn__))
#endif
static void yy_fatal_error (yyconst char msg[] );
/* Done after the current pattern has been matched and before the
@ -373,8 +379,8 @@ static void yy_fatal_error (yyconst char msg[] );
*yy_cp = '\0'; \
(yy_c_buf_p) = yy_cp;
#define YY_NUM_RULES 30
#define YY_END_OF_BUFFER 31
#define YY_NUM_RULES 31
#define YY_END_OF_BUFFER 32
/* This struct is not used in this scanner,
but its presence is necessary. */
struct yy_trans_info
@ -382,28 +388,29 @@ struct yy_trans_info
flex_int32_t yy_verify;
flex_int32_t yy_nxt;
};
static yyconst flex_int16_t yy_accept[159] =
static yyconst flex_int16_t yy_accept[166] =
{ 0,
0, 0, 0, 0, 0, 0, 0, 0, 31, 29,
18, 18, 29, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 15, 16, 16, 29,
16, 10, 10, 18, 26, 0, 3, 0, 27, 12,
0, 0, 11, 0, 0, 0, 0, 0, 0, 0,
21, 23, 25, 24, 22, 0, 9, 28, 0, 0,
0, 14, 14, 16, 16, 16, 10, 10, 10, 0,
12, 0, 11, 0, 0, 0, 20, 0, 0, 0,
0, 0, 0, 0, 0, 16, 10, 10, 10, 0,
13, 19, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 32, 30,
19, 19, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 16, 17, 17, 30,
17, 11, 11, 19, 27, 0, 3, 0, 28, 13,
0, 0, 12, 0, 0, 0, 0, 0, 0, 0,
0, 22, 24, 26, 25, 23, 0, 10, 29, 0,
0, 0, 15, 15, 17, 17, 17, 11, 11, 11,
0, 13, 0, 12, 0, 0, 0, 21, 0, 0,
0, 0, 0, 0, 0, 0, 0, 17, 11, 11,
11, 0, 14, 20, 0, 0, 0, 0, 0, 0,
0, 16, 0, 0, 0, 0, 0, 0, 0, 0,
0, 16, 6, 0, 0, 0, 0, 0, 0, 2,
0, 0, 0, 0, 0, 0, 0, 0, 4, 17,
0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
5, 8, 0, 0, 0, 0, 7, 0
0, 0, 0, 0, 17, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 17, 7, 0, 0, 0,
0, 0, 0, 0, 2, 0, 0, 0, 0, 0,
0, 0, 0, 0, 4, 18, 0, 0, 5, 2,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 6, 9, 0,
0, 0, 0, 8, 0
} ;
static yyconst flex_int32_t yy_ec[256] =
static yyconst YY_CHAR yy_ec[256] =
{ 0,
1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
4, 4, 4, 1, 1, 1, 1, 1, 1, 1,
@ -416,9 +423,9 @@ static yyconst flex_int32_t yy_ec[256] =
22, 22, 22, 22, 24, 22, 22, 25, 22, 22,
1, 26, 27, 1, 22, 1, 21, 28, 29, 30,
31, 21, 22, 22, 32, 22, 22, 33, 34, 35,
36, 37, 22, 38, 39, 40, 41, 42, 22, 25,
43, 22, 44, 45, 46, 1, 1, 1, 1, 1,
31, 21, 32, 22, 33, 22, 22, 34, 35, 36,
37, 38, 22, 39, 40, 41, 42, 43, 22, 25,
44, 22, 45, 46, 47, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@ -435,163 +442,165 @@ static yyconst flex_int32_t yy_ec[256] =
1, 1, 1, 1, 1
} ;
static yyconst flex_int32_t yy_meta[47] =
static yyconst YY_CHAR yy_meta[48] =
{ 0,
1, 1, 1, 1, 1, 1, 2, 3, 1, 2,
2, 2, 4, 5, 5, 5, 6, 1, 1, 1,
7, 8, 8, 8, 8, 1, 1, 7, 7, 7,
7, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 3, 1, 4
8, 8, 8, 8, 3, 1, 4
} ;
static yyconst flex_int16_t yy_base[173] =
static yyconst flex_uint16_t yy_base[180] =
{ 0,
0, 383, 34, 382, 65, 381, 37, 105, 387, 391,
54, 111, 367, 110, 109, 109, 112, 41, 366, 104,
367, 338, 124, 117, 0, 144, 391, 0, 121, 0,
135, 155, 140, 179, 391, 160, 391, 379, 391, 0,
368, 141, 391, 167, 370, 376, 346, 103, 342, 345,
391, 391, 391, 391, 391, 358, 391, 391, 175, 342,
338, 391, 355, 0, 185, 339, 184, 347, 346, 0,
0, 322, 175, 357, 175, 363, 352, 324, 330, 323,
332, 326, 201, 324, 329, 322, 391, 333, 181, 309,
391, 341, 340, 313, 320, 338, 178, 311, 146, 317,
0, 393, 35, 392, 66, 391, 38, 107, 397, 401,
55, 113, 377, 112, 111, 111, 114, 42, 376, 106,
377, 347, 126, 120, 0, 147, 401, 0, 124, 0,
137, 158, 170, 163, 401, 153, 401, 389, 401, 0,
378, 120, 401, 131, 380, 386, 355, 139, 351, 355,
351, 401, 401, 401, 401, 401, 367, 401, 401, 185,
350, 346, 401, 364, 0, 185, 347, 189, 356, 355,
0, 0, 330, 180, 366, 141, 372, 361, 332, 338,
331, 341, 334, 326, 205, 331, 337, 329, 401, 341,
167, 316, 401, 349, 348, 320, 328, 346, 180, 318,
314, 315, 335, 331, 303, 300, 309, 299, 308, 188,
336, 335, 391, 305, 320, 281, 283, 271, 203, 288,
281, 271, 266, 264, 245, 242, 208, 104, 391, 391,
244, 218, 204, 219, 206, 224, 201, 212, 204, 229,
215, 208, 207, 200, 219, 391, 233, 221, 200, 181,
391, 391, 149, 122, 86, 41, 391, 391, 245, 251,
259, 263, 267, 273, 280, 284, 292, 300, 304, 310,
318, 326
324, 209, 324, 320, 322, 342, 338, 309, 306, 315,
305, 315, 312, 192, 342, 341, 401, 293, 306, 282,
268, 252, 255, 203, 285, 282, 272, 268, 252, 233,
232, 239, 208, 107, 401, 401, 238, 211, 401, 211,
212, 208, 228, 203, 215, 207, 233, 222, 212, 211,
203, 227, 401, 237, 225, 204, 185, 401, 401, 149,
128, 88, 42, 401, 401, 253, 259, 267, 271, 275,
281, 288, 292, 300, 308, 312, 318, 326, 334
} ;
static yyconst flex_int16_t yy_def[173] =
static yyconst flex_int16_t yy_def[180] =
{ 0,
158, 1, 1, 3, 158, 5, 1, 1, 158, 158,
158, 158, 158, 159, 160, 161, 158, 158, 158, 158,
162, 158, 158, 158, 163, 162, 158, 164, 165, 164,
164, 158, 158, 158, 158, 159, 158, 159, 158, 166,
158, 161, 158, 161, 167, 168, 158, 158, 158, 158,
158, 158, 158, 158, 158, 162, 158, 158, 158, 158,
158, 158, 162, 164, 165, 164, 158, 158, 158, 169,
166, 170, 161, 167, 167, 168, 158, 158, 158, 158,
158, 158, 158, 158, 158, 164, 158, 158, 169, 170,
158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
165, 1, 1, 3, 165, 5, 1, 1, 165, 165,
165, 165, 165, 166, 167, 168, 165, 165, 165, 165,
169, 165, 165, 165, 170, 169, 165, 171, 172, 171,
171, 165, 165, 165, 165, 166, 165, 166, 165, 173,
165, 168, 165, 168, 174, 175, 165, 165, 165, 165,
165, 165, 165, 165, 165, 165, 169, 165, 165, 165,
165, 165, 165, 169, 171, 172, 171, 165, 165, 165,
176, 173, 177, 168, 174, 174, 175, 165, 165, 165,
165, 165, 165, 165, 165, 165, 165, 171, 165, 165,
176, 177, 165, 165, 165, 165, 165, 165, 165, 165,
158, 164, 158, 158, 158, 158, 158, 158, 158, 171,
158, 164, 158, 158, 158, 158, 158, 158, 171, 158,
171, 158, 158, 158, 158, 158, 158, 158, 158, 158,
158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
172, 158, 158, 158, 172, 158, 172, 158, 158, 158,
158, 158, 158, 158, 158, 158, 158, 0, 158, 158,
158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
158, 158
165, 165, 165, 165, 171, 165, 165, 165, 165, 165,
165, 165, 165, 178, 165, 171, 165, 165, 165, 165,
165, 165, 165, 178, 165, 178, 165, 165, 165, 165,
165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
165, 165, 165, 165, 165, 165, 165, 179, 165, 165,
165, 179, 165, 179, 165, 165, 165, 165, 165, 165,
165, 165, 165, 165, 0, 165, 165, 165, 165, 165,
165, 165, 165, 165, 165, 165, 165, 165, 165
} ;
static yyconst flex_int16_t yy_nxt[438] =
static yyconst flex_uint16_t yy_nxt[449] =
{ 0,
10, 11, 12, 11, 13, 14, 10, 15, 16, 10,
10, 10, 17, 10, 10, 10, 10, 18, 19, 20,
21, 21, 21, 21, 21, 10, 10, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 10, 22, 10, 24, 25, 25, 25,
32, 33, 33, 157, 26, 34, 34, 34, 51, 52,
27, 26, 26, 26, 26, 10, 11, 12, 11, 13,
14, 28, 15, 16, 28, 28, 28, 24, 28, 28,
28, 10, 18, 19, 20, 29, 29, 29, 29, 29,
30, 10, 29, 29, 29, 29, 29, 29, 29, 29,
21, 21, 21, 21, 10, 22, 10, 24, 25, 25,
25, 32, 33, 33, 164, 26, 34, 34, 34, 52,
53, 27, 26, 26, 26, 26, 10, 11, 12, 11,
13, 14, 28, 15, 16, 28, 28, 28, 24, 28,
28, 28, 10, 18, 19, 20, 29, 29, 29, 29,
29, 30, 10, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29, 10, 22,
10, 23, 34, 34, 34, 37, 39, 43, 32, 33,
33, 45, 54, 55, 46, 59, 45, 64, 156, 46,
64, 64, 64, 79, 44, 38, 59, 57, 134, 47,
135, 48, 80, 49, 47, 50, 48, 99, 61, 43,
50, 110, 41, 67, 67, 67, 60, 63, 63, 63,
57, 155, 68, 69, 63, 37, 44, 66, 67, 67,
67, 63, 63, 63, 63, 73, 59, 68, 69, 70,
34, 34, 34, 43, 75, 38, 154, 92, 83, 83,
83, 64, 44, 120, 64, 64, 64, 67, 67, 67,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
10, 22, 10, 23, 34, 34, 34, 37, 39, 43,
32, 33, 33, 45, 55, 56, 46, 60, 43, 45,
65, 163, 46, 65, 65, 65, 44, 38, 60, 74,
58, 47, 141, 48, 142, 44, 49, 47, 50, 48,
76, 51, 62, 94, 50, 41, 44, 51, 37, 61,
64, 64, 64, 58, 34, 34, 34, 64, 162, 80,
67, 68, 68, 68, 64, 64, 64, 64, 38, 81,
69, 70, 71, 68, 68, 68, 60, 161, 43, 69,
70, 65, 69, 70, 65, 65, 65, 125, 85, 85,
44, 57, 99, 68, 69, 107, 68, 69, 120, 127,
108, 153, 152, 121, 83, 83, 83, 133, 133, 133,
146, 133, 133, 133, 146, 140, 140, 140, 121, 141,
140, 140, 140, 151, 141, 158, 150, 149, 148, 144,
147, 143, 142, 139, 147, 36, 36, 36, 36, 36,
36, 36, 36, 40, 138, 137, 136, 40, 40, 42,
42, 42, 42, 42, 42, 42, 42, 56, 56, 56,
56, 62, 132, 62, 64, 131, 130, 64, 129, 64,
64, 65, 128, 158, 65, 65, 65, 65, 71, 127,
71, 71, 74, 74, 74, 74, 74, 74, 74, 74,
85, 58, 68, 68, 68, 44, 102, 110, 125, 133,
102, 69, 70, 111, 114, 160, 159, 126, 85, 85,
85, 140, 140, 140, 140, 140, 140, 153, 126, 147,
147, 147, 153, 148, 147, 147, 147, 158, 148, 165,
157, 156, 155, 151, 150, 149, 146, 154, 145, 144,
143, 139, 154, 36, 36, 36, 36, 36, 36, 36,
36, 40, 138, 137, 136, 40, 40, 42, 42, 42,
42, 42, 42, 42, 42, 57, 57, 57, 57, 63,
135, 63, 65, 134, 165, 65, 133, 65, 65, 66,
132, 131, 66, 66, 66, 66, 72, 130, 72, 72,
76, 76, 76, 76, 76, 76, 76, 76, 89, 126,
89, 90, 125, 90, 90, 124, 90, 90, 119, 119,
119, 119, 119, 119, 119, 119, 145, 145, 145, 145,
145, 145, 145, 145, 123, 122, 59, 59, 118, 117,
116, 115, 114, 113, 45, 112, 108, 111, 109, 106,
105, 104, 46, 103, 91, 87, 102, 101, 100, 98,
97, 96, 95, 94, 93, 77, 75, 91, 88, 87,
86, 57, 85, 84, 57, 82, 81, 78, 77, 75,
72, 158, 58, 57, 53, 35, 158, 31, 23, 23,
9, 158, 158, 158, 158, 158, 158, 158, 158, 158,
75, 75, 75, 75, 75, 75, 75, 75, 77, 77,
77, 77, 77, 77, 77, 77, 91, 129, 91, 92,
128, 92, 92, 127, 92, 92, 124, 124, 124, 124,
124, 124, 124, 124, 152, 152, 152, 152, 152, 152,
152, 152, 60, 60, 123, 122, 121, 120, 119, 118,
117, 45, 116, 111, 115, 113, 112, 109, 108, 107,
46, 106, 93, 89, 105, 104, 103, 101, 100, 99,
98, 97, 96, 95, 78, 76, 93, 90, 89, 88,
58, 87, 86, 58, 84, 83, 82, 79, 78, 76,
73, 165, 59, 58, 54, 35, 165, 31, 23, 23,
158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
158, 158, 158, 158, 158, 158, 158
9, 165, 165, 165, 165, 165, 165, 165, 165, 165,
165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
165, 165, 165, 165, 165, 165, 165, 165
} ;
static yyconst flex_int16_t yy_chk[438] =
static yyconst flex_int16_t yy_chk[449] =
{ 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 3, 3, 3, 3,
7, 7, 7, 156, 3, 11, 11, 11, 18, 18,
3, 3, 3, 3, 3, 5, 5, 5, 5, 5,
1, 1, 1, 1, 1, 1, 1, 3, 3, 3,
3, 7, 7, 7, 163, 3, 11, 11, 11, 18,
18, 3, 3, 3, 3, 3, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 8, 12, 12, 12, 14, 15, 16, 8, 8,
8, 17, 20, 20, 17, 23, 24, 29, 155, 24,
29, 29, 29, 48, 16, 14, 31, 29, 128, 17,
128, 17, 48, 17, 24, 17, 24, 99, 24, 42,
24, 99, 15, 33, 33, 33, 23, 26, 26, 26,
26, 154, 33, 33, 26, 36, 42, 31, 32, 32,
32, 26, 26, 26, 26, 44, 59, 32, 32, 32,
34, 34, 34, 73, 75, 36, 153, 75, 59, 59,
59, 65, 44, 110, 65, 65, 65, 67, 67, 67,
5, 5, 5, 8, 12, 12, 12, 14, 15, 16,
8, 8, 8, 17, 20, 20, 17, 23, 42, 24,
29, 162, 24, 29, 29, 29, 16, 14, 31, 44,
29, 17, 134, 17, 134, 42, 17, 24, 17, 24,
76, 17, 24, 76, 24, 15, 44, 24, 36, 23,
26, 26, 26, 26, 34, 34, 34, 26, 161, 48,
31, 32, 32, 32, 26, 26, 26, 26, 36, 48,
32, 32, 32, 33, 33, 33, 60, 160, 74, 91,
91, 66, 33, 33, 66, 66, 66, 114, 60, 60,
73, 65, 83, 89, 89, 97, 67, 67, 119, 127,
97, 150, 149, 110, 83, 83, 83, 133, 133, 133,
141, 127, 127, 127, 145, 136, 136, 136, 119, 136,
140, 140, 140, 148, 140, 147, 144, 143, 142, 139,
141, 138, 137, 135, 145, 159, 159, 159, 159, 159,
159, 159, 159, 160, 134, 132, 131, 160, 160, 161,
161, 161, 161, 161, 161, 161, 161, 162, 162, 162,
162, 163, 126, 163, 164, 125, 124, 164, 123, 164,
164, 165, 122, 121, 165, 165, 165, 165, 166, 120,
166, 166, 167, 167, 167, 167, 167, 167, 167, 167,
60, 66, 68, 68, 68, 74, 85, 99, 124, 133,
102, 68, 68, 99, 102, 157, 156, 114, 85, 85,
85, 133, 133, 133, 140, 140, 140, 148, 124, 143,
143, 143, 152, 143, 147, 147, 147, 155, 147, 154,
151, 150, 149, 146, 145, 144, 142, 148, 141, 138,
137, 132, 152, 166, 166, 166, 166, 166, 166, 166,
166, 167, 131, 130, 129, 167, 167, 168, 168, 168,
168, 168, 168, 168, 168, 169, 169, 169, 169, 170,
128, 170, 171, 127, 126, 171, 125, 171, 171, 172,
123, 122, 172, 172, 172, 172, 173, 121, 173, 173,
168, 168, 168, 168, 168, 168, 168, 168, 169, 118,
169, 170, 117, 170, 170, 116, 170, 170, 171, 171,
171, 171, 171, 171, 171, 171, 172, 172, 172, 172,
172, 172, 172, 172, 115, 114, 112, 111, 109, 108,
107, 106, 105, 104, 103, 102, 101, 100, 98, 96,
95, 94, 93, 92, 90, 88, 86, 85, 84, 82,
81, 80, 79, 78, 77, 76, 74, 72, 69, 68,
66, 63, 61, 60, 56, 50, 49, 47, 46, 45,
174, 174, 174, 174, 174, 174, 174, 174, 175, 175,
175, 175, 175, 175, 175, 175, 176, 120, 176, 177,
119, 177, 177, 118, 177, 177, 178, 178, 178, 178,
178, 178, 178, 178, 179, 179, 179, 179, 179, 179,
179, 179, 116, 115, 113, 112, 111, 110, 109, 108,
107, 106, 105, 104, 103, 101, 100, 98, 97, 96,
95, 94, 92, 90, 88, 87, 86, 84, 83, 82,
81, 80, 79, 78, 77, 75, 73, 70, 69, 67,
64, 62, 61, 57, 51, 50, 49, 47, 46, 45,
41, 38, 22, 21, 19, 13, 9, 6, 4, 2,
158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
158, 158, 158, 158, 158, 158, 158, 158, 158, 158,
158, 158, 158, 158, 158, 158, 158
165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
165, 165, 165, 165, 165, 165, 165, 165
} ;
static yy_state_type yy_last_accepting_state;
@ -662,7 +671,7 @@ static int dts_version = 1;
static void push_input_file(const char *filename);
static bool pop_input_file(void);
static void lexical_error(const char *fmt, ...);
#line 666 "dtc-lexer.lex.c"
#line 675 "dtc-lexer.lex.c"
#define INITIAL 0
#define BYTESTRING 1
@ -698,11 +707,11 @@ void yyset_extra (YY_EXTRA_TYPE user_defined );
FILE *yyget_in (void );
void yyset_in (FILE * in_str );
void yyset_in (FILE * _in_str );
FILE *yyget_out (void );
void yyset_out (FILE * out_str );
void yyset_out (FILE * _out_str );
yy_size_t yyget_leng (void );
@ -710,7 +719,7 @@ char *yyget_text (void );
int yyget_lineno (void );
void yyset_lineno (int line_number );
void yyset_lineno (int _line_number );
/* Macros after this point can all be overridden by user definitions in
* section 1.
@ -724,6 +733,10 @@ extern int yywrap (void );
#endif
#endif
#ifndef YY_NO_UNPUT
#endif
#ifndef yytext_ptr
static void yy_flex_strncpy (char *,yyconst char *,int );
#endif
@ -836,7 +849,7 @@ extern int yylex (void);
/* Code executed at the end of each rule. */
#ifndef YY_BREAK
#define YY_BREAK break;
#define YY_BREAK /*LINTED*/break;
#endif
#define YY_RULE_SETUP \
@ -849,9 +862,9 @@ extern int yylex (void);
*/
YY_DECL
{
register yy_state_type yy_current_state;
register char *yy_cp, *yy_bp;
register int yy_act;
yy_state_type yy_current_state;
char *yy_cp, *yy_bp;
int yy_act;
if ( !(yy_init) )
{
@ -882,9 +895,9 @@ YY_DECL
{
#line 68 "dtc-lexer.l"
#line 886 "dtc-lexer.lex.c"
#line 899 "dtc-lexer.lex.c"
while ( 1 ) /* loops until end-of-file is reached */
while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
{
yy_cp = (yy_c_buf_p);
@ -901,7 +914,7 @@ YY_DECL
yy_match:
do
{
register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
if ( yy_accept[yy_current_state] )
{
(yy_last_accepting_state) = yy_current_state;
@ -910,13 +923,13 @@ yy_match:
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 159 )
if ( yy_current_state >= 166 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
++yy_cp;
}
while ( yy_current_state != 158 );
while ( yy_current_state != 165 );
yy_cp = (yy_last_accepting_cpos);
yy_current_state = (yy_last_accepting_state);
@ -1014,24 +1027,32 @@ YY_RULE_SETUP
case 5:
YY_RULE_SETUP
#line 124 "dtc-lexer.l"
{
DPRINT("Keyword: /plugin/\n");
return DT_PLUGIN;
}
YY_BREAK
case 6:
YY_RULE_SETUP
#line 129 "dtc-lexer.l"
{
DPRINT("Keyword: /memreserve/\n");
BEGIN_DEFAULT();
return DT_MEMRESERVE;
}
YY_BREAK
case 6:
case 7:
YY_RULE_SETUP
#line 130 "dtc-lexer.l"
#line 135 "dtc-lexer.l"
{
DPRINT("Keyword: /bits/\n");
BEGIN_DEFAULT();
return DT_BITS;
}
YY_BREAK
case 7:
case 8:
YY_RULE_SETUP
#line 136 "dtc-lexer.l"
#line 141 "dtc-lexer.l"
{
DPRINT("Keyword: /delete-property/\n");
DPRINT("<PROPNODENAME>\n");
@ -1039,9 +1060,9 @@ YY_RULE_SETUP
return DT_DEL_PROP;
}
YY_BREAK
case 8:
case 9:
YY_RULE_SETUP
#line 143 "dtc-lexer.l"
#line 148 "dtc-lexer.l"
{
DPRINT("Keyword: /delete-node/\n");
DPRINT("<PROPNODENAME>\n");
@ -1049,9 +1070,9 @@ YY_RULE_SETUP
return DT_DEL_NODE;
}
YY_BREAK
case 9:
case 10:
YY_RULE_SETUP
#line 150 "dtc-lexer.l"
#line 155 "dtc-lexer.l"
{
DPRINT("Label: %s\n", yytext);
yylval.labelref = xstrdup(yytext);
@ -1059,9 +1080,9 @@ YY_RULE_SETUP
return DT_LABEL;
}
YY_BREAK
case 10:
case 11:
YY_RULE_SETUP
#line 157 "dtc-lexer.l"
#line 162 "dtc-lexer.l"
{
char *e;
DPRINT("Integer Literal: '%s'\n", yytext);
@ -1084,10 +1105,10 @@ YY_RULE_SETUP
return DT_LITERAL;
}
YY_BREAK
case 11:
/* rule 11 can match eol */
case 12:
/* rule 12 can match eol */
YY_RULE_SETUP
#line 179 "dtc-lexer.l"
#line 184 "dtc-lexer.l"
{
struct data d;
DPRINT("Character literal: %s\n", yytext);
@ -1096,31 +1117,31 @@ YY_RULE_SETUP
if (d.len == 1) {
lexical_error("Empty character literal");
yylval.integer = 0;
return DT_CHAR_LITERAL;
} else {
yylval.integer = (unsigned char)d.val[0];
if (d.len > 2)
lexical_error("Character literal has %d"
" characters instead of 1",
d.len - 1);
}
yylval.integer = (unsigned char)d.val[0];
if (d.len > 2)
lexical_error("Character literal has %d"
" characters instead of 1",
d.len - 1);
data_free(d);
return DT_CHAR_LITERAL;
}
YY_BREAK
case 12:
case 13:
YY_RULE_SETUP
#line 200 "dtc-lexer.l"
#line 205 "dtc-lexer.l"
{ /* label reference */
DPRINT("Ref: %s\n", yytext+1);
yylval.labelref = xstrdup(yytext+1);
return DT_REF;
}
YY_BREAK
case 13:
case 14:
YY_RULE_SETUP
#line 206 "dtc-lexer.l"
#line 211 "dtc-lexer.l"
{ /* new-style path reference */
yytext[yyleng-1] = '\0';
DPRINT("Ref: %s\n", yytext+2);
@ -1128,27 +1149,27 @@ YY_RULE_SETUP
return DT_REF;
}
YY_BREAK
case 14:
case 15:
YY_RULE_SETUP
#line 213 "dtc-lexer.l"
#line 218 "dtc-lexer.l"
{
yylval.byte = strtol(yytext, NULL, 16);
DPRINT("Byte: %02x\n", (int)yylval.byte);
return DT_BYTE;
}
YY_BREAK
case 15:
case 16:
YY_RULE_SETUP
#line 219 "dtc-lexer.l"
#line 224 "dtc-lexer.l"
{
DPRINT("/BYTESTRING\n");
BEGIN_DEFAULT();
return ']';
}
YY_BREAK
case 16:
case 17:
YY_RULE_SETUP
#line 225 "dtc-lexer.l"
#line 230 "dtc-lexer.l"
{
DPRINT("PropNodeName: %s\n", yytext);
yylval.propnodename = xstrdup((yytext[0] == '\\') ?
@ -1157,75 +1178,75 @@ YY_RULE_SETUP
return DT_PROPNODENAME;
}
YY_BREAK
case 17:
case 18:
YY_RULE_SETUP
#line 233 "dtc-lexer.l"
#line 238 "dtc-lexer.l"
{
DPRINT("Binary Include\n");
return DT_INCBIN;
}
YY_BREAK
case 18:
/* rule 18 can match eol */
YY_RULE_SETUP
#line 238 "dtc-lexer.l"
/* eat whitespace */
YY_BREAK
case 19:
/* rule 19 can match eol */
YY_RULE_SETUP
#line 239 "dtc-lexer.l"
/* eat C-style comments */
#line 243 "dtc-lexer.l"
/* eat whitespace */
YY_BREAK
case 20:
/* rule 20 can match eol */
YY_RULE_SETUP
#line 240 "dtc-lexer.l"
/* eat C++-style comments */
#line 244 "dtc-lexer.l"
/* eat C-style comments */
YY_BREAK
case 21:
/* rule 21 can match eol */
YY_RULE_SETUP
#line 242 "dtc-lexer.l"
{ return DT_LSHIFT; };
#line 245 "dtc-lexer.l"
/* eat C++-style comments */
YY_BREAK
case 22:
YY_RULE_SETUP
#line 243 "dtc-lexer.l"
{ return DT_RSHIFT; };
#line 247 "dtc-lexer.l"
{ return DT_LSHIFT; };
YY_BREAK
case 23:
YY_RULE_SETUP
#line 244 "dtc-lexer.l"
{ return DT_LE; };
#line 248 "dtc-lexer.l"
{ return DT_RSHIFT; };
YY_BREAK
case 24:
YY_RULE_SETUP
#line 245 "dtc-lexer.l"
{ return DT_GE; };
#line 249 "dtc-lexer.l"
{ return DT_LE; };
YY_BREAK
case 25:
YY_RULE_SETUP
#line 246 "dtc-lexer.l"
{ return DT_EQ; };
#line 250 "dtc-lexer.l"
{ return DT_GE; };
YY_BREAK
case 26:
YY_RULE_SETUP
#line 247 "dtc-lexer.l"
{ return DT_NE; };
#line 251 "dtc-lexer.l"
{ return DT_EQ; };
YY_BREAK
case 27:
YY_RULE_SETUP
#line 248 "dtc-lexer.l"
{ return DT_AND; };
#line 252 "dtc-lexer.l"
{ return DT_NE; };
YY_BREAK
case 28:
YY_RULE_SETUP
#line 249 "dtc-lexer.l"
{ return DT_OR; };
#line 253 "dtc-lexer.l"
{ return DT_AND; };
YY_BREAK
case 29:
YY_RULE_SETUP
#line 251 "dtc-lexer.l"
#line 254 "dtc-lexer.l"
{ return DT_OR; };
YY_BREAK
case 30:
YY_RULE_SETUP
#line 256 "dtc-lexer.l"
{
DPRINT("Char: %c (\\x%02x)\n", yytext[0],
(unsigned)yytext[0]);
@ -1241,12 +1262,12 @@ YY_RULE_SETUP
return yytext[0];
}
YY_BREAK
case 30:
case 31:
YY_RULE_SETUP
#line 266 "dtc-lexer.l"
#line 271 "dtc-lexer.l"
ECHO;
YY_BREAK
#line 1250 "dtc-lexer.lex.c"
#line 1271 "dtc-lexer.lex.c"
case YY_END_OF_BUFFER:
{
@ -1388,9 +1409,9 @@ ECHO;
*/
static int yy_get_next_buffer (void)
{
register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
register char *source = (yytext_ptr);
register int number_to_move, i;
char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
char *source = (yytext_ptr);
yy_size_t number_to_move, i;
int ret_val;
if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
@ -1419,7 +1440,7 @@ static int yy_get_next_buffer (void)
/* Try to read more data. */
/* First move last chars to start of buffer. */
number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
number_to_move = (yy_size_t) ((yy_c_buf_p) - (yytext_ptr)) - 1;
for ( i = 0; i < number_to_move; ++i )
*(dest++) = *(source++);
@ -1501,9 +1522,9 @@ static int yy_get_next_buffer (void)
else
ret_val = EOB_ACT_CONTINUE_SCAN;
if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
if ((int) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
/* Extend the array by 50%, plus the number we really need. */
yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size );
if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
@ -1522,15 +1543,15 @@ static int yy_get_next_buffer (void)
static yy_state_type yy_get_previous_state (void)
{
register yy_state_type yy_current_state;
register char *yy_cp;
yy_state_type yy_current_state;
char *yy_cp;
yy_current_state = (yy_start);
yy_current_state += YY_AT_BOL();
for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
{
register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
if ( yy_accept[yy_current_state] )
{
(yy_last_accepting_state) = yy_current_state;
@ -1539,7 +1560,7 @@ static int yy_get_next_buffer (void)
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 159 )
if ( yy_current_state >= 166 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
@ -1555,10 +1576,10 @@ static int yy_get_next_buffer (void)
*/
static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
{
register int yy_is_jam;
register char *yy_cp = (yy_c_buf_p);
int yy_is_jam;
char *yy_cp = (yy_c_buf_p);
register YY_CHAR yy_c = 1;
YY_CHAR yy_c = 1;
if ( yy_accept[yy_current_state] )
{
(yy_last_accepting_state) = yy_current_state;
@ -1567,15 +1588,19 @@ static int yy_get_next_buffer (void)
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 159 )
if ( yy_current_state >= 166 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
yy_is_jam = (yy_current_state == 158);
yy_is_jam = (yy_current_state == 165);
return yy_is_jam ? 0 : yy_current_state;
}
#ifndef YY_NO_UNPUT
#endif
#ifndef YY_NO_INPUT
#ifdef __cplusplus
static int yyinput (void)
@ -1727,7 +1752,7 @@ static void yy_load_buffer_state (void)
if ( ! b )
YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
b->yy_buf_size = size;
b->yy_buf_size = (yy_size_t)size;
/* yy_ch_buf has to be 2 characters longer than the size given because
* we need to put in 2 end-of-buffer characters.
@ -1882,7 +1907,7 @@ static void yyensure_buffer_stack (void)
* scanner will even need a stack. We use 2 instead of 1 to avoid an
* immediate realloc on the next call.
*/
num_to_alloc = 1;
num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
(yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
(num_to_alloc * sizeof(struct yy_buffer_state*)
);
@ -1899,7 +1924,7 @@ static void yyensure_buffer_stack (void)
if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
/* Increase the buffer to prepare for a possible push. */
int grow_size = 8 /* arbitrary grow size */;
yy_size_t grow_size = 8 /* arbitrary grow size */;
num_to_alloc = (yy_buffer_stack_max) + grow_size;
(yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
@ -2007,7 +2032,7 @@ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len
static void yy_fatal_error (yyconst char* msg )
{
(void) fprintf( stderr, "%s\n", msg );
(void) fprintf( stderr, "%s\n", msg );
exit( YY_EXIT_FAILURE );
}
@ -2073,29 +2098,29 @@ char *yyget_text (void)
}
/** Set the current line number.
* @param line_number
* @param _line_number line number
*
*/
void yyset_lineno (int line_number )
void yyset_lineno (int _line_number )
{
yylineno = line_number;
yylineno = _line_number;
}
/** Set the input stream. This does not discard the current
* input buffer.
* @param in_str A readable stream.
* @param _in_str A readable stream.
*
* @see yy_switch_to_buffer
*/
void yyset_in (FILE * in_str )
void yyset_in (FILE * _in_str )
{
yyin = in_str ;
yyin = _in_str ;
}
void yyset_out (FILE * out_str )
void yyset_out (FILE * _out_str )
{
yyout = out_str ;
yyout = _out_str ;
}
int yyget_debug (void)
@ -2103,9 +2128,9 @@ int yyget_debug (void)
return yy_flex_debug;
}
void yyset_debug (int bdebug )
void yyset_debug (int _bdebug )
{
yy_flex_debug = bdebug ;
yy_flex_debug = _bdebug ;
}
static int yy_init_globals (void)
@ -2165,7 +2190,7 @@ int yylex_destroy (void)
#ifndef yytext_ptr
static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
{
register int i;
int i;
for ( i = 0; i < n; ++i )
s1[i] = s2[i];
}
@ -2174,7 +2199,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
#ifdef YY_NEED_STRLEN
static int yy_flex_strlen (yyconst char * s )
{
register int n;
int n;
for ( n = 0; s[n]; ++n )
;
@ -2184,7 +2209,7 @@ static int yy_flex_strlen (yyconst char * s )
void *yyalloc (yy_size_t size )
{
return (void *) malloc( size );
return (void *) malloc( size );
}
void *yyrealloc (void * ptr, yy_size_t size )
@ -2201,12 +2226,12 @@ void *yyrealloc (void * ptr, yy_size_t size )
void yyfree (void * ptr )
{
free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
}
#define YYTABLES_NAME "yytables"
#line 265 "dtc-lexer.l"
#line 271 "dtc-lexer.l"

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,8 @@
/* A Bison parser, made by GNU Bison 3.0.2. */
/* A Bison parser, made by GNU Bison 3.0.4. */
/* Bison interface for Yacc-like parsers in C
Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -46,35 +46,36 @@ extern int yydebug;
enum yytokentype
{
DT_V1 = 258,
DT_MEMRESERVE = 259,
DT_LSHIFT = 260,
DT_RSHIFT = 261,
DT_LE = 262,
DT_GE = 263,
DT_EQ = 264,
DT_NE = 265,
DT_AND = 266,
DT_OR = 267,
DT_BITS = 268,
DT_DEL_PROP = 269,
DT_DEL_NODE = 270,
DT_PROPNODENAME = 271,
DT_LITERAL = 272,
DT_CHAR_LITERAL = 273,
DT_BYTE = 274,
DT_STRING = 275,
DT_LABEL = 276,
DT_REF = 277,
DT_INCBIN = 278
DT_PLUGIN = 259,
DT_MEMRESERVE = 260,
DT_LSHIFT = 261,
DT_RSHIFT = 262,
DT_LE = 263,
DT_GE = 264,
DT_EQ = 265,
DT_NE = 266,
DT_AND = 267,
DT_OR = 268,
DT_BITS = 269,
DT_DEL_PROP = 270,
DT_DEL_NODE = 271,
DT_PROPNODENAME = 272,
DT_LITERAL = 273,
DT_CHAR_LITERAL = 274,
DT_BYTE = 275,
DT_STRING = 276,
DT_LABEL = 277,
DT_REF = 278,
DT_INCBIN = 279
};
#endif
/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE YYSTYPE;
union YYSTYPE
{
#line 38 "dtc-parser.y" /* yacc.c:1909 */
#line 39 "dtc-parser.y" /* yacc.c:1909 */
char *propnodename;
char *labelref;
@ -92,9 +93,12 @@ union YYSTYPE
struct node *nodelist;
struct reserve_info *re;
uint64_t integer;
unsigned int flags;
#line 97 "dtc-parser.tab.h" /* yacc.c:1909 */
#line 99 "dtc-parser.tab.h" /* yacc.c:1909 */
};
typedef union YYSTYPE YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1
#endif

View file

@ -19,6 +19,7 @@
*/
%{
#include <stdio.h>
#include <inttypes.h>
#include "dtc.h"
#include "srcpos.h"
@ -31,7 +32,7 @@ extern void yyerror(char const *s);
treesource_error = true; \
} while (0)
extern struct boot_info *the_boot_info;
extern struct dt_info *parser_output;
extern bool treesource_error;
%}
@ -52,9 +53,11 @@ extern bool treesource_error;
struct node *nodelist;
struct reserve_info *re;
uint64_t integer;
unsigned int flags;
}
%token DT_V1
%token DT_PLUGIN
%token DT_MEMRESERVE
%token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
%token DT_BITS
@ -71,6 +74,8 @@ extern bool treesource_error;
%type <data> propdata
%type <data> propdataprefix
%type <flags> header
%type <flags> headers
%type <re> memreserve
%type <re> memreserves
%type <array> arrayprefix
@ -101,10 +106,31 @@ extern bool treesource_error;
%%
sourcefile:
DT_V1 ';' memreserves devicetree
headers memreserves devicetree
{
the_boot_info = build_boot_info($3, $4,
guess_boot_cpuid($4));
parser_output = build_dt_info($1, $2, $3,
guess_boot_cpuid($3));
}
;
header:
DT_V1 ';'
{
$$ = DTSF_V1;
}
| DT_V1 ';' DT_PLUGIN ';'
{
$$ = DTSF_V1 | DTSF_PLUGIN;
}
;
headers:
header
| header headers
{
if ($2 != $1)
ERROR(&@2, "Header flags don't match earlier ones");
$$ = $1;
}
;
@ -145,10 +171,10 @@ devicetree:
{
struct node *target = get_node_by_ref($1, $3);
add_label(&target->labels, $2);
if (target)
if (target) {
add_label(&target->labels, $2);
merge_nodes(target, $4);
else
} else
ERROR(&@3, "Label or path %s not found", $3);
$$ = $1;
}
@ -156,10 +182,19 @@ devicetree:
{
struct node *target = get_node_by_ref($1, $2);
if (target)
if (target) {
merge_nodes(target, $3);
else
ERROR(&@2, "Label or path %s not found", $2);
} else {
/*
* We rely on the rule being always:
* versioninfo plugindecl memreserves devicetree
* so $-1 is what we want (plugindecl)
*/
if ($<flags>-1 & DTSF_PLUGIN)
add_orphan_node($1, $3, $2);
else
ERROR(&@2, "Label or path %s not found", $2);
}
$$ = $1;
}
| devicetree DT_DEL_NODE DT_REF ';'
@ -174,6 +209,11 @@ devicetree:
$$ = $1;
}
| /* empty */
{
/* build empty node */
$$ = name_node(build_node(NULL, NULL), "");
}
;
nodedef:

View file

@ -30,7 +30,16 @@ int quiet; /* Level of quietness */
int reservenum; /* Number of memory reservation slots */
int minsize; /* Minimum blob size */
int padsize; /* Additional padding to blob */
int alignsize; /* Additional padding to blob accroding to the alignsize */
int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */
int generate_symbols; /* enable symbols & fixup support */
int generate_fixups; /* suppress generation of fixups on symbol support */
int auto_label_aliases; /* auto generate labels -> aliases */
static int is_power_of_2(int x)
{
return (x > 0) && ((x & (x - 1)) == 0);
}
static void fill_fullpaths(struct node *tree, const char *prefix)
{
@ -53,7 +62,7 @@ static void fill_fullpaths(struct node *tree, const char *prefix)
#define FDT_VERSION(version) _FDT_VERSION(version)
#define _FDT_VERSION(version) #version
static const char usage_synopsis[] = "dtc [options] <input file>";
static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv";
static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@Ahv";
static struct option const usage_long_opts[] = {
{"quiet", no_argument, NULL, 'q'},
{"in-format", a_argument, NULL, 'I'},
@ -64,6 +73,7 @@ static struct option const usage_long_opts[] = {
{"reserve", a_argument, NULL, 'R'},
{"space", a_argument, NULL, 'S'},
{"pad", a_argument, NULL, 'p'},
{"align", a_argument, NULL, 'a'},
{"boot-cpu", a_argument, NULL, 'b'},
{"force", no_argument, NULL, 'f'},
{"include", a_argument, NULL, 'i'},
@ -71,6 +81,8 @@ static struct option const usage_long_opts[] = {
{"phandle", a_argument, NULL, 'H'},
{"warning", a_argument, NULL, 'W'},
{"error", a_argument, NULL, 'E'},
{"symbols", no_argument, NULL, '@'},
{"auto-alias", no_argument, NULL, 'A'},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'v'},
{NULL, no_argument, NULL, 0x0},
@ -91,6 +103,7 @@ static const char * const usage_opts_help[] = {
"\n\tMake space for <number> reserve map entries (for dtb and asm output)",
"\n\tMake the blob at least <bytes> long (extra space)",
"\n\tAdd padding to the blob of <bytes> long (extra space)",
"\n\tMake the blob align to the <bytes> (extra space)",
"\n\tSet the physical boot cpu",
"\n\tTry to produce output even if the input tree has errors",
"\n\tAdd a path to search for include files",
@ -101,6 +114,8 @@ static const char * const usage_opts_help[] = {
"\t\tboth - Both \"linux,phandle\" and \"phandle\" properties",
"\n\tEnable/disable warnings (prefix with \"no-\")",
"\n\tEnable/disable errors (prefix with \"no-\")",
"\n\tEnable generation of symbols",
"\n\tEnable auto-alias of labels",
"\n\tPrint this help and exit",
"\n\tPrint version and exit",
NULL,
@ -153,7 +168,7 @@ static const char *guess_input_format(const char *fname, const char *fallback)
int main(int argc, char *argv[])
{
struct boot_info *bi;
struct dt_info *dti;
const char *inform = NULL;
const char *outform = NULL;
const char *outname = "-";
@ -169,6 +184,7 @@ int main(int argc, char *argv[])
reservenum = 0;
minsize = 0;
padsize = 0;
alignsize = 0;
while ((opt = util_getopt_long()) != EOF) {
switch (opt) {
@ -196,6 +212,12 @@ int main(int argc, char *argv[])
case 'p':
padsize = strtol(optarg, NULL, 0);
break;
case 'a':
alignsize = strtol(optarg, NULL, 0);
if (!is_power_of_2(alignsize))
die("Invalid argument \"%d\" to -a option\n",
optarg);
break;
case 'f':
force = true;
break;
@ -234,6 +256,13 @@ int main(int argc, char *argv[])
parse_checks_option(false, true, optarg);
break;
case '@':
generate_symbols = 1;
break;
case 'A':
auto_label_aliases = 1;
break;
case 'h':
usage(NULL);
default:
@ -272,11 +301,11 @@ int main(int argc, char *argv[])
}
}
if (streq(inform, "dts"))
bi = dt_from_source(arg);
dti = dt_from_source(arg);
else if (streq(inform, "fs"))
bi = dt_from_fs(arg);
dti = dt_from_fs(arg);
else if(streq(inform, "dtb"))
bi = dt_from_blob(arg);
dti = dt_from_blob(arg);
else
die("Unknown input format \"%s\"\n", inform);
@ -286,13 +315,29 @@ int main(int argc, char *argv[])
}
if (cmdline_boot_cpuid != -1)
bi->boot_cpuid_phys = cmdline_boot_cpuid;
dti->boot_cpuid_phys = cmdline_boot_cpuid;
fill_fullpaths(bi->dt, "");
process_checks(force, bi);
fill_fullpaths(dti->dt, "");
process_checks(force, dti);
/* on a plugin, generate by default */
if (dti->dtsflags & DTSF_PLUGIN) {
generate_fixups = 1;
}
if (auto_label_aliases)
generate_label_tree(dti, "aliases", false);
if (generate_symbols)
generate_label_tree(dti, "__symbols__", true);
if (generate_fixups) {
generate_fixups_tree(dti, "__fixups__");
generate_local_fixups_tree(dti, "__local_fixups__");
}
if (sort)
sort_tree(bi);
sort_tree(dti);
if (streq(outname, "-")) {
outf = stdout;
@ -304,11 +349,11 @@ int main(int argc, char *argv[])
}
if (streq(outform, "dts")) {
dt_to_source(outf, bi);
dt_to_source(outf, dti);
} else if (streq(outform, "dtb")) {
dt_to_blob(outf, bi, outversion);
dt_to_blob(outf, dti, outversion);
} else if (streq(outform, "asm")) {
dt_to_asm(outf, bi, outversion);
dt_to_asm(outf, dti, outversion);
} else if (streq(outform, "null")) {
/* do nothing */
} else {

View file

@ -53,7 +53,11 @@ extern int quiet; /* Level of quietness */
extern int reservenum; /* Number of memory reservation slots */
extern int minsize; /* Minimum blob size */
extern int padsize; /* Additional padding to blob */
extern int alignsize; /* Additional padding to blob accroding to the alignsize */
extern int phandle_format; /* Use linux,phandle or phandle properties */
extern int generate_symbols; /* generate symbols for nodes with labels */
extern int generate_fixups; /* generate fixups */
extern int auto_label_aliases; /* auto generate labels -> aliases */
#define PHANDLE_LEGACY 0x1
#define PHANDLE_EPAPR 0x2
@ -194,6 +198,7 @@ struct node *build_node_delete(void);
struct node *name_node(struct node *node, char *name);
struct node *chain_node(struct node *first, struct node *list);
struct node *merge_nodes(struct node *old_node, struct node *new_node);
void add_orphan_node(struct node *old_node, struct node *new_node, char *ref);
void add_property(struct node *node, struct property *prop);
void delete_property_by_name(struct node *node, char *name);
@ -201,6 +206,8 @@ void delete_property(struct property *prop);
void add_child(struct node *parent, struct node *child);
void delete_node_by_name(struct node *parent, char *name);
void delete_node(struct node *node);
void append_to_property(struct node *node,
char *name, const void *data, int len);
const char *get_unitname(struct node *node);
struct property *get_property(struct node *node, const char *propname);
@ -235,35 +242,44 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
struct reserve_info *new);
struct boot_info {
struct dt_info {
unsigned int dtsflags;
struct reserve_info *reservelist;
struct node *dt; /* the device tree */
uint32_t boot_cpuid_phys;
struct node *dt; /* the device tree */
};
struct boot_info *build_boot_info(struct reserve_info *reservelist,
struct node *tree, uint32_t boot_cpuid_phys);
void sort_tree(struct boot_info *bi);
/* DTS version flags definitions */
#define DTSF_V1 0x0001 /* /dts-v1/ */
#define DTSF_PLUGIN 0x0002 /* /plugin/ */
struct dt_info *build_dt_info(unsigned int dtsflags,
struct reserve_info *reservelist,
struct node *tree, uint32_t boot_cpuid_phys);
void sort_tree(struct dt_info *dti);
void generate_label_tree(struct dt_info *dti, char *name, bool allocph);
void generate_fixups_tree(struct dt_info *dti, char *name);
void generate_local_fixups_tree(struct dt_info *dti, char *name);
/* Checks */
void parse_checks_option(bool warn, bool error, const char *arg);
void process_checks(bool force, struct boot_info *bi);
void process_checks(bool force, struct dt_info *dti);
/* Flattened trees */
void dt_to_blob(FILE *f, struct boot_info *bi, int version);
void dt_to_asm(FILE *f, struct boot_info *bi, int version);
void dt_to_blob(FILE *f, struct dt_info *dti, int version);
void dt_to_asm(FILE *f, struct dt_info *dti, int version);
struct boot_info *dt_from_blob(const char *fname);
struct dt_info *dt_from_blob(const char *fname);
/* Tree source */
void dt_to_source(FILE *f, struct boot_info *bi);
struct boot_info *dt_from_source(const char *f);
void dt_to_source(FILE *f, struct dt_info *dti);
struct dt_info *dt_from_source(const char *f);
/* FS trees */
struct boot_info *dt_from_fs(const char *dirname);
struct dt_info *dt_from_fs(const char *dirname);
#endif /* _DTC_H */

View file

@ -366,7 +366,7 @@ static void make_fdt_header(struct fdt_header *fdt,
fdt->size_dt_struct = cpu_to_fdt32(dtsize);
}
void dt_to_blob(FILE *f, struct boot_info *bi, int version)
void dt_to_blob(FILE *f, struct dt_info *dti, int version)
{
struct version_info *vi = NULL;
int i;
@ -384,29 +384,36 @@ void dt_to_blob(FILE *f, struct boot_info *bi, int version)
if (!vi)
die("Unknown device tree blob version %d\n", version);
flatten_tree(bi->dt, &bin_emitter, &dtbuf, &strbuf, vi);
flatten_tree(dti->dt, &bin_emitter, &dtbuf, &strbuf, vi);
bin_emit_cell(&dtbuf, FDT_END);
reservebuf = flatten_reserve_list(bi->reservelist, vi);
reservebuf = flatten_reserve_list(dti->reservelist, vi);
/* Make header */
make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
bi->boot_cpuid_phys);
dti->boot_cpuid_phys);
/*
* If the user asked for more space than is used, adjust the totalsize.
*/
if (minsize > 0) {
padlen = minsize - fdt32_to_cpu(fdt.totalsize);
if ((padlen < 0) && (quiet < 1))
fprintf(stderr,
"Warning: blob size %d >= minimum size %d\n",
fdt32_to_cpu(fdt.totalsize), minsize);
if (padlen < 0) {
padlen = 0;
if (quiet < 1)
fprintf(stderr,
"Warning: blob size %d >= minimum size %d\n",
fdt32_to_cpu(fdt.totalsize), minsize);
}
}
if (padsize > 0)
padlen = padsize;
if (alignsize > 0)
padlen = ALIGN(fdt32_to_cpu(fdt.totalsize) + padlen, alignsize)
- fdt32_to_cpu(fdt.totalsize);
if (padlen > 0) {
int tsize = fdt32_to_cpu(fdt.totalsize);
tsize += padlen;
@ -460,7 +467,7 @@ static void dump_stringtable_asm(FILE *f, struct data strbuf)
}
}
void dt_to_asm(FILE *f, struct boot_info *bi, int version)
void dt_to_asm(FILE *f, struct dt_info *dti, int version)
{
struct version_info *vi = NULL;
int i;
@ -500,7 +507,7 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version)
if (vi->flags & FTF_BOOTCPUID) {
fprintf(f, "\t/* boot_cpuid_phys */\n");
asm_emit_cell(f, bi->boot_cpuid_phys);
asm_emit_cell(f, dti->boot_cpuid_phys);
}
if (vi->flags & FTF_STRTABSIZE) {
@ -530,7 +537,7 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version)
* Use .long on high and low halfs of u64s to avoid .quad
* as it appears .quad isn't available in some assemblers.
*/
for (re = bi->reservelist; re; re = re->next) {
for (re = dti->reservelist; re; re = re->next) {
struct label *l;
for_each_label(re->labels, l) {
@ -550,7 +557,7 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version)
fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n");
emit_label(f, symprefix, "struct_start");
flatten_tree(bi->dt, &asm_emitter, f, &strbuf, vi);
flatten_tree(dti->dt, &asm_emitter, f, &strbuf, vi);
fprintf(f, "\t/* FDT_END */\n");
asm_emit_cell(f, FDT_END);
@ -572,6 +579,8 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version)
if (padsize > 0) {
fprintf(f, "\t.space\t%d, 0\n", padsize);
}
if (alignsize > 0)
asm_emit_align(f, alignsize);
emit_label(f, symprefix, "blob_abs_end");
data_free(strbuf);
@ -797,11 +806,15 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
}
} while (val != FDT_END_NODE);
if (node->name != flatname) {
free(flatname);
}
return node;
}
struct boot_info *dt_from_blob(const char *fname)
struct dt_info *dt_from_blob(const char *fname)
{
FILE *f;
uint32_t magic, totalsize, version, size_dt, boot_cpuid_phys;
@ -929,5 +942,5 @@ struct boot_info *dt_from_blob(const char *fname)
fclose(f);
return build_boot_info(reservelist, tree, boot_cpuid_phys);
return build_dt_info(DTSF_V1, reservelist, tree, boot_cpuid_phys);
}

View file

@ -79,13 +79,12 @@ static struct node *read_fstree(const char *dirname)
return tree;
}
struct boot_info *dt_from_fs(const char *dirname)
struct dt_info *dt_from_fs(const char *dirname)
{
struct node *tree;
tree = read_fstree(dirname);
tree = name_node(tree, "");
return build_boot_info(NULL, tree, guess_boot_cpuid(tree));
return build_dt_info(DTSF_V1, NULL, tree, guess_boot_cpuid(tree));
}

View file

@ -7,5 +7,5 @@ LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1
LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h
LIBFDT_VERSION = version.lds
LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c \
fdt_addresses.c
fdt_addresses.c fdt_overlay.c
LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)

View file

@ -0,0 +1,94 @@
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au>
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 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 "libfdt_env.h"
#include <fdt.h>
#include <libfdt.h>
#include "libfdt_internal.h"
int fdt_address_cells(const void *fdt, int nodeoffset)
{
const fdt32_t *ac;
int val;
int len;
ac = fdt_getprop(fdt, nodeoffset, "#address-cells", &len);
if (!ac)
return 2;
if (len != sizeof(*ac))
return -FDT_ERR_BADNCELLS;
val = fdt32_to_cpu(*ac);
if ((val <= 0) || (val > FDT_MAX_NCELLS))
return -FDT_ERR_BADNCELLS;
return val;
}
int fdt_size_cells(const void *fdt, int nodeoffset)
{
const fdt32_t *sc;
int val;
int len;
sc = fdt_getprop(fdt, nodeoffset, "#size-cells", &len);
if (!sc)
return 2;
if (len != sizeof(*sc))
return -FDT_ERR_BADNCELLS;
val = fdt32_to_cpu(*sc);
if ((val < 0) || (val > FDT_MAX_NCELLS))
return -FDT_ERR_BADNCELLS;
return val;
}

View file

@ -0,0 +1,676 @@
#include "libfdt_env.h"
#include <fdt.h>
#include <libfdt.h>
#include "libfdt_internal.h"
/**
* overlay_get_target_phandle - retrieves the target phandle of a fragment
* @fdto: pointer to the device tree overlay blob
* @fragment: node offset of the fragment in the overlay
*
* overlay_get_target_phandle() retrieves the target phandle of an
* overlay fragment when that fragment uses a phandle (target
* property) instead of a path (target-path property).
*
* returns:
* the phandle pointed by the target property
* 0, if the phandle was not found
* -1, if the phandle was malformed
*/
static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
{
const uint32_t *val;
int len;
val = fdt_getprop(fdto, fragment, "target", &len);
if (!val)
return 0;
if ((len != sizeof(*val)) || (*val == (uint32_t)-1))
return (uint32_t)-1;
return fdt32_to_cpu(*val);
}
/**
* overlay_get_target - retrieves the offset of a fragment's target
* @fdt: Base device tree blob
* @fdto: Device tree overlay blob
* @fragment: node offset of the fragment in the overlay
*
* overlay_get_target() retrieves the target offset in the base
* device tree of a fragment, no matter how the actual targetting is
* done (through a phandle or a path)
*
* returns:
* the targetted node offset in the base device tree
* Negative error code on error
*/
static int overlay_get_target(const void *fdt, const void *fdto,
int fragment)
{
uint32_t phandle;
const char *path;
int path_len;
/* Try first to do a phandle based lookup */
phandle = overlay_get_target_phandle(fdto, fragment);
if (phandle == (uint32_t)-1)
return -FDT_ERR_BADPHANDLE;
if (phandle)
return fdt_node_offset_by_phandle(fdt, phandle);
/* And then a path based lookup */
path = fdt_getprop(fdto, fragment, "target-path", &path_len);
if (!path) {
/*
* If we haven't found either a target or a
* target-path property in a node that contains a
* __overlay__ subnode (we wouldn't be called
* otherwise), consider it a improperly written
* overlay
*/
if (path_len == -FDT_ERR_NOTFOUND)
return -FDT_ERR_BADOVERLAY;
return path_len;
}
return fdt_path_offset(fdt, path);
}
/**
* overlay_phandle_add_offset - Increases a phandle by an offset
* @fdt: Base device tree blob
* @node: Device tree overlay blob
* @name: Name of the property to modify (phandle or linux,phandle)
* @delta: offset to apply
*
* overlay_phandle_add_offset() increments a node phandle by a given
* offset.
*
* returns:
* 0 on success.
* Negative error code on error
*/
static int overlay_phandle_add_offset(void *fdt, int node,
const char *name, uint32_t delta)
{
const uint32_t *val;
uint32_t adj_val;
int len;
val = fdt_getprop(fdt, node, name, &len);
if (!val)
return len;
if (len != sizeof(*val))
return -FDT_ERR_BADPHANDLE;
adj_val = fdt32_to_cpu(*val);
if ((adj_val + delta) < adj_val)
return -FDT_ERR_NOPHANDLES;
adj_val += delta;
if (adj_val == (uint32_t)-1)
return -FDT_ERR_NOPHANDLES;
return fdt_setprop_inplace_u32(fdt, node, name, adj_val);
}
/**
* overlay_adjust_node_phandles - Offsets the phandles of a node
* @fdto: Device tree overlay blob
* @node: Offset of the node we want to adjust
* @delta: Offset to shift the phandles of
*
* overlay_adjust_node_phandles() adds a constant to all the phandles
* of a given node. This is mainly use as part of the overlay
* application process, when we want to update all the overlay
* phandles to not conflict with the overlays of the base device tree.
*
* returns:
* 0 on success
* Negative error code on failure
*/
static int overlay_adjust_node_phandles(void *fdto, int node,
uint32_t delta)
{
int child;
int ret;
ret = overlay_phandle_add_offset(fdto, node, "phandle", delta);
if (ret && ret != -FDT_ERR_NOTFOUND)
return ret;
ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta);
if (ret && ret != -FDT_ERR_NOTFOUND)
return ret;
fdt_for_each_subnode(child, fdto, node) {
ret = overlay_adjust_node_phandles(fdto, child, delta);
if (ret)
return ret;
}
return 0;
}
/**
* overlay_adjust_local_phandles - Adjust the phandles of a whole overlay
* @fdto: Device tree overlay blob
* @delta: Offset to shift the phandles of
*
* overlay_adjust_local_phandles() adds a constant to all the
* phandles of an overlay. This is mainly use as part of the overlay
* application process, when we want to update all the overlay
* phandles to not conflict with the overlays of the base device tree.
*
* returns:
* 0 on success
* Negative error code on failure
*/
static int overlay_adjust_local_phandles(void *fdto, uint32_t delta)
{
/*
* Start adjusting the phandles from the overlay root
*/
return overlay_adjust_node_phandles(fdto, 0, delta);
}
/**
* overlay_update_local_node_references - Adjust the overlay references
* @fdto: Device tree overlay blob
* @tree_node: Node offset of the node to operate on
* @fixup_node: Node offset of the matching local fixups node
* @delta: Offset to shift the phandles of
*
* overlay_update_local_nodes_references() update the phandles
* pointing to a node within the device tree overlay by adding a
* constant delta.
*
* This is mainly used as part of a device tree application process,
* where you want the device tree overlays phandles to not conflict
* with the ones from the base device tree before merging them.
*
* returns:
* 0 on success
* Negative error code on failure
*/
static int overlay_update_local_node_references(void *fdto,
int tree_node,
int fixup_node,
uint32_t delta)
{
int fixup_prop;
int fixup_child;
int ret;
fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) {
const uint32_t *fixup_val;
const char *tree_val;
const char *name;
int fixup_len;
int tree_len;
int i;
fixup_val = fdt_getprop_by_offset(fdto, fixup_prop,
&name, &fixup_len);
if (!fixup_val)
return fixup_len;
if (fixup_len % sizeof(uint32_t))
return -FDT_ERR_BADOVERLAY;
tree_val = fdt_getprop(fdto, tree_node, name, &tree_len);
if (!tree_val) {
if (tree_len == -FDT_ERR_NOTFOUND)
return -FDT_ERR_BADOVERLAY;
return tree_len;
}
for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) {
uint32_t adj_val, poffset;
poffset = fdt32_to_cpu(fixup_val[i]);
/*
* phandles to fixup can be unaligned.
*
* Use a memcpy for the architectures that do
* not support unaligned accesses.
*/
memcpy(&adj_val, tree_val + poffset, sizeof(adj_val));
adj_val = fdt32_to_cpu(adj_val);
adj_val += delta;
adj_val = cpu_to_fdt32(adj_val);
ret = fdt_setprop_inplace_namelen_partial(fdto,
tree_node,
name,
strlen(name),
poffset,
&adj_val,
sizeof(adj_val));
if (ret == -FDT_ERR_NOSPACE)
return -FDT_ERR_BADOVERLAY;
if (ret)
return ret;
}
}
fdt_for_each_subnode(fixup_child, fdto, fixup_node) {
const char *fixup_child_name = fdt_get_name(fdto, fixup_child,
NULL);
int tree_child;
tree_child = fdt_subnode_offset(fdto, tree_node,
fixup_child_name);
if (ret == -FDT_ERR_NOTFOUND)
return -FDT_ERR_BADOVERLAY;
if (tree_child < 0)
return tree_child;
ret = overlay_update_local_node_references(fdto,
tree_child,
fixup_child,
delta);
if (ret)
return ret;
}
return 0;
}
/**
* overlay_update_local_references - Adjust the overlay references
* @fdto: Device tree overlay blob
* @delta: Offset to shift the phandles of
*
* overlay_update_local_references() update all the phandles pointing
* to a node within the device tree overlay by adding a constant
* delta to not conflict with the base overlay.
*
* This is mainly used as part of a device tree application process,
* where you want the device tree overlays phandles to not conflict
* with the ones from the base device tree before merging them.
*
* returns:
* 0 on success
* Negative error code on failure
*/
static int overlay_update_local_references(void *fdto, uint32_t delta)
{
int fixups;
fixups = fdt_path_offset(fdto, "/__local_fixups__");
if (fixups < 0) {
/* There's no local phandles to adjust, bail out */
if (fixups == -FDT_ERR_NOTFOUND)
return 0;
return fixups;
}
/*
* Update our local references from the root of the tree
*/
return overlay_update_local_node_references(fdto, 0, fixups,
delta);
}
/**
* overlay_fixup_one_phandle - Set an overlay phandle to the base one
* @fdt: Base Device Tree blob
* @fdto: Device tree overlay blob
* @symbols_off: Node offset of the symbols node in the base device tree
* @path: Path to a node holding a phandle in the overlay
* @path_len: number of path characters to consider
* @name: Name of the property holding the phandle reference in the overlay
* @name_len: number of name characters to consider
* @poffset: Offset within the overlay property where the phandle is stored
* @label: Label of the node referenced by the phandle
*
* overlay_fixup_one_phandle() resolves an overlay phandle pointing to
* a node in the base device tree.
*
* This is part of the device tree overlay application process, when
* you want all the phandles in the overlay to point to the actual
* base dt nodes.
*
* returns:
* 0 on success
* Negative error code on failure
*/
static int overlay_fixup_one_phandle(void *fdt, void *fdto,
int symbols_off,
const char *path, uint32_t path_len,
const char *name, uint32_t name_len,
int poffset, const char *label)
{
const char *symbol_path;
uint32_t phandle;
int symbol_off, fixup_off;
int prop_len;
if (symbols_off < 0)
return symbols_off;
symbol_path = fdt_getprop(fdt, symbols_off, label,
&prop_len);
if (!symbol_path)
return prop_len;
symbol_off = fdt_path_offset(fdt, symbol_path);
if (symbol_off < 0)
return symbol_off;
phandle = fdt_get_phandle(fdt, symbol_off);
if (!phandle)
return -FDT_ERR_NOTFOUND;
fixup_off = fdt_path_offset_namelen(fdto, path, path_len);
if (fixup_off == -FDT_ERR_NOTFOUND)
return -FDT_ERR_BADOVERLAY;
if (fixup_off < 0)
return fixup_off;
phandle = cpu_to_fdt32(phandle);
return fdt_setprop_inplace_namelen_partial(fdto, fixup_off,
name, name_len, poffset,
&phandle, sizeof(phandle));
};
/**
* overlay_fixup_phandle - Set an overlay phandle to the base one
* @fdt: Base Device Tree blob
* @fdto: Device tree overlay blob
* @symbols_off: Node offset of the symbols node in the base device tree
* @property: Property offset in the overlay holding the list of fixups
*
* overlay_fixup_phandle() resolves all the overlay phandles pointed
* to in a __fixups__ property, and updates them to match the phandles
* in use in the base device tree.
*
* This is part of the device tree overlay application process, when
* you want all the phandles in the overlay to point to the actual
* base dt nodes.
*
* returns:
* 0 on success
* Negative error code on failure
*/
static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
int property)
{
const char *value;
const char *label;
int len;
value = fdt_getprop_by_offset(fdto, property,
&label, &len);
if (!value) {
if (len == -FDT_ERR_NOTFOUND)
return -FDT_ERR_INTERNAL;
return len;
}
do {
const char *path, *name, *fixup_end;
const char *fixup_str = value;
uint32_t path_len, name_len;
uint32_t fixup_len;
char *sep, *endptr;
int poffset, ret;
fixup_end = memchr(value, '\0', len);
if (!fixup_end)
return -FDT_ERR_BADOVERLAY;
fixup_len = fixup_end - fixup_str;
len -= fixup_len + 1;
value += fixup_len + 1;
path = fixup_str;
sep = memchr(fixup_str, ':', fixup_len);
if (!sep || *sep != ':')
return -FDT_ERR_BADOVERLAY;
path_len = sep - path;
if (path_len == (fixup_len - 1))
return -FDT_ERR_BADOVERLAY;
fixup_len -= path_len + 1;
name = sep + 1;
sep = memchr(name, ':', fixup_len);
if (!sep || *sep != ':')
return -FDT_ERR_BADOVERLAY;
name_len = sep - name;
if (!name_len)
return -FDT_ERR_BADOVERLAY;
poffset = strtoul(sep + 1, &endptr, 10);
if ((*endptr != '\0') || (endptr <= (sep + 1)))
return -FDT_ERR_BADOVERLAY;
ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off,
path, path_len, name, name_len,
poffset, label);
if (ret)
return ret;
} while (len > 0);
return 0;
}
/**
* overlay_fixup_phandles - Resolve the overlay phandles to the base
* device tree
* @fdt: Base Device Tree blob
* @fdto: Device tree overlay blob
*
* overlay_fixup_phandles() resolves all the overlay phandles pointing
* to nodes in the base device tree.
*
* This is one of the steps of the device tree overlay application
* process, when you want all the phandles in the overlay to point to
* the actual base dt nodes.
*
* returns:
* 0 on success
* Negative error code on failure
*/
static int overlay_fixup_phandles(void *fdt, void *fdto)
{
int fixups_off, symbols_off;
int property;
/* We can have overlays without any fixups */
fixups_off = fdt_path_offset(fdto, "/__fixups__");
if (fixups_off == -FDT_ERR_NOTFOUND)
return 0; /* nothing to do */
if (fixups_off < 0)
return fixups_off;
/* And base DTs without symbols */
symbols_off = fdt_path_offset(fdt, "/__symbols__");
if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND)))
return symbols_off;
fdt_for_each_property_offset(property, fdto, fixups_off) {
int ret;
ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property);
if (ret)
return ret;
}
return 0;
}
/**
* overlay_apply_node - Merges a node into the base device tree
* @fdt: Base Device Tree blob
* @target: Node offset in the base device tree to apply the fragment to
* @fdto: Device tree overlay blob
* @node: Node offset in the overlay holding the changes to merge
*
* overlay_apply_node() merges a node into a target base device tree
* node pointed.
*
* This is part of the final step in the device tree overlay
* application process, when all the phandles have been adjusted and
* resolved and you just have to merge overlay into the base device
* tree.
*
* returns:
* 0 on success
* Negative error code on failure
*/
static int overlay_apply_node(void *fdt, int target,
void *fdto, int node)
{
int property;
int subnode;
fdt_for_each_property_offset(property, fdto, node) {
const char *name;
const void *prop;
int prop_len;
int ret;
prop = fdt_getprop_by_offset(fdto, property, &name,
&prop_len);
if (prop_len == -FDT_ERR_NOTFOUND)
return -FDT_ERR_INTERNAL;
if (prop_len < 0)
return prop_len;
ret = fdt_setprop(fdt, target, name, prop, prop_len);
if (ret)
return ret;
}
fdt_for_each_subnode(subnode, fdto, node) {
const char *name = fdt_get_name(fdto, subnode, NULL);
int nnode;
int ret;
nnode = fdt_add_subnode(fdt, target, name);
if (nnode == -FDT_ERR_EXISTS) {
nnode = fdt_subnode_offset(fdt, target, name);
if (nnode == -FDT_ERR_NOTFOUND)
return -FDT_ERR_INTERNAL;
}
if (nnode < 0)
return nnode;
ret = overlay_apply_node(fdt, nnode, fdto, subnode);
if (ret)
return ret;
}
return 0;
}
/**
* overlay_merge - Merge an overlay into its base device tree
* @fdt: Base Device Tree blob
* @fdto: Device tree overlay blob
*
* overlay_merge() merges an overlay into its base device tree.
*
* This is the final step in the device tree overlay application
* process, when all the phandles have been adjusted and resolved and
* you just have to merge overlay into the base device tree.
*
* returns:
* 0 on success
* Negative error code on failure
*/
static int overlay_merge(void *fdt, void *fdto)
{
int fragment;
fdt_for_each_subnode(fragment, fdto, 0) {
int overlay;
int target;
int ret;
/*
* Each fragments will have an __overlay__ node. If
* they don't, it's not supposed to be merged
*/
overlay = fdt_subnode_offset(fdto, fragment, "__overlay__");
if (overlay == -FDT_ERR_NOTFOUND)
continue;
if (overlay < 0)
return overlay;
target = overlay_get_target(fdt, fdto, fragment);
if (target < 0)
return target;
ret = overlay_apply_node(fdt, target, fdto, overlay);
if (ret)
return ret;
}
return 0;
}
int fdt_overlay_apply(void *fdt, void *fdto)
{
uint32_t delta = fdt_get_max_phandle(fdt);
int ret;
FDT_CHECK_HEADER(fdt);
FDT_CHECK_HEADER(fdto);
ret = overlay_adjust_local_phandles(fdto, delta);
if (ret)
goto err;
ret = overlay_update_local_references(fdto, delta);
if (ret)
goto err;
ret = overlay_fixup_phandles(fdt, fdto);
if (ret)
goto err;
ret = overlay_merge(fdt, fdto);
if (ret)
goto err;
/*
* The overlay has been damaged, erase its magic.
*/
fdt_set_magic(fdto, ~0);
return 0;
err:
/*
* The overlay might have been damaged, erase its magic.
*/
fdt_set_magic(fdto, ~0);
/*
* The base device tree might have been damaged, erase its
* magic.
*/
fdt_set_magic(fdt, ~0);
return ret;
}

View file

@ -88,6 +88,32 @@ static int _fdt_string_eq(const void *fdt, int stroffset,
return (strlen(p) == len) && (memcmp(p, s, len) == 0);
}
uint32_t fdt_get_max_phandle(const void *fdt)
{
uint32_t max_phandle = 0;
int offset;
for (offset = fdt_next_node(fdt, -1, NULL);;
offset = fdt_next_node(fdt, offset, NULL)) {
uint32_t phandle;
if (offset == -FDT_ERR_NOTFOUND)
return max_phandle;
if (offset < 0)
return (uint32_t)-1;
phandle = fdt_get_phandle(fdt, offset);
if (phandle == (uint32_t)-1)
continue;
if (phandle > max_phandle)
max_phandle = phandle;
}
return 0;
}
int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
{
FDT_CHECK_HEADER(fdt);
@ -545,7 +571,7 @@ int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property)
list = fdt_getprop(fdt, nodeoffset, property, &length);
if (!list)
return -length;
return length;
end = list + length;
@ -571,7 +597,7 @@ int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
list = fdt_getprop(fdt, nodeoffset, property, &length);
if (!list)
return -length;
return length;
len = strlen(string) + 1;
end = list + length;

View file

@ -191,17 +191,13 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
int fdt_del_mem_rsv(void *fdt, int n)
{
struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
int err;
FDT_RW_CHECK_HEADER(fdt);
if (n >= fdt_num_mem_rsv(fdt))
return -FDT_ERR_NOTFOUND;
err = _fdt_splice_mem_rsv(fdt, re, 1, 0);
if (err)
return err;
return 0;
return _fdt_splice_mem_rsv(fdt, re, 1, 0);
}
static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,

View file

@ -69,6 +69,7 @@ static struct fdt_errtabent fdt_errtable[] = {
FDT_ERRTABENT(FDT_ERR_BADOFFSET),
FDT_ERRTABENT(FDT_ERR_BADPATH),
FDT_ERRTABENT(FDT_ERR_BADPHANDLE),
FDT_ERRTABENT(FDT_ERR_BADSTATE),
FDT_ERRTABENT(FDT_ERR_TRUNCATED),
@ -76,6 +77,11 @@ static struct fdt_errtabent fdt_errtable[] = {
FDT_ERRTABENT(FDT_ERR_BADVERSION),
FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE),
FDT_ERRTABENT(FDT_ERR_BADLAYOUT),
FDT_ERRTABENT(FDT_ERR_INTERNAL),
FDT_ERRTABENT(FDT_ERR_BADNCELLS),
FDT_ERRTABENT(FDT_ERR_BADVALUE),
FDT_ERRTABENT(FDT_ERR_BADOVERLAY),
FDT_ERRTABENT(FDT_ERR_NOPHANDLES),
};
#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))

View file

@ -55,21 +55,42 @@
#include "libfdt_internal.h"
int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
const void *val, int len)
int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
const char *name, int namelen,
uint32_t idx, const void *val,
int len)
{
void *propval;
int proplen;
propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen);
propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen,
&proplen);
if (!propval)
return proplen;
if (proplen < (len + idx))
return -FDT_ERR_NOSPACE;
memcpy((char *)propval + idx, val, len);
return 0;
}
int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
const void *val, int len)
{
const void *propval;
int proplen;
propval = fdt_getprop(fdt, nodeoffset, name, &proplen);
if (! propval)
return proplen;
if (proplen != len)
return -FDT_ERR_NOSPACE;
memcpy(propval, val, len);
return 0;
return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name,
strlen(name), 0,
val, len);
}
static void _fdt_nop_region(void *start, int len)

View file

@ -61,7 +61,7 @@
#define FDT_ERR_NOTFOUND 1
/* FDT_ERR_NOTFOUND: The requested node or property does not exist */
#define FDT_ERR_EXISTS 2
/* FDT_ERR_EXISTS: Attemped to create a node or property which
/* FDT_ERR_EXISTS: Attempted to create a node or property which
* already exists */
#define FDT_ERR_NOSPACE 3
/* FDT_ERR_NOSPACE: Operation needed to expand the device
@ -79,8 +79,10 @@
* (e.g. missing a leading / for a function which requires an
* absolute path) */
#define FDT_ERR_BADPHANDLE 6
/* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle
* value. phandle values of 0 and -1 are not permitted. */
/* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle.
* This can be caused either by an invalid phandle property
* length, or the phandle value was either 0 or -1, which are
* not permitted. */
#define FDT_ERR_BADSTATE 7
/* FDT_ERR_BADSTATE: Function was passed an incomplete device
* tree created by the sequential-write functions, which is
@ -126,7 +128,16 @@
* value. For example: a property expected to contain a string list
* is not NUL-terminated within the length of its value. */
#define FDT_ERR_MAX 15
#define FDT_ERR_BADOVERLAY 16
/* FDT_ERR_BADOVERLAY: The device tree overlay, while
* correctly structured, cannot be applied due to some
* unexpected or missing value, property or node. */
#define FDT_ERR_NOPHANDLES 17
/* FDT_ERR_NOPHANDLES: The device tree doesn't have any
* phandle available anymore without causing an overflow */
#define FDT_ERR_MAX 17
/**********************************************************************/
/* Low-level functions (you probably don't need these) */
@ -168,27 +179,55 @@ int fdt_first_subnode(const void *fdt, int offset);
*/
int fdt_next_subnode(const void *fdt, int offset);
/**
* fdt_for_each_subnode - iterate over all subnodes of a parent
*
* @node: child node (int, lvalue)
* @fdt: FDT blob (const void *)
* @parent: parent node (int)
*
* This is actually a wrapper around a for loop and would be used like so:
*
* fdt_for_each_subnode(node, fdt, parent) {
* Use node
* ...
* }
*
* if ((node < 0) && (node != -FDT_ERR_NOT_FOUND)) {
* Error handling
* }
*
* Note that this is implemented as a macro and @node is used as
* iterator in the loop. The parent variable be constant or even a
* literal.
*
*/
#define fdt_for_each_subnode(node, fdt, parent) \
for (node = fdt_first_subnode(fdt, parent); \
node >= 0; \
node = fdt_next_subnode(fdt, node))
/**********************************************************************/
/* General functions */
/**********************************************************************/
#define fdt_get_header(fdt, field) \
(fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
#define fdt_magic(fdt) (fdt_get_header(fdt, magic))
#define fdt_magic(fdt) (fdt_get_header(fdt, magic))
#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize))
#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct))
#define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings))
#define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap))
#define fdt_version(fdt) (fdt_get_header(fdt, version))
#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version))
#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys))
#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings))
#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version))
#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys))
#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings))
#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct))
#define __fdt_set_hdr(name) \
static inline void fdt_set_##name(void *fdt, uint32_t val) \
{ \
struct fdt_header *fdth = (struct fdt_header*)fdt; \
struct fdt_header *fdth = (struct fdt_header *)fdt; \
fdth->name = cpu_to_fdt32(val); \
}
__fdt_set_hdr(magic);
@ -258,6 +297,21 @@ int fdt_move(const void *fdt, void *buf, int bufsize);
*/
const char *fdt_string(const void *fdt, int stroffset);
/**
* fdt_get_max_phandle - retrieves the highest phandle in a tree
* @fdt: pointer to the device tree blob
*
* fdt_get_max_phandle retrieves the highest phandle in the given
* device tree. This will ignore badly formatted phandles, or phandles
* with a value of 0 or -1.
*
* returns:
* the highest phandle on success
* 0, if no phandle was found in the device tree
* -1, if an error occurred
*/
uint32_t fdt_get_max_phandle(const void *fdt);
/**
* fdt_num_mem_rsv - retrieve the number of memory reserve map entries
* @fdt: pointer to the device tree blob
@ -318,8 +372,9 @@ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
* returns:
* structure block offset of the requested subnode (>=0), on success
* -FDT_ERR_NOTFOUND, if the requested subnode does not exist
* -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE
* tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
@ -351,7 +406,8 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen);
* address).
*
* returns:
* structure block offset of the node with the requested path (>=0), on success
* structure block offset of the node with the requested path (>=0), on
* success
* -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid
* -FDT_ERR_NOTFOUND, if the requested node does not exist
* -FDT_ERR_BADMAGIC,
@ -375,10 +431,12 @@ int fdt_path_offset(const void *fdt, const char *path);
*
* returns:
* pointer to the node's name, on success
* If lenp is non-NULL, *lenp contains the length of that name (>=0)
* If lenp is non-NULL, *lenp contains the length of that name
* (>=0)
* NULL, on error
* if lenp is non-NULL *lenp contains an error code (<0):
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
* tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE, standard meanings
@ -426,6 +484,33 @@ int fdt_first_property_offset(const void *fdt, int nodeoffset);
*/
int fdt_next_property_offset(const void *fdt, int offset);
/**
* fdt_for_each_property_offset - iterate over all properties of a node
*
* @property_offset: property offset (int, lvalue)
* @fdt: FDT blob (const void *)
* @node: node offset (int)
*
* This is actually a wrapper around a for loop and would be used like so:
*
* fdt_for_each_property_offset(property, fdt, node) {
* Use property
* ...
* }
*
* if ((property < 0) && (property != -FDT_ERR_NOT_FOUND)) {
* Error handling
* }
*
* Note that this is implemented as a macro and property is used as
* iterator in the loop. The node variable can be constant or even a
* literal.
*/
#define fdt_for_each_property_offset(property, fdt, node) \
for (property = fdt_first_property_offset(fdt, node); \
property >= 0; \
property = fdt_next_property_offset(fdt, property))
/**
* fdt_get_property_by_offset - retrieve the property at a given offset
* @fdt: pointer to the device tree blob
@ -490,7 +575,8 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt,
* NULL, on error
* if lenp is non-NULL, *lenp contains an error code (<0):
* -FDT_ERR_NOTFOUND, node does not have named property
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
* tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
@ -554,6 +640,13 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
*/
const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
const char *name, int namelen, int *lenp);
static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset,
const char *name, int namelen,
int *lenp)
{
return (void *)(uintptr_t)fdt_getprop_namelen(fdt, nodeoffset, name,
namelen, lenp);
}
/**
* fdt_getprop - retrieve the value of a given property
@ -575,7 +668,8 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
* NULL, on error
* if lenp is non-NULL, *lenp contains an error code (<0):
* -FDT_ERR_NOTFOUND, node does not have named property
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
* tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
@ -617,7 +711,7 @@ const char *fdt_get_alias_namelen(const void *fdt,
const char *name, int namelen);
/**
* fdt_get_alias - retreive the path referenced by a given alias
* fdt_get_alias - retrieve the path referenced by a given alias
* @fdt: pointer to the device tree blob
* @name: name of the alias th look up
*
@ -647,7 +741,7 @@ const char *fdt_get_alias(const void *fdt, const char *name);
* 0, on success
* buf contains the absolute path of the node at
* nodeoffset, as a NUL-terminated string.
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
* -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1)
* characters and will not fit in the given buffer.
* -FDT_ERR_BADMAGIC,
@ -677,11 +771,11 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen);
* structure from the start to nodeoffset.
*
* returns:
* structure block offset of the node at node offset's ancestor
* of depth supernodedepth (>=0), on success
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
* -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
* -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of
* nodeoffset
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
@ -703,7 +797,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
*
* returns:
* depth of the node at nodeoffset (>=0), on success
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
@ -726,7 +820,7 @@ int fdt_node_depth(const void *fdt, int nodeoffset);
* returns:
* structure block offset of the parent of the node at nodeoffset
* (>=0), on success
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
@ -766,7 +860,7 @@ int fdt_parent_offset(const void *fdt, int nodeoffset);
* on success
* -FDT_ERR_NOTFOUND, no node matching the criterion exists in the
* tree after startoffset
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
@ -813,7 +907,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle);
* 1, if the node has a 'compatible' property, but it does not list
* the given string
* -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property
* -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag
* -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
@ -850,7 +944,7 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset,
* on success
* -FDT_ERR_NOTFOUND, no node matching the criterion exists in the
* tree after startoffset
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
@ -960,7 +1054,8 @@ const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
* returns:
* 0 <= n < FDT_MAX_NCELLS, on success
* 2, if the node has no #address-cells property
* -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid #address-cells property
* -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
* #address-cells property
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
@ -980,7 +1075,8 @@ int fdt_address_cells(const void *fdt, int nodeoffset);
* returns:
* 0 <= n < FDT_MAX_NCELLS, on success
* 2, if the node has no #address-cells property
* -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid #size-cells property
* -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
* #size-cells property
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
@ -994,6 +1090,27 @@ int fdt_size_cells(const void *fdt, int nodeoffset);
/* Write-in-place functions */
/**********************************************************************/
/**
* fdt_setprop_inplace_namelen_partial - change a property's value,
* but not its size
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node whose property to change
* @name: name of the property to change
* @namelen: number of characters of name to consider
* @idx: index of the property to change in the array
* @val: pointer to data to replace the property value with
* @len: length of the property value
*
* Identical to fdt_setprop_inplace(), but modifies the given property
* starting from the given index, and using only the first characters
* of the name. It is useful when you want to manipulate only one value of
* an array and you have a string that doesn't end with \0.
*/
int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
const char *name, int namelen,
uint32_t idx, const void *val,
int len);
/**
* fdt_setprop_inplace - change a property's value, but not its size
* @fdt: pointer to the device tree blob
@ -1604,9 +1721,11 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
* change the offsets of some existing nodes.
* returns:
* structure block offset of the created nodeequested subnode (>=0), on success
* structure block offset of the created nodeequested subnode (>=0), on
* success
* -FDT_ERR_NOTFOUND, if the requested subnode does not exist
* -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
* -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE
* tag
* -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of
* the given name
* -FDT_ERR_NOSPACE, if there is insufficient free space in the
@ -1644,6 +1763,37 @@ int fdt_add_subnode(void *fdt, int parentoffset, const char *name);
*/
int fdt_del_node(void *fdt, int nodeoffset);
/**
* fdt_overlay_apply - Applies a DT overlay on a base DT
* @fdt: pointer to the base device tree blob
* @fdto: pointer to the device tree overlay blob
*
* fdt_overlay_apply() will apply the given device tree overlay on the
* given base device tree.
*
* Expect the base device tree to be modified, even if the function
* returns an error.
*
* returns:
* 0, on success
* -FDT_ERR_NOSPACE, there's not enough space in the base device tree
* -FDT_ERR_NOTFOUND, the overlay points to some inexistant nodes or
* properties in the base DT
* -FDT_ERR_BADPHANDLE,
* -FDT_ERR_BADOVERLAY,
* -FDT_ERR_NOPHANDLES,
* -FDT_ERR_INTERNAL,
* -FDT_ERR_BADLAYOUT,
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADOFFSET,
* -FDT_ERR_BADPATH,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_TRUNCATED, standard meanings
*/
int fdt_overlay_apply(void *fdt, void *fdto);
/**********************************************************************/
/* Debugging / informational functions */
/**********************************************************************/

View file

@ -54,6 +54,7 @@
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#ifdef __CHECKER__

View file

@ -204,7 +204,7 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
}
}
/* if no collision occured, add child to the old node. */
/* if no collision occurred, add child to the old node. */
if (new_child)
add_child(old_node, new_child);
}
@ -216,6 +216,28 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node)
return old_node;
}
void add_orphan_node(struct node *dt, struct node *new_node, char *ref)
{
static unsigned int next_orphan_fragment;
struct node *node;
struct property *p;
struct data d = empty_data;
char *name;
d = data_add_marker(d, REF_PHANDLE, ref);
d = data_append_integer(d, 0xffffffff, 32);
p = build_property("target", d);
xasprintf(&name, "fragment@%u",
next_orphan_fragment++);
name_node(new_node, "__overlay__");
node = build_node(p, new_node);
name_node(node, name);
add_child(dt, node);
}
struct node *chain_node(struct node *first, struct node *list)
{
assert(first->next_sibling == NULL);
@ -242,7 +264,7 @@ void delete_property_by_name(struct node *node, char *name)
struct property *prop = node->proplist;
while (prop) {
if (!strcmp(prop->name, name)) {
if (streq(prop->name, name)) {
delete_property(prop);
return;
}
@ -275,7 +297,7 @@ void delete_node_by_name(struct node *parent, char *name)
struct node *node = parent->children;
while (node) {
if (!strcmp(node->name, name)) {
if (streq(node->name, name)) {
delete_node(node);
return;
}
@ -296,6 +318,23 @@ void delete_node(struct node *node)
delete_labels(&node->labels);
}
void append_to_property(struct node *node,
char *name, const void *data, int len)
{
struct data d;
struct property *p;
p = get_property(node, name);
if (p) {
d = data_append_data(p->val, data, len);
p->val = d;
} else {
d = data_append_data(empty_data, data, len);
p = build_property(name, d);
add_property(node, p);
}
}
struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size)
{
struct reserve_info *new = xmalloc(sizeof(*new));
@ -335,17 +374,19 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
return list;
}
struct boot_info *build_boot_info(struct reserve_info *reservelist,
struct node *tree, uint32_t boot_cpuid_phys)
struct dt_info *build_dt_info(unsigned int dtsflags,
struct reserve_info *reservelist,
struct node *tree, uint32_t boot_cpuid_phys)
{
struct boot_info *bi;
struct dt_info *dti;
bi = xmalloc(sizeof(*bi));
bi->reservelist = reservelist;
bi->dt = tree;
bi->boot_cpuid_phys = boot_cpuid_phys;
dti = xmalloc(sizeof(*dti));
dti->dtsflags = dtsflags;
dti->reservelist = reservelist;
dti->dt = tree;
dti->boot_cpuid_phys = boot_cpuid_phys;
return bi;
return dti;
}
/*
@ -592,12 +633,12 @@ static int cmp_reserve_info(const void *ax, const void *bx)
return 0;
}
static void sort_reserve_entries(struct boot_info *bi)
static void sort_reserve_entries(struct dt_info *dti)
{
struct reserve_info *ri, **tbl;
int n = 0, i = 0;
for (ri = bi->reservelist;
for (ri = dti->reservelist;
ri;
ri = ri->next)
n++;
@ -607,14 +648,14 @@ static void sort_reserve_entries(struct boot_info *bi)
tbl = xmalloc(n * sizeof(*tbl));
for (ri = bi->reservelist;
for (ri = dti->reservelist;
ri;
ri = ri->next)
tbl[i++] = ri;
qsort(tbl, n, sizeof(*tbl), cmp_reserve_info);
bi->reservelist = tbl[0];
dti->reservelist = tbl[0];
for (i = 0; i < (n-1); i++)
tbl[i]->next = tbl[i+1];
tbl[n-1]->next = NULL;
@ -704,8 +745,258 @@ static void sort_node(struct node *node)
sort_node(c);
}
void sort_tree(struct boot_info *bi)
void sort_tree(struct dt_info *dti)
{
sort_reserve_entries(bi);
sort_node(bi->dt);
sort_reserve_entries(dti);
sort_node(dti->dt);
}
/* utility helper to avoid code duplication */
static struct node *build_and_name_child_node(struct node *parent, char *name)
{
struct node *node;
node = build_node(NULL, NULL);
name_node(node, xstrdup(name));
add_child(parent, node);
return node;
}
static struct node *build_root_node(struct node *dt, char *name)
{
struct node *an;
an = get_subnode(dt, name);
if (!an)
an = build_and_name_child_node(dt, name);
if (!an)
die("Could not build root node /%s\n", name);
return an;
}
static bool any_label_tree(struct dt_info *dti, struct node *node)
{
struct node *c;
if (node->labels)
return true;
for_each_child(node, c)
if (any_label_tree(dti, c))
return true;
return false;
}
static void generate_label_tree_internal(struct dt_info *dti,
struct node *an, struct node *node,
bool allocph)
{
struct node *dt = dti->dt;
struct node *c;
struct property *p;
struct label *l;
/* if there are labels */
if (node->labels) {
/* now add the label in the node */
for_each_label(node->labels, l) {
/* check whether the label already exists */
p = get_property(an, l->label);
if (p) {
fprintf(stderr, "WARNING: label %s already"
" exists in /%s", l->label,
an->name);
continue;
}
/* insert it */
p = build_property(l->label,
data_copy_mem(node->fullpath,
strlen(node->fullpath) + 1));
add_property(an, p);
}
/* force allocation of a phandle for this node */
if (allocph)
(void)get_node_phandle(dt, node);
}
for_each_child(node, c)
generate_label_tree_internal(dti, an, c, allocph);
}
static bool any_fixup_tree(struct dt_info *dti, struct node *node)
{
struct node *c;
struct property *prop;
struct marker *m;
for_each_property(node, prop) {
m = prop->val.markers;
for_each_marker_of_type(m, REF_PHANDLE) {
if (!get_node_by_ref(dti->dt, m->ref))
return true;
}
}
for_each_child(node, c) {
if (any_fixup_tree(dti, c))
return true;
}
return false;
}
static void add_fixup_entry(struct dt_info *dti, struct node *fn,
struct node *node, struct property *prop,
struct marker *m)
{
char *entry;
/* m->ref can only be a REF_PHANDLE, but check anyway */
assert(m->type == REF_PHANDLE);
/* there shouldn't be any ':' in the arguments */
if (strchr(node->fullpath, ':') || strchr(prop->name, ':'))
die("arguments should not contain ':'\n");
xasprintf(&entry, "%s:%s:%u",
node->fullpath, prop->name, m->offset);
append_to_property(fn, m->ref, entry, strlen(entry) + 1);
free(entry);
}
static void generate_fixups_tree_internal(struct dt_info *dti,
struct node *fn,
struct node *node)
{
struct node *dt = dti->dt;
struct node *c;
struct property *prop;
struct marker *m;
struct node *refnode;
for_each_property(node, prop) {
m = prop->val.markers;
for_each_marker_of_type(m, REF_PHANDLE) {
refnode = get_node_by_ref(dt, m->ref);
if (!refnode)
add_fixup_entry(dti, fn, node, prop, m);
}
}
for_each_child(node, c)
generate_fixups_tree_internal(dti, fn, c);
}
static bool any_local_fixup_tree(struct dt_info *dti, struct node *node)
{
struct node *c;
struct property *prop;
struct marker *m;
for_each_property(node, prop) {
m = prop->val.markers;
for_each_marker_of_type(m, REF_PHANDLE) {
if (get_node_by_ref(dti->dt, m->ref))
return true;
}
}
for_each_child(node, c) {
if (any_local_fixup_tree(dti, c))
return true;
}
return false;
}
static void add_local_fixup_entry(struct dt_info *dti,
struct node *lfn, struct node *node,
struct property *prop, struct marker *m,
struct node *refnode)
{
struct node *wn, *nwn; /* local fixup node, walk node, new */
uint32_t value_32;
char **compp;
int i, depth;
/* walk back retreiving depth */
depth = 0;
for (wn = node; wn; wn = wn->parent)
depth++;
/* allocate name array */
compp = xmalloc(sizeof(*compp) * depth);
/* store names in the array */
for (wn = node, i = depth - 1; wn; wn = wn->parent, i--)
compp[i] = wn->name;
/* walk the path components creating nodes if they don't exist */
for (wn = lfn, i = 1; i < depth; i++, wn = nwn) {
/* if no node exists, create it */
nwn = get_subnode(wn, compp[i]);
if (!nwn)
nwn = build_and_name_child_node(wn, compp[i]);
}
free(compp);
value_32 = cpu_to_fdt32(m->offset);
append_to_property(wn, prop->name, &value_32, sizeof(value_32));
}
static void generate_local_fixups_tree_internal(struct dt_info *dti,
struct node *lfn,
struct node *node)
{
struct node *dt = dti->dt;
struct node *c;
struct property *prop;
struct marker *m;
struct node *refnode;
for_each_property(node, prop) {
m = prop->val.markers;
for_each_marker_of_type(m, REF_PHANDLE) {
refnode = get_node_by_ref(dt, m->ref);
if (refnode)
add_local_fixup_entry(dti, lfn, node, prop, m, refnode);
}
}
for_each_child(node, c)
generate_local_fixups_tree_internal(dti, lfn, c);
}
void generate_label_tree(struct dt_info *dti, char *name, bool allocph)
{
if (!any_label_tree(dti, dti->dt))
return;
generate_label_tree_internal(dti, build_root_node(dti->dt, name),
dti->dt, allocph);
}
void generate_fixups_tree(struct dt_info *dti, char *name)
{
if (!any_fixup_tree(dti, dti->dt))
return;
generate_fixups_tree_internal(dti, build_root_node(dti->dt, name),
dti->dt);
}
void generate_local_fixups_tree(struct dt_info *dti, char *name)
{
if (!any_local_fixup_tree(dti, dti->dt))
return;
generate_local_fixups_tree_internal(dti, build_root_node(dti->dt, name),
dti->dt);
}

View file

@ -246,46 +246,27 @@ srcpos_copy(struct srcpos *pos)
return pos_new;
}
void
srcpos_dump(struct srcpos *pos)
{
printf("file : \"%s\"\n",
pos->file ? (char *) pos->file : "<no file>");
printf("first_line : %d\n", pos->first_line);
printf("first_column: %d\n", pos->first_column);
printf("last_line : %d\n", pos->last_line);
printf("last_column : %d\n", pos->last_column);
printf("file : %s\n", pos->file->name);
}
char *
srcpos_string(struct srcpos *pos)
{
const char *fname = "<no-file>";
char *pos_str;
int rc;
if (pos)
if (pos->file && pos->file->name)
fname = pos->file->name;
if (pos->first_line != pos->last_line)
rc = asprintf(&pos_str, "%s:%d.%d-%d.%d", fname,
pos->first_line, pos->first_column,
pos->last_line, pos->last_column);
xasprintf(&pos_str, "%s:%d.%d-%d.%d", fname,
pos->first_line, pos->first_column,
pos->last_line, pos->last_column);
else if (pos->first_column != pos->last_column)
rc = asprintf(&pos_str, "%s:%d.%d-%d", fname,
pos->first_line, pos->first_column,
pos->last_column);
xasprintf(&pos_str, "%s:%d.%d-%d", fname,
pos->first_line, pos->first_column,
pos->last_column);
else
rc = asprintf(&pos_str, "%s:%d.%d", fname,
pos->first_line, pos->first_column);
if (rc == -1)
die("Couldn't allocate in srcpos string");
xasprintf(&pos_str, "%s:%d.%d", fname,
pos->first_line, pos->first_column);
return pos_str;
}

View file

@ -105,7 +105,6 @@ extern struct srcpos srcpos_empty;
extern void srcpos_update(struct srcpos *pos, const char *text, int len);
extern struct srcpos *srcpos_copy(struct srcpos *pos);
extern char *srcpos_string(struct srcpos *pos);
extern void srcpos_dump(struct srcpos *pos);
extern void srcpos_verror(struct srcpos *pos, const char *prefix,
const char *fmt, va_list va)

View file

@ -25,12 +25,12 @@ extern FILE *yyin;
extern int yyparse(void);
extern YYLTYPE yylloc;
struct boot_info *the_boot_info;
struct dt_info *parser_output;
bool treesource_error;
struct boot_info *dt_from_source(const char *fname)
struct dt_info *dt_from_source(const char *fname)
{
the_boot_info = NULL;
parser_output = NULL;
treesource_error = false;
srcfile_push(fname);
@ -43,7 +43,7 @@ struct boot_info *dt_from_source(const char *fname)
if (treesource_error)
die("Syntax error parsing input tree\n");
return the_boot_info;
return parser_output;
}
static void write_prefix(FILE *f, int level)
@ -263,13 +263,13 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level)
}
void dt_to_source(FILE *f, struct boot_info *bi)
void dt_to_source(FILE *f, struct dt_info *dti)
{
struct reserve_info *re;
fprintf(f, "/dts-v1/;\n\n");
for (re = bi->reservelist; re; re = re->next) {
for (re = dti->reservelist; re; re = re->next) {
struct label *l;
for_each_label(re->labels, l)
@ -279,6 +279,6 @@ void dt_to_source(FILE *f, struct boot_info *bi)
(unsigned long long)re->re.size);
}
write_tree_source_node(f, bi->dt, 0);
write_tree_source_node(f, dti->dt, 0);
}

View file

@ -34,7 +34,7 @@ DTC_SOURCE="checks.c data.c dtc.c dtc.h flattree.c fstree.c livetree.c srcpos.c
srcpos.h treesource.c util.c util.h version_gen.h Makefile.dtc \
dtc-lexer.l dtc-parser.y"
DTC_GENERATED="dtc-lexer.lex.c dtc-parser.tab.c dtc-parser.tab.h"
LIBFDT_SOURCE="Makefile.libfdt fdt.c fdt.h fdt_empty_tree.c fdt_ro.c fdt_rw.c fdt_strerror.c fdt_sw.c fdt_wip.c libfdt.h libfdt_env.h libfdt_internal.h"
LIBFDT_SOURCE="Makefile.libfdt fdt.c fdt.h fdt_empty_tree.c fdt_ro.c fdt_rw.c fdt_strerror.c fdt_sw.c fdt_wip.c fdt_address.c fdt_overlay.c libfdt.h libfdt_env.h libfdt_internal.h"
# Build DTC
cd $DTC_UPSTREAM_PATH

View file

@ -34,7 +34,7 @@
#include "libfdt.h"
#include "util.h"
#include "version_gen.h"
#include "version_non_gen.h"
char *xstrdup(const char *s)
{
@ -46,6 +46,36 @@ char *xstrdup(const char *s)
return d;
}
/* based in part from (3) vsnprintf */
int xasprintf(char **strp, const char *fmt, ...)
{
int n, size = 128; /* start with 128 bytes */
char *p;
va_list ap;
/* initial pointer is NULL making the fist realloc to be malloc */
p = NULL;
while (1) {
p = xrealloc(p, size);
/* Try to print in the allocated space. */
va_start(ap, fmt);
n = vsnprintf(p, size, fmt, ap);
va_end(ap);
/* If that worked, return the string. */
if (n > -1 && n < size)
break;
/* Else try again with more space. */
if (n > -1) /* glibc 2.1 */
size = n + 1; /* precisely what is needed */
else /* glibc 2.0 */
size *= 2; /* twice the old size */
}
*strp = p;
return strlen(p);
}
char *join_path(const char *path, const char *name)
{
int lenp = strlen(path);

View file

@ -59,6 +59,7 @@ static inline void *xrealloc(void *p, size_t len)
}
extern char *xstrdup(const char *s);
extern int xasprintf(char **strp, const char *fmt, ...);
extern char *join_path(const char *path, const char *name);
/**

View file

@ -0,0 +1 @@
#define DTC_VERSION "DTC 1.4.2-Android-build"

View file

@ -0,0 +1,14 @@
#!/bin/bash
# find_matching_version src_path version
TOP_DIR="$1"
SRC_PATH="$2"
FULL_SRC_PATH="$1/$2"
INPUT_VERSION="$3"
if [[ -d "${FULL_SRC_PATH}_${INPUT_VERSION}" ]]
then
printf "${SRC_PATH}_${INPUT_VERSION}"
else
printf "${SRC_PATH}"
fi

View file

@ -0,0 +1,29 @@
#!/bin/bash
# find_matching_version src_path version
TOP_DIR="$1"
SRC_PATH="$2"
FULL_SRC_PATH="$1/$2"
INPUT_VERSION="$3"
if [[ -d "${FULL_SRC_PATH}_v${INPUT_VERSION}" ]]
then
printf "${SRC_PATH}_v${INPUT_VERSION}"
else
LIST=$(ls -d ${FULL_SRC_PATH}_v*)
PREV_VERSION=${INPUT_VERSION}
for i in $LIST
do
VERSION=${i//${FULL_SRC_PATH}_v/}
if [ $VERSION -lt $INPUT_VERSION ]
then
PREV_VERSION=$VERSION
fi
done
if [ "x$PREV_VERSION" == "x$INPUT_VERSION" ]
then
printf "${SRC_PATH}"
else
printf "${SRC_PATH}_v${PREV_VERSION}"
fi
fi

20
scripts/fix_patch.sh Normal file
View file

@ -0,0 +1,20 @@
#! /usr/bin/env bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
if [[ -z $1 ]]
then
COMMIT="HEAD"
else
COMMIT="$1"
fi
FLIST=$(git diff-tree --no-commit-id --name-only -r "$COMMIT")
for f in $FLIST
do
"$DIR/cleanfile" -width 120 "$f"
"$DIR/checkpatch.pl" --max-line-length=120 --show-types --ignore GERRIT_CHANGE_ID,UNDOCUMENTED_DT_STRING,FILE_PATH_CHANGES,NOT_UNIFIED_DIFF,MODIFIED_INCLUDE_ASM --fix-inplace -f "$f"
if [[ ( $f == *.c ) || ( $f == *.h ) ]]
then
chmod 644 "$f"
fi
done

255
scripts/fmp/ELF.py Normal file
View file

@ -0,0 +1,255 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Module ELF contains ELF, Symbol, Section classes for manipulation over ELF files.
It can parse, and change ELF file. This version works only with vmlinux and doesn't properly work with ELF that contains
UND symbols
"""
import subprocess
import re
import os
from Utils import Utils
from collections import OrderedDict
__author__ = "Vadym Stupakov"
__copyright__ = "Copyright (c) 2017 Samsung Electronics"
__credits__ = ["Vadym Stupakov"]
__version__ = "1.0"
__maintainer__ = "Vadym Stupakov"
__email__ = "v.stupakov@samsung.com"
__status__ = "Production"
class Symbol:
def __init__(self, name=str(), sym_type=str(), bind=str(), visibility=str(), addr=int(), size=int(), ndx=str()):
self.utils = Utils()
self.name = str(name)
self.type = str(sym_type)
self.bind = str(bind)
self.ndx = str(ndx)
self.visibility = str(visibility)
self.addr = self.utils.to_int(addr)
self.size = self.utils.to_int(size)
def __str__(self):
return "name: '{}', type: '{}', bind: '{}', ndx: '{}', visibility: '{}', address: '{}', size: '{}'".format(
self.name, self.type, self.bind, self.ndx, self.visibility, hex(self.addr), hex(self.size)
)
def __lt__(self, other):
return self.addr <= other.addr
class Section:
def __init__(self, name=str(), sec_type=str(), addr=int(), offset=int(), size=int()):
self.utils = Utils()
self.name = str(name)
self.type = str(sec_type)
self.addr = self.utils.to_int(addr)
self.offset = self.utils.to_int(offset)
self.size = self.utils.to_int(size)
def __str__(self):
return "name: '{}', type: '{}', address: '{}', offset: '{}', size: '{}'".format(
self.name, self.type, hex(self.addr), hex(self.offset), hex(self.size)
)
def __lt__(self, other):
return self.addr <= other.addr
class ELF:
"""
Utils for manipulating over ELF
"""
def __init__(self, elf_file, readelf_path="readelf"):
self.__elf_file = elf_file
self.utils = Utils()
self.__readelf_path = readelf_path
self.__sections = OrderedDict()
self.__symbols = OrderedDict()
self.__relocs = list()
self.__re_hexdecimal = "\s*[0-9A-Fa-f]+\s*"
self.__re_sec_name = "\s*[._a-zA-Z]+\s*"
self.__re_type = "\s*[A-Z]+\s*"
def __readelf_raw(self, options):
"""
Execute readelf with options and print raw output
:param options readelf options: ["opt1", "opt2", "opt3", ..., "optN"]
:returns raw output
"""
ret = subprocess.Popen(args=[self.__readelf_path] + options,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout, stderr = ret.communicate()
if "readelf: Error: the PHDR segment is not covered by a LOAD segment" in stderr.decode("utf-8").strip():
ret.returncode = 0
if ret.returncode != 0:
raise ChildProcessError(stderr.decode("utf-8") + stdout.decode("utf-8"))
return stdout.decode("utf-8")
def set_elf_file(self, elf_file):
if os.path.abspath(self.__elf_file) != os.path.abspath(elf_file):
self.__elf_file = os.path.abspath(elf_file)
self.__sections.clear()
self.__symbols.clear()
self.__relocs.clear()
def get_elf_file(self):
return os.path.abspath(self.__elf_file)
def get_sections(self):
""""
Execute -> parse -> transform to dict() readelf output
:returns dict: {sec_addr : Section()}
"""
if len(self.__sections) == 0:
sec_header = self.__readelf_raw(["-SW", self.__elf_file]).strip()
secs = re.compile("^.*\[.*\](" + self.__re_sec_name + self.__re_type + self.__re_hexdecimal +
self.__re_hexdecimal + self.__re_hexdecimal + ")", re.MULTILINE)
found = secs.findall(sec_header)
for line in found:
line = line.split()
if len(line) == 5:
self.__sections[int(line[2], 16)] = Section(name=line[0], sec_type=line[1], addr=int(line[2], 16),
offset=int(line[3], 16), size=int(line[4], 16))
self.__sections = OrderedDict(sorted(self.__sections.items()))
return self.__sections
def get_symbols(self):
""""
Execute -> parse -> transform to dict() readelf output
:returns dict: {sym_addr : Symbol()}
"""
if len(self.__symbols) == 0:
sym_tab = self.__readelf_raw(["-sW", self.__elf_file])
syms = re.compile(r"^.*\d+:\s(.*$)", re.MULTILINE)
found = syms.findall(sym_tab.strip())
for line in found:
line = line.split()
if len(line) == 7:
size = line[1]
# This needs, because readelf prints sizes in hex if size is large
if size[:2].upper() == "0X":
size = int(size, 16)
else:
size = int(size, 10)
self.__symbols[int(line[0], 16)] = Symbol(addr=int(line[0], 16), size=size, sym_type=line[2],
bind=line[3], visibility=line[4], ndx=line[5],
name=line[6])
self.__symbols = OrderedDict(sorted(self.__symbols.items()))
return self.__symbols
def get_relocs(self, start_addr=None, end_addr=None):
""""
:param start_addr: start address :int
:param end_addr: end address: int
:returns list: [reloc1, reloc2, reloc3, ..., relocN]
"""
if len(self.__relocs) == 0:
relocs = self.__readelf_raw(["-rW", self.__elf_file])
rel = re.compile(r"^(" + self.__re_hexdecimal + ")\s*", re.MULTILINE)
self.__relocs = [self.utils.to_int(el) for el in rel.findall(relocs.strip())]
if start_addr and end_addr is not None:
ranged_rela = list()
for el in self.__relocs:
if self.utils.to_int(start_addr) <= self.utils.to_int(el) <= self.utils.to_int(end_addr):
ranged_rela.append(el)
return ranged_rela
return self.__relocs
def get_symbol_by_name(self, sym_names):
"""
Get symbol by_name
:param sym_names: "sym_name" : str or list
:return: Symbol() or [Symbol()]
"""
if isinstance(sym_names, str):
for addr, symbol_obj in self.get_symbols().items():
if symbol_obj.name == sym_names:
return symbol_obj
elif isinstance(sym_names, list):
symbols = [self.get_symbol_by_name(sym_name) for sym_name in sym_names]
return symbols
else:
raise ValueError
return None
def get_symbol_by_vaddr(self, vaddrs=None):
"""
Get symbol by virtual address
:param vaddrs: vaddr : int or list
:return: Symbol() or [Symbol()]
"""
if isinstance(vaddrs, int):
if vaddrs in self.get_symbols():
return self.get_symbols()[vaddrs]
for addr, symbol_obj in self.get_symbols().items():
if (addr + symbol_obj.size) >= vaddrs >= addr:
return symbol_obj
elif isinstance(vaddrs, list):
symbol = [self.get_symbol_by_vaddr(vaddr) for vaddr in vaddrs]
return symbol
else:
raise ValueError
return None
def get_section_by_name(self, sec_names=None):
"""
Get section by_name
:param sec_names: "sec_name" : str or list
:return: Section() or [Section()]
"""
if isinstance(sec_names, str):
for addr, section_obj in self.get_sections().items():
if section_obj.name == sec_names:
return section_obj
elif isinstance(sec_names, list):
sections = [self.get_section_by_name(sec_name) for sec_name in sec_names]
return sections
else:
raise ValueError
return None
def get_section_by_vaddr(self, vaddrs=None):
"""
Get section by virtual address
:param vaddrs: vaddr : int or list
:return: Section() or [Section()]
"""
if isinstance(vaddrs, int):
if vaddrs in self.get_sections():
return self.get_sections()[vaddrs]
for addr, section_obj in self.get_sections().items():
if (addr + section_obj.size) >= vaddrs >= addr:
return section_obj
elif isinstance(vaddrs, list):
sections = [self.get_symbol_by_vaddr(vaddr) for vaddr in vaddrs]
return sections
else:
raise ValueError
return None
def vaddr_to_file_offset(self, vaddrs):
"""
Transform virtual address to file offset
:param vaddrs: addr string or int or list
:returns file offset or list
"""
if isinstance(vaddrs, str) or isinstance(vaddrs, int):
section = self.get_section_by_vaddr(vaddrs)
return self.utils.to_int(vaddrs, 16) - section.addr + section.offset
elif isinstance(vaddrs, list):
return [self.vaddr_to_file_offset(vaddr) for vaddr in vaddrs]
else:
raise ValueError
def read_data_from_vaddr(self, vaddr, size, out_file):
with open(self.__elf_file, "rb") as elf_fp:
elf_fp.seek(self.vaddr_to_file_offset(vaddr))
with open(out_file, "wb") as out_fp:
out_fp.write(elf_fp.read(size))

View file

@ -0,0 +1,305 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Module IntegrityRoutine Contains IntegrityRoutine class helps with FIPS 140-2 build time integrity routine.
This module is needed to calculate HMAC and embed other needed stuff.
"""
import hmac
import hashlib
import bisect
import itertools
import binascii
from ELF import *
__author__ = "Vadym Stupakov"
__copyright__ = "Copyright (c) 2017 Samsung Electronics"
__credits__ = ["Vadym Stupakov"]
__version__ = "1.0"
__maintainer__ = "Vadym Stupakov"
__email__ = "v.stupakov@samsung.com"
__status__ = "Production"
class IntegrityRoutine(ELF):
"""
Utils for fips-integrity process
"""
def __init__(self, elf_file, readelf_path="readelf"):
ELF.__init__(self, elf_file, readelf_path)
@staticmethod
def __remove_all_dublicates(lst):
"""
Removes all occurrences of tha same value. For instance: transforms [1, 2, 3, 1] -> [2, 3]
:param lst: input list
:return: lst w/o duplicates
"""
to_remove = list()
for i in range(len(lst)):
it = itertools.islice(lst, i + 1, len(lst) - 1, None)
for j, val in enumerate(it, start=i+1):
if val == lst[i]:
to_remove.extend([lst[i], lst[j]])
for el in to_remove:
lst.remove(el)
def get_reloc_gaps(self, start_addr, end_addr):
"""
:param start_addr: start address :int
:param end_addr: end address: int
:returns list of relocation gaps like [[gap_start, gap_end], [gap_start, gap_end], ...]
"""
all_relocs = self.get_relocs(start_addr, end_addr)
relocs_gaps = list()
for addr in all_relocs:
relocs_gaps.append(addr)
relocs_gaps.append(addr + 8)
self.__remove_all_dublicates(relocs_gaps)
relocs_gaps.sort()
relocs_gaps = [[addr1, addr2] for addr1, addr2 in self.utils.pairwise(relocs_gaps)]
return relocs_gaps
def get_addrs_for_hmac(self, sec_sym_sequence, relocs_gaps=None):
"""
Generate addresses for calculating HMAC
:param sec_sym_sequence: [addr_start1, addr_end1, ..., addr_startN, addr_endN],
:param relocs_gaps: [[start_gap_addr, end_gap_addr], [start_gap_addr, end_gap_addr]]
:return: addresses for calculating HMAC: [[addr_start, addr_end], [addr_start, addr_end], ...]
"""
addrs_for_hmac = list()
for section_name, sym_names in sec_sym_sequence.items():
if relocs_gaps is not None and section_name == ".rodata":
for symbol in self.get_symbol_by_name(sym_names):
addrs_for_hmac.append(symbol.addr)
else:
for symbol in self.get_symbol_by_name(sym_names):
addrs_for_hmac.append(symbol.addr)
addrs_for_hmac.extend(self.utils.flatten(relocs_gaps))
addrs_for_hmac.sort()
return [[item1, item2] for item1, item2 in self.utils.pairwise(addrs_for_hmac)]
def embed_bytes(self, vaddr, in_bytes):
"""
Write bytes to ELF file
:param vaddr: virtual address in ELF
:param in_bytes: byte array to write
"""
offset = self.vaddr_to_file_offset(vaddr)
with open(self.get_elf_file(), "rb+") as elf_file:
elf_file.seek(offset)
elf_file.write(in_bytes)
def __update_hmac(self, hmac_obj, file_obj, file_offset_start, file_offset_end):
"""
Update hmac from addrstart tp addr_end
FIXMI: it needs to implement this function via fixed block size
:param file_offset_start: could be string or int
:param file_offset_end: could be string or int
"""
file_offset_start = self.utils.to_int(file_offset_start)
file_offset_end = self.utils.to_int(file_offset_end)
file_obj.seek(self.vaddr_to_file_offset(file_offset_start))
block_size = file_offset_end - file_offset_start
msg = file_obj.read(block_size)
hmac_obj.update(msg)
def get_hmac(self, offset_sequence, key, output_type="byte"):
"""
Calculate HMAC
:param offset_sequence: start and end addresses sequence [addr_start, addr_end], [addr_start, addr_end], ...]
:param key HMAC key: string value
:param output_type string value. Could be "hex" or "byte"
:return: bytearray or hex string
"""
digest = hmac.new(bytearray(key.encode("utf-8")), digestmod=hashlib.sha256)
with open(self.get_elf_file(), "rb") as file:
for addr_start, addr_end in offset_sequence:
self.__update_hmac(digest, file, addr_start, addr_end)
if output_type == "byte":
return digest.digest()
if output_type == "hex":
return digest.hexdigest()
def __find_nearest_symbol_by_vaddr(self, vaddr, method):
"""
Find nearest symbol near vaddr
:param vaddr:
:return: idx of symbol from self.get_symbols()
"""
symbol = self.get_symbol_by_vaddr(vaddr)
if symbol is None:
raise ValueError("Can't find symbol by vaddr")
idx = method(list(self.get_symbols()), vaddr)
return idx
def find_rnearest_symbol_by_vaddr(self, vaddr):
"""
Find right nearest symbol near vaddr
:param vaddr:
:return: idx of symbol from self.get_symbols()
"""
return self.__find_nearest_symbol_by_vaddr(vaddr, bisect.bisect_right)
def find_lnearest_symbol_by_vaddr(self, vaddr):
"""
Find left nearest symbol near vaddr
:param vaddr:
:return: idx of symbol from self.get_symbols()
"""
return self.__find_nearest_symbol_by_vaddr(vaddr, bisect.bisect_left)
def find_symbols_between_vaddrs(self, vaddr_start, vaddr_end):
"""
Returns list of symbols between two virtual addresses
:param vaddr_start:
:param vaddr_end:
:return: [(Symbol(), Section)]
"""
symbol_start = self.get_symbol_by_vaddr(vaddr_start)
symbol_end = self.get_symbol_by_vaddr(vaddr_end)
if symbol_start is None or symbol_end is None:
raise ValueError("Error: Cannot find symbol by vaddr. vaddr should coincide with symbol address!")
idx_start = self.find_lnearest_symbol_by_vaddr(vaddr_start)
idx_end = self.find_lnearest_symbol_by_vaddr(vaddr_end)
sym_sec = list()
for idx in range(idx_start, idx_end):
symbol_addr = list(self.get_symbols())[idx]
symbol = self.get_symbol_by_vaddr(symbol_addr)
section = self.get_section_by_vaddr(symbol_addr)
sym_sec.append((symbol, section))
sym_sec.sort(key=lambda x: x[0])
return sym_sec
@staticmethod
def __get_skipped_bytes(symbol, relocs):
"""
:param symbol: Symbol()
:param relocs: [[start1, end1], [start2, end2]]
:return: Returns skipped bytes and [[start, end]] addresses that show which bytes were skipped
"""
symbol_start_addr = symbol.addr
symbol_end_addr = symbol.addr + symbol.size
skipped_bytes = 0
reloc_addrs = list()
for reloc_start, reloc_end in relocs:
if reloc_start >= symbol_start_addr and reloc_end <= symbol_end_addr:
skipped_bytes += reloc_end - reloc_start
reloc_addrs.append([reloc_start, reloc_end])
if reloc_start > symbol_end_addr:
break
return skipped_bytes, reloc_addrs
def print_covered_info(self, sec_sym, relocs, print_reloc_addrs=False, sort_by="address", reverse=False):
"""
Prints information about covered symbols in detailed table:
|N| symbol name | symbol address | symbol section | bytes skipped | skipped bytes address range |
|1| symbol | 0xXXXXXXXXXXXXXXXX | .rodata | 8 | [[addr1, addr2], [addr1, addr2]] |
:param sec_sym: {section_name : [sym_name1, sym_name2]}
:param relocs: [[start1, end1], [start2, end2]]
:param print_reloc_addrs: print or not skipped bytes address range
:param sort_by: method for sorting table. Could be: "address", "name", "section"
:param reverse: sort order
"""
if sort_by.lower() == "address":
def sort_method(x): return x[0].addr
elif sort_by.lower() == "name":
def sort_method(x): return x[0].name
elif sort_by.lower() == "section":
def sort_method(x): return x[1].name
else:
raise ValueError("Invalid sort type!")
table_format = "|{:4}| {:50} | {:18} | {:20} | {:15} |"
if print_reloc_addrs is True:
table_format += "{:32} |"
print(table_format.format("N", "symbol name", "symbol address", "symbol section", "bytes skipped",
"skipped bytes address range"))
data_to_print = list()
for sec_name, sym_names in sec_sym.items():
for symbol_start, symbol_end in self.utils.pairwise(self.get_symbol_by_name(sym_names)):
symbol_sec_in_range = self.find_symbols_between_vaddrs(symbol_start.addr, symbol_end.addr)
for symbol, section in symbol_sec_in_range:
skipped_bytes, reloc_addrs = self.__get_skipped_bytes(symbol, relocs)
reloc_addrs_str = "["
for start_addr, end_addr in reloc_addrs:
reloc_addrs_str += "[{}, {}], ".format(hex(start_addr), hex(end_addr))
reloc_addrs_str += "]"
if symbol.size > 0:
data_to_print.append((symbol, section, skipped_bytes, reloc_addrs_str))
skipped_bytes_size = 0
symbol_covered_size = 0
cnt = 0
data_to_print.sort(key=sort_method, reverse=reverse)
for symbol, section, skipped_bytes, reloc_addrs_str in data_to_print:
cnt += 1
symbol_covered_size += symbol.size
skipped_bytes_size += skipped_bytes
if print_reloc_addrs is True:
print(table_format.format(cnt, symbol.name, hex(symbol.addr), section.name,
self.utils.human_size(skipped_bytes), reloc_addrs_str))
else:
print(table_format.format(cnt, symbol.name, hex(symbol.addr), section.name,
self.utils.human_size(skipped_bytes)))
addrs_for_hmac = self.get_addrs_for_hmac(sec_sym, relocs)
all_covered_size = 0
for addr_start, addr_end in addrs_for_hmac:
all_covered_size += addr_end - addr_start
print("Symbol covered bytes len: {} ".format(self.utils.human_size(symbol_covered_size - skipped_bytes_size)))
print("All covered bytes len : {} ".format(self.utils.human_size(all_covered_size)))
print("Skipped bytes len : {} ".format(self.utils.human_size(skipped_bytes_size)))
def dump_covered_bytes(self, vaddr_seq, out_file):
"""
Dumps covered bytes
:param vaddr_seq: [[start1, end1], [start2, end2]] start - end sequence of covered bytes
:param out_file: file where will be stored dumped bytes
"""
with open(self.get_elf_file(), "rb") as elf_fp:
with open(out_file, "wb") as out_fp:
for vaddr_start, vaddr_end, in vaddr_seq:
elf_fp.seek(self.vaddr_to_file_offset(vaddr_start))
out_fp.write(elf_fp.read(vaddr_end - vaddr_start))
def make_integrity(self, sec_sym, module_name, debug=False, print_reloc_addrs=False, sort_by="address",
reverse=False):
"""
Calculate HMAC and embed needed info
:param sec_sym: {sec_name: [addr1, addr2, ..., addrN]}
:param module_name: module name that you want to make integrity. See Makefile targets
:param debug: If True prints debug information
:param print_reloc_addrs: If True, print relocation addresses that are skipped
:param sort_by: sort method
:param reverse: sort order
"""
rel_addr_start = self.get_symbol_by_name("first_" + module_name + "_rodata")
rel_addr_end = self.get_symbol_by_name("last_" + module_name + "_rodata")
reloc_gaps = self.get_reloc_gaps(rel_addr_start.addr, rel_addr_end.addr)
addrs_for_hmac = self.get_addrs_for_hmac(sec_sym, reloc_gaps)
digest = self.get_hmac(addrs_for_hmac, "The quick brown fox jumps over the lazy dog")
self.embed_bytes(self.get_symbol_by_name("builtime_" + module_name + "_hmac").addr,
self.utils.to_bytearray(digest))
self.embed_bytes(self.get_symbol_by_name("integrity_" + module_name + "_addrs").addr,
self.utils.to_bytearray(addrs_for_hmac))
self.embed_bytes(self.get_symbol_by_name(module_name + "_buildtime_address").addr,
self.utils.to_bytearray(self.get_symbol_by_name(module_name + "_buildtime_address").addr))
print("HMAC for \"{}\" module is: {}".format(module_name, binascii.hexlify(digest)))
if debug:
self.print_covered_info(sec_sym, reloc_gaps, print_reloc_addrs=print_reloc_addrs, sort_by=sort_by,
reverse=reverse)
self.dump_covered_bytes(addrs_for_hmac, "covered_dump_for_" + module_name + ".bin")
print("FIPS integrity procedure has been finished for {}".format(module_name))

100
scripts/fmp/Utils.py Normal file
View file

@ -0,0 +1,100 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Module Utils contains Utils class with general purpose helper functions.
"""
import struct
import os
from itertools import chain
__author__ = "Vadym Stupakov"
__copyright__ = "Copyright (c) 2017 Samsung Electronics"
__credits__ = ["Vadym Stupakov"]
__version__ = "1.0"
__maintainer__ = "Vadym Stupakov"
__email__ = "v.stupakov@samsung.com"
__status__ = "Production"
class Utils:
"""
Utils class with general purpose helper functions.
"""
@staticmethod
def flatten(alist):
"""
Make list from sub lists
:param alist: any list: [[item1, item2], [item3, item4], ..., [itemN, itemN+1]]
:return: [item1, item2, item3, item4, ..., itemN, itemN+1]
"""
if alist is []:
return []
elif type(alist) is not list:
return [alist]
else:
return [el for el in chain.from_iterable(alist)]
@staticmethod
def pairwise(iterable):
"""
Iter over two elements: [s0, s1, s2, s3, ..., sN] -> (s0, s1), (s2, s3), ..., (sN, sN+1)
:param iterable:
:return: (s0, s1), (s2, s3), ..., (sN, sN+1)
"""
a = iter(iterable)
return zip(a, a)
@staticmethod
def paths_exists(path_list):
"""
Check if path exist, otherwise raise FileNotFoundError exception
:param path_list: list of paths
"""
for path in path_list:
if not os.path.exists(path):
raise FileNotFoundError("File: \"" + path + "\" doesn't exist!\n")
@staticmethod
def to_int(value, base=16):
"""
Converts string to int
:param value: string or int
:param base: string base int
:return: integer value
"""
if isinstance(value, int):
return value
elif isinstance(value, str):
return int(value.strip(), base)
def to_bytearray(self, value):
"""
Converts list to bytearray with block size 8 byte
:param value: list of integers or bytearray or int
:return: bytes
"""
if isinstance(value, bytearray) or isinstance(value, bytes):
return value
elif isinstance(value, list):
value = self.flatten(value)
return struct.pack("%sQ" % len(value), *value)
elif isinstance(value, int):
return struct.pack("Q", value)
@staticmethod
def human_size(nbytes):
"""
Print in human readable
:param nbytes: number of bytes
:return: human readable string. For instance: 0x26a5d (154.6 K)
"""
raw = nbytes
suffixes = ("B", "K", "M")
i = 0
while nbytes >= 1024 and i < len(suffixes) - 1:
nbytes /= 1024.
i += 1
f = "{:.1f}".format(nbytes).rstrip("0").rstrip(".")
return "{} ({} {})".format(hex(raw), f, suffixes[i])

View file

@ -0,0 +1,44 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
This script is needed for buildtime integrity routine.
It calculates and embeds HMAC and other needed stuff for in terms of FIPS 140-2
"""
import os
import sys
from IntegrityRoutine import IntegrityRoutine
from Utils import Utils
__author__ = "Vadym Stupakov"
__copyright__ = "Copyright (c) 2017 Samsung Electronics"
__credits__ = ["Vadym Stupakov"]
__version__ = "1.0"
__maintainer__ = "Vadym Stupakov"
__email__ = "v.stupakov@samsung.com"
__status__ = "Production"
sec_sym = {".text": ["first_fmp_text", "last_fmp_text"],
".rodata": ["first_fmp_rodata", "last_fmp_rodata"],
"init.text": ["first_fmp_init", "last_fmp_init"]
}
module_name = "fmp"
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage " + sys.argv[0] + " elf_file")
sys.exit(-1)
elf_file = os.path.abspath(sys.argv[1])
modules = sys.argv[2:]
utils = Utils()
utils.paths_exists([elf_file])
integrity = IntegrityRoutine(elf_file)
integrity.make_integrity(sec_sym=sec_sym, module_name=module_name, debug=False, print_reloc_addrs=False,
sort_by="address", reverse=False)

View file

@ -367,5 +367,21 @@ if [ -n "${CONFIG_KALLSYMS}" ]; then
fi
fi
# CFP instrumentation will change binary, need to be before FIPS
if [ -n "${CONFIG_RKP_CFP_JOPP}" ]; then
echo ' RKP_CFP : instrumenting vmlinux... '
"${srctree}/scripts/rkp_cfp/instrument.py" --vmlinux "${objtree}/vmlinux" --config "${objtree}/.config" --inplace
fi
if [ -n "${CONFIG_CRYPTO_FIPS}" ]; then
echo ' FIPS : Generating hmac of crypto and updating vmlinux... '
PYTHONDONTWRITEBYTECODE=0 "${srctree}/scripts/crypto/fips_crypto_integrity.py" "${objtree}/vmlinux"
fi
if [ -n "${CONFIG_EXYNOS_FMP_FIPS}" ]; then
echo ' FIPS : Generating hmac of fmp and updating vmlinux... '
PYTHONDONTWRITEBYTECODE=0 "${srctree}/scripts/fmp/fips_fmp_integrity.py" "${objtree}/vmlinux"
fi
# We made a new kernel - delete old version file
rm -f .old_version

24
scripts/replace_dir.sh Normal file
View file

@ -0,0 +1,24 @@
#!/bin/sh
# Support selinux version
# replace_directory dst src
DST="$1/$2"
SRC="$1/$3"
if [ "x${DST}" == "x${SRC}" ]
then
#echo "${DST} and ${SRC} is same"
exit 0
else
if [ -d ${SRC} ]
then
if [ -L ${DST} ] || [ -d ${DST} ]
then
rm -rf ${DST}
fi
ln -s $(basename ${SRC}) ${DST}
else
echo "${SRC} does not exit"
exit -1
fi
fi

139
scripts/rkp_cfp/common.py Normal file
View file

@ -0,0 +1,139 @@
import re
import pprint
hex_re = r'(?:[a-f0-9]{16})'
hex_rec = re.compile(hex_re)
reg_re = r'\b(?:(?:x|w)(\d+))\b'
reg_rec = re.compile(reg_re)
fun_re = r'(?P<func_addr>' + hex_re + ') <(?P<func_name>[^>]+)>:$'
fun_rec = re.compile(fun_re)
ident_re = r'(?:[a-zA-Z_][a-zA-Z0-9_]*)'
ident_rec = re.compile(ident_re)
class MyPrettyPrinter(pprint.PrettyPrinter):
def format(self, object, context, maxlevels, level):
if isinstance(object, unicode):
return (object.encode('utf8'), True, False)
return pprint.PrettyPrinter.format(self, object, context, maxlevels, level)
_printer = MyPrettyPrinter()
def pr(x):
return _printer.pprint(x)
def run_from_ipython():
try:
__IPYTHON__
return True
except NameError:
return False
class Log(object):
def __init__(self, filename=None):
self.filename = filename
self.f = None
if self.filename is not None:
self.f = open(filename, 'w+')
def __call__(self, msg=''):
if self.f is not None:
self.f.write(msg)
self.f.write('\n')
self.f.flush()
def __enter__(self):
pass
def __exit__(self, type, value, traceback):
if self.f is not None:
self.f.close()
self.f = None
# Default logging object just print to stdout
LOG = Log()
def log(msg=''):
global Log
LOG(msg)
"""
Centralized skip and CONFIG flag
"""
#File containing functions to skip instrumenting
skip = set([])
"""
File containing assembly functions that have been manually inspected to
disable preemption/interrupts instead of doing 'stp x29, x30'
(i.e. don't error out during validation for these functions)
"""
skip_save_lr_to_stack = set([
'flush_cache_all',
'flush_cache_louis'])
skip_stp = set([
'__cpu_suspend_enter'])
#File containing assembly file paths whose functions we should skip instrumenting
skip_asm = set([])
#ASM functions code that are permitted to have br instructions in them
skip_br=set([
'stext',
'__turn_mmu_on',
'el0_svc_naked',
'__sys_trace',
'fpsimd_save_partial_state',
'fpsimd_load_partial_state',
'cpu_resume_mmu' ])
skip_blr=set([
'stext',
'__primary_switch',
'__primary_switched',
'start_kernel',
'secondary_startup',
'el0_svc_naked',
'__sys_trace',
'fimc_is_lib_vra_os_funcs',
'fimc_is_hw_vra_init',
'fimc_is_hw_3aa_init',
'fimc_is_hw_dcp_init',
'fimc_is_hw_tpu_init',
'fimc_is_hw_isp_init',
'fimc_is_load_ddk_bin',
'fimc_is_load_rta_bin',
'sensor_module_init',
'fimc_is_itf_sensor_mode_wrap',
])
skip_magic=set([
'rkp_call',
# do_execve
'try_to_run_init_process',
'run_init_process',
#cred related
'copy_creds',
'commit_creds',
'exit_creds',
'get_new_cred',
'get_task_cred',
'prepare_creds',
'prepare_kernel_cred',
'put_cred',
'put_ro_cred',
'rkp_free_security',
'rkp_get_init_cred',
'rkp_get_usecount',
'rkp_override_creds',
'revert_creds',
'set_security_override',
'set_security_override_from_ctx',
])

453
scripts/rkp_cfp/debug.py Normal file
View file

@ -0,0 +1,453 @@
#!/usr/bin/env python
# Code for validating instrumention (i.e. for detecting bugs in instrument.py).
import re
import multiprocessing
import textwrap
import subprocess
import mmap
import instrument
import common
from common import pr, log
register_re = r'(?:(x|w)\d+|xzr|sp)'
hex_char_re = r'(?:[a-f0-9])'
def validate_instrumentation(objdump_uninstr, skip, skip_stp, skip_asm, skip_save_lr_to_stack, skip_br, threads=1):
"""
Make sure that we instrumented vmlinux properly by checking some properties from its objdump.
Properties to check for:
- make sure there aren't any uninstrumented instructions
- i.e. a bl instruction that doesn't go through the springboard
- make sure there aren't any assembly routines that do things with LR that would keep us from re-encrypting it properly
- e.g. storing x30 in a callee saved register (instead of placing it on the stack and adjusting x29)
el1_preempt:
mov x24, x30
...
ret x24
- make sure there aren't any uninstrumented function prologues
i.e.
<assembled_c_function>:
(not a nop)
stp x29, x30, [sp,#-<frame>]!
(insns)
mov x29, sp
<assembled_c_function>:
nop
stp x29, x30, [sp,#-<frame>]!
(insns)
mov x29, sp
<assembled_c_function>:
nop
stp x29, x30, [sp,#<offset>]
add x29, sp, #<offset>
<assembled_c_function>:
(not a nop)
stp x29, x30, [sp,#<offset>]
add x29, sp, #<offset>
"""
lock = multiprocessing.Lock()
success = multiprocessing.Value('i', True)
def insn_text(line):
"""
>>> insn_text("ffffffc000080148: d503201f nop")
"nop"
"""
m = re.search(r'^{hex_char_re}{{16}}:\s+{hex_char_re}{{8}}\s+(.*)'.format(
hex_char_re=hex_char_re), line)
if m:
return m.group(1)
return ''
#
# Error reporting functions.
#
def _msg(list_of_func_lines, msg, is_failure):
with lock:
if len(list_of_func_lines) > 0:
log(textwrap.dedent(msg))
for func_lines in list_of_func_lines:
log()
for line in func_lines:
log(line.rstrip('\n'))
success.value = False
def errmsg(list_of_func_lines, msg):
_msg(list_of_func_lines, msg, True)
def warmsg(list_of_func_lines, msg):
_msg(list_of_func_lines, msg, False)
def err(list_of_args, msg, error):
with lock:
if len(list_of_args) > 0:
log(textwrap.dedent(msg))
for args in list_of_args:
log()
log(error(*args).rstrip('\n'))
success.value = False
asm_functions = instrument.parse_all_asm_functions(objdump_uninstr.kernel_src)
c_functions = objdump_uninstr.c_functions
#
# Validation functions. Each one runs in its own thread.
#
def validate_bin():
# Files must differ.
# subprocess.check_call('! diff -q {vmlinux_uninstr} {vmlinux_instr} > /dev/null'.format(
# vmlinux_uninstr=objdump_uninstr.vmlinux_old, vmlinux_instr=objdump_uninstr.instr), shell=True)
cmd = 'cmp -l {vmlinux_uninstr} {vmlinux_instr}'.format(
vmlinux_uninstr=objdump_uninstr.vmlinux_old, vmlinux_instr=objdump_uninstr.instr) + \
" | gawk '{printf \"%08X %02X %02X\\n\", $1, strtonum(0$2), strtonum(0$3)}'"
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
f = instrument.each_procline(proc)
to_int = lambda x: int(x, 16)
bin_errors = []
for line in f:
byte_offset, byte1, byte2 = map(to_int, re.split(r'\s+', line))
byte_offset -= 1
section = instrument.offset_to_section(byte_offset, objdump_uninstr.sections['sections'])
if section is None:
name = 'None'
bin_errors.append((byte_offset, None, None))
else:
addr = section['address'] + byte_offset - section['offset']
if 'CODE' not in section['type'] or section['name'] == '.vmm':
bin_errors.append((byte_offset, addr, section['name']))
def _to_str(byte_offset, addr, section):
if section is None:
return "byte offset 0x{byte_offset}".format(
byte_offset=instrument._hex(byte_offset))
return "0x{addr} (byte offset 0x{byte_offset}) in section {section}".format(
addr=instrument._hex(addr), byte_offset=instrument._hex(byte_offset), section=section)
err(bin_errors, """
Saw changes in binary sections of instrumented vmlinux that should not be there!
Changes should only be in the code.
""", error=_to_str)
def validate_instr():
"""
Validations to perform on the instrumented vmlinux.
"""
objdump_instr = instrument.load_and_cache_objdump(objdump_uninstr.instr,
kernel_src=objdump_uninstr.kernel_src, config_file=objdump_uninstr.config_file, make_copy=False, just_lines=True)
uninstrumented_br = []
uninstrumented_blr = []
def err_uninstr_branch(uninstr_lines):
with lock:
if len(uninstr_lines) > 0:
log()
log(textwrap.dedent("""
ERROR: instrumentation does not look right (instrument.py has a bug).
These lines in objdump of vmlinux_instr aren't instrumented correcly:
"""))
n = min(5, len(uninstr_lines))
for line in uninstr_lines[0:n]:
log(line)
if n < len(uninstr_lines):
log("...")
success.value = False
def is_uninstr_blr_branch(func, branch_pattern, uninstr_lines):
if not func.startswith('jopp_springboard_') and (
re.search(branch_pattern, line) and not re.search(r'<jopp_springboard_\w+>', line)
):
uninstr_lines.append(line)
return True
uninstrumented_prologue_errors = []
prologue_errors = []
nargs_errors = []
#import pdb; pdb.set_trace()
check_prologue = objdump_instr.is_conf_set('CONFIG_RKP_CFP_ROPP')
for func, lines, last_insns in objdump_instr.each_func_lines(num_last_insns=2):
if instrument.skip_func(func, skip, skip_asm):
continue
prologue_error = False
# TODO: This check incorrectly goes off for cases where objdump skips showing 0 .word's.
# e.g.
# ffffffc000c25d74: d503201f nop
# ...
## ffffffc000c25d84: b3ea3bad .inst 0xb3ea3bad ; undefined
##
# ffffffc003c25d88 <vcs_init>:
# ffffffc000c25d88: a9bd7ffd stp x29, xzr, [sp,#-48]!
# ffffffc000c25d8c: 910003fd mov x29, sp
# ...
#
for i, line in enumerate(lines):
#for checking BR
if re.search(r'\s+br\t', line) and (func not in skip_br):
uninstrumented_br.append(line)
# for checking BLR
if is_uninstr_blr_branch(func, r'\s+blr\t', uninstrumented_blr):
continue
# Detect uninstrumented prologues:
# nop <--- should be eor RRX, x30, RRK
# stp x29, 30
if re.search(r'^nop', insn_text(line)) and i + 1 < len(lines) and re.search(r'stp\tx29, x30, .*sp', lines[i+1]):
uninstrumented_prologue_errors.append(lines)
continue
if check_prologue:
m = re.search(r'stp\tx29, x30, .*sp', line)
if m and func not in skip_stp:
# We are in error if "stp x29, x30, [sp ..." exists in this function.
# (hopefully this doesn't raise false alarms in any assembly functions)
prologue_error = True
continue
if prologue_error:
prologue_errors.append(lines)
err_uninstr_branch(uninstrumented_br)
err_uninstr_branch(uninstrumented_blr)
errmsg(prologue_errors, """
Saw an assembly routine(s) that looks like it is saving x29 and x30 on the stack, but
has not been instrumented to save x29, xzr FIRST.
i.e.
Saw:
stp x29, x30, [sp,#-<frame>]!
(insns)
mov x29, sp <--- might get preempted just before doing this
(won't reencrypt x30!)
Expected:
stp x29, xzr, [sp,#-<frame>]!
mov x29, sp <--- it's ok if we get preempted
(insns) (x30 not stored yet)
str x30, [sp,#<+ 8>]
""")
errmsg(nargs_errors, """
Saw a dissassembled routine that doesn't have the the "number of function
arugments" and the "function entry point magic number" annotated above it.
""")
errmsg(uninstrumented_prologue_errors, """
Saw a function that doesn't have an instrumented C prologue.
In particular, we saw:
<func>:
nop
stp x29, x30, ...
...
But we expected to see:
<func>:
eor RRX, x30, RRK
stp x29, x30, ...
...
""")
def validate_uninstr_binary():
"""
Validations to perform on the uninstrumented vmlinux binary words.
"""
if objdump_uninstr.JOPP_CHECK_MAGIC_NUMBER_ON_BLR:
magic_errors = []
def each_word(section):
read_f = open(objdump_uninstr.vmlinux_old, 'rb')
read_f.seek(0)
read_mmap = mmap.mmap(read_f.fileno(), 0, access=mmap.ACCESS_READ)
try:
i = section['offset']
while i + 4 < section['size']:
word = read_mmap[i:i+4]
yield i, word
i += 4
finally:
read_mmap.close()
read_f.close()
for section in objdump_uninstr.sections['sections']:
if 'CODE' in section['type']:
# Make sure JOPP_FUNCTION_ENTRY_POINT_MAGIC_NUMBER
# doesn't appear in a word of an uninstrumented vmlinux.
for i, word in each_word(section):
if word == objdump_uninstr.JOPP_FUNCTION_ENTRY_POINT_MAGIC_NUMBER:
magic_errors.append([i, section])
err(magic_errors, """
The magic number chosen to place at the start of every function already
appears in the uninstrumented vmlinux. Find a new magic number!
(JOPP_FUNCTION_ENTRY_POINT_MAGIC_NUMBER = {JOPP_FUNCTION_ENTRY_POINT_MAGIC_NUMBER})
""",
error=lambda i, section: "0x{addr} in section {section}".format(
addr=instrument._hex(i + section['address']), section=section['name']))
def validate_uninstr_lines():
"""
Validations to perform on the uninstrumented vmlinux objdump lines.
"""
if objdump_uninstr.JOPP_FUNCTION_NOP_SPACERS:
# Assume that the key might change and require return-address reencryption. This
# means we need to have all copies of x30 either in x30 itself, or saved in memory
# and pointed to by a frame pointer.
#
# In particular, we can't allow return-addresses being saved in callee registers
# as is done in some low-level assembly routines, since when the key changes these
# registers will become invalid and not be re-encrypted.
#
# Look for and warn about:
#
# mov <rd>, x30
# ...
# ret <rd>
mov_ret_errors = []
nop_spacer_errors = []
missing_asm_annot_errors = []
c_func_br_errors = []
ldp_spacer_error_funcs = set([])
stp_spacer_error_funcs = set([])
ldp_spacer_errors = []
stp_spacer_errors = []
atomic_prologue_errors = []
atomic_prologue_error_funcs = set([])
for func_i, func, lines, last_insns in objdump_uninstr.each_func_lines(num_last_insns=2, with_func_i=True):
mov_registers = set([])
ret_registers = set([])
is_c_func = func in c_functions
saw_br = False
#if objdump_uninstr.JOPP_FUNCTION_NOP_SPACERS and \
#not instrument.skip_func(func, skip, skip_asm) and func in asm_functions:
#if any(not re.search('\tnop$', l) for l in last_insns if l is not None):
#nop_spacer_errors.append(lines)
for i, line in enumerate(lines, start=func_i):
def slice_lines(start, end):
return lines[start-func_i:end-func_i]
m = re.search(r'mov\t(?P<mov_register>{register_re}), x30'.format(register_re=register_re), line)
if m and m.group('mov_register') != 'sp':
mov_registers.add(m.group('mov_register'))
continue
m = re.search(r'ret\t(?P<ret_register>{register_re})'.format(register_re=register_re), line)
if m:
ret_registers.add(m.group('ret_register'))
continue
m = re.search(r'ldp\tx29,\s+x30,', line)
if m:
for l in lines[i+1:i+3]:
if not re.search(r'nop$'):
ldp_spacer_errors.append(lines)
ldp_spacer_error_funcs.add(func)
break
continue
m = re.search(r'stp\tx29,\s+x30,', line)
if m and func not in skip_stp:
missing_nop = False
for l in slice_lines(i-1, i):
if not re.search(r'nop$', l):
stp_spacer_errors.append(lines)
stp_spacer_error_funcs.add(func)
missing_nop = True
break
if missing_nop:
continue
if func == '__kvm_vcpu_run':
pr({'func':func})
mov_j, movx29_insn = instrument.find_add_x29_x30_imm(objdump_uninstr, func, func_i, i)
for l in slice_lines(i+1, mov_j):
if func not in atomic_prologue_error_funcs and re.search(r'\b(x29|sp)\b', insn_text(l)):
atomic_prologue_errors.append(lines)
atomic_prologue_error_funcs.add(func)
break
continue
# End of function; check for errors in that function, and if so, perserve its output.
if len(mov_registers.intersection(ret_registers)) > 0 and func not in skip_save_lr_to_stack:
mov_ret_errors.append(lines)
errmsg(c_func_br_errors, """
Saw a C function in vmlinux without information about the number of arguments it takes.
We need to know this to zero registers on BLR jumps.
""")
errmsg(missing_asm_annot_errors, """
Saw an assembly rountine(s) that hasn't been annotated with the number of
general purpose registers it uses.
Change ENTRY to FUNC_ENTRY for these assembly functions.
""")
errmsg(nop_spacer_errors, """
Saw an assembly rountine(s) that doesn't have 2 nop instruction immediately
before the function label.
We need these for any function that might be the target of a blr instruction!
""")
errmsg(mov_ret_errors, """
Saw an assembly routine(s) saving LR into a register instead of on the stack.
This would prevent us from re-encrypting it properly!
Modify these routine(s) to save LR on the stack and adjust the frame pointer (like in prologues of C functions).
e.g.
stp x29, x30, [sp,#-16]!
mov x29, sp
...
ldp x29, x30, [sp],#16
ret
NOTE: We're only reporting functions found in the compiled vmlinux
(gcc might remove dead code that needs patching as well)
""")
errmsg(ldp_spacer_errors, """
Saw a function with ldp x29, x30 but without 2 nops following it.
Either add an LDP_SPACER to this, use the right compiler, or make an exception.
""")
errmsg(stp_spacer_errors, """
Saw a function with stp x29, x30 but without 1 nop before it.
Either add an STP_SPACER to this, use the right compiler, or make an exception.
""")
warmsg(atomic_prologue_errors, """
Saw a function prologue with:
<func>:
stp x29, x30, ...
(insns)
add x29, sp, #...
BUT, one of the "(insns)" mentions either x29 or sp, so it might not be safe to turn this into:
<func>:
stp x29, x30, ...
add x29, sp, #...
(insns)
""")
procs = []
# for validate in [validate_uninstr_lines]:
for validate in [validate_bin, validate_instr, validate_uninstr_lines, validate_uninstr_binary]:
if threads == 1:
validate()
continue
proc = multiprocessing.Process(target=validate, args=())
proc.start()
procs.append(proc)
for proc in procs:
proc.join()
return bool(success.value)
if common.run_from_ipython():
def _x(*hexints):
xored = 0
for hexint in hexints:
xored ^= hexint
return "0x{0:x}".format(xored)
def _d(*addrs):
"""
Assume key is like
0x1111111111111111
Guess key, then decrypt used guessed key.
"""
def __d(addr):
addr = re.sub('^0x', '', addr)
first_4bits = int(addr[0], 16)
first_byte_of_key = (0xf ^ first_4bits) << 4 | (0xf ^ first_4bits)
key = 0
for i in xrange(0, 8):
key |= first_byte_of_key << i*8
return {'decaddr':'0x' + instrument._hex(instrument._int(addr) ^ key),
'key':'0x' + instrument._hex(key)}
return map(__d, addrs)

File diff suppressed because it is too large Load diff