import G965FXXU7DTAA OSRC
*First release for Android (Q). Signed-off-by: FAROVITUS <farovitus@gmail.com>
This commit is contained in:
parent
856452b4f2
commit
2b92eefa41
7696 changed files with 3763754 additions and 92661 deletions
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
9
scripts/android-major-version.sh
Normal file
9
scripts/android-major-version.sh
Normal 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
|
2
scripts/android-version.sh
Normal file
2
scripts/android-version.sh
Normal file
|
@ -0,0 +1,2 @@
|
|||
#!/bin/sh
|
||||
echo $1 | awk -F. '{ printf "%d%02d%02d", $1, $2, $3 }'
|
|
@ -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
255
scripts/crypto/ELF.py
Normal 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))
|
305
scripts/crypto/IntegrityRoutine.py
Normal file
305
scripts/crypto/IntegrityRoutine.py
Normal 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
100
scripts/crypto/Utils.py
Normal 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])
|
48
scripts/crypto/fips_crypto_integrity.py
Normal file
48
scripts/crypto/fips_crypto_integrity.py
Normal 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)
|
|
@ -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, ®_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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
94
scripts/dtc/libfdt/fdt_addresses.c
Normal file
94
scripts/dtc/libfdt/fdt_addresses.c
Normal 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;
|
||||
}
|
676
scripts/dtc/libfdt/fdt_overlay.c
Normal file
676
scripts/dtc/libfdt/fdt_overlay.c
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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]))
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
||||
/**********************************************************************/
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __CHECKER__
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
/**
|
||||
|
|
1
scripts/dtc/version_non_gen.h
Normal file
1
scripts/dtc/version_non_gen.h
Normal file
|
@ -0,0 +1 @@
|
|||
#define DTC_VERSION "DTC 1.4.2-Android-build"
|
14
scripts/find_matching_major.sh
Normal file
14
scripts/find_matching_major.sh
Normal 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
|
29
scripts/find_matching_version.sh
Normal file
29
scripts/find_matching_version.sh
Normal 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
20
scripts/fix_patch.sh
Normal 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
255
scripts/fmp/ELF.py
Normal 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))
|
305
scripts/fmp/IntegrityRoutine.py
Normal file
305
scripts/fmp/IntegrityRoutine.py
Normal 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
100
scripts/fmp/Utils.py
Normal 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])
|
44
scripts/fmp/fips_fmp_integrity.py
Normal file
44
scripts/fmp/fips_fmp_integrity.py
Normal 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)
|
|
@ -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
24
scripts/replace_dir.sh
Normal 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
139
scripts/rkp_cfp/common.py
Normal 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
453
scripts/rkp_cfp/debug.py
Normal 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)
|
1277
scripts/rkp_cfp/instrument.py
Normal file
1277
scripts/rkp_cfp/instrument.py
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue