From b595076a180a56d1bb170e6eceda6eb9d76f4cd3 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 1 Nov 2010 15:38:34 -0400 Subject: tree-wide: fix comment/printk typos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "gadget", "through", "command", "maintain", "maintain", "controller", "address", "between", "initiali[zs]e", "instead", "function", "select", "already", "equal", "access", "management", "hierarchy", "registration", "interest", "relative", "memory", "offset", "already", Signed-off-by: Uwe Kleine-König Signed-off-by: Jiri Kosina --- scripts/kconfig/confdata.c | 2 +- scripts/mod/modpost.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 9df80114b47..c06f1503aa8 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -946,7 +946,7 @@ static void randomize_choice_values(struct symbol *csym) int cnt, def; /* - * If choice is mod then we may have more items slected + * If choice is mod then we may have more items selected * and if no then no-one. * In both cases stop. */ diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 33122ca04e7..6619ed8843f 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -1614,7 +1614,7 @@ static void section_rel(const char *modname, struct elf_info *elf, * A module includes a number of sections that are discarded * either when loaded or when used as built-in. * For loaded modules all functions marked __init and all data - * marked __initdata will be discarded when the module has been intialized. + * marked __initdata will be discarded when the module has been initialized. * Likewise for modules used built-in the sections marked __exit * are discarded because __exit marked function are supposed to be called * only when a module is unloaded which never happens for built-in modules. -- cgit v1.2.3-70-g09d2 From e86c2412c88fbe4676920c40348d3c547c9edb0d Mon Sep 17 00:00:00 2001 From: maximilian attems Date: Fri, 29 Oct 2010 15:55:50 +0200 Subject: kbuild, deb-pkg: Fix build with paranoid umask umask 077 make deb-pkg dpkg-deb: building package `linux-image-2.6.36+' in `../linux-image-2.6.36+_2.6.36+-4_amd64.deb'. dpkg-deb: control directory has bad permissions 700 (must be >=0755 and <=0775) make[1]: *** [deb-pkg] Error 2 Reported-by: Bastian Blank Signed-off-by: maximilian attems Signed-off-by: Michal Marek --- scripts/package/builddeb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'scripts') diff --git a/scripts/package/builddeb b/scripts/package/builddeb index 49b74e1ee12..4dfec9aaaac 100644 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -49,8 +49,10 @@ fi # Setup the directory structure rm -rf "$tmpdir" "$fwdir" -mkdir -p "$tmpdir/DEBIAN" "$tmpdir/lib" "$tmpdir/boot" "$tmpdir/usr/share/doc/$packagename" -mkdir -p "$fwdir/DEBIAN" "$fwdir/lib" "$fwdir/usr/share/doc/$fwpackagename" +mkdir -m 755 -p "$tmpdir/DEBIAN" +mkdir -p "$tmpdir/lib" "$tmpdir/boot" "$tmpdir/usr/share/doc/$packagename" +mkdir -m 755 -p "$fwdir/DEBIAN" +mkdir -p "$fwdir/lib" "$fwdir/usr/share/doc/$fwpackagename" if [ "$ARCH" = "um" ] ; then mkdir -p "$tmpdir/usr/lib/uml/modules/$version" "$tmpdir/usr/bin" fi -- cgit v1.2.3-70-g09d2 From 8af27e1dc4e4dd7a7b04c2cd0fc3d419d91d45b0 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 9 Nov 2010 16:29:27 +0100 Subject: fixdep: use hash table instead of a single array I noticed fixdep uses ~2% of cpu time in kernel build, in function use_config() fixdep spends a lot of cpu cycles in linear searches in its internal string array. With about 400 stored strings per dep file, this begins to be noticeable. Convert fixdep to use a hash table. kbuild results on my x86_64 allmodconfig Before patch : real 10m30.414s user 61m51.456s sys 8m28.200s real 10m12.334s user 61m50.236s sys 8m30.448s real 10m42.947s user 61m50.028s sys 8m32.380s After: real 10m8.180s user 61m22.506s sys 8m32.384s real 10m35.039s user 61m21.654s sys 8m32.212s real 10m14.487s user 61m23.498s sys 8m32.312s Signed-off-by: Eric Dumazet Signed-off-by: Michal Marek --- scripts/basic/fixdep.c | 109 +++++++++++++++++++++++++++---------------------- 1 file changed, 61 insertions(+), 48 deletions(-) (limited to 'scripts') diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c index ea26b23de08..ed058462369 100644 --- a/scripts/basic/fixdep.c +++ b/scripts/basic/fixdep.c @@ -138,38 +138,36 @@ static void print_cmdline(void) printf("cmd_%s := %s\n\n", target, cmdline); } -char * str_config = NULL; -int size_config = 0; -int len_config = 0; +struct item { + struct item *next; + unsigned int len; + unsigned int hash; + char name[0]; +}; -/* - * Grow the configuration string to a desired length. - * Usually the first growth is plenty. - */ -static void grow_config(int len) -{ - while (len_config + len > size_config) { - if (size_config == 0) - size_config = 2048; - str_config = realloc(str_config, size_config *= 2); - if (str_config == NULL) - { perror("fixdep:malloc"); exit(1); } - } -} +#define HASHSZ 256 +static struct item *hashtab[HASHSZ]; +static unsigned int strhash(const char *str, unsigned int sz) +{ + /* fnv32 hash */ + unsigned int i, hash = 2166136261U; + for (i = 0; i < sz; i++) + hash = (hash ^ str[i]) * 0x01000193; + return hash; +} /* * Lookup a value in the configuration string. */ -static int is_defined_config(const char * name, int len) +static int is_defined_config(const char *name, int len, unsigned int hash) { - const char * pconfig; - const char * plast = str_config + len_config - len; - for ( pconfig = str_config + 1; pconfig < plast; pconfig++ ) { - if (pconfig[ -1] == '\n' - && pconfig[len] == '\n' - && !memcmp(pconfig, name, len)) + struct item *aux; + + for (aux = hashtab[hash % HASHSZ]; aux; aux = aux->next) { + if (aux->hash == hash && aux->len == len && + memcmp(aux->name, name, len) == 0) return 1; } return 0; @@ -178,13 +176,19 @@ static int is_defined_config(const char * name, int len) /* * Add a new value to the configuration string. */ -static void define_config(const char * name, int len) +static void define_config(const char *name, int len, unsigned int hash) { - grow_config(len + 1); + struct item *aux = malloc(sizeof(*aux) + len); - memcpy(str_config+len_config, name, len); - len_config += len; - str_config[len_config++] = '\n'; + if (!aux) { + perror("fixdep:malloc"); + exit(1); + } + memcpy(aux->name, name, len); + aux->len = len; + aux->hash = hash; + aux->next = hashtab[hash % HASHSZ]; + hashtab[hash % HASHSZ] = aux; } /* @@ -192,40 +196,49 @@ static void define_config(const char * name, int len) */ static void clear_config(void) { - len_config = 0; - define_config("", 0); + struct item *aux, *next; + unsigned int i; + + for (i = 0; i < HASHSZ; i++) { + for (aux = hashtab[i]; aux; aux = next) { + next = aux->next; + free(aux); + } + hashtab[i] = NULL; + } } /* * Record the use of a CONFIG_* word. */ -static void use_config(char *m, int slen) +static void use_config(const char *m, int slen) { - char s[PATH_MAX]; - char *p; + unsigned int hash = strhash(m, slen); + int c, i; - if (is_defined_config(m, slen)) + if (is_defined_config(m, slen, hash)) return; - define_config(m, slen); - - memcpy(s, m, slen); s[slen] = 0; + define_config(m, slen, hash); - for (p = s; p < s + slen; p++) { - if (*p == '_') - *p = '/'; + printf(" $(wildcard include/config/"); + for (i = 0; i < slen; i++) { + c = m[i]; + if (c == '_') + c = '/'; else - *p = tolower((int)*p); + c = tolower(c); + putchar(c); } - printf(" $(wildcard include/config/%s.h) \\\n", s); + printf(".h) \\\n"); } -static void parse_config_file(char *map, size_t len) +static void parse_config_file(const char *map, size_t len) { - int *end = (int *) (map + len); + const int *end = (const int *) (map + len); /* start at +1, so that p can never be < map */ - int *m = (int *) map + 1; - char *p, *q; + const int *m = (const int *) map + 1; + const char *p, *q; for (; m < end; m++) { if (*m == INT_CONF) { p = (char *) m ; goto conf; } @@ -265,7 +278,7 @@ static int strrcmp(char *s, char *sub) return memcmp(s + slen - sublen, sub, sublen); } -static void do_config_file(char *filename) +static void do_config_file(const char *filename) { struct stat st; int fd; -- cgit v1.2.3-70-g09d2 From 45677454dd6d128608117abe7dcd2bdfdd7cdf72 Mon Sep 17 00:00:00 2001 From: Wu Zhangjin Date: Thu, 28 Oct 2010 00:24:34 +0800 Subject: ftrace: Speed up recordmcount cmd_record_mcount is used to locate the _mcount symbols in the object files, only the files compiled with -pg has the _mcount symbol, so, it is only needed for such files, but the current cmd_record_mcount is used for all of the object files, so, we need to fix it and speed it up. Since -pg may be removed by the method used in kernel/trace/Makefile: ORIG_CFLAGS := $(KBUILD_CFLAGS) KBUILD_CFLAGS = $(subst -pg,,$(ORIG_CFLAGS)) Or may be removed by the method used in arch/x86/kernel/Makefile: CFLAGS_REMOVE_file.o = -pg So, we must check the last variable stores the compiling flags, that is c_flags(Please refer to cmd_cc_o_c and rule_cc_o_c defined in scripts/Makefile.build) and since the CFLAGS_REMOVE_file.o is already filtered in _c_flags(Please refer to scripts/Makefile.lib) and _c_flags has less symbols, therefore, we only need to check _c_flags. --------------- Changes from v1: o Don't touch Makefile for CONFIG_FTRACE_MCOUNT_RECORD is enough o Use _c_flags intead of KBUILD_CFLAGS to cover CONFIG_REMOVE_file.o = -pg (feedback from Steven Rostedt ) Acked-by: Michal Marek Signed-off-by: Wu Zhangjin LKML-Reference: <3dc8cddf022eb7024f9f2cf857529a15bee8999a.1288196498.git.wuzhangjin@gmail.com> [ changed if [ .. == .. ] to if [ .. = .. ] to handle dash environments ] Signed-off-by: Steven Rostedt --- scripts/Makefile.build | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'scripts') diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 5ad25e17b6c..4eb99ab3405 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -214,17 +214,22 @@ ifdef BUILD_C_RECORDMCOUNT # The empty.o file is created in the make process in order to determine # the target endianness and word size. It is made before all other C # files, including recordmcount. -cmd_record_mcount = if [ $(@) != "scripts/mod/empty.o" ]; then \ - $(objtree)/scripts/recordmcount "$(@)"; \ - fi; +sub_cmd_record_mcount = \ + if [ $(@) != "scripts/mod/empty.o" ]; then \ + $(objtree)/scripts/recordmcount "$(@)"; \ + fi; else -cmd_record_mcount = set -e ; perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \ +sub_cmd_record_mcount = set -e ; perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \ "$(if $(CONFIG_CPU_BIG_ENDIAN),big,little)" \ "$(if $(CONFIG_64BIT),64,32)" \ "$(OBJDUMP)" "$(OBJCOPY)" "$(CC) $(KBUILD_CFLAGS)" \ "$(LD)" "$(NM)" "$(RM)" "$(MV)" \ "$(if $(part-of-module),1,0)" "$(@)"; endif +cmd_record_mcount = \ + if [ "$(findstring -pg,$(_c_flags))" = "-pg" ]; then \ + $(sub_cmd_record_mcount) \ + fi; endif define rule_cc_o_c -- cgit v1.2.3-70-g09d2 From 10f26fa64200095af0e5d80a980e47877865e4b7 Mon Sep 17 00:00:00 2001 From: Asbjoern Sloth Toennesen Date: Fri, 5 Nov 2010 13:30:08 +0000 Subject: kbuild, deb-pkg: select userland architecture based on UTS_MACHINE Instead of creating the debian package for the compiling userland, create it for a userland matching the kernel thats being compiled. This patch supports all Lenny release architectures, and Linux-based architecture candidates for Squeeze. If it can't find a proper Debian userspace it displays a warning, and fallback to let deb-gencontrol use the host's userspace arch. Eg. with this patch the following make command: make ARCH=i386 deb-pkg will output an i386 Debian package instead of an amd64 one, when run on an amd64 machine. Signed-off-by: Asbjoern Sloth Toennesen Acked-by: maximilian attems Signed-off-by: Michal Marek --- scripts/package/builddeb | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/package/builddeb b/scripts/package/builddeb index 4dfec9aaaac..5d6be3f5e7f 100644 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -25,8 +25,41 @@ create_package() { chown -R root:root "$pdir" chmod -R go-w "$pdir" + # Attempt to find the correct Debian architecture + local forcearch="" debarch="" + case "$UTS_MACHINE" in + i386|ia64|alpha) + debarch="$UTS_MACHINE" ;; + x86_64) + debarch=amd64 ;; + sparc*) + debarch=sparc ;; + s390*) + debarch=s390 ;; + ppc*) + debarch=powerpc ;; + parisc*) + debarch=hppa ;; + mips*) + debarch=mips$(grep -q CPU_LITTLE_ENDIAN=y .config && echo el) ;; + arm*) + debarch=arm$(grep -q CONFIG_AEABI=y .config && echo el) ;; + *) + echo "" >&2 + echo "** ** ** WARNING ** ** **" >&2 + echo "" >&2 + echo "Your architecture doesn't have it's equivalent" >&2 + echo "Debian userspace architecture defined!" >&2 + echo "Falling back to using your current userspace instead!" >&2 + echo "Please add support for $UTS_MACHINE to ${0} ..." >&2 + echo "" >&2 + esac + if [ -n "$debarch" ] ; then + forcearch="-DArchitecture=$debarch" + fi + # Create the package - dpkg-gencontrol -isp -p$pname -P"$pdir" + dpkg-gencontrol -isp $forcearch -p$pname -P"$pdir" dpkg --build "$pdir" .. } -- cgit v1.2.3-70-g09d2 From 6e5b86924a633f5b6eefb051404339a5a7bb005e Mon Sep 17 00:00:00 2001 From: Américo Wang Date: Fri, 5 Nov 2010 14:16:10 +0800 Subject: gitignore: add scripts/recordmcount This file is generated, should be ignored by git. Signed-off-by: WANG Cong Signed-off-by: Michal Marek --- scripts/.gitignore | 1 + 1 file changed, 1 insertion(+) (limited to 'scripts') diff --git a/scripts/.gitignore b/scripts/.gitignore index c5d5db54c00..e2741d23bab 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -7,3 +7,4 @@ pnmtologo bin2c unifdef ihex2fw +recordmcount -- cgit v1.2.3-70-g09d2 From 45f53cc90e8f0e46ab024d0bc1de49ebee0dc583 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Fri, 5 Nov 2010 12:06:05 +0100 Subject: Kconfig: fix single letter command in scripts/config The one letter commands in scripts/config didn't work and always printed usage. Fix this here. Cc: erick@openchill.org Reported-by: erick@openchill.org Signed-off-by: Andi Kleen Signed-off-by: Michal Marek --- scripts/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/config b/scripts/config index 608d7fdb13e..dfd4732f709 100755 --- a/scripts/config +++ b/scripts/config @@ -86,7 +86,7 @@ while [ "$1" != "" ] ; do B=$ARG shift 2 ;; - --*) + -*) checkarg "$1" shift ;; -- cgit v1.2.3-70-g09d2 From 01660dfc37933c92dbb7c5718aea61f88025d71f Mon Sep 17 00:00:00 2001 From: Arnaud Lacombe Date: Mon, 8 Nov 2010 18:31:53 -0500 Subject: scripts/genksyms: fix header usage FreeBSD does not like when __STDC__ is defined, use the standard instead. Signed-off-by: Arnaud Lacombe Signed-off-by: Michal Marek --- scripts/genksyms/parse.c_shipped | 2 +- scripts/genksyms/parse.y | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'scripts') diff --git a/scripts/genksyms/parse.c_shipped b/scripts/genksyms/parse.c_shipped index eaee44e66a4..809b949e495 100644 --- a/scripts/genksyms/parse.c_shipped +++ b/scripts/genksyms/parse.c_shipped @@ -160,7 +160,7 @@ #include -#include +#include #include "genksyms.h" static int is_typedef; diff --git a/scripts/genksyms/parse.y b/scripts/genksyms/parse.y index 10d7dc724b6..09a265cd719 100644 --- a/scripts/genksyms/parse.y +++ b/scripts/genksyms/parse.y @@ -24,7 +24,7 @@ %{ #include -#include +#include #include "genksyms.h" static int is_typedef; -- cgit v1.2.3-70-g09d2 From 35d3778a8fe3c8b4a7513565e34d3bde00ce43ec Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 24 Nov 2010 10:43:55 +0100 Subject: scripts/tags.sh: Add magic for trace-events Make tags find the trace-event definitions Signed-off-by: Peter Zijlstra Acked-by: WANG Cong LKML-Reference: <1290591835.2072.438.camel@laptop> Signed-off-by: Ingo Molnar --- scripts/tags.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/tags.sh b/scripts/tags.sh index 8509bb51293..bbbe584d449 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -125,7 +125,9 @@ exuberant() -I DEFINE_TRACE,EXPORT_TRACEPOINT_SYMBOL,EXPORT_TRACEPOINT_SYMBOL_GPL \ --extra=+f --c-kinds=-px \ --regex-asm='/^ENTRY\(([^)]*)\).*/\1/' \ - --regex-c='/^SYSCALL_DEFINE[[:digit:]]?\(([^,)]*).*/sys_\1/' + --regex-c='/^SYSCALL_DEFINE[[:digit:]]?\(([^,)]*).*/sys_\1/' \ + --regex-c++='/^TRACE_EVENT\(([^,)]*).*/trace_\1/' \ + --regex-c++='/^DEFINE_EVENT\(([^,)]*).*/trace_\1/' all_kconfigs | xargs $1 -a \ --langdef=kconfig --language-force=kconfig \ -- cgit v1.2.3-70-g09d2 From 0a18a9386c056028799938960f91be338c4ff349 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 4 Nov 2010 10:24:16 +0100 Subject: tags: put function prototypes back! MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 7db86dc (ctags: usability fix) removed function prototypes from tags file claiming "It makes no real sense to include function prototypes". But it is useful for quickly determining which header file developer needs to include to fix compilation. Now if someone wants to remove forward declarations (which I agree are baggage), write a postprocessing script. Signed-off-by: Alexey Dobriyan Signed-off-by: Uwe Kleine-König Signed-off-by: Michal Marek --- scripts/tags.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/tags.sh b/scripts/tags.sh index 8509bb51293..e091db312dd 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -123,7 +123,7 @@ exuberant() -I ____cacheline_internodealigned_in_smp \ -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL \ -I DEFINE_TRACE,EXPORT_TRACEPOINT_SYMBOL,EXPORT_TRACEPOINT_SYMBOL_GPL \ - --extra=+f --c-kinds=-px \ + --extra=+f --c-kinds=+px \ --regex-asm='/^ENTRY\(([^)]*)\).*/\1/' \ --regex-c='/^SYSCALL_DEFINE[[:digit:]]?\(([^,)]*).*/sys_\1/' -- cgit v1.2.3-70-g09d2 From a1087ef6abedf0bfd60e5e3fddf33192cb2c1325 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 24 Nov 2010 15:54:18 +0100 Subject: scripts/coccinelle: update for compatability with Coccinelle 0.2.4 For doubleinit.cocci, Coccinelle 0.2.4 requires a comma after ... in a field list. Coccinelle also now behaves gracefully when a definition is provided for a virtual that doesn't exist, so there is no need for the semantic patch code to check for this case. Updated the documentation to reflect the fact that the best results will now be obtained with Coccinelle version 0.2.4 or later. Signed-off-by: Julia Lawall --- Documentation/coccinelle.txt | 4 ++++ scripts/coccinelle/misc/doubleinit.cocci | 6 ++--- scripts/coccinelle/null/deref_null.cocci | 39 ++++++++++++-------------------- 3 files changed, 21 insertions(+), 28 deletions(-) (limited to 'scripts') diff --git a/Documentation/coccinelle.txt b/Documentation/coccinelle.txt index 4a276ea7001..96b690348ba 100644 --- a/Documentation/coccinelle.txt +++ b/Documentation/coccinelle.txt @@ -36,6 +36,10 @@ as a regular user, and install it with sudo make install +The semantic patches in the kernel will work best with Coccinelle version +0.2.4 or later. Using earlier versions may incur some parse errors in the +semantic patch code, but any results that are obtained should still be +correct. Using Coccinelle on the Linux kernel ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/scripts/coccinelle/misc/doubleinit.cocci b/scripts/coccinelle/misc/doubleinit.cocci index 55d7dc19dfe..156b20adb35 100644 --- a/scripts/coccinelle/misc/doubleinit.cocci +++ b/scripts/coccinelle/misc/doubleinit.cocci @@ -7,7 +7,7 @@ // Copyright: (C) 2010 Julia Lawall, DIKU. GPLv2. // Copyright: (C) 2010 Gilles Muller, INRIA/LiP6. GPLv2. // URL: http://coccinelle.lip6.fr/ -// Comments: +// Comments: requires at least Coccinelle 0.2.4, lex or parse error otherwise // Options: -no_includes -include_headers virtual org @@ -19,7 +19,7 @@ position p0,p; expression E; @@ -struct I s =@p0 { ... .fld@p = E, ...}; +struct I s =@p0 { ..., .fld@p = E, ...}; @s@ identifier I, s, r.fld; @@ -27,7 +27,7 @@ position r.p0,p; expression E; @@ -struct I s =@p0 { ... .fld@p = E, ...}; +struct I s =@p0 { ..., .fld@p = E, ...}; @script:python depends on org@ p0 << r.p0; diff --git a/scripts/coccinelle/null/deref_null.cocci b/scripts/coccinelle/null/deref_null.cocci index 9969d76d0f4..cdac6cfcce9 100644 --- a/scripts/coccinelle/null/deref_null.cocci +++ b/scripts/coccinelle/null/deref_null.cocci @@ -11,21 +11,10 @@ // Options: virtual context -virtual patch virtual org virtual report -@initialize:python depends on !context && patch && !org && !report@ - -import sys -print >> sys.stderr, "This semantic patch does not support the 'patch' mode." - -@depends on patch@ -@@ - -this_rule_should_never_matches(); - -@ifm depends on !patch@ +@ifm@ expression *E; statement S1,S2; position p1; @@ -35,7 +24,7 @@ if@p1 ((E == NULL && ...) || ...) S1 else S2 // The following two rules are separate, because both can match a single // expression in different ways -@pr1 depends on !patch expression@ +@pr1 expression@ expression *ifm.E; identifier f; position p1; @@ -43,7 +32,7 @@ position p1; (E != NULL && ...) ? <+...E->f@p1...+> : ... -@pr2 depends on !patch expression@ +@pr2 expression@ expression *ifm.E; identifier f; position p2; @@ -59,7 +48,7 @@ position p2; // For org and report modes -@r depends on !context && !patch && (org || report) exists@ +@r depends on !context && (org || report) exists@ expression subE <= ifm.E; expression *ifm.E; expression E1,E2; @@ -99,7 +88,7 @@ if@p1 ((E == NULL && ...) || ...) } else S3 -@script:python depends on !context && !patch && !org && report@ +@script:python depends on !context && !org && report@ p << r.p; p1 << ifm.p1; x << ifm.E; @@ -109,7 +98,7 @@ msg="ERROR: %s is NULL but dereferenced." % (x) coccilib.report.print_report(p[0], msg) cocci.include_match(False) -@script:python depends on !context && !patch && org && !report@ +@script:python depends on !context && org && !report@ p << r.p; p1 << ifm.p1; x << ifm.E; @@ -120,7 +109,7 @@ msg_safe=msg.replace("[","@(").replace("]",")") cocci.print_main(msg_safe,p) cocci.include_match(False) -@s depends on !context && !patch && (org || report) exists@ +@s depends on !context && (org || report) exists@ expression subE <= ifm.E; expression *ifm.E; expression E1,E2; @@ -159,7 +148,7 @@ if@p1 ((E == NULL && ...) || ...) } else S3 -@script:python depends on !context && !patch && !org && report@ +@script:python depends on !context && !org && report@ p << s.p; p1 << ifm.p1; x << ifm.E; @@ -168,7 +157,7 @@ x << ifm.E; msg="ERROR: %s is NULL but dereferenced." % (x) coccilib.report.print_report(p[0], msg) -@script:python depends on !context && !patch && org && !report@ +@script:python depends on !context && org && !report@ p << s.p; p1 << ifm.p1; x << ifm.E; @@ -180,7 +169,7 @@ cocci.print_main(msg_safe,p) // For context mode -@depends on context && !patch && !org && !report exists@ +@depends on context && !org && !report exists@ expression subE <= ifm.E; expression *ifm.E; expression E1,E2; @@ -223,7 +212,7 @@ else S3 // The following three rules are duplicates of ifm, pr1 and pr2 respectively. // It is need because the previous rule as already made a "change". -@ifm1 depends on !patch@ +@ifm1@ expression *E; statement S1,S2; position p1; @@ -231,7 +220,7 @@ position p1; if@p1 ((E == NULL && ...) || ...) S1 else S2 -@pr11 depends on !patch expression@ +@pr11 expression@ expression *ifm1.E; identifier f; position p1; @@ -239,7 +228,7 @@ position p1; (E != NULL && ...) ? <+...E->f@p1...+> : ... -@pr12 depends on !patch expression@ +@pr12 expression@ expression *ifm1.E; identifier f; position p2; @@ -253,7 +242,7 @@ position p2; sizeof(<+...E->f@p2...+>) ) -@depends on context && !patch && !org && !report exists@ +@depends on context && !org && !report exists@ expression subE <= ifm1.E; expression *ifm1.E; expression E1,E2; -- cgit v1.2.3-70-g09d2 From cd3478f2bd8f2cec19f9247a8a9cd711cbe37683 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 30 Nov 2010 17:33:53 +0100 Subject: ARM: 6509/1: ftrace: ignore any ftrace.o in C version of recordmcount arch/arm/kernel/ftrace.c references mcount like kernel/tracing/ftrace.c, so change the exclusion filter to match any ftrace.o. Acked-by: Steven Rostedt Signed-off-by: Rabin Vincent Signed-off-by: Russell King --- scripts/recordmcount.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index f2f32eee2c5..ac6e51ceed5 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c @@ -357,7 +357,7 @@ do_file(char const *const fname) int main(int argc, char const *argv[]) { - const char ftrace[] = "kernel/trace/ftrace.o"; + const char ftrace[] = "/ftrace.o"; int ftrace_size = sizeof(ftrace) - 1; int n_error = 0; /* gcc-4.3.0 false positive complaint */ -- cgit v1.2.3-70-g09d2 From ed60453fa8f8fc3d034dfdf10371a99cc6905626 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 30 Nov 2010 17:36:48 +0100 Subject: ARM: 6511/1: ftrace: add ARM support for C version of recordmcount Depending on the compiler version, ARM GCC calls the mcount function either __gnu_mcount_nc or mcount. Acked-by: Steven Rostedt Signed-off-by: Rabin Vincent Signed-off-by: Russell King --- arch/arm/Kconfig | 1 + scripts/recordmcount.c | 5 ++++- scripts/recordmcount.h | 5 +++-- 3 files changed, 8 insertions(+), 3 deletions(-) (limited to 'scripts') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index db524e75c4a..a7b9070b661 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -23,6 +23,7 @@ config ARM select PERF_USE_VMALLOC select HAVE_REGS_AND_STACK_ACCESS_API select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V7)) + select HAVE_C_RECORDMCOUNT help The ARM series is a line of low-power-consumption RISC chip designs licensed by ARM Ltd and targeted at embedded applications and diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index ac6e51ceed5..038b3d1e298 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c @@ -38,6 +38,7 @@ static void *ehdr_curr; /* current ElfXX_Ehdr * for resource cleanup */ static char gpfx; /* prefix for global symbol name (sometimes '_') */ static struct stat sb; /* Remember .st_size, etc. */ static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */ +static const char *altmcount; /* alternate mcount symbol name */ /* setjmp() return values */ enum { @@ -299,7 +300,9 @@ do_file(char const *const fname) fail_file(); } break; case EM_386: reltype = R_386_32; break; - case EM_ARM: reltype = R_ARM_ABS32; break; + case EM_ARM: reltype = R_ARM_ABS32; + altmcount = "__gnu_mcount_nc"; + break; case EM_IA_64: reltype = R_IA64_IMM64; gpfx = '_'; break; case EM_MIPS: /* reltype: e_class */ gpfx = '_'; break; case EM_PPC: reltype = R_PPC_ADDR32; gpfx = '_'; break; diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h index 58e933a2054..8087bc8cd2d 100644 --- a/scripts/recordmcount.h +++ b/scripts/recordmcount.h @@ -275,11 +275,12 @@ static uint_t *sift_rel_mcount(uint_t *mlocp, Elf_Sym const *const symp = &sym0[Elf_r_sym(relp)]; char const *symname = &str0[w(symp->st_name)]; + char const *mcount = '_' == gpfx ? "_mcount" : "mcount"; if ('.' == symname[0]) ++symname; /* ppc64 hack */ - if (0 == strcmp((('_' == gpfx) ? "_mcount" : "mcount"), - symname)) + if (0 == strcmp(mcount, symname) || + (altmcount && 0 == strcmp(altmcount, symname))) mcountsym = Elf_r_sym(relp); } -- cgit v1.2.3-70-g09d2 From 2979076fbf17a0947d6eba367b0cac19c907c160 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 23 Nov 2010 19:54:02 -0500 Subject: headers_install: check exit status of unifdef MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If unifdef fails for any reason (like segfaulting), we should be aborting the install steps. So check its exit status in this unlikely scenario. Reported-by: Diego Elio Pettenò Signed-off-by: Mike Frysinger Signed-off-by: Michal Marek --- scripts/headers_install.pl | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'scripts') diff --git a/scripts/headers_install.pl b/scripts/headers_install.pl index 4ca3be3b2e5..efb3be10d42 100644 --- a/scripts/headers_install.pl +++ b/scripts/headers_install.pl @@ -45,6 +45,13 @@ foreach my $file (@files) { close $in; system $unifdef . " $tmpfile > $installdir/$file"; + # unifdef will exit 0 on success, and will exit 1 when the + # file was processed successfully but no changes were made, + # so abort only when it's higher than that. + my $e = $? >> 8; + if ($e > 1) { + die "$tmpfile: $!\n"; + } unlink $tmpfile; } exit 0; -- cgit v1.2.3-70-g09d2 From de323f22a83b024b7432e813609c6efb74b1bbfc Mon Sep 17 00:00:00 2001 From: "akpm@linux-foundation.org" Date: Tue, 30 Nov 2010 13:51:13 -0800 Subject: headers_check: better search for functions in headers Some headers don't bother with "extern" in function prototypes, which results in said prototypes being unnoticed and exported to userland. This patch slightly improves detection of such cases by checking for C type names as well in the beginning of a line. Signed-off-by: Alexander Shishkin Cc: Stephen Hemminger Cc: Michal Marek Cc: WANG Cong Cc: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Michal Marek --- scripts/headers_check.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/headers_check.pl b/scripts/headers_check.pl index 50d6cfd1fa7..e0e25a1c2c1 100644 --- a/scripts/headers_check.pl +++ b/scripts/headers_check.pl @@ -64,7 +64,7 @@ sub check_include sub check_declarations { - if ($line =~m/^\s*extern\b/) { + if ($line =~m/^(\s*extern|unsigned|char|short|int|long|void)\b/) { printf STDERR "$filename:$lineno: " . "userspace cannot call function or variable " . "defined in the kernel\n"; -- cgit v1.2.3-70-g09d2 From d52784eb3607bf887628742f99041b4f18d7d1de Mon Sep 17 00:00:00 2001 From: "akpm@linux-foundation.org" Date: Tue, 30 Nov 2010 13:52:14 -0800 Subject: headers_check: Fix warning text Fix the warning text too, per Randy. Cc: Alexander Shishkin Cc: Michal Marek Cc: Randy Dunlap Cc: Stephen Hemminger Cc: WANG Cong Signed-off-by: Andrew Morton Signed-off-by: Michal Marek --- scripts/headers_check.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'scripts') diff --git a/scripts/headers_check.pl b/scripts/headers_check.pl index e0e25a1c2c1..7957e7a5166 100644 --- a/scripts/headers_check.pl +++ b/scripts/headers_check.pl @@ -66,8 +66,8 @@ sub check_declarations { if ($line =~m/^(\s*extern|unsigned|char|short|int|long|void)\b/) { printf STDERR "$filename:$lineno: " . - "userspace cannot call function or variable " . - "defined in the kernel\n"; + "userspace cannot reference function or " . + "variable defined in the kernel\n"; } } -- cgit v1.2.3-70-g09d2 From f6820308e025d645d9d766c97586badd4ddb8754 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Mon, 13 Dec 2010 19:10:28 +0200 Subject: kbuild: introduce HDR_ARCH_LIST for headers_install_all Using HDR_ARCH_LIST you can specify subset of architectures you want to get headers for. Signed-off-by: Kirill A. Shutemov Signed-off-by: Michal Marek --- Documentation/make/headers_install.txt | 5 +++-- scripts/headers.sh | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'scripts') diff --git a/Documentation/make/headers_install.txt b/Documentation/make/headers_install.txt index f2481cabffc..951eb9f1e04 100644 --- a/Documentation/make/headers_install.txt +++ b/Documentation/make/headers_install.txt @@ -39,8 +39,9 @@ INSTALL_HDR_PATH indicates where to install the headers. It defaults to The command "make headers_install_all" exports headers for all architectures simultaneously. (This is mostly of interest to distribution maintainers, who create an architecture-independent tarball from the resulting include -directory.) Remember to provide the appropriate linux/asm directory via "mv" -or "ln -s" before building a C library with headers exported this way. +directory.) You also can use HDR_ARCH_LIST to specify list of architectures. +Remember to provide the appropriate linux/asm directory via "mv" or "ln -s" +before building a C library with headers exported this way. The kernel header export infrastructure is maintained by David Woodhouse . diff --git a/scripts/headers.sh b/scripts/headers.sh index 1ddcdd38d97..978b42b3acd 100755 --- a/scripts/headers.sh +++ b/scripts/headers.sh @@ -13,7 +13,7 @@ do_command() fi } -archs=$(ls ${srctree}/arch) +archs=${HDR_ARCH_LIST:-$(ls ${srctree}/arch)} for arch in ${archs}; do case ${arch} in -- cgit v1.2.3-70-g09d2 From 6e71fabe9e60b1c6db587fbeac349848647920ab Mon Sep 17 00:00:00 2001 From: Arnaud Lacombe Date: Sun, 5 Dec 2010 01:31:57 -0500 Subject: kconfig: do not define AUTOCONF_INCLUDED AUTOCONF_INCLUDED is not checked is not used within the tree and its parent header, `autoconf.h', is safe to be re-included. Signed-off-by: Arnaud Lacombe Signed-off-by: Michal Marek --- scripts/kconfig/confdata.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 9df80114b47..f349bdcffa9 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -833,8 +833,7 @@ int conf_write_autoconf(void) " * Automatically generated C config: don't edit\n" " * %s\n" " * %s" - " */\n" - "#define AUTOCONF_INCLUDED\n", + " */\n", rootmenu.prompt->text, ctime(&now)); for_all_symbols(i, sym) { -- cgit v1.2.3-70-g09d2 From 0dce631092f410bb22b21b3d47ef20d69389dfd9 Mon Sep 17 00:00:00 2001 From: Arnaud Lacombe Date: Sun, 5 Dec 2010 01:33:16 -0500 Subject: kconfig: nuke second argument of conf_write_symbol() Replacing S_TRISTATE by S_BOOLEAN is a no-op for conf_write_symbol(). Signed-off-by: Arnaud Lacombe [mmarek: Fix unused variable warning in conf_write()] Signed-off-by: Michal Marek --- scripts/kconfig/confdata.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index f349bdcffa9..d1bab0f42d1 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -440,12 +440,11 @@ static void conf_write_string(bool headerfile, const char *name, fputs("\"\n", out); } -static void conf_write_symbol(struct symbol *sym, enum symbol_type type, - FILE *out, bool write_no) +static void conf_write_symbol(struct symbol *sym, FILE *out, bool write_no) { const char *str; - switch (type) { + switch (sym->type) { case S_BOOLEAN: case S_TRISTATE: switch (sym_get_tristate_value(sym)) { @@ -532,7 +531,7 @@ int conf_write_defconfig(const char *filename) goto next_menu; } } - conf_write_symbol(sym, sym->type, out, true); + conf_write_symbol(sym, out, true); } next_menu: if (menu->list != NULL) { @@ -561,7 +560,6 @@ int conf_write(const char *name) const char *basename; const char *str; char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1]; - enum symbol_type type; time_t now; int use_timestamp = 1; char *env; @@ -633,14 +631,8 @@ int conf_write(const char *name) if (!(sym->flags & SYMBOL_WRITE)) goto next; sym->flags &= ~SYMBOL_WRITE; - type = sym->type; - if (type == S_TRISTATE) { - sym_calc_value(modules_sym); - if (modules_sym->curr.tri == no) - type = S_BOOLEAN; - } /* Write config symbol to file */ - conf_write_symbol(sym, type, out, true); + conf_write_symbol(sym, out, true); } next: @@ -842,7 +834,7 @@ int conf_write_autoconf(void) continue; /* write symbol to config file */ - conf_write_symbol(sym, sym->type, out, false); + conf_write_symbol(sym, out, false); /* update autoconf and tristate files */ switch (sym->type) { -- cgit v1.2.3-70-g09d2 From fe04ce0bf955eaf53f7e4cd6bb35976fa94e0925 Mon Sep 17 00:00:00 2001 From: Arnaud Lacombe Date: Sun, 5 Dec 2010 01:41:14 -0500 Subject: kbuild/nconf: fix spaces damage Signed-off-by: Arnaud Lacombe Signed-off-by: Michal Marek --- scripts/kconfig/nconf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c index 272a987f23e..eda49ffc1c8 100644 --- a/scripts/kconfig/nconf.c +++ b/scripts/kconfig/nconf.c @@ -248,7 +248,7 @@ search_help[] = N_( "Only relevant lines are shown.\n" "\n\n" "Search examples:\n" -"Examples: USB = > find all symbols containing USB\n" +"Examples: USB => find all symbols containing USB\n" " ^USB => find all symbols starting with USB\n" " USB$ => find all symbols ending with USB\n" "\n"); -- cgit v1.2.3-70-g09d2 From 1ebfa5198ee96f34f2ee4ae95c92318f07341fbd Mon Sep 17 00:00:00 2001 From: Arnaud Lacombe Date: Sun, 5 Dec 2010 01:41:15 -0500 Subject: kbuild/gconf: add dummy inline for bind_textdomain_codeset() This symbols is used by gconf. Signed-off-by: Arnaud Lacombe Signed-off-by: Michal Marek --- scripts/kconfig/lkc.h | 1 + 1 file changed, 1 insertion(+) (limited to 'scripts') diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index 753cdbd7b80..a542c6ba84b 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -14,6 +14,7 @@ static inline const char *gettext(const char *txt) { return txt; } static inline void textdomain(const char *domainname) {} static inline void bindtextdomain(const char *name, const char *dir) {} +static inline char *bind_textdomain_codeset(const char *dn, char *c) { return c; } #endif #ifdef __cplusplus -- cgit v1.2.3-70-g09d2 From 579fb8e741fecef7dfd64afcc7b0b0c68ea207cc Mon Sep 17 00:00:00 2001 From: Arnaud Lacombe Date: Sun, 5 Dec 2010 01:41:16 -0500 Subject: kconfig: fix typos Signed-off-by: Arnaud Lacombe Signed-off-by: Michal Marek --- scripts/kconfig/confdata.c | 6 +++--- scripts/kconfig/symbol.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index d1bab0f42d1..61c35bf2d9c 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -937,7 +937,7 @@ static void randomize_choice_values(struct symbol *csym) int cnt, def; /* - * If choice is mod then we may have more items slected + * If choice is mod then we may have more items selected * and if no then no-one. * In both cases stop. */ @@ -1033,10 +1033,10 @@ void conf_set_all_new_symbols(enum conf_def_mode mode) /* * We have different type of choice blocks. - * If curr.tri equal to mod then we can select several + * If curr.tri equals to mod then we can select several * choice symbols in one block. * In this case we do nothing. - * If curr.tri equal yes then only one symbol can be + * If curr.tri equals yes then only one symbol can be * selected in a choice block and we set it to yes, * and the rest to no. */ diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index c0efe102d65..60830ce4a0a 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -686,7 +686,7 @@ const char *sym_get_string_default(struct symbol *sym) switch (sym->type) { case S_BOOLEAN: case S_TRISTATE: - /* The visibility imay limit the value from yes => mod */ + /* The visibility may limit the value from yes => mod */ val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri); break; default: -- cgit v1.2.3-70-g09d2 From bf128f5265625b8015789ea8f12b3582dc29faa3 Mon Sep 17 00:00:00 2001 From: Arnaud Lacombe Date: Sun, 5 Dec 2010 01:41:17 -0500 Subject: kconfig/conf: merge duplicate switch's case Signed-off-by: Arnaud Lacombe Signed-off-by: Michal Marek --- scripts/kconfig/conf.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c index 5459a38be86..659326c3e89 100644 --- a/scripts/kconfig/conf.c +++ b/scripts/kconfig/conf.c @@ -529,8 +529,6 @@ int main(int ac, char **av) } break; case savedefconfig: - conf_read(NULL); - break; case silentoldconfig: case oldaskconfig: case oldconfig: -- cgit v1.2.3-70-g09d2 From 4ce2c1e8e899831dd152bd0d534a60da6fb1582a Mon Sep 17 00:00:00 2001 From: Arnaud Lacombe Date: Sun, 5 Dec 2010 01:41:18 -0500 Subject: kconfig: fix `zconfdebug' extern declaration This symbol is only exist if YYDEBUG is defined. Signed-off-by: Arnaud Lacombe Signed-off-by: Michal Marek --- scripts/kconfig/lkc.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index a542c6ba84b..6d38b7c9c82 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -68,10 +68,12 @@ struct kconf_id { enum symbol_type stype; }; +#ifdef YYDEBUG +extern int zconfdebug; +#endif + int zconfparse(void); void zconfdump(FILE *out); - -extern int zconfdebug; void zconf_starthelp(void); FILE *zconf_fopen(const char *name); void zconf_initscan(const char *name); -- cgit v1.2.3-70-g09d2 From f0a6332ce221614fbd0731af92f668892fa4b700 Mon Sep 17 00:00:00 2001 From: Jonas Aaberg Date: Wed, 15 Dec 2010 08:37:00 +0100 Subject: kbuild: add numeric --set-val option to scripts/config Add new option to scripts/config for changing .config numeric values Acked-by: Linus Walleij Signed-off-by: Jonas Aaberg Signed-off-by: Michal Marek --- scripts/config | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'scripts') diff --git a/scripts/config b/scripts/config index dfd4732f709..a7c7c4b8e95 100755 --- a/scripts/config +++ b/scripts/config @@ -10,8 +10,10 @@ commands: --enable|-e option Enable option --disable|-d option Disable option --module|-m option Turn option into a module - --set-str option value - Set option to "value" + --set-str option string + Set option to "string" + --set-val option value + Set option to value --state|-s option Print state of option (n,y,m,undef) --enable-after|-E beforeopt option @@ -109,6 +111,11 @@ while [ "$1" != "" ] ; do shift ;; + --set-val) + set_var "CONFIG_$ARG" "CONFIG_$ARG=$1" + shift + ;; + --state|-s) if grep -q "# CONFIG_$ARG is not set" $FN ; then echo n -- cgit v1.2.3-70-g09d2 From ab60bd0b92ec57c98df08616b7d0664be5551eae Mon Sep 17 00:00:00 2001 From: Arnaud Lacombe Date: Sun, 5 Dec 2010 01:29:25 -0500 Subject: kconfig: add more S_INT and S_HEX consistency checks This patch add more number consistency checkg, trying to catch the following situation: config FOO0 hex default 42 config FOO1 string config BAR0 int default FOO1 config BAR1 hex default FOO1 config FOO2 hex default 42h config FOO3 int default "1bar" Signed-off-by: Arnaud Lacombe Signed-off-by: Michal Marek --- scripts/kconfig/menu.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 7e83aef42c6..8a8bc9be783 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -183,7 +183,7 @@ void menu_add_option(int token, char *arg) } } -static int menu_range_valid_sym(struct symbol *sym, struct symbol *sym2) +static int menu_validate_number(struct symbol *sym, struct symbol *sym2) { return sym2->type == S_INT || sym2->type == S_HEX || (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name)); @@ -201,6 +201,15 @@ static void sym_check_prop(struct symbol *sym) prop_warn(prop, "default for config symbol '%s'" " must be a single symbol", sym->name); + if (prop->expr->type != E_SYMBOL) + break; + sym2 = prop_get_symbol(prop); + if (sym->type == S_HEX || sym->type == S_INT) { + if (!menu_validate_number(sym, sym2)) + prop_warn(prop, + "'%s': number is invalid", + sym->name); + } break; case P_SELECT: sym2 = prop_get_symbol(prop); @@ -220,8 +229,8 @@ static void sym_check_prop(struct symbol *sym) if (sym->type != S_INT && sym->type != S_HEX) prop_warn(prop, "range is only allowed " "for int or hex symbols"); - if (!menu_range_valid_sym(sym, prop->expr->left.sym) || - !menu_range_valid_sym(sym, prop->expr->right.sym)) + if (!menu_validate_number(sym, prop->expr->left.sym) || + !menu_validate_number(sym, prop->expr->right.sym)) prop_warn(prop, "range is invalid"); break; default: -- cgit v1.2.3-70-g09d2 From 1121584f5db8a99a7ad94c6c5d62431b3187ad98 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Wed, 15 Dec 2010 17:11:22 -0800 Subject: modpost: Put .zdebug* section on white list "as --compress-debug-sections" will generate compressed debug sections with section names ".zdebug*". This patch puts .zdebug* section on white list. Signed-off-by: H.J. Lu Signed-off-by: Michal Marek --- scripts/mod/modpost.c | 1 + 1 file changed, 1 insertion(+) (limited to 'scripts') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 33122ca04e7..194e2c45360 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -790,6 +790,7 @@ static const char *section_white_list[] = { ".comment*", ".debug*", + ".zdebug*", /* Compressed debug sections. */ ".GCC-command-line", /* mn10300 */ ".mdebug*", /* alpha, score, mips etc. */ ".pdr", /* alpha, score, mips etc. */ -- cgit v1.2.3-70-g09d2 From 6e5f6856427abe5418f535cb46c454ae8ea7f8e7 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 25 Aug 2010 12:22:40 +0200 Subject: checksyscalls: Fix stand-alone usage The usage help in the comments - refers to the wrong script name, - doesn't mention that $srctree must be set. Hence correct the script name, and derive the source tree path from the script path, so we no longer need to rely on $srctree being set by the caller. Signed-off-by: Geert Uytterhoeven Acked-by: Sam Ravnborg Signed-off-by: Michal Marek --- scripts/checksyscalls.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'scripts') diff --git a/scripts/checksyscalls.sh b/scripts/checksyscalls.sh index 6bb42e72e0e..3ab316e5231 100755 --- a/scripts/checksyscalls.sh +++ b/scripts/checksyscalls.sh @@ -6,7 +6,7 @@ # and listed below so they are ignored. # # Usage: -# syscallchk gcc gcc-options +# checksyscalls.sh gcc gcc-options # ignore_list() { @@ -204,5 +204,5 @@ sed -n -e '/^\#define/ s/[^_]*__NR_\([^[:space:]]*\).*/\ \#endif/p' $1 } -(ignore_list && syscall_list ${srctree}/arch/x86/include/asm/unistd_32.h) | \ +(ignore_list && syscall_list $(dirname $0)/../arch/x86/include/asm/unistd_32.h) | \ $* -E -x c - > /dev/null -- cgit v1.2.3-70-g09d2 From 55f88eccf9c288eed2f93f9ca7d7fe4dd2da762e Mon Sep 17 00:00:00 2001 From: Asbjoern Sloth Toennesen Date: Sun, 12 Dec 2010 17:39:40 +0000 Subject: kbuild, deb-pkg: support overriding userland architecture Usefull if building for sparc64 userland, because the sparc and sparc64 userlands use the same 64-bit kernel, making it impossible to always select the correct userland architecture for the resulting debian package. Might also be usefull, if you want a i386 userland with a amd64 kernel. Example usage: make KBUILD_DEBARCH=i386 deb-pkg LKML-reference: Signed-off-by: Asbjoern Sloth Toennesen Reviewed-by: WANG Cong Acked-by: maximilian attems Signed-off-by: Michal Marek --- Documentation/kbuild/kbuild.txt | 8 ++++++++ scripts/package/builddeb | 3 +++ 2 files changed, 11 insertions(+) (limited to 'scripts') diff --git a/Documentation/kbuild/kbuild.txt b/Documentation/kbuild/kbuild.txt index 634c625da8c..b146eb86e49 100644 --- a/Documentation/kbuild/kbuild.txt +++ b/Documentation/kbuild/kbuild.txt @@ -51,6 +51,14 @@ Specify the output directory when building the kernel. The output directory can also be specificed using "O=...". Setting "O=..." takes precedence over KBUILD_OUTPUT. +KBUILD_DEBARCH +-------------------------------------------------- +For the deb-pkg target, allows overriding the normal heuristics deployed by +deb-pkg. Normally deb-pkg attempts to guess the right architecture based on +the UTS_MACHINE variable, and on some architectures also the kernel config. +The value of KBUILD_DEBARCH is assumed (not checked) to be a valid Debian +architecture. + ARCH -------------------------------------------------- Set ARCH to the architecture to be built. diff --git a/scripts/package/builddeb b/scripts/package/builddeb index 5d6be3f5e7f..ffe24194b76 100644 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -54,6 +54,9 @@ create_package() { echo "Please add support for $UTS_MACHINE to ${0} ..." >&2 echo "" >&2 esac + if [ -n "$KBUILD_DEBARCH" ] ; then + debarch="$KBUILD_DEBARCH" + fi if [ -n "$debarch" ] ; then forcearch="-DArchitecture=$debarch" fi -- cgit v1.2.3-70-g09d2 From 1137c56b7420c801147e0863845c03b07554721a Mon Sep 17 00:00:00 2001 From: Arnaud Lacombe Date: Sun, 26 Sep 2010 16:24:08 -0400 Subject: kconfig: simplify select-with-unmet-direct-dependency warning This is an attempt to simplify the expressing printed by kconfig when a symbol is selected but still has direct unmet dependency. First, the symbol reverse dependency is split in sub-expression. Then, each sub-expression is checked to ensure that it does not contains the unmet dependency. This removes the false-positive symbols and fixed symbol which already have the correct dependency. Finally, only the symbol responsible of the "select" is printed, instead of its full dependency tree. CC: Catalin Marinas Signed-off-by: Arnaud Lacombe Signed-off-by: Michal Marek --- scripts/kconfig/expr.c | 42 ++++++++++++++++++++++++++++++++++++++++++ scripts/kconfig/symbol.c | 6 +++++- 2 files changed, 47 insertions(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c index 330e7c0048a..65531a7f28a 100644 --- a/scripts/kconfig/expr.c +++ b/scripts/kconfig/expr.c @@ -1013,6 +1013,48 @@ int expr_compare_type(enum expr_type t1, enum expr_type t2) #endif } +static inline struct expr * +expr_get_leftmost_symbol(const struct expr *e) +{ + + if (e == NULL) + return NULL; + + while (e->type != E_SYMBOL) + e = e->left.expr; + + return expr_copy(e); +} + +/* + * Given expression `e1' and `e2', returns the leaf of the longest + * sub-expression of `e1' not containing 'e2. + */ +struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2) +{ + struct expr *ret; + + switch (e1->type) { + case E_OR: + return expr_alloc_and( + expr_simplify_unmet_dep(e1->left.expr, e2), + expr_simplify_unmet_dep(e1->right.expr, e2)); + case E_AND: { + struct expr *e; + e = expr_alloc_and(expr_copy(e1), expr_copy(e2)); + e = expr_eliminate_dups(e); + ret = (!expr_eq(e, e1)) ? e1 : NULL; + expr_free(e); + break; + } + default: + ret = e1; + break; + } + + return expr_get_leftmost_symbol(ret); +} + void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken) { if (!e) { diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index 60830ce4a0a..fa52e6f44ac 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -351,12 +351,16 @@ void sym_calc_value(struct symbol *sym) } calc_newval: if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) { + struct expr *e; + e = expr_simplify_unmet_dep(sym->rev_dep.expr, + sym->dir_dep.expr); fprintf(stderr, "warning: ("); - expr_fprint(sym->rev_dep.expr, stderr); + expr_fprint(e, stderr); fprintf(stderr, ") selects %s which has unmet direct dependencies (", sym->name); expr_fprint(sym->dir_dep.expr, stderr); fprintf(stderr, ")\n"); + expr_free(e); } newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri); } -- cgit v1.2.3-70-g09d2 From 17742dc743716eebbf5892add0e0bf91f541fc39 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Mon, 20 Dec 2010 16:06:44 +0100 Subject: kconfig: Make expr_copy() take a const argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes scripts/kconfig/expr.c: In function ‘expr_get_leftmost_symbol’: scripts/kconfig/expr.c:1026:2: warning: passing argument 1 of ‘expr_copy’ discards qualifiers from pointer target type scripts/kconfig/expr.c:67:14: note: expected ‘struct expr *’ but argument is of type ‘const struct expr *’ Signed-off-by: Michal Marek --- scripts/kconfig/expr.c | 2 +- scripts/kconfig/expr.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c index 65531a7f28a..001003452f6 100644 --- a/scripts/kconfig/expr.c +++ b/scripts/kconfig/expr.c @@ -64,7 +64,7 @@ struct expr *expr_alloc_or(struct expr *e1, struct expr *e2) return e2 ? expr_alloc_two(E_OR, e1, e2) : e1; } -struct expr *expr_copy(struct expr *org) +struct expr *expr_copy(const struct expr *org) { struct expr *e; diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index 184eb6a0b50..218991b26d9 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -191,7 +191,7 @@ struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2); struct expr *expr_alloc_and(struct expr *e1, struct expr *e2); struct expr *expr_alloc_or(struct expr *e1, struct expr *e2); -struct expr *expr_copy(struct expr *org); +struct expr *expr_copy(const struct expr *org); void expr_free(struct expr *e); int expr_eq(struct expr *e1, struct expr *e2); void expr_eliminate_eq(struct expr **ep1, struct expr **ep2); -- cgit v1.2.3-70-g09d2 From a3ba81131aca243bfecfa78c42edec0cd69f72d6 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Wed, 22 Dec 2010 13:30:14 -0500 Subject: Make fixdep error handling more explicit Also add missing error handling to fstat call Signed-off-by: Ben Gamari Signed-off-by: Michal Marek --- scripts/basic/fixdep.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'scripts') diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c index ed058462369..c9a16abacab 100644 --- a/scripts/basic/fixdep.c +++ b/scripts/basic/fixdep.c @@ -286,7 +286,7 @@ static void do_config_file(const char *filename) fd = open(filename, O_RDONLY); if (fd < 0) { - fprintf(stderr, "fixdep: "); + fprintf(stderr, "fixdep: error opening config file: "); perror(filename); exit(2); } @@ -357,11 +357,15 @@ static void print_deps(void) fd = open(depfile, O_RDONLY); if (fd < 0) { - fprintf(stderr, "fixdep: "); + fprintf(stderr, "fixdep: error opening depfile: "); perror(depfile); exit(2); } - fstat(fd, &st); + if (fstat(fd, &st) < 0) { + fprintf(stderr, "fixdep: error fstat'ing depfile: "); + perror(depfile); + exit(2); + } if (st.st_size == 0) { fprintf(stderr,"fixdep: %s is empty\n",depfile); close(fd); -- cgit v1.2.3-70-g09d2 From aab94339cd85d726abeae78fc02351fc1910e6a4 Mon Sep 17 00:00:00 2001 From: Dirk Brandewie Date: Wed, 22 Dec 2010 11:57:26 -0800 Subject: of: Add support for linking device tree blobs into vmlinux This patch adds support for linking device tree blob(s) into vmlinux. Modifies asm-generic/vmlinux.lds.h to add linking .dtb sections into vmlinux. To maintain compatiblity with the of/fdt driver code platforms MUST copy the blob to a non-init memory location before the kernel frees the .init.* sections in the image. Modifies scripts/Makefile.lib to add a kbuild command to compile DTS files to device tree blobs and a rule to create objects to wrap the blobs for linking. STRUCT_ALIGNMENT is defined in vmlinux.lds.h for use in the rule to create wrapper objects for the dtb in Makefile.lib. The STRUCT_ALIGN() macro in vmlinux.lds.h is modified to use the STRUCT_ALIGNMENT definition. The DTB's are placed on 32 byte boundries to allow parsing the blob with driver/of/fdt.c during early boot without having to copy the blob to get the structure alignment GCC expects. A DTB is linked in by adding the DTB object to the list of objects to be linked into vmlinux in the archtecture specific Makefile using obj-y += foo.dtb.o Signed-off-by: Dirk Brandewie Acked-by: Michal Marek [grant.likely@secretlab.ca: cleaned up whitespace inconsistencies] Signed-off-by: Grant Likely --- Documentation/kbuild/makefiles.txt | 15 +++++++++++++++ include/asm-generic/vmlinux.lds.h | 13 +++++++++++-- scripts/Makefile.lib | 23 +++++++++++++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) (limited to 'scripts') diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt index 0ef00bd6e54..86e3cd0d26a 100644 --- a/Documentation/kbuild/makefiles.txt +++ b/Documentation/kbuild/makefiles.txt @@ -1136,6 +1136,21 @@ When kbuild executes, the following steps are followed (roughly): resulting in the target file being recompiled for no obvious reason. + dtc + Create flattend device tree blob object suitable for linking + into vmlinux. Device tree blobs linked into vmlinux are placed + in an init section in the image. Platform code *must* copy the + blob to non-init memory prior to calling unflatten_device_tree(). + + Example: + #arch/x86/platform/ce4100/Makefile + clean-files := *dtb.S + + DTC_FLAGS := -p 1024 + obj-y += foo.dtb.o + + $(obj)/%.dtb: $(src)/%.dts + $(call cmd,dtc) --- 6.7 Custom kbuild commands diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index bd69d79208d..05cbad03c5a 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -67,7 +67,8 @@ * Align to a 32 byte boundary equal to the * alignment gcc 4.5 uses for a struct */ -#define STRUCT_ALIGN() . = ALIGN(32) +#define STRUCT_ALIGNMENT 32 +#define STRUCT_ALIGN() . = ALIGN(STRUCT_ALIGNMENT) /* The actual configuration determine if the init/exit sections * are handled as text/data or they can be discarded (which @@ -146,6 +147,13 @@ #define TRACE_SYSCALLS() #endif + +#define KERNEL_DTB() \ + STRUCT_ALIGN(); \ + VMLINUX_SYMBOL(__dtb_start) = .; \ + *(.dtb.init.rodata) \ + VMLINUX_SYMBOL(__dtb_end) = .; + /* .data section */ #define DATA_DATA \ *(.data) \ @@ -468,7 +476,8 @@ MCOUNT_REC() \ DEV_DISCARD(init.rodata) \ CPU_DISCARD(init.rodata) \ - MEM_DISCARD(init.rodata) + MEM_DISCARD(init.rodata) \ + KERNEL_DTB() #define INIT_TEXT \ *(.init.text) \ diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 4c72c118947..396da16aabf 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -200,6 +200,29 @@ quiet_cmd_gzip = GZIP $@ cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -f -9 > $@) || \ (rm -f $@ ; false) +# DTC +# --------------------------------------------------------------------------- + +# Generate an assembly file to wrap the output of the device tree compiler +quiet_cmd_dt_S_dtb= DTB $@ +cmd_dt_S_dtb= \ +( \ + echo '\#include '; \ + echo '.section .dtb.init.rodata,"a"'; \ + echo '.balign STRUCT_ALIGNMENT'; \ + echo '.global __dtb_$(*F)_begin'; \ + echo '__dtb_$(*F)_begin:'; \ + echo '.incbin "$<" '; \ + echo '__dtb_$(*F)_end:'; \ + echo '.global __dtb_$(*F)_end'; \ + echo '.balign STRUCT_ALIGNMENT'; \ +) > $@ + +$(obj)/%.dtb.S: $(obj)/%.dtb + $(call cmd,dt_S_dtb) + +quiet_cmd_dtc = DTC $@ +cmd_dtc = $(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 $(DTC_FLAGS) $< # Bzip2 # --------------------------------------------------------------------------- -- cgit v1.2.3-70-g09d2 From 0597fcd08b858df83b9f20afd6035311d92c48f8 Mon Sep 17 00:00:00 2001 From: Arnaud Lacombe Date: Thu, 23 Dec 2010 03:25:16 -0500 Subject: kconfig: fix warning In file included from scripts/kconfig/zconf.tab.c:2502: scripts/kconfig/expr.c:1033: warning: no previous prototype for 'expr_simplify_unmet_dep' Reported-by: Stephen Rothwell Signed-off-by: Arnaud Lacombe Signed-off-by: Michal Marek --- scripts/kconfig/expr.h | 1 + 1 file changed, 1 insertion(+) (limited to 'scripts') diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index 218991b26d9..79ab6e746f5 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -206,6 +206,7 @@ struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2); struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2); void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2); struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym); +struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2); void expr_fprint(struct expr *e, FILE *out); struct gstr; /* forward */ -- cgit v1.2.3-70-g09d2 From 731ece41fb1047816303295a0cdfed90a528137e Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Fri, 10 Dec 2010 02:09:23 -0600 Subject: modpost: Fix address calculation in reloc_location() This patch fixes a segfault in modpost that is observed when the gold linker is used to link the input objects. The problem is that reloc_location (modpost.c) is computing the address of the relocation target incorrectly. Here, elf->hdr points to the beginning of the ELF file in memory, sechdr points to the relocation section header, section is the index of the section being relocated, and sechdrs[section].sh_offset would be the offset of that section, relative to the beginning of the ELF file. Adding elf->hdr + sechdrs[section].sh_offset gives you the address of the beginning of the section, and adding r->r_offset to that gives you the address of the location to be relocated. You do not need to subtract sechdrs[section].sh_addr from that -- the result of this is an address outside the file, and causes the segfault when addend_386_rel tries to dereference it. This bug is not observed when GNU ld is used to link the inputs. The object file ubuntu/omnibook/omnibook.o is the result of an ld -r of several other files. When GNU ld does an ld -r, it sets the vaddr field for each section to 0, but gold lays out the section addresses sequentially instead: Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .text PROGBITS 00000000 000034 004794 00 AX 0 0 4 [ 2] .data PROGBITS 0000b9d0 0047c8 0009c0 00 WA 0 0 4 [ 3] .bss NOBITS 000162f8 005188 00013c 00 WA 0 0 4 [ 4] .rodata.str1.1 PROGBITS 00004f2d 0052c4 001b1a 01 AMS 0 0 1 [ 5] .init.text PROGBITS 00004794 006dde 0005fa 00 AX 0 0 1 [ 6] .exit.text PROGBITS 00004d8e 0073d8 00018a 00 AX 0 0 1 ... So the bug in the tool remained undiscovered because the section's vaddr always happened to be 0. Signed-off-by: Raymes Khoury Signed-off-by: Olof Johansson Signed-off-by: Michal Marek --- scripts/mod/modpost.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 194e2c45360..97d2259ae99 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -1442,7 +1442,7 @@ static unsigned int *reloc_location(struct elf_info *elf, int section = shndx2secindex(sechdr->sh_info); return (void *)elf->hdr + sechdrs[section].sh_offset + - r->r_offset - sechdrs[section].sh_addr; + r->r_offset; } static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) -- cgit v1.2.3-70-g09d2 From cd8d60a20a4516016c117ac0f1ac7b06ff606f7e Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Fri, 24 Dec 2010 09:42:10 -0500 Subject: kbuild: create linux-headers package in deb-pkg Create a linux-headers-$KVER.deb package which can be used to build external modules without having the source tree around. Signed-off-by: "Theodore Ts'o" Signed-off-by: Michal Marek --- scripts/package/builddeb | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/package/builddeb b/scripts/package/builddeb index ffe24194b76..5fc1e6f7183 100644 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -76,15 +76,17 @@ else fi tmpdir="$objtree/debian/tmp" fwdir="$objtree/debian/fwtmp" +hdrdir="$objtree/debian/hdrtmp" packagename=linux-image-$version fwpackagename=linux-firmware-image +hdrpackagename=linux-headers-$version if [ "$ARCH" = "um" ] ; then packagename=user-mode-linux-$version fi # Setup the directory structure -rm -rf "$tmpdir" "$fwdir" +rm -rf "$tmpdir" "$fwdir" "$hdrdir" mkdir -m 755 -p "$tmpdir/DEBIAN" mkdir -p "$tmpdir/lib" "$tmpdir/boot" "$tmpdir/usr/share/doc/$packagename" mkdir -m 755 -p "$fwdir/DEBIAN" @@ -226,6 +228,30 @@ EOF fi +# Build header package +find . -name Makefile -o -name Kconfig\* -o -name \*.pl > /tmp/files$$ +find arch/x86/include include scripts -type f >> /tmp/files$$ +(cd $objtree; find .config Module.symvers include scripts -type f >> /tmp/objfiles$$) +destdir=$hdrdir/usr/src/linux-headers-$version +mkdir -p "$destdir" "$hdrdir/DEBIAN" "$hdrdir/usr/share/doc/$hdrpackagename" +tar -c -f - -T /tmp/files$$ | (cd $destdir; tar -xf -) +(cd $objtree; tar -c -f - -T /tmp/objfiles$$) | (cd $destdir; tar -xf -) +rm -f /tmp/files$$ /tmp/objfiles$$ +arch=$(dpkg --print-architecture) + +cat <> debian/control + +Package: $hdrpackagename +Provides: linux-headers, linux-headers-2.6 +Architecture: $arch +Description: Linux kernel headers for $KERNELRELEASE on $arch + This package provides kernel header files for $KERNELRELEASE on $arch + . + This is useful for people who need to build external modules +EOF + +create_package "$hdrpackagename" "$hdrdir" + # Do we have firmware? Move it out of the way and build it into a package. if [ -e "$tmpdir/lib/firmware" ]; then mv "$tmpdir/lib/firmware" "$fwdir/lib/" -- cgit v1.2.3-70-g09d2 From 658f29a51e9830e620bb9a1ce3534b318a38bfeb Mon Sep 17 00:00:00 2001 From: John Bonesio Date: Wed, 17 Nov 2010 15:28:20 -0800 Subject: of/flattree: Update dtc to current mainline. Pull in recent changes from the main dtc repository. These changes primarily allow multiple device trees to be declared which are merged by dtc. This feature allows us to include a basic dts file and then provide more information for the specific system through the merging functionality. Changes pulled from git://git.jdl.com/software/dtc.git commit id: 37c0b6a0, "dtc: Add code to make diffing trees easier" Signed-off-by: John Bonesio Signed-off-by: Grant Likely --- scripts/dtc/Makefile | 3 +- scripts/dtc/checks.c | 105 ++++- scripts/dtc/dtc-lexer.l | 175 +------ scripts/dtc/dtc-lexer.lex.c_shipped | 551 +++++++--------------- scripts/dtc/dtc-parser.tab.c_shipped | 892 +++++++++++++++++------------------ scripts/dtc/dtc-parser.tab.h_shipped | 82 ++-- scripts/dtc/dtc-parser.y | 160 +++---- scripts/dtc/dtc.c | 57 ++- scripts/dtc/dtc.h | 77 ++- scripts/dtc/flattree.c | 192 ++++---- scripts/dtc/fstree.c | 12 +- scripts/dtc/livetree.c | 345 +++++++++++++- scripts/dtc/srcpos.c | 258 +++++++--- scripts/dtc/srcpos.h | 99 ++-- scripts/dtc/treesource.c | 48 +- scripts/dtc/util.c | 59 +++ scripts/dtc/util.h | 56 +++ scripts/dtc/version_gen.h | 2 +- 18 files changed, 1721 insertions(+), 1452 deletions(-) create mode 100644 scripts/dtc/util.c create mode 100644 scripts/dtc/util.h (limited to 'scripts') diff --git a/scripts/dtc/Makefile b/scripts/dtc/Makefile index 01cdb36fc58..04a31c17639 100644 --- a/scripts/dtc/Makefile +++ b/scripts/dtc/Makefile @@ -4,7 +4,7 @@ hostprogs-y := dtc always := $(hostprogs-y) dtc-objs := dtc.o flattree.o fstree.o data.o livetree.o treesource.o \ - srcpos.o checks.o + srcpos.o checks.o util.o dtc-objs += dtc-lexer.lex.o dtc-parser.tab.o # Source files need to get at the userspace version of libfdt_env.h to compile @@ -19,6 +19,7 @@ HOSTCFLAGS_fstree.o := $(HOSTCFLAGS_DTC) HOSTCFLAGS_livetree.o := $(HOSTCFLAGS_DTC) HOSTCFLAGS_srcpos.o := $(HOSTCFLAGS_DTC) HOSTCFLAGS_treesource.o := $(HOSTCFLAGS_DTC) +HOSTCFLAGS_util.o := $(HOSTCFLAGS_DTC) HOSTCFLAGS_dtc-lexer.lex.o := $(HOSTCFLAGS_DTC) HOSTCFLAGS_dtc-parser.tab.o := $(HOSTCFLAGS_DTC) diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c index 95485796f25..a662a004479 100644 --- a/scripts/dtc/checks.c +++ b/scripts/dtc/checks.c @@ -278,32 +278,112 @@ static void check_property_name_chars(struct check *c, struct node *dt, } PROP_CHECK(property_name_chars, PROPNODECHARS, ERROR); +#define DESCLABEL_FMT "%s%s%s%s%s" +#define DESCLABEL_ARGS(node,prop,mark) \ + ((mark) ? "value of " : ""), \ + ((prop) ? "'" : ""), \ + ((prop) ? (prop)->name : ""), \ + ((prop) ? "' in " : ""), (node)->fullpath + +static void check_duplicate_label(struct check *c, struct node *dt, + const char *label, struct node *node, + struct property *prop, struct marker *mark) +{ + struct node *othernode = NULL; + struct property *otherprop = NULL; + struct marker *othermark = NULL; + + othernode = get_node_by_label(dt, label); + + if (!othernode) + otherprop = get_property_by_label(dt, label, &othernode); + if (!othernode) + othermark = get_marker_label(dt, label, &othernode, + &otherprop); + + if (!othernode) + return; + + if ((othernode != node) || (otherprop != prop) || (othermark != mark)) + FAIL(c, "Duplicate label '%s' on " DESCLABEL_FMT + " and " DESCLABEL_FMT, + label, DESCLABEL_ARGS(node, prop, mark), + DESCLABEL_ARGS(othernode, otherprop, othermark)); +} + +static void check_duplicate_label_node(struct check *c, struct node *dt, + struct node *node) +{ + struct label *l; + + for_each_label(node->labels, l) + check_duplicate_label(c, dt, l->label, node, NULL, NULL); +} +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); +} +CHECK(duplicate_label, NULL, check_duplicate_label_node, + check_duplicate_label_prop, NULL, ERROR); + static void check_explicit_phandles(struct check *c, struct node *root, - struct node *node) + struct node *node, struct property *prop) { - struct property *prop; + struct marker *m; struct node *other; cell_t phandle; - prop = get_property(node, "linux,phandle"); - if (! prop) - return; /* No phandle, that's fine */ + if (!streq(prop->name, "phandle") + && !streq(prop->name, "linux,phandle")) + return; if (prop->val.len != sizeof(cell_t)) { - FAIL(c, "%s has bad length (%d) linux,phandle property", - node->fullpath, prop->val.len); + FAIL(c, "%s has bad length (%d) %s property", + node->fullpath, prop->val.len, prop->name); + return; + } + + m = prop->val.markers; + for_each_marker_of_type(m, REF_PHANDLE) { + assert(m->offset == 0); + if (node != get_node_by_ref(root, m->ref)) + /* "Set this node's phandle equal to some + * other node's phandle". That's nonsensical + * 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; } phandle = propval_cell(prop); + if ((phandle == 0) || (phandle == -1)) { - FAIL(c, "%s has invalid linux,phandle value 0x%x", - node->fullpath, phandle); + FAIL(c, "%s has bad value (0x%x) in %s property", + node->fullpath, phandle, prop->name); return; } + if (node->phandle && (node->phandle != phandle)) + FAIL(c, "%s has %s property which replaces existing phandle information", + node->fullpath, prop->name); + other = get_node_by_phandle(root, phandle); - if (other) { + if (other && (other != node)) { FAIL(c, "%s has duplicated phandle 0x%x (seen before at %s)", node->fullpath, phandle, other->fullpath); return; @@ -311,7 +391,7 @@ static void check_explicit_phandles(struct check *c, struct node *root, node->phandle = phandle; } -NODE_CHECK(explicit_phandles, NULL, ERROR); +PROP_CHECK(explicit_phandles, NULL, ERROR); static void check_name_properties(struct check *c, struct node *root, struct node *node) @@ -549,6 +629,9 @@ static struct check *check_table[] = { &duplicate_node_names, &duplicate_property_names, &node_name_chars, &node_name_format, &property_name_chars, &name_is_string, &name_properties, + + &duplicate_label, + &explicit_phandles, &phandle_references, &path_references, diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l index a627bbee91d..e866ea5166a 100644 --- a/scripts/dtc/dtc-lexer.l +++ b/scripts/dtc/dtc-lexer.l @@ -18,7 +18,7 @@ * USA */ -%option noyywrap noinput nounput yylineno +%option noyywrap nounput noinput never-interactive %x INCLUDE %x BYTESTRING @@ -38,6 +38,13 @@ LINECOMMENT "//".*\n #include "srcpos.h" #include "dtc-parser.tab.h" +YYLTYPE yylloc; + +/* CAUTION: this will stop working if we ever use yyless() or yyunput() */ +#define YY_USER_ACTION \ + { \ + srcpos_update(&yylloc, yytext, yyleng); \ + } /*#define LEXDEBUG 1*/ @@ -47,15 +54,10 @@ LINECOMMENT "//".*\n #define DPRINT(fmt, ...) do { } while (0) #endif -static int dts_version; /* = 0 */ +static int dts_version = 1; -#define BEGIN_DEFAULT() if (dts_version == 0) { \ - DPRINT("\n"); \ - BEGIN(INITIAL); \ - } else { \ - DPRINT("\n"); \ +#define BEGIN_DEFAULT() DPRINT("\n"); \ BEGIN(V1); \ - } static void push_input_file(const char *filename); static int pop_input_file(void); @@ -75,18 +77,13 @@ static int pop_input_file(void); } <*>{STRING} { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; DPRINT("String: %s\n", yytext); yylval.data = data_copy_escape_string(yytext+1, yyleng-2); - yylloc.first_line = yylineno; return DT_STRING; } <*>"/dts-v1/" { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; DPRINT("Keyword: /dts-v1/\n"); dts_version = 1; BEGIN_DEFAULT(); @@ -94,106 +91,57 @@ static int pop_input_file(void); } <*>"/memreserve/" { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; DPRINT("Keyword: /memreserve/\n"); BEGIN_DEFAULT(); return DT_MEMRESERVE; } <*>{LABEL}: { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; DPRINT("Label: %s\n", yytext); - yylval.labelref = strdup(yytext); + yylval.labelref = xstrdup(yytext); yylval.labelref[yyleng-1] = '\0'; return DT_LABEL; } -[bodh]# { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; - if (*yytext == 'b') - yylval.cbase = 2; - else if (*yytext == 'o') - yylval.cbase = 8; - else if (*yytext == 'd') - yylval.cbase = 10; - else - yylval.cbase = 16; - DPRINT("Base: %d\n", yylval.cbase); - return DT_BASE; - } - -[0-9a-fA-F]+ { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; - yylval.literal = strdup(yytext); - DPRINT("Literal: '%s'\n", yylval.literal); - return DT_LEGACYLITERAL; - } - [0-9]+|0[xX][0-9a-fA-F]+ { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; - yylval.literal = strdup(yytext); + yylval.literal = xstrdup(yytext); DPRINT("Literal: '%s'\n", yylval.literal); return DT_LITERAL; } -\&{LABEL} { /* label reference */ - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; +<*>\&{LABEL} { /* label reference */ DPRINT("Ref: %s\n", yytext+1); - yylval.labelref = strdup(yytext+1); + yylval.labelref = xstrdup(yytext+1); return DT_REF; } -"&{/"{PATHCHAR}+\} { /* new-style path reference */ - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; +<*>"&{/"{PATHCHAR}+\} { /* new-style path reference */ yytext[yyleng-1] = '\0'; DPRINT("Ref: %s\n", yytext+2); - yylval.labelref = strdup(yytext+2); - return DT_REF; - } - -"&/"{PATHCHAR}+ { /* old-style path reference */ - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; - DPRINT("Ref: %s\n", yytext+1); - yylval.labelref = strdup(yytext+1); + yylval.labelref = xstrdup(yytext+2); return DT_REF; } [0-9a-fA-F]{2} { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; yylval.byte = strtol(yytext, NULL, 16); DPRINT("Byte: %02x\n", (int)yylval.byte); return DT_BYTE; } "]" { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; DPRINT("/BYTESTRING\n"); BEGIN_DEFAULT(); return ']'; } {PROPNODECHAR}+ { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; DPRINT("PropNodeName: %s\n", yytext); - yylval.propnodename = strdup(yytext); + yylval.propnodename = xstrdup(yytext); BEGIN_DEFAULT(); return DT_PROPNODENAME; } "/incbin/" { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; DPRINT("Binary Include\n"); return DT_INCBIN; } @@ -203,8 +151,6 @@ static int pop_input_file(void); <*>{LINECOMMENT}+ /* eat C++-style comments */ <*>. { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; DPRINT("Char: %c (\\x%02x)\n", yytext[0], (unsigned)yytext[0]); if (yytext[0] == '[') { @@ -221,100 +167,25 @@ static int pop_input_file(void); %% - -/* - * Stack of nested include file contexts. - */ - -struct incl_file { - struct dtc_file *file; - YY_BUFFER_STATE yy_prev_buf; - int yy_prev_lineno; - struct incl_file *prev; -}; - -static struct incl_file *incl_file_stack; - - -/* - * Detect infinite include recursion. - */ -#define MAX_INCLUDE_DEPTH (100) - -static int incl_depth = 0; - - static void push_input_file(const char *filename) { - struct incl_file *incl_file; - struct dtc_file *newfile; - struct search_path search, *searchptr = NULL; - assert(filename); - if (incl_depth++ >= MAX_INCLUDE_DEPTH) - die("Includes nested too deeply"); - - if (srcpos_file) { - search.dir = srcpos_file->dir; - search.next = NULL; - search.prev = NULL; - searchptr = &search; - } - - newfile = dtc_open_file(filename, searchptr); + srcfile_push(filename); - incl_file = xmalloc(sizeof(struct incl_file)); + yyin = current_srcfile->f; - /* - * Save current context. - */ - incl_file->yy_prev_buf = YY_CURRENT_BUFFER; - incl_file->yy_prev_lineno = yylineno; - incl_file->file = srcpos_file; - incl_file->prev = incl_file_stack; - - incl_file_stack = incl_file; - - /* - * Establish new context. - */ - srcpos_file = newfile; - yylineno = 1; - yyin = newfile->file; - yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); + yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE)); } static int pop_input_file(void) { - struct incl_file *incl_file; - - if (incl_file_stack == 0) + if (srcfile_pop() == 0) return 0; - dtc_close_file(srcpos_file); - - /* - * Pop. - */ - --incl_depth; - incl_file = incl_file_stack; - incl_file_stack = incl_file->prev; - - /* - * Recover old context. - */ - yy_delete_buffer(YY_CURRENT_BUFFER); - yy_switch_to_buffer(incl_file->yy_prev_buf); - yylineno = incl_file->yy_prev_lineno; - srcpos_file = incl_file->file; - yyin = incl_file->file ? incl_file->file->file : NULL; - - /* - * Free old state. - */ - free(incl_file); + yypop_buffer_state(); + yyin = current_srcfile->f; return 1; } diff --git a/scripts/dtc/dtc-lexer.lex.c_shipped b/scripts/dtc/dtc-lexer.lex.c_shipped index e27cc636e32..50c4420b4b2 100644 --- a/scripts/dtc/dtc-lexer.lex.c_shipped +++ b/scripts/dtc/dtc-lexer.lex.c_shipped @@ -170,20 +170,7 @@ extern FILE *yyin, *yyout; #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 - /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires - * access to the local variable yy_act. Since yyless() is a macro, it would break - * existing scanners that call yyless() from OUTSIDE yylex. - * One obvious solution it to make yy_act a global. I tried that, and saw - * a 5% performance hit in a non-yylineno scanner, because yy_act is - * normally declared as a register variable-- so it is not worth it. - */ - #define YY_LESS_LINENO(n) \ - do { \ - int yyl;\ - for ( yyl = n; yyl < yyleng; ++yyl )\ - if ( yytext[yyl] == '\n' )\ - --yylineno;\ - }while(0) + #define YY_LESS_LINENO(n) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ @@ -385,8 +372,8 @@ static void yy_fatal_error (yyconst char msg[] ); *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; -#define YY_NUM_RULES 20 -#define YY_END_OF_BUFFER 21 +#define YY_NUM_RULES 17 +#define YY_END_OF_BUFFER 18 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -394,20 +381,19 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static yyconst flex_int16_t yy_accept[104] = +static yyconst flex_int16_t yy_accept[94] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 21, 19, 16, 16, 19, 19, 19, 7, 7, 19, - 7, 19, 19, 19, 19, 13, 14, 14, 19, 8, - 8, 16, 0, 2, 0, 0, 9, 0, 0, 0, - 0, 0, 0, 7, 7, 5, 0, 6, 0, 12, - 12, 14, 14, 8, 0, 11, 9, 0, 0, 0, - 0, 18, 0, 0, 0, 0, 8, 0, 17, 0, - 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 3, 15, + 18, 16, 13, 13, 16, 16, 16, 16, 16, 16, + 16, 10, 11, 11, 6, 6, 13, 0, 2, 0, + 7, 0, 0, 0, 0, 0, 0, 0, 5, 0, + 9, 9, 11, 11, 6, 0, 7, 0, 0, 0, + 0, 15, 0, 0, 0, 0, 6, 0, 14, 0, + 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 3, 12, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, - 0, 4, 0 + } ; static yyconst flex_int32_t yy_ec[256] = @@ -416,16 +402,16 @@ static yyconst flex_int32_t yy_ec[256] = 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 4, 5, 1, 1, 6, 1, 1, - 1, 7, 8, 8, 9, 8, 10, 11, 12, 13, - 13, 13, 13, 13, 13, 13, 13, 14, 1, 1, - 1, 1, 8, 8, 15, 15, 15, 15, 15, 15, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 17, 16, 16, - 1, 18, 19, 1, 16, 1, 15, 20, 21, 22, - - 23, 15, 16, 24, 25, 16, 16, 26, 27, 28, - 24, 16, 16, 29, 30, 31, 32, 33, 16, 17, - 16, 16, 34, 1, 35, 1, 1, 1, 1, 1, + 1, 7, 5, 5, 8, 5, 9, 10, 11, 12, + 12, 12, 12, 12, 12, 12, 12, 13, 1, 1, + 1, 1, 5, 5, 14, 14, 14, 14, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 16, 15, 15, + 1, 17, 18, 1, 15, 1, 14, 19, 20, 21, + + 22, 14, 15, 15, 23, 15, 15, 24, 25, 26, + 15, 15, 15, 27, 28, 29, 30, 31, 15, 16, + 15, 15, 32, 1, 33, 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, @@ -442,136 +428,114 @@ static yyconst flex_int32_t yy_ec[256] = 1, 1, 1, 1, 1 } ; -static yyconst flex_int32_t yy_meta[36] = +static yyconst flex_int32_t yy_meta[34] = { 0, - 1, 1, 1, 1, 2, 1, 2, 2, 2, 3, - 4, 4, 4, 5, 6, 7, 7, 1, 1, 6, - 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 8, 1 + 1, 1, 1, 1, 2, 1, 2, 2, 3, 4, + 4, 4, 5, 6, 7, 7, 1, 1, 6, 6, + 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 8, 1 } ; -static yyconst flex_int16_t yy_base[117] = +static yyconst flex_int16_t yy_base[106] = { 0, - 0, 0, 30, 0, 44, 0, 67, 0, 97, 105, - 302, 303, 35, 44, 40, 94, 112, 0, 129, 152, - 296, 295, 159, 0, 176, 303, 0, 116, 95, 165, - 49, 46, 102, 303, 296, 0, 0, 288, 290, 293, - 264, 266, 270, 0, 0, 303, 0, 303, 264, 303, - 0, 0, 195, 101, 0, 0, 0, 0, 284, 125, - 277, 265, 225, 230, 216, 218, 0, 202, 224, 221, - 217, 107, 196, 188, 303, 206, 179, 186, 178, 185, - 183, 162, 161, 150, 169, 160, 145, 125, 303, 303, - 137, 109, 190, 103, 203, 167, 108, 197, 303, 123, - - 29, 303, 303, 215, 221, 226, 229, 234, 240, 246, - 250, 257, 265, 270, 275, 282 + 0, 0, 237, 236, 25, 0, 47, 0, 30, 71, + 244, 247, 82, 84, 84, 211, 95, 229, 218, 0, + 111, 247, 0, 84, 83, 95, 106, 86, 247, 237, + 0, 230, 231, 234, 207, 209, 212, 220, 247, 206, + 247, 218, 0, 106, 116, 0, 0, 0, 223, 89, + 226, 219, 199, 206, 200, 204, 0, 190, 213, 212, + 202, 91, 178, 161, 247, 172, 144, 150, 140, 130, + 140, 124, 128, 120, 138, 137, 123, 122, 247, 247, + 134, 114, 132, 86, 135, 125, 90, 136, 247, 97, + 29, 247, 247, 153, 156, 161, 165, 170, 176, 180, + + 187, 195, 200, 205, 212 } ; -static yyconst flex_int16_t yy_def[117] = +static yyconst flex_int16_t yy_def[106] = { 0, - 103, 1, 1, 3, 3, 5, 103, 7, 3, 3, - 103, 103, 103, 103, 104, 105, 103, 106, 103, 19, - 19, 20, 103, 107, 20, 103, 108, 109, 105, 103, - 103, 103, 104, 103, 104, 110, 111, 103, 112, 113, - 103, 103, 103, 106, 19, 103, 20, 103, 103, 103, - 20, 108, 109, 103, 114, 110, 111, 115, 112, 112, - 113, 103, 103, 103, 103, 103, 114, 115, 103, 103, - 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, - 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, - 103, 103, 103, 103, 103, 116, 103, 116, 103, 116, - - 103, 103, 0, 103, 103, 103, 103, 103, 103, 103, - 103, 103, 103, 103, 103, 103 + 93, 1, 1, 1, 1, 5, 93, 7, 1, 1, + 93, 93, 93, 93, 94, 95, 93, 96, 17, 97, + 96, 93, 98, 99, 93, 93, 93, 94, 93, 94, + 100, 93, 101, 102, 93, 93, 93, 96, 93, 93, + 93, 96, 98, 99, 93, 103, 100, 104, 101, 101, + 102, 93, 93, 93, 93, 93, 103, 104, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 105, 93, 105, 93, 105, + 93, 93, 0, 93, 93, 93, 93, 93, 93, 93, + + 93, 93, 93, 93, 93 } ; -static yyconst flex_int16_t yy_nxt[339] = +static yyconst flex_int16_t yy_nxt[281] = { 0, - 12, 13, 14, 15, 12, 16, 12, 12, 12, 17, - 18, 18, 18, 12, 19, 20, 20, 12, 12, 21, - 19, 21, 19, 22, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 12, 12, 12, 32, 32, 102, 23, - 12, 12, 12, 34, 20, 32, 32, 32, 32, 20, - 20, 20, 20, 20, 24, 24, 24, 35, 25, 54, - 54, 54, 26, 25, 25, 25, 25, 12, 13, 14, - 15, 27, 12, 27, 27, 27, 23, 27, 27, 27, - 12, 28, 28, 28, 12, 12, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, - - 12, 12, 29, 36, 103, 34, 17, 30, 31, 31, - 29, 54, 54, 54, 17, 30, 31, 31, 39, 35, - 52, 40, 52, 52, 52, 103, 78, 38, 38, 46, - 101, 60, 79, 41, 69, 97, 42, 94, 43, 45, - 45, 45, 46, 45, 47, 47, 93, 92, 45, 45, - 45, 45, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 39, 47, 91, 40, 90, - 99, 47, 47, 47, 47, 54, 54, 54, 89, 88, - 41, 55, 87, 49, 100, 43, 51, 51, 51, 86, - 51, 95, 95, 96, 85, 51, 51, 51, 51, 52, - - 99, 52, 52, 52, 95, 95, 96, 84, 46, 83, - 82, 81, 39, 79, 100, 33, 33, 33, 33, 33, - 33, 33, 33, 37, 80, 77, 37, 37, 37, 44, - 40, 44, 50, 76, 50, 52, 75, 52, 74, 52, - 52, 53, 73, 53, 53, 53, 53, 56, 56, 56, - 72, 56, 56, 57, 71, 57, 57, 59, 59, 59, - 59, 59, 59, 59, 59, 61, 61, 61, 61, 61, - 61, 61, 61, 67, 70, 67, 68, 68, 68, 62, - 68, 68, 98, 98, 98, 98, 98, 98, 98, 98, - 60, 66, 65, 64, 63, 62, 60, 58, 103, 48, - - 48, 103, 11, 103, 103, 103, 103, 103, 103, 103, - 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, - 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, - 103, 103, 103, 103, 103, 103, 103, 103 + 12, 13, 14, 15, 12, 16, 12, 12, 17, 12, + 12, 12, 12, 18, 18, 18, 12, 12, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 12, 12, 19, 20, 20, 20, 92, 21, 25, + 26, 26, 22, 21, 21, 21, 21, 12, 13, 14, + 15, 23, 16, 23, 23, 19, 23, 23, 23, 12, + 24, 24, 24, 12, 12, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 12, 12, + 25, 26, 26, 27, 27, 27, 27, 29, 43, 29, + 43, 43, 45, 45, 45, 50, 39, 59, 46, 93, + + 30, 33, 30, 34, 45, 45, 45, 27, 27, 68, + 43, 91, 43, 43, 69, 35, 87, 36, 39, 37, + 42, 42, 42, 39, 42, 45, 45, 45, 89, 42, + 42, 42, 42, 85, 85, 86, 85, 85, 86, 89, + 84, 90, 83, 82, 81, 80, 79, 78, 77, 76, + 75, 74, 90, 28, 28, 28, 28, 28, 28, 28, + 28, 31, 31, 31, 38, 38, 38, 38, 41, 73, + 41, 43, 72, 43, 71, 43, 43, 44, 33, 44, + 44, 44, 44, 47, 69, 47, 47, 49, 49, 49, + 49, 49, 49, 49, 49, 51, 51, 51, 51, 51, + + 51, 51, 51, 57, 70, 57, 58, 58, 58, 67, + 58, 58, 88, 88, 88, 88, 88, 88, 88, 88, + 34, 66, 65, 64, 63, 62, 61, 60, 52, 50, + 39, 56, 39, 55, 54, 53, 52, 50, 48, 93, + 40, 39, 32, 93, 19, 19, 11, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93 } ; -static yyconst flex_int16_t yy_chk[339] = +static yyconst flex_int16_t yy_chk[281] = { 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, 3, 13, 13, 101, 3, - 3, 3, 3, 15, 3, 14, 14, 32, 32, 3, - 3, 3, 3, 3, 5, 5, 5, 15, 5, 31, - 31, 31, 5, 5, 5, 5, 5, 7, 7, 7, + 1, 1, 1, 5, 5, 5, 5, 91, 5, 9, + 9, 9, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - - 7, 7, 9, 16, 29, 33, 9, 9, 9, 9, - 10, 54, 54, 54, 10, 10, 10, 10, 17, 33, - 28, 17, 28, 28, 28, 100, 72, 16, 29, 28, - 97, 60, 72, 17, 60, 94, 17, 92, 17, 19, - 19, 19, 19, 19, 19, 19, 91, 88, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 20, 20, 20, 23, 20, 87, 23, 86, - 96, 20, 20, 20, 20, 30, 30, 30, 85, 84, - 23, 30, 83, 23, 96, 23, 25, 25, 25, 82, - 25, 93, 93, 93, 81, 25, 25, 25, 25, 53, - - 98, 53, 53, 53, 95, 95, 95, 80, 53, 79, - 78, 77, 76, 74, 98, 104, 104, 104, 104, 104, - 104, 104, 104, 105, 73, 71, 105, 105, 105, 106, - 70, 106, 107, 69, 107, 108, 68, 108, 66, 108, - 108, 109, 65, 109, 109, 109, 109, 110, 110, 110, - 64, 110, 110, 111, 63, 111, 111, 112, 112, 112, - 112, 112, 112, 112, 112, 113, 113, 113, 113, 113, - 113, 113, 113, 114, 62, 114, 115, 115, 115, 61, - 115, 115, 116, 116, 116, 116, 116, 116, 116, 116, - 59, 49, 43, 42, 41, 40, 39, 38, 35, 22, - - 21, 11, 103, 103, 103, 103, 103, 103, 103, 103, - 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, - 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, - 103, 103, 103, 103, 103, 103, 103, 103 + 10, 10, 10, 13, 13, 14, 14, 15, 24, 28, + 24, 24, 25, 25, 25, 50, 24, 50, 25, 90, + + 15, 17, 28, 17, 26, 26, 26, 27, 27, 62, + 44, 87, 44, 44, 62, 17, 84, 17, 44, 17, + 21, 21, 21, 21, 21, 45, 45, 45, 86, 21, + 21, 21, 21, 83, 83, 83, 85, 85, 85, 88, + 82, 86, 81, 78, 77, 76, 75, 74, 73, 72, + 71, 70, 88, 94, 94, 94, 94, 94, 94, 94, + 94, 95, 95, 95, 96, 96, 96, 96, 97, 69, + 97, 98, 68, 98, 67, 98, 98, 99, 66, 99, + 99, 99, 99, 100, 64, 100, 100, 101, 101, 101, + 101, 101, 101, 101, 101, 102, 102, 102, 102, 102, + + 102, 102, 102, 103, 63, 103, 104, 104, 104, 61, + 104, 104, 105, 105, 105, 105, 105, 105, 105, 105, + 60, 59, 58, 56, 55, 54, 53, 52, 51, 49, + 42, 40, 38, 37, 36, 35, 34, 33, 32, 30, + 19, 18, 16, 11, 4, 3, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93 } ; -/* Table of booleans, true if rule could match eol. */ -static yyconst flex_int32_t yy_rule_can_match_eol[21] = - { 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, - 0, }; - static yy_state_type yy_last_accepting_state; static char *yy_last_accepting_cpos; @@ -616,6 +580,13 @@ char *yytext; #include "srcpos.h" #include "dtc-parser.tab.h" +YYLTYPE yylloc; + +/* CAUTION: this will stop working if we ever use yyless() or yyunput() */ +#define YY_USER_ACTION \ + { \ + srcpos_update(&yylloc, yytext, yyleng); \ + } /*#define LEXDEBUG 1*/ @@ -625,19 +596,14 @@ char *yytext; #define DPRINT(fmt, ...) do { } while (0) #endif -static int dts_version; /* = 0 */ +static int dts_version = 1; -#define BEGIN_DEFAULT() if (dts_version == 0) { \ - DPRINT("\n"); \ - BEGIN(INITIAL); \ - } else { \ - DPRINT("\n"); \ +#define BEGIN_DEFAULT() DPRINT("\n"); \ BEGIN(V1); \ - } static void push_input_file(const char *filename); static int pop_input_file(void); -#line 641 "dtc-lexer.lex.c" +#line 607 "dtc-lexer.lex.c" #define INITIAL 0 #define INCLUDE 1 @@ -826,9 +792,9 @@ YY_DECL register char *yy_cp, *yy_bp; register int yy_act; -#line 64 "dtc-lexer.l" +#line 66 "dtc-lexer.l" -#line 832 "dtc-lexer.lex.c" +#line 798 "dtc-lexer.lex.c" if ( !(yy_init) ) { @@ -881,35 +847,21 @@ 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 >= 104 ) + if ( yy_current_state >= 94 ) 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_base[yy_current_state] != 303 ); + while ( yy_current_state != 93 ); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); yy_find_action: yy_act = yy_accept[yy_current_state]; - if ( yy_act == 0 ) - { /* have to back up */ - yy_cp = (yy_last_accepting_cpos); - yy_current_state = (yy_last_accepting_state); - yy_act = yy_accept[yy_current_state]; - } YY_DO_BEFORE_ACTION; - if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] ) - { - int yyl; - for ( yyl = 0; yyl < yyleng; ++yyl ) - if ( yytext[yyl] == '\n' ) - - yylineno++; -; - } - do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) @@ -924,7 +876,7 @@ do_action: /* This label is used only to access EOF actions. */ case 1: /* rule 1 can match eol */ YY_RULE_SETUP -#line 65 "dtc-lexer.l" +#line 67 "dtc-lexer.l" { char *name = strchr(yytext, '\"') + 1; yytext[yyleng-1] = '\0'; @@ -936,7 +888,7 @@ case YY_STATE_EOF(INCLUDE): case YY_STATE_EOF(BYTESTRING): case YY_STATE_EOF(PROPNODENAME): case YY_STATE_EOF(V1): -#line 71 "dtc-lexer.l" +#line 73 "dtc-lexer.l" { if (!pop_input_file()) { yyterminate(); @@ -946,23 +898,18 @@ case YY_STATE_EOF(V1): case 2: /* rule 2 can match eol */ YY_RULE_SETUP -#line 77 "dtc-lexer.l" +#line 79 "dtc-lexer.l" { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; DPRINT("String: %s\n", yytext); yylval.data = data_copy_escape_string(yytext+1, yyleng-2); - yylloc.first_line = yylineno; return DT_STRING; } YY_BREAK case 3: YY_RULE_SETUP -#line 87 "dtc-lexer.l" +#line 86 "dtc-lexer.l" { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; DPRINT("Keyword: /dts-v1/\n"); dts_version = 1; BEGIN_DEFAULT(); @@ -971,10 +918,8 @@ YY_RULE_SETUP YY_BREAK case 4: YY_RULE_SETUP -#line 96 "dtc-lexer.l" +#line 93 "dtc-lexer.l" { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; DPRINT("Keyword: /memreserve/\n"); BEGIN_DEFAULT(); return DT_MEMRESERVE; @@ -982,158 +927,100 @@ YY_RULE_SETUP YY_BREAK case 5: YY_RULE_SETUP -#line 104 "dtc-lexer.l" +#line 99 "dtc-lexer.l" { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; DPRINT("Label: %s\n", yytext); - yylval.labelref = strdup(yytext); + yylval.labelref = xstrdup(yytext); yylval.labelref[yyleng-1] = '\0'; return DT_LABEL; } YY_BREAK case 6: YY_RULE_SETUP -#line 113 "dtc-lexer.l" -{ - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; - if (*yytext == 'b') - yylval.cbase = 2; - else if (*yytext == 'o') - yylval.cbase = 8; - else if (*yytext == 'd') - yylval.cbase = 10; - else - yylval.cbase = 16; - DPRINT("Base: %d\n", yylval.cbase); - return DT_BASE; - } - YY_BREAK -case 7: -YY_RULE_SETUP -#line 128 "dtc-lexer.l" +#line 106 "dtc-lexer.l" { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; - yylval.literal = strdup(yytext); - DPRINT("Literal: '%s'\n", yylval.literal); - return DT_LEGACYLITERAL; - } - YY_BREAK -case 8: -YY_RULE_SETUP -#line 136 "dtc-lexer.l" -{ - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; - yylval.literal = strdup(yytext); + yylval.literal = xstrdup(yytext); DPRINT("Literal: '%s'\n", yylval.literal); return DT_LITERAL; } YY_BREAK -case 9: +case 7: YY_RULE_SETUP -#line 144 "dtc-lexer.l" +#line 112 "dtc-lexer.l" { /* label reference */ - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; DPRINT("Ref: %s\n", yytext+1); - yylval.labelref = strdup(yytext+1); + yylval.labelref = xstrdup(yytext+1); return DT_REF; } YY_BREAK -case 10: +case 8: YY_RULE_SETUP -#line 152 "dtc-lexer.l" +#line 118 "dtc-lexer.l" { /* new-style path reference */ - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; yytext[yyleng-1] = '\0'; DPRINT("Ref: %s\n", yytext+2); - yylval.labelref = strdup(yytext+2); + yylval.labelref = xstrdup(yytext+2); return DT_REF; } YY_BREAK -case 11: -YY_RULE_SETUP -#line 161 "dtc-lexer.l" -{ /* old-style path reference */ - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; - DPRINT("Ref: %s\n", yytext+1); - yylval.labelref = strdup(yytext+1); - return DT_REF; - } - YY_BREAK -case 12: +case 9: YY_RULE_SETUP -#line 169 "dtc-lexer.l" +#line 125 "dtc-lexer.l" { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; yylval.byte = strtol(yytext, NULL, 16); DPRINT("Byte: %02x\n", (int)yylval.byte); return DT_BYTE; } YY_BREAK -case 13: +case 10: YY_RULE_SETUP -#line 177 "dtc-lexer.l" +#line 131 "dtc-lexer.l" { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; DPRINT("/BYTESTRING\n"); BEGIN_DEFAULT(); return ']'; } YY_BREAK -case 14: +case 11: YY_RULE_SETUP -#line 185 "dtc-lexer.l" +#line 137 "dtc-lexer.l" { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; DPRINT("PropNodeName: %s\n", yytext); - yylval.propnodename = strdup(yytext); + yylval.propnodename = xstrdup(yytext); BEGIN_DEFAULT(); return DT_PROPNODENAME; } YY_BREAK -case 15: +case 12: YY_RULE_SETUP -#line 194 "dtc-lexer.l" +#line 144 "dtc-lexer.l" { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; DPRINT("Binary Include\n"); return DT_INCBIN; } YY_BREAK -case 16: -/* rule 16 can match eol */ +case 13: +/* rule 13 can match eol */ YY_RULE_SETUP -#line 201 "dtc-lexer.l" +#line 149 "dtc-lexer.l" /* eat whitespace */ YY_BREAK -case 17: -/* rule 17 can match eol */ +case 14: +/* rule 14 can match eol */ YY_RULE_SETUP -#line 202 "dtc-lexer.l" +#line 150 "dtc-lexer.l" /* eat C-style comments */ YY_BREAK -case 18: -/* rule 18 can match eol */ +case 15: +/* rule 15 can match eol */ YY_RULE_SETUP -#line 203 "dtc-lexer.l" +#line 151 "dtc-lexer.l" /* eat C++-style comments */ YY_BREAK -case 19: +case 16: YY_RULE_SETUP -#line 205 "dtc-lexer.l" +#line 153 "dtc-lexer.l" { - yylloc.file = srcpos_file; - yylloc.first_line = yylineno; DPRINT("Char: %c (\\x%02x)\n", yytext[0], (unsigned)yytext[0]); if (yytext[0] == '[') { @@ -1148,12 +1035,12 @@ YY_RULE_SETUP return yytext[0]; } YY_BREAK -case 20: +case 17: YY_RULE_SETUP -#line 222 "dtc-lexer.l" +#line 168 "dtc-lexer.l" ECHO; YY_BREAK -#line 1157 "dtc-lexer.lex.c" +#line 1044 "dtc-lexer.lex.c" case YY_END_OF_BUFFER: { @@ -1218,7 +1105,8 @@ ECHO; else { - yy_cp = (yy_c_buf_p); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); goto yy_find_action; } } @@ -1443,7 +1331,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 >= 104 ) + if ( yy_current_state >= 94 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; @@ -1471,11 +1359,11 @@ 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 >= 104 ) + if ( yy_current_state >= 94 ) 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 == 103); + yy_is_jam = (yy_current_state == 93); return yy_is_jam ? 0 : yy_current_state; } @@ -1550,11 +1438,6 @@ static int yy_get_next_buffer (void) *(yy_c_buf_p) = '\0'; /* preserve yytext */ (yy_hold_char) = *++(yy_c_buf_p); - if ( c == '\n' ) - - yylineno++; -; - return c; } #endif /* ifndef YY_NO_INPUT */ @@ -1669,10 +1552,6 @@ static void yy_load_buffer_state (void) yyfree((void *) b ); } -#ifndef __cplusplus -extern int isatty (int ); -#endif /* __cplusplus */ - /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a yyrestart() or at EOF. @@ -1696,7 +1575,7 @@ extern int isatty (int ); b->yy_bs_column = 0; } - b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + b->yy_is_interactive = 0; errno = oerrno; } @@ -2025,9 +1904,6 @@ static int yy_init_globals (void) * This function is called from yylex_destroy(), so don't allocate here. */ - /* We do not touch yylineno unless the option is enabled. */ - yylineno = 1; - (yy_buffer_stack) = 0; (yy_buffer_stack_top) = 0; (yy_buffer_stack_max) = 0; @@ -2120,104 +1996,29 @@ void yyfree (void * ptr ) #define YYTABLES_NAME "yytables" -#line 222 "dtc-lexer.l" - - - - -/* - * Stack of nested include file contexts. - */ - -struct incl_file { - struct dtc_file *file; - YY_BUFFER_STATE yy_prev_buf; - int yy_prev_lineno; - struct incl_file *prev; -}; - -static struct incl_file *incl_file_stack; +#line 168 "dtc-lexer.l" -/* - * Detect infinite include recursion. - */ -#define MAX_INCLUDE_DEPTH (100) - -static int incl_depth = 0; - static void push_input_file(const char *filename) { - struct incl_file *incl_file; - struct dtc_file *newfile; - struct search_path search, *searchptr = NULL; - assert(filename); - if (incl_depth++ >= MAX_INCLUDE_DEPTH) - die("Includes nested too deeply"); - - if (srcpos_file) { - search.dir = srcpos_file->dir; - search.next = NULL; - search.prev = NULL; - searchptr = &search; - } - - newfile = dtc_open_file(filename, searchptr); + srcfile_push(filename); - incl_file = xmalloc(sizeof(struct incl_file)); + yyin = current_srcfile->f; - /* - * Save current context. - */ - incl_file->yy_prev_buf = YY_CURRENT_BUFFER; - incl_file->yy_prev_lineno = yylineno; - incl_file->file = srcpos_file; - incl_file->prev = incl_file_stack; - - incl_file_stack = incl_file; - - /* - * Establish new context. - */ - srcpos_file = newfile; - yylineno = 1; - yyin = newfile->file; - yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE)); + yypush_buffer_state(yy_create_buffer(yyin,YY_BUF_SIZE)); } static int pop_input_file(void) { - struct incl_file *incl_file; - - if (incl_file_stack == 0) + if (srcfile_pop() == 0) return 0; - dtc_close_file(srcpos_file); - - /* - * Pop. - */ - --incl_depth; - incl_file = incl_file_stack; - incl_file_stack = incl_file->prev; - - /* - * Recover old context. - */ - yy_delete_buffer(YY_CURRENT_BUFFER); - yy_switch_to_buffer(incl_file->yy_prev_buf); - yylineno = incl_file->yy_prev_lineno; - srcpos_file = incl_file->file; - yyin = incl_file->file ? incl_file->file->file : NULL; - - /* - * Free old state. - */ - free(incl_file); + yypop_buffer_state(); + yyin = current_srcfile->f; return 1; } diff --git a/scripts/dtc/dtc-parser.tab.c_shipped b/scripts/dtc/dtc-parser.tab.c_shipped index 27129377e5d..9be2eea18a3 100644 --- a/scripts/dtc/dtc-parser.tab.c_shipped +++ b/scripts/dtc/dtc-parser.tab.c_shipped @@ -1,24 +1,23 @@ -/* A Bison parser, made by GNU Bison 2.3. */ -/* Skeleton implementation for Bison's Yacc-like parsers in C +/* A Bison parser, made by GNU Bison 2.4.1. */ - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify + + 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 - the Free Software Foundation; either version 2, or (at your option) - any later version. - + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + This program 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ + along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work @@ -29,7 +28,7 @@ special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. - + This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ @@ -47,7 +46,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "2.3" +#define YYBISON_VERSION "2.4.1" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -55,55 +54,32 @@ /* Pure parsers. */ #define YYPURE 0 -/* Using locations. */ -#define YYLSP_NEEDED 1 - +/* Push parsers. */ +#define YYPUSH 0 +/* Pull parsers. */ +#define YYPULL 1 -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - DT_V1 = 258, - DT_MEMRESERVE = 259, - DT_PROPNODENAME = 260, - DT_LITERAL = 261, - DT_LEGACYLITERAL = 262, - DT_BASE = 263, - DT_BYTE = 264, - DT_STRING = 265, - DT_LABEL = 266, - DT_REF = 267, - DT_INCBIN = 268 - }; -#endif -/* Tokens. */ -#define DT_V1 258 -#define DT_MEMRESERVE 259 -#define DT_PROPNODENAME 260 -#define DT_LITERAL 261 -#define DT_LEGACYLITERAL 262 -#define DT_BASE 263 -#define DT_BYTE 264 -#define DT_STRING 265 -#define DT_LABEL 266 -#define DT_REF 267 -#define DT_INCBIN 268 - +/* Using locations. */ +#define YYLSP_NEEDED 0 /* Copy the first part of user declarations. */ -#line 23 "dtc-parser.y" + +/* Line 189 of yacc.c */ +#line 21 "dtc-parser.y" #include #include "dtc.h" #include "srcpos.h" +YYLTYPE yylloc; + extern int yylex(void); +extern void print_error(char const *fmt, ...); +extern void yyerror(char const *s); extern struct boot_info *the_boot_info; extern int treesource_error; @@ -111,6 +87,9 @@ extern int treesource_error; static unsigned long long eval_literal(const char *s, int base, int bits); +/* Line 189 of yacc.c */ +#line 92 "dtc-parser.tab.c" + /* Enabling traces. */ #ifndef YYDEBUG # define YYDEBUG 0 @@ -129,10 +108,35 @@ static unsigned long long eval_literal(const char *s, int base, int bits); # define YYTOKEN_TABLE 0 #endif + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + DT_V1 = 258, + DT_MEMRESERVE = 259, + DT_PROPNODENAME = 260, + DT_LITERAL = 261, + DT_BASE = 262, + DT_BYTE = 263, + DT_STRING = 264, + DT_LABEL = 265, + DT_REF = 266, + DT_INCBIN = 267 + }; +#endif + + + #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE -#line 37 "dtc-parser.y" { + +/* Line 214 of yacc.c */ +#line 39 "dtc-parser.y" + char *propnodename; char *literal; char *labelref; @@ -147,34 +151,23 @@ typedef union YYSTYPE struct node *node; struct node *nodelist; struct reserve_info *re; -} -/* Line 187 of yacc.c. */ -#line 153 "dtc-parser.tab.c" - YYSTYPE; + + + +/* Line 214 of yacc.c */ +#line 159 "dtc-parser.tab.c" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 -# define YYSTYPE_IS_TRIVIAL 1 -#endif - -#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED -typedef struct YYLTYPE -{ - int first_line; - int first_column; - int last_line; - int last_column; -} YYLTYPE; -# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ -# define YYLTYPE_IS_DECLARED 1 -# define YYLTYPE_IS_TRIVIAL 1 #endif /* Copy the second part of user declarations. */ -/* Line 216 of yacc.c. */ -#line 178 "dtc-parser.tab.c" +/* Line 264 of yacc.c */ +#line 171 "dtc-parser.tab.c" #ifdef short # undef short @@ -249,14 +242,14 @@ typedef short int yytype_int16; #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static int -YYID (int i) +YYID (int yyi) #else static int -YYID (i) - int i; +YYID (yyi) + int yyi; #endif { - return i; + return yyi; } #endif @@ -332,15 +325,13 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */ #if (! defined yyoverflow \ && (! defined __cplusplus \ - || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ - && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { - yytype_int16 yyss; - YYSTYPE yyvs; - YYLTYPE yyls; + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ @@ -349,8 +340,8 @@ union yyalloc /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ - ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ - + 2 * YYSTACK_GAP_MAXIMUM) + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) /* Copy COUNT objects from FROM to TO. The source and destination do not overlap. */ @@ -375,12 +366,12 @@ union yyalloc elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ -# define YYSTACK_RELOCATE(Stack) \ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack, Stack, yysize); \ - Stack = &yyptr->Stack; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / sizeof (*yyptr); \ } \ @@ -389,22 +380,22 @@ union yyalloc #endif /* YYFINAL -- State number of the termination state. */ -#define YYFINAL 9 +#define YYFINAL 4 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 73 +#define YYLAST 56 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 27 +#define YYNTOKENS 25 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 20 +#define YYNNTS 16 /* YYNRULES -- Number of rules. */ -#define YYNRULES 45 +#define YYNRULES 39 /* YYNRULES -- Number of states. */ -#define YYNSTATES 76 +#define YYNSTATES 67 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 -#define YYMAXUTOK 268 +#define YYMAXUTOK 267 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) @@ -416,15 +407,15 @@ static const yytype_uint8 yytranslate[] = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 24, 26, 2, 2, 25, 15, 2, 16, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 14, - 20, 19, 21, 2, 2, 2, 2, 2, 2, 2, + 22, 24, 2, 2, 23, 2, 2, 14, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 13, + 18, 17, 19, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 22, 2, 23, 2, 2, 2, 2, 2, 2, + 2, 20, 2, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 17, 2, 18, 2, 2, 2, 2, + 2, 2, 2, 15, 2, 16, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -438,7 +429,7 @@ static const yytype_uint8 yytranslate[] = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13 + 5, 6, 7, 8, 9, 10, 11, 12 }; #if YYDEBUG @@ -446,41 +437,37 @@ static const yytype_uint8 yytranslate[] = YYRHS. */ static const yytype_uint8 yyprhs[] = { - 0, 0, 3, 8, 11, 12, 15, 21, 22, 25, - 27, 34, 36, 38, 41, 47, 48, 51, 57, 61, - 64, 69, 74, 77, 87, 93, 96, 97, 100, 103, - 104, 107, 110, 113, 114, 116, 118, 121, 122, 125, - 128, 129, 132, 135, 139, 140 + 0, 0, 3, 8, 9, 12, 17, 20, 22, 25, + 29, 33, 39, 40, 43, 48, 51, 54, 57, 62, + 67, 70, 80, 86, 89, 90, 93, 96, 97, 100, + 103, 106, 108, 109, 112, 115, 116, 119, 122, 125 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int8 yyrhs[] = { - 28, 0, -1, 3, 14, 29, 34, -1, 31, 34, - -1, -1, 30, 29, -1, 46, 4, 33, 33, 14, - -1, -1, 32, 31, -1, 30, -1, 46, 4, 33, - 15, 33, 14, -1, 6, -1, 7, -1, 16, 35, - -1, 17, 36, 44, 18, 14, -1, -1, 36, 37, - -1, 46, 5, 19, 38, 14, -1, 46, 5, 14, - -1, 39, 10, -1, 39, 20, 40, 21, -1, 39, - 22, 43, 23, -1, 39, 12, -1, 39, 13, 24, - 10, 25, 33, 25, 33, 26, -1, 39, 13, 24, - 10, 26, -1, 38, 11, -1, -1, 38, 25, -1, - 39, 11, -1, -1, 40, 42, -1, 40, 12, -1, - 40, 11, -1, -1, 8, -1, 6, -1, 41, 7, - -1, -1, 43, 9, -1, 43, 11, -1, -1, 45, - 44, -1, 45, 37, -1, 46, 5, 35, -1, -1, - 11, -1 + 26, 0, -1, 3, 13, 27, 30, -1, -1, 28, + 27, -1, 4, 29, 29, 13, -1, 10, 28, -1, + 6, -1, 14, 31, -1, 30, 14, 31, -1, 30, + 11, 31, -1, 15, 32, 39, 16, 13, -1, -1, + 32, 33, -1, 5, 17, 34, 13, -1, 5, 13, + -1, 10, 33, -1, 35, 9, -1, 35, 18, 36, + 19, -1, 35, 20, 38, 21, -1, 35, 11, -1, + 35, 12, 22, 9, 23, 29, 23, 29, 24, -1, + 35, 12, 22, 9, 24, -1, 34, 10, -1, -1, + 34, 23, -1, 35, 10, -1, -1, 36, 37, -1, + 36, 11, -1, 36, 10, -1, 6, -1, -1, 38, + 8, -1, 38, 10, -1, -1, 40, 39, -1, 40, + 33, -1, 5, 31, -1, 10, 40, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 89, 89, 93, 101, 104, 111, 119, 122, 129, - 133, 140, 144, 151, 158, 166, 169, 176, 180, 187, - 191, 195, 199, 203, 220, 231, 239, 242, 246, 254, - 257, 261, 266, 274, 277, 281, 285, 293, 296, 300, - 308, 311, 315, 323, 331, 334 + 0, 86, 86, 95, 98, 105, 109, 117, 124, 128, + 132, 145, 153, 156, 163, 167, 171, 179, 183, 187, + 191, 195, 212, 222, 230, 233, 237, 245, 248, 252, + 257, 264, 272, 275, 279, 287, 290, 294, 302, 306 }; #endif @@ -490,13 +477,12 @@ static const yytype_uint16 yyrline[] = static const char *const yytname[] = { "$end", "error", "$undefined", "DT_V1", "DT_MEMRESERVE", - "DT_PROPNODENAME", "DT_LITERAL", "DT_LEGACYLITERAL", "DT_BASE", - "DT_BYTE", "DT_STRING", "DT_LABEL", "DT_REF", "DT_INCBIN", "';'", "'-'", - "'/'", "'{'", "'}'", "'='", "'<'", "'>'", "'['", "']'", "'('", "','", - "')'", "$accept", "sourcefile", "memreserves", "memreserve", - "v0_memreserves", "v0_memreserve", "addr", "devicetree", "nodedef", - "proplist", "propdef", "propdata", "propdataprefix", "celllist", - "cellbase", "cellval", "bytestring", "subnodes", "subnode", "label", 0 + "DT_PROPNODENAME", "DT_LITERAL", "DT_BASE", "DT_BYTE", "DT_STRING", + "DT_LABEL", "DT_REF", "DT_INCBIN", "';'", "'/'", "'{'", "'}'", "'='", + "'<'", "'>'", "'['", "']'", "'('", "','", "')'", "$accept", "sourcefile", + "memreserves", "memreserve", "addr", "devicetree", "nodedef", "proplist", + "propdef", "propdata", "propdataprefix", "celllist", "cellval", + "bytestring", "subnodes", "subnode", 0 }; #endif @@ -506,29 +492,27 @@ static const char *const yytname[] = static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 59, 45, 47, 123, 125, 61, - 60, 62, 91, 93, 40, 44, 41 + 265, 266, 267, 59, 47, 123, 125, 61, 60, 62, + 91, 93, 40, 44, 41 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { - 0, 27, 28, 28, 29, 29, 30, 31, 31, 32, - 32, 33, 33, 34, 35, 36, 36, 37, 37, 38, - 38, 38, 38, 38, 38, 38, 39, 39, 39, 40, - 40, 40, 40, 41, 41, 42, 42, 43, 43, 43, - 44, 44, 44, 45, 46, 46 + 0, 25, 26, 27, 27, 28, 28, 29, 30, 30, + 30, 31, 32, 32, 33, 33, 33, 34, 34, 34, + 34, 34, 34, 34, 35, 35, 35, 36, 36, 36, + 36, 37, 38, 38, 38, 39, 39, 39, 40, 40 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { - 0, 2, 4, 2, 0, 2, 5, 0, 2, 1, - 6, 1, 1, 2, 5, 0, 2, 5, 3, 2, - 4, 4, 2, 9, 5, 2, 0, 2, 2, 0, - 2, 2, 2, 0, 1, 1, 2, 0, 2, 2, - 0, 2, 2, 3, 0, 1 + 0, 2, 4, 0, 2, 4, 2, 1, 2, 3, + 3, 5, 0, 2, 4, 2, 2, 2, 4, 4, + 2, 9, 5, 2, 0, 2, 2, 0, 2, 2, + 2, 1, 0, 2, 2, 0, 2, 2, 2, 2 }; /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state @@ -536,86 +520,79 @@ static const yytype_uint8 yyr2[] = means the default is an error. */ static const yytype_uint8 yydefact[] = { - 7, 0, 45, 0, 9, 0, 7, 0, 4, 1, - 0, 3, 8, 0, 0, 4, 0, 15, 13, 11, - 12, 0, 2, 5, 0, 40, 0, 0, 0, 16, - 0, 40, 0, 0, 6, 0, 42, 41, 0, 10, - 14, 18, 26, 43, 0, 0, 25, 17, 27, 19, - 28, 22, 0, 29, 37, 0, 33, 0, 0, 35, - 34, 32, 31, 20, 0, 30, 38, 39, 21, 0, - 24, 36, 0, 0, 0, 23 + 0, 0, 0, 3, 1, 0, 0, 0, 3, 7, + 0, 6, 0, 2, 4, 0, 12, 8, 0, 0, + 5, 35, 10, 9, 0, 0, 13, 0, 35, 15, + 24, 38, 16, 39, 0, 37, 36, 0, 0, 11, + 23, 14, 25, 17, 26, 20, 0, 27, 32, 0, + 0, 0, 0, 31, 30, 29, 18, 28, 33, 34, + 19, 0, 22, 0, 0, 0, 21 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { - -1, 3, 14, 4, 5, 6, 27, 11, 18, 25, - 29, 44, 45, 56, 64, 65, 57, 30, 31, 7 + -1, 2, 7, 8, 10, 13, 17, 21, 26, 37, + 38, 50, 57, 51, 27, 28 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ -#define YYPACT_NINF -14 +#define YYPACT_NINF -12 static const yytype_int8 yypact[] = { - 30, -11, -14, 7, -14, -1, 27, 13, 27, -14, - 8, -14, -14, 40, -1, 27, 35, -14, -14, -14, - -14, 21, -14, -14, 40, 24, 40, 28, 40, -14, - 32, 24, 46, 38, -14, 39, -14, -14, 26, -14, - -14, -14, -14, -14, -9, 10, -14, -14, -14, -14, - -14, -14, 31, -14, -14, 44, -2, 3, 23, -14, - -14, -14, -14, -14, 50, -14, -14, -14, -14, 40, - -14, -14, 33, 40, 36, -14 + 10, -11, 18, -1, -12, 22, -1, 15, -1, -12, + 22, -12, 20, 1, -12, 17, -12, -12, 20, 20, + -12, 6, -12, -12, 21, 6, -12, 23, 6, -12, + -12, -12, -12, -12, 28, -12, -12, -6, 13, -12, + -12, -12, -12, -12, -12, -12, 24, -12, -12, 33, + -5, 0, -4, -12, -12, -12, -12, -12, -12, -12, + -12, 22, -12, 25, 22, 19, -12 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { - -14, -14, 48, 29, 53, -14, -13, 47, 34, -14, - 37, -14, -14, -14, -14, -14, -14, 42, -14, -7 + -12, -12, 36, 39, -10, -12, 8, -12, 12, -12, + -12, -12, -12, -12, 27, 31 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which number is the opposite. If zero, do what YYDEFACT says. If YYTABLE_NINF, syntax error. */ -#define YYTABLE_NINF -45 -static const yytype_int8 yytable[] = +#define YYTABLE_NINF -1 +static const yytype_uint8 yytable[] = { - 21, 16, 46, 8, 59, 47, 60, 9, 16, 61, - 62, 28, 66, 33, 67, 10, 48, 13, 32, 63, - 49, 50, 51, 52, 32, 17, 68, 19, 20, -44, - 53, -44, 54, 1, -44, 2, 26, 15, 2, 24, - 41, 2, 34, 17, 15, 42, 19, 20, 69, 70, - 35, 38, 39, 40, 58, 55, 72, 71, 73, 12, - 74, 22, 75, 23, 0, 0, 0, 0, 36, 0, - 0, 0, 43, 37 + 15, 53, 3, 5, 40, 54, 55, 41, 58, 6, + 59, 24, 18, 1, 56, 19, 25, 42, 4, 61, + 62, 60, 43, 44, 45, 46, 22, 23, 9, 12, + 20, 47, 31, 48, 29, 16, 16, 32, 30, 34, + 35, 39, 52, 66, 14, 11, 49, 0, 64, 0, + 0, 63, 0, 0, 65, 36, 33 }; static const yytype_int8 yycheck[] = { - 13, 8, 11, 14, 6, 14, 8, 0, 15, 11, - 12, 24, 9, 26, 11, 16, 25, 4, 25, 21, - 10, 11, 12, 13, 31, 17, 23, 6, 7, 5, - 20, 4, 22, 3, 4, 11, 15, 8, 11, 4, - 14, 11, 14, 17, 15, 19, 6, 7, 25, 26, - 18, 5, 14, 14, 10, 24, 69, 7, 25, 6, - 73, 14, 26, 15, -1, -1, -1, -1, 31, -1, - -1, -1, 38, 31 + 10, 6, 13, 4, 10, 10, 11, 13, 8, 10, + 10, 5, 11, 3, 19, 14, 10, 23, 0, 23, + 24, 21, 9, 10, 11, 12, 18, 19, 6, 14, + 13, 18, 24, 20, 13, 15, 15, 25, 17, 16, + 28, 13, 9, 24, 8, 6, 22, -1, 23, -1, + -1, 61, -1, -1, 64, 28, 25 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { - 0, 3, 11, 28, 30, 31, 32, 46, 14, 0, - 16, 34, 31, 4, 29, 30, 46, 17, 35, 6, - 7, 33, 34, 29, 4, 36, 15, 33, 33, 37, - 44, 45, 46, 33, 14, 18, 37, 44, 5, 14, - 14, 14, 19, 35, 38, 39, 11, 14, 25, 10, - 11, 12, 13, 20, 22, 24, 40, 43, 10, 6, - 8, 11, 12, 21, 41, 42, 9, 11, 23, 25, - 26, 7, 33, 25, 33, 26 + 0, 3, 26, 13, 0, 4, 10, 27, 28, 6, + 29, 28, 14, 30, 27, 29, 15, 31, 11, 14, + 13, 32, 31, 31, 5, 10, 33, 39, 40, 13, + 17, 31, 33, 40, 16, 33, 39, 34, 35, 13, + 10, 13, 23, 9, 10, 11, 12, 18, 20, 22, + 36, 38, 9, 6, 10, 11, 19, 37, 8, 10, + 21, 23, 24, 29, 23, 29, 24 }; #define yyerrok (yyerrstatus = 0) @@ -728,7 +705,7 @@ do { \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ - Type, Value, Location); \ + Type, Value); \ YYFPRINTF (stderr, "\n"); \ } \ } while (YYID (0)) @@ -742,19 +719,17 @@ do { \ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void -yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp) +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) #else static void -yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp) +yy_symbol_value_print (yyoutput, yytype, yyvaluep) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; - YYLTYPE const * const yylocationp; #endif { if (!yyvaluep) return; - YYUSE (yylocationp); # ifdef YYPRINT if (yytype < YYNTOKENS) YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); @@ -776,14 +751,13 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp) #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void -yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp) +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) #else static void -yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp) +yy_symbol_print (yyoutput, yytype, yyvaluep) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; - YYLTYPE const * const yylocationp; #endif { if (yytype < YYNTOKENS) @@ -791,9 +765,7 @@ yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp) else YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); - YY_LOCATION_PRINT (yyoutput, *yylocationp); - YYFPRINTF (yyoutput, ": "); - yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp); + yy_symbol_value_print (yyoutput, yytype, yyvaluep); YYFPRINTF (yyoutput, ")"); } @@ -805,17 +777,20 @@ yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp) #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void -yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) #else static void -yy_stack_print (bottom, top) - yytype_int16 *bottom; - yytype_int16 *top; +yy_stack_print (yybottom, yytop) + yytype_int16 *yybottom; + yytype_int16 *yytop; #endif { YYFPRINTF (stderr, "Stack now"); - for (; bottom <= top; ++bottom) - YYFPRINTF (stderr, " %d", *bottom); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } YYFPRINTF (stderr, "\n"); } @@ -833,12 +808,11 @@ do { \ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void -yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule) +yy_reduce_print (YYSTYPE *yyvsp, int yyrule) #else static void -yy_reduce_print (yyvsp, yylsp, yyrule) +yy_reduce_print (yyvsp, yyrule) YYSTYPE *yyvsp; - YYLTYPE *yylsp; int yyrule; #endif { @@ -850,18 +824,18 @@ yy_reduce_print (yyvsp, yylsp, yyrule) /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { - fprintf (stderr, " $%d = ", yyi + 1); + YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], &(yyvsp[(yyi + 1) - (yynrhs)]) - , &(yylsp[(yyi + 1) - (yynrhs)]) ); - fprintf (stderr, "\n"); + ); + YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ - yy_reduce_print (yyvsp, yylsp, Rule); \ + yy_reduce_print (yyvsp, Rule); \ } while (YYID (0)) /* Nonzero means print parse trace. It is left uninitialized so that @@ -1112,18 +1086,16 @@ yysyntax_error (char *yyresult, int yystate, int yychar) #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void -yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp) +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) #else static void -yydestruct (yymsg, yytype, yyvaluep, yylocationp) +yydestruct (yymsg, yytype, yyvaluep) const char *yymsg; int yytype; YYSTYPE *yyvaluep; - YYLTYPE *yylocationp; #endif { YYUSE (yyvaluep); - YYUSE (yylocationp); if (!yymsg) yymsg = "Deleting"; @@ -1136,10 +1108,8 @@ yydestruct (yymsg, yytype, yyvaluep, yylocationp) break; } } - /* Prevent warnings from -Wmissing-prototypes. */ - #ifdef YYPARSE_PARAM #if defined __STDC__ || defined __cplusplus int yyparse (void *YYPARSE_PARAM); @@ -1155,23 +1125,20 @@ int yyparse (); #endif /* ! YYPARSE_PARAM */ - -/* The look-ahead symbol. */ +/* The lookahead symbol. */ int yychar; -/* The semantic value of the look-ahead symbol. */ +/* The semantic value of the lookahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; -/* Location data for the look-ahead symbol. */ -YYLTYPE yylloc; -/*----------. -| yyparse. | -`----------*/ +/*-------------------------. +| yyparse or yypush_parse. | +`-------------------------*/ #ifdef YYPARSE_PARAM #if (defined __STDC__ || defined __C99__FUNC__ \ @@ -1195,79 +1162,70 @@ yyparse () #endif #endif { - - int yystate; - int yyn; - int yyresult; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - /* Look-ahead token as an internal (translated) token number. */ - int yytoken = 0; -#if YYERROR_VERBOSE - /* Buffer for error messages, and its allocated size. */ - char yymsgbuf[128]; - char *yymsg = yymsgbuf; - YYSIZE_T yymsg_alloc = sizeof yymsgbuf; -#endif - /* Three stacks and their tools: - `yyss': related to states, - `yyvs': related to semantic values, - `yyls': related to locations. - Refer to the stacks thru separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; - /* The state stack. */ - yytype_int16 yyssa[YYINITDEPTH]; - yytype_int16 *yyss = yyssa; - yytype_int16 *yyssp; + /* The stacks and their tools: + `yyss': related to states. + `yyvs': related to semantic values. - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs = yyvsa; - YYSTYPE *yyvsp; + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ - /* The location stack. */ - YYLTYPE yylsa[YYINITDEPTH]; - YYLTYPE *yyls = yylsa; - YYLTYPE *yylsp; - /* The locations where the error started and ended. */ - YYLTYPE yyerror_range[2]; + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; -#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; - YYSIZE_T yystacksize = YYINITDEPTH; + YYSIZE_T yystacksize; + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; - YYLTYPE yyloc; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; + yytoken = 0; + yyss = yyssa; + yyvs = yyvsa; + yystacksize = YYINITDEPTH; + YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ + yychar = YYEMPTY; /* Cause a token to be read. */ /* Initialize stack pointers. Waste one element of value and location stack so that they stay on the same level as the state stack. The wasted elements are never initialized. */ - yyssp = yyss; yyvsp = yyvs; - yylsp = yyls; -#if YYLTYPE_IS_TRIVIAL - /* Initialize the default location before parsing starts. */ - yylloc.first_line = yylloc.last_line = 1; - yylloc.first_column = yylloc.last_column = 0; -#endif goto yysetstate; @@ -1294,7 +1252,6 @@ yyparse () memory. */ YYSTYPE *yyvs1 = yyvs; yytype_int16 *yyss1 = yyss; - YYLTYPE *yyls1 = yyls; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a @@ -1303,9 +1260,8 @@ yyparse () yyoverflow (YY_("memory exhausted"), &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), - &yyls1, yysize * sizeof (*yylsp), &yystacksize); - yyls = yyls1; + yyss = yyss1; yyvs = yyvs1; } @@ -1326,9 +1282,8 @@ yyparse () (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyexhaustedlab; - YYSTACK_RELOCATE (yyss); - YYSTACK_RELOCATE (yyvs); - YYSTACK_RELOCATE (yyls); + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); @@ -1338,7 +1293,6 @@ yyparse () yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; - yylsp = yyls + yysize - 1; YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) yystacksize)); @@ -1349,6 +1303,9 @@ yyparse () YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + if (yystate == YYFINAL) + YYACCEPT; + goto yybackup; /*-----------. @@ -1357,16 +1314,16 @@ yyparse () yybackup: /* Do appropriate processing given the current state. Read a - look-ahead token if we need one and don't already have one. */ + lookahead token if we need one and don't already have one. */ - /* First try to decide what to do without reference to look-ahead token. */ + /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yyn == YYPACT_NINF) goto yydefault; - /* Not known => get a look-ahead token if don't already have one. */ + /* Not known => get a lookahead token if don't already have one. */ - /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); @@ -1398,24 +1355,20 @@ yybackup: goto yyreduce; } - if (yyn == YYFINAL) - YYACCEPT; - /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; - /* Shift the look-ahead token. */ + /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); - /* Discard the shifted token unless it is eof. */ - if (yychar != YYEOF) - yychar = YYEMPTY; + /* Discard the shifted token. */ + yychar = YYEMPTY; yystate = yyn; *++yyvsp = yylval; - *++yylsp = yylloc; + goto yynewstate; @@ -1446,337 +1399,387 @@ yyreduce: GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; - /* Default location. */ - YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); + YY_REDUCE_PRINT (yyn); switch (yyn) { case 2: -#line 90 "dtc-parser.y" + +/* Line 1455 of yacc.c */ +#line 87 "dtc-parser.y" { - the_boot_info = build_boot_info((yyvsp[(3) - (4)].re), (yyvsp[(4) - (4)].node), 0); + the_boot_info = build_boot_info((yyvsp[(3) - (4)].re), (yyvsp[(4) - (4)].node), + guess_boot_cpuid((yyvsp[(4) - (4)].node))); ;} break; case 3: -#line 94 "dtc-parser.y" + +/* Line 1455 of yacc.c */ +#line 95 "dtc-parser.y" { - the_boot_info = build_boot_info((yyvsp[(1) - (2)].re), (yyvsp[(2) - (2)].node), 0); + (yyval.re) = NULL; ;} break; case 4: -#line 101 "dtc-parser.y" + +/* Line 1455 of yacc.c */ +#line 99 "dtc-parser.y" { - (yyval.re) = NULL; + (yyval.re) = chain_reserve_entry((yyvsp[(1) - (2)].re), (yyvsp[(2) - (2)].re)); ;} break; case 5: -#line 105 "dtc-parser.y" + +/* Line 1455 of yacc.c */ +#line 106 "dtc-parser.y" { - (yyval.re) = chain_reserve_entry((yyvsp[(1) - (2)].re), (yyvsp[(2) - (2)].re)); + (yyval.re) = build_reserve_entry((yyvsp[(2) - (4)].addr), (yyvsp[(3) - (4)].addr)); ;} break; case 6: -#line 112 "dtc-parser.y" + +/* Line 1455 of yacc.c */ +#line 110 "dtc-parser.y" { - (yyval.re) = build_reserve_entry((yyvsp[(3) - (5)].addr), (yyvsp[(4) - (5)].addr), (yyvsp[(1) - (5)].labelref)); + add_label(&(yyvsp[(2) - (2)].re)->labels, (yyvsp[(1) - (2)].labelref)); + (yyval.re) = (yyvsp[(2) - (2)].re); ;} break; case 7: -#line 119 "dtc-parser.y" + +/* Line 1455 of yacc.c */ +#line 118 "dtc-parser.y" { - (yyval.re) = NULL; + (yyval.addr) = eval_literal((yyvsp[(1) - (1)].literal), 0, 64); ;} break; case 8: -#line 123 "dtc-parser.y" + +/* Line 1455 of yacc.c */ +#line 125 "dtc-parser.y" { - (yyval.re) = chain_reserve_entry((yyvsp[(1) - (2)].re), (yyvsp[(2) - (2)].re)); + (yyval.node) = name_node((yyvsp[(2) - (2)].node), ""); ;} break; case 9: -#line 130 "dtc-parser.y" + +/* Line 1455 of yacc.c */ +#line 129 "dtc-parser.y" { - (yyval.re) = (yyvsp[(1) - (1)].re); + (yyval.node) = merge_nodes((yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); ;} break; case 10: -#line 134 "dtc-parser.y" + +/* Line 1455 of yacc.c */ +#line 133 "dtc-parser.y" { - (yyval.re) = build_reserve_entry((yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].addr) - (yyvsp[(3) - (6)].addr) + 1, (yyvsp[(1) - (6)].labelref)); + struct node *target = get_node_by_ref((yyvsp[(1) - (3)].node), (yyvsp[(2) - (3)].labelref)); + + if (target) + merge_nodes(target, (yyvsp[(3) - (3)].node)); + else + print_error("label or path, '%s', not found", (yyvsp[(2) - (3)].labelref)); + (yyval.node) = (yyvsp[(1) - (3)].node); ;} break; case 11: -#line 141 "dtc-parser.y" + +/* Line 1455 of yacc.c */ +#line 146 "dtc-parser.y" { - (yyval.addr) = eval_literal((yyvsp[(1) - (1)].literal), 0, 64); + (yyval.node) = build_node((yyvsp[(2) - (5)].proplist), (yyvsp[(3) - (5)].nodelist)); ;} break; case 12: -#line 145 "dtc-parser.y" + +/* Line 1455 of yacc.c */ +#line 153 "dtc-parser.y" { - (yyval.addr) = eval_literal((yyvsp[(1) - (1)].literal), 16, 64); + (yyval.proplist) = NULL; ;} break; case 13: -#line 152 "dtc-parser.y" + +/* Line 1455 of yacc.c */ +#line 157 "dtc-parser.y" { - (yyval.node) = name_node((yyvsp[(2) - (2)].node), "", NULL); + (yyval.proplist) = chain_property((yyvsp[(2) - (2)].prop), (yyvsp[(1) - (2)].proplist)); ;} break; case 14: -#line 159 "dtc-parser.y" + +/* Line 1455 of yacc.c */ +#line 164 "dtc-parser.y" { - (yyval.node) = build_node((yyvsp[(2) - (5)].proplist), (yyvsp[(3) - (5)].nodelist)); + (yyval.prop) = build_property((yyvsp[(1) - (4)].propnodename), (yyvsp[(3) - (4)].data)); ;} break; case 15: -#line 166 "dtc-parser.y" + +/* Line 1455 of yacc.c */ +#line 168 "dtc-parser.y" { - (yyval.proplist) = NULL; + (yyval.prop) = build_property((yyvsp[(1) - (2)].propnodename), empty_data); ;} break; case 16: -#line 170 "dtc-parser.y" + +/* Line 1455 of yacc.c */ +#line 172 "dtc-parser.y" { - (yyval.proplist) = chain_property((yyvsp[(2) - (2)].prop), (yyvsp[(1) - (2)].proplist)); + add_label(&(yyvsp[(2) - (2)].prop)->labels, (yyvsp[(1) - (2)].labelref)); + (yyval.prop) = (yyvsp[(2) - (2)].prop); ;} break; case 17: -#line 177 "dtc-parser.y" + +/* Line 1455 of yacc.c */ +#line 180 "dtc-parser.y" { - (yyval.prop) = build_property((yyvsp[(2) - (5)].propnodename), (yyvsp[(4) - (5)].data), (yyvsp[(1) - (5)].labelref)); + (yyval.data) = data_merge((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].data)); ;} break; case 18: -#line 181 "dtc-parser.y" + +/* Line 1455 of yacc.c */ +#line 184 "dtc-parser.y" { - (yyval.prop) = build_property((yyvsp[(2) - (3)].propnodename), empty_data, (yyvsp[(1) - (3)].labelref)); + (yyval.data) = data_merge((yyvsp[(1) - (4)].data), (yyvsp[(3) - (4)].data)); ;} break; case 19: + +/* Line 1455 of yacc.c */ #line 188 "dtc-parser.y" { - (yyval.data) = data_merge((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].data)); + (yyval.data) = data_merge((yyvsp[(1) - (4)].data), (yyvsp[(3) - (4)].data)); ;} break; case 20: + +/* Line 1455 of yacc.c */ #line 192 "dtc-parser.y" { - (yyval.data) = data_merge((yyvsp[(1) - (4)].data), (yyvsp[(3) - (4)].data)); + (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), REF_PATH, (yyvsp[(2) - (2)].labelref)); ;} break; case 21: -#line 196 "dtc-parser.y" - { - (yyval.data) = data_merge((yyvsp[(1) - (4)].data), (yyvsp[(3) - (4)].data)); - ;} - break; - - case 22: -#line 200 "dtc-parser.y" - { - (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), REF_PATH, (yyvsp[(2) - (2)].labelref)); - ;} - break; - case 23: -#line 204 "dtc-parser.y" +/* Line 1455 of yacc.c */ +#line 196 "dtc-parser.y" { - struct search_path path = { srcpos_file->dir, NULL, NULL }; - struct dtc_file *file = dtc_open_file((yyvsp[(4) - (9)].data).val, &path); - struct data d = empty_data; + FILE *f = srcfile_relative_open((yyvsp[(4) - (9)].data).val, NULL); + struct data d; if ((yyvsp[(6) - (9)].addr) != 0) - if (fseek(file->file, (yyvsp[(6) - (9)].addr), SEEK_SET) != 0) - yyerrorf("Couldn't seek to offset %llu in \"%s\": %s", - (unsigned long long)(yyvsp[(6) - (9)].addr), - (yyvsp[(4) - (9)].data).val, strerror(errno)); + if (fseek(f, (yyvsp[(6) - (9)].addr), SEEK_SET) != 0) + print_error("Couldn't seek to offset %llu in \"%s\": %s", + (unsigned long long)(yyvsp[(6) - (9)].addr), + (yyvsp[(4) - (9)].data).val, + strerror(errno)); - d = data_copy_file(file->file, (yyvsp[(8) - (9)].addr)); + d = data_copy_file(f, (yyvsp[(8) - (9)].addr)); (yyval.data) = data_merge((yyvsp[(1) - (9)].data), d); - dtc_close_file(file); + fclose(f); ;} break; - case 24: -#line 221 "dtc-parser.y" + case 22: + +/* Line 1455 of yacc.c */ +#line 213 "dtc-parser.y" { - struct search_path path = { srcpos_file->dir, NULL, NULL }; - struct dtc_file *file = dtc_open_file((yyvsp[(4) - (5)].data).val, &path); + FILE *f = srcfile_relative_open((yyvsp[(4) - (5)].data).val, NULL); struct data d = empty_data; - d = data_copy_file(file->file, -1); + d = data_copy_file(f, -1); (yyval.data) = data_merge((yyvsp[(1) - (5)].data), d); - dtc_close_file(file); + fclose(f); ;} break; - case 25: -#line 232 "dtc-parser.y" + case 23: + +/* Line 1455 of yacc.c */ +#line 223 "dtc-parser.y" { (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref)); ;} break; - case 26: -#line 239 "dtc-parser.y" + case 24: + +/* Line 1455 of yacc.c */ +#line 230 "dtc-parser.y" { (yyval.data) = empty_data; ;} break; - case 27: -#line 243 "dtc-parser.y" + case 25: + +/* Line 1455 of yacc.c */ +#line 234 "dtc-parser.y" { (yyval.data) = (yyvsp[(1) - (2)].data); ;} break; - case 28: -#line 247 "dtc-parser.y" + case 26: + +/* Line 1455 of yacc.c */ +#line 238 "dtc-parser.y" { (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref)); ;} break; - case 29: -#line 254 "dtc-parser.y" + case 27: + +/* Line 1455 of yacc.c */ +#line 245 "dtc-parser.y" { (yyval.data) = empty_data; ;} break; - case 30: -#line 258 "dtc-parser.y" + case 28: + +/* Line 1455 of yacc.c */ +#line 249 "dtc-parser.y" { (yyval.data) = data_append_cell((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].cell)); ;} break; - case 31: -#line 262 "dtc-parser.y" + case 29: + +/* Line 1455 of yacc.c */ +#line 253 "dtc-parser.y" { (yyval.data) = data_append_cell(data_add_marker((yyvsp[(1) - (2)].data), REF_PHANDLE, (yyvsp[(2) - (2)].labelref)), -1); ;} break; - case 32: -#line 267 "dtc-parser.y" + case 30: + +/* Line 1455 of yacc.c */ +#line 258 "dtc-parser.y" { (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref)); ;} break; - case 33: -#line 274 "dtc-parser.y" - { - (yyval.cbase) = 16; - ;} - break; + case 31: - case 35: -#line 282 "dtc-parser.y" +/* Line 1455 of yacc.c */ +#line 265 "dtc-parser.y" { (yyval.cell) = eval_literal((yyvsp[(1) - (1)].literal), 0, 32); ;} break; - case 36: -#line 286 "dtc-parser.y" - { - (yyval.cell) = eval_literal((yyvsp[(2) - (2)].literal), (yyvsp[(1) - (2)].cbase), 32); - ;} - break; + case 32: - case 37: -#line 293 "dtc-parser.y" +/* Line 1455 of yacc.c */ +#line 272 "dtc-parser.y" { (yyval.data) = empty_data; ;} break; - case 38: -#line 297 "dtc-parser.y" + case 33: + +/* Line 1455 of yacc.c */ +#line 276 "dtc-parser.y" { (yyval.data) = data_append_byte((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].byte)); ;} break; - case 39: -#line 301 "dtc-parser.y" + case 34: + +/* Line 1455 of yacc.c */ +#line 280 "dtc-parser.y" { (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref)); ;} break; - case 40: -#line 308 "dtc-parser.y" + case 35: + +/* Line 1455 of yacc.c */ +#line 287 "dtc-parser.y" { (yyval.nodelist) = NULL; ;} break; - case 41: -#line 312 "dtc-parser.y" + case 36: + +/* Line 1455 of yacc.c */ +#line 291 "dtc-parser.y" { (yyval.nodelist) = chain_node((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].nodelist)); ;} break; - case 42: -#line 316 "dtc-parser.y" + case 37: + +/* Line 1455 of yacc.c */ +#line 295 "dtc-parser.y" { - yyerror("syntax error: properties must precede subnodes"); + print_error("syntax error: properties must precede subnodes"); YYERROR; ;} break; - case 43: -#line 324 "dtc-parser.y" - { - (yyval.node) = name_node((yyvsp[(3) - (3)].node), (yyvsp[(2) - (3)].propnodename), (yyvsp[(1) - (3)].labelref)); - ;} - break; + case 38: - case 44: -#line 331 "dtc-parser.y" +/* Line 1455 of yacc.c */ +#line 303 "dtc-parser.y" { - (yyval.labelref) = NULL; + (yyval.node) = name_node((yyvsp[(2) - (2)].node), (yyvsp[(1) - (2)].propnodename)); ;} break; - case 45: -#line 335 "dtc-parser.y" + case 39: + +/* Line 1455 of yacc.c */ +#line 307 "dtc-parser.y" { - (yyval.labelref) = (yyvsp[(1) - (1)].labelref); + add_label(&(yyvsp[(2) - (2)].node)->labels, (yyvsp[(1) - (2)].labelref)); + (yyval.node) = (yyvsp[(2) - (2)].node); ;} break; -/* Line 1267 of yacc.c. */ -#line 1780 "dtc-parser.tab.c" + +/* Line 1455 of yacc.c */ +#line 1783 "dtc-parser.tab.c" default: break; } YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); @@ -1786,7 +1789,6 @@ yyreduce: YY_STACK_PRINT (yyss, yyssp); *++yyvsp = yyval; - *++yylsp = yyloc; /* Now `shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule @@ -1848,11 +1850,11 @@ yyerrlab: #endif } - yyerror_range[0] = yylloc; + if (yyerrstatus == 3) { - /* If just tried and failed to reuse look-ahead token after an + /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) @@ -1864,12 +1866,12 @@ yyerrlab: else { yydestruct ("Error: discarding", - yytoken, &yylval, &yylloc); + yytoken, &yylval); yychar = YYEMPTY; } } - /* Else will try to reuse look-ahead token after shifting the error + /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; @@ -1885,7 +1887,6 @@ yyerrorlab: if (/*CONSTCOND*/ 0) goto yyerrorlab; - yyerror_range[0] = yylsp[1-yylen]; /* Do not reclaim the symbols of the rule which action triggered this YYERROR. */ YYPOPSTACK (yylen); @@ -1919,24 +1920,16 @@ yyerrlab1: if (yyssp == yyss) YYABORT; - yyerror_range[0] = *yylsp; + yydestruct ("Error: popping", - yystos[yystate], yyvsp, yylsp); + yystos[yystate], yyvsp); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } - if (yyn == YYFINAL) - YYACCEPT; - *++yyvsp = yylval; - yyerror_range[1] = yylloc; - /* Using YYLLOC is tempting, but would change the location of - the look-ahead. YYLOC is available though. */ - YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2); - *++yylsp = yyloc; /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); @@ -1959,7 +1952,7 @@ yyabortlab: yyresult = 1; goto yyreturn; -#ifndef yyoverflow +#if !defined(yyoverflow) || YYERROR_VERBOSE /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ @@ -1970,9 +1963,9 @@ yyexhaustedlab: #endif yyreturn: - if (yychar != YYEOF && yychar != YYEMPTY) + if (yychar != YYEMPTY) yydestruct ("Cleanup: discarding lookahead", - yytoken, &yylval, &yylloc); + yytoken, &yylval); /* Do not reclaim the symbols of the rule which action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); @@ -1980,7 +1973,7 @@ yyreturn: while (yyssp != yyss) { yydestruct ("Cleanup: popping", - yystos[*yyssp], yyvsp, yylsp); + yystos[*yyssp], yyvsp); YYPOPSTACK (1); } #ifndef yyoverflow @@ -1996,29 +1989,24 @@ yyreturn: } -#line 340 "dtc-parser.y" + +/* Line 1675 of yacc.c */ +#line 313 "dtc-parser.y" -void yyerrorf(char const *s, ...) +void print_error(char const *fmt, ...) { - const char *fname = srcpos_file ? srcpos_file->name : ""; va_list va; - va_start(va, s); - - if (strcmp(fname, "-") == 0) - fname = "stdin"; - fprintf(stderr, "%s:%d ", fname, yylloc.first_line); - vfprintf(stderr, s, va); - fprintf(stderr, "\n"); + va_start(va, fmt); + srcpos_verror(&yylloc, fmt, va); + va_end(va); treesource_error = 1; - va_end(va); } -void yyerror (char const *s) -{ - yyerrorf("%s", s); +void yyerror(char const *s) { + print_error("%s", s); } static unsigned long long eval_literal(const char *s, int base, int bits) @@ -2029,12 +2017,12 @@ static unsigned long long eval_literal(const char *s, int base, int bits) errno = 0; val = strtoull(s, &e, base); if (*e) - yyerror("bad characters in literal"); + print_error("bad characters in literal"); else if ((errno == ERANGE) || ((bits < 64) && (val >= (1ULL << bits)))) - yyerror("literal out of range"); + print_error("literal out of range"); else if (errno != 0) - yyerror("bad literal"); + print_error("bad literal"); return val; } diff --git a/scripts/dtc/dtc-parser.tab.h_shipped b/scripts/dtc/dtc-parser.tab.h_shipped index ba99100d55c..95c9547adea 100644 --- a/scripts/dtc/dtc-parser.tab.h_shipped +++ b/scripts/dtc/dtc-parser.tab.h_shipped @@ -1,24 +1,23 @@ -/* A Bison parser, made by GNU Bison 2.3. */ -/* Skeleton interface for Bison's Yacc-like parsers in C +/* A Bison parser, made by GNU Bison 2.4.1. */ - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify + + 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 - the Free Software Foundation; either version 2, or (at your option) - any later version. - + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + This program 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ + along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work @@ -29,10 +28,11 @@ special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. - + This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ + /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE @@ -43,35 +43,24 @@ DT_MEMRESERVE = 259, DT_PROPNODENAME = 260, DT_LITERAL = 261, - DT_LEGACYLITERAL = 262, - DT_BASE = 263, - DT_BYTE = 264, - DT_STRING = 265, - DT_LABEL = 266, - DT_REF = 267, - DT_INCBIN = 268 + DT_BASE = 262, + DT_BYTE = 263, + DT_STRING = 264, + DT_LABEL = 265, + DT_REF = 266, + DT_INCBIN = 267 }; #endif -/* Tokens. */ -#define DT_V1 258 -#define DT_MEMRESERVE 259 -#define DT_PROPNODENAME 260 -#define DT_LITERAL 261 -#define DT_LEGACYLITERAL 262 -#define DT_BASE 263 -#define DT_BYTE 264 -#define DT_STRING 265 -#define DT_LABEL 266 -#define DT_REF 267 -#define DT_INCBIN 268 - #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE -#line 37 "dtc-parser.y" { + +/* Line 1676 of yacc.c */ +#line 39 "dtc-parser.y" + char *propnodename; char *literal; char *labelref; @@ -86,28 +75,17 @@ typedef union YYSTYPE struct node *node; struct node *nodelist; struct reserve_info *re; -} -/* Line 1489 of yacc.c. */ -#line 92 "dtc-parser.tab.h" - YYSTYPE; + + + +/* Line 1676 of yacc.c */ +#line 83 "dtc-parser.tab.h" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 -# define YYSTYPE_IS_TRIVIAL 1 #endif extern YYSTYPE yylval; -#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED -typedef struct YYLTYPE -{ - int first_line; - int first_column; - int last_line; - int last_column; -} YYLTYPE; -# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ -# define YYLTYPE_IS_DECLARED 1 -# define YYLTYPE_IS_TRIVIAL 1 -#endif -extern YYLTYPE yylloc; diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y index b2ab562420e..5e84a67fc1d 100644 --- a/scripts/dtc/dtc-parser.y +++ b/scripts/dtc/dtc-parser.y @@ -18,15 +18,17 @@ * USA */ -%locations - %{ #include #include "dtc.h" #include "srcpos.h" +YYLTYPE yylloc; + extern int yylex(void); +extern void print_error(char const *fmt, ...); +extern void yyerror(char const *s); extern struct boot_info *the_boot_info; extern int treesource_error; @@ -55,7 +57,6 @@ static unsigned long long eval_literal(const char *s, int base, int bits); %token DT_MEMRESERVE %token DT_PROPNODENAME %token DT_LITERAL -%token DT_LEGACYLITERAL %token DT_BASE %token DT_BYTE %token DT_STRING @@ -67,11 +68,8 @@ static unsigned long long eval_literal(const char *s, int base, int bits); %type propdataprefix %type memreserve %type memreserves -%type v0_memreserve -%type v0_memreserves %type addr %type celllist -%type cellbase %type cellval %type bytestring %type propdef @@ -81,18 +79,14 @@ static unsigned long long eval_literal(const char *s, int base, int bits); %type nodedef %type subnode %type subnodes -%type label %% sourcefile: DT_V1 ';' memreserves devicetree { - the_boot_info = build_boot_info($3, $4, 0); - } - | v0_memreserves devicetree - { - the_boot_info = build_boot_info($1, $2, 0); + the_boot_info = build_boot_info($3, $4, + guess_boot_cpuid($4)); } ; @@ -108,31 +102,14 @@ memreserves: ; memreserve: - label DT_MEMRESERVE addr addr ';' + DT_MEMRESERVE addr addr ';' { - $$ = build_reserve_entry($3, $4, $1); + $$ = build_reserve_entry($2, $3); } - ; - -v0_memreserves: - /* empty */ + | DT_LABEL memreserve { - $$ = NULL; - } - | v0_memreserve v0_memreserves - { - $$ = chain_reserve_entry($1, $2); - }; - ; - -v0_memreserve: - memreserve - { - $$ = $1; - } - | label DT_MEMRESERVE addr '-' addr ';' - { - $$ = build_reserve_entry($3, $5 - $3 + 1, $1); + add_label(&$2->labels, $1); + $$ = $2; } ; @@ -141,16 +118,26 @@ addr: { $$ = eval_literal($1, 0, 64); } - | DT_LEGACYLITERAL - { - $$ = eval_literal($1, 16, 64); - } ; devicetree: '/' nodedef { - $$ = name_node($2, "", NULL); + $$ = name_node($2, ""); + } + | devicetree '/' nodedef + { + $$ = merge_nodes($1, $3); + } + | devicetree DT_REF nodedef + { + struct node *target = get_node_by_ref($1, $2); + + if (target) + merge_nodes(target, $3); + else + print_error("label or path, '%s', not found", $2); + $$ = $1; } ; @@ -173,13 +160,18 @@ proplist: ; propdef: - label DT_PROPNODENAME '=' propdata ';' + DT_PROPNODENAME '=' propdata ';' + { + $$ = build_property($1, $3); + } + | DT_PROPNODENAME ';' { - $$ = build_property($2, $4, $1); + $$ = build_property($1, empty_data); } - | label DT_PROPNODENAME ';' + | DT_LABEL propdef { - $$ = build_property($2, empty_data, $1); + add_label(&$2->labels, $1); + $$ = $2; } ; @@ -202,31 +194,30 @@ propdata: } | propdataprefix DT_INCBIN '(' DT_STRING ',' addr ',' addr ')' { - struct search_path path = { srcpos_file->dir, NULL, NULL }; - struct dtc_file *file = dtc_open_file($4.val, &path); - struct data d = empty_data; + FILE *f = srcfile_relative_open($4.val, NULL); + struct data d; if ($6 != 0) - if (fseek(file->file, $6, SEEK_SET) != 0) - yyerrorf("Couldn't seek to offset %llu in \"%s\": %s", - (unsigned long long)$6, - $4.val, strerror(errno)); + if (fseek(f, $6, SEEK_SET) != 0) + print_error("Couldn't seek to offset %llu in \"%s\": %s", + (unsigned long long)$6, + $4.val, + strerror(errno)); - d = data_copy_file(file->file, $8); + d = data_copy_file(f, $8); $$ = data_merge($1, d); - dtc_close_file(file); + fclose(f); } | propdataprefix DT_INCBIN '(' DT_STRING ')' { - struct search_path path = { srcpos_file->dir, NULL, NULL }; - struct dtc_file *file = dtc_open_file($4.val, &path); + FILE *f = srcfile_relative_open($4.val, NULL); struct data d = empty_data; - d = data_copy_file(file->file, -1); + d = data_copy_file(f, -1); $$ = data_merge($1, d); - dtc_close_file(file); + fclose(f); } | propdata DT_LABEL { @@ -269,23 +260,11 @@ celllist: } ; -cellbase: - /* empty */ - { - $$ = 16; - } - | DT_BASE - ; - cellval: DT_LITERAL { $$ = eval_literal($1, 0, 32); } - | cellbase DT_LEGACYLITERAL - { - $$ = eval_literal($2, $1, 32); - } ; bytestring: @@ -308,57 +287,44 @@ subnodes: { $$ = NULL; } - | subnode subnodes + | subnode subnodes { $$ = chain_node($1, $2); } | subnode propdef { - yyerror("syntax error: properties must precede subnodes"); + print_error("syntax error: properties must precede subnodes"); YYERROR; } ; subnode: - label DT_PROPNODENAME nodedef + DT_PROPNODENAME nodedef { - $$ = name_node($3, $2, $1); + $$ = name_node($2, $1); } - ; - -label: - /* empty */ + | DT_LABEL subnode { - $$ = NULL; - } - | DT_LABEL - { - $$ = $1; + add_label(&$2->labels, $1); + $$ = $2; } ; %% -void yyerrorf(char const *s, ...) +void print_error(char const *fmt, ...) { - const char *fname = srcpos_file ? srcpos_file->name : ""; va_list va; - va_start(va, s); - - if (strcmp(fname, "-") == 0) - fname = "stdin"; - fprintf(stderr, "%s:%d ", fname, yylloc.first_line); - vfprintf(stderr, s, va); - fprintf(stderr, "\n"); + va_start(va, fmt); + srcpos_verror(&yylloc, fmt, va); + va_end(va); treesource_error = 1; - va_end(va); } -void yyerror (char const *s) -{ - yyerrorf("%s", s); +void yyerror(char const *s) { + print_error("%s", s); } static unsigned long long eval_literal(const char *s, int base, int bits) @@ -369,11 +335,11 @@ static unsigned long long eval_literal(const char *s, int base, int bits) errno = 0; val = strtoull(s, &e, base); if (*e) - yyerror("bad characters in literal"); + print_error("bad characters in literal"); else if ((errno == ERANGE) || ((bits < 64) && (val >= (1ULL << bits)))) - yyerror("literal out of range"); + print_error("literal out of range"); else if (errno != 0) - yyerror("bad literal"); + print_error("bad literal"); return val; } diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c index d8fd43b4ac1..cbc0193098e 100644 --- a/scripts/dtc/dtc.c +++ b/scripts/dtc/dtc.c @@ -30,30 +30,7 @@ int quiet; /* Level of quietness */ int reservenum; /* Number of memory reservation slots */ int minsize; /* Minimum blob size */ int padsize; /* Additional padding to blob */ - -char *join_path(const char *path, const char *name) -{ - int lenp = strlen(path); - int lenn = strlen(name); - int len; - int needslash = 1; - char *str; - - len = lenp + lenn + 2; - if ((lenp > 0) && (path[lenp-1] == '/')) { - needslash = 0; - len--; - } - - str = xmalloc(len); - memcpy(str, path, lenp); - if (needslash) { - str[lenp] = '/'; - lenp++; - } - memcpy(str+lenp, name, lenn+1); - return str; -} +int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */ static void fill_fullpaths(struct node *tree, const char *prefix) { @@ -104,8 +81,15 @@ static void __attribute__ ((noreturn)) usage(void) fprintf(stderr, "\t\tSet the physical boot cpu\n"); fprintf(stderr, "\t-f\n"); fprintf(stderr, "\t\tForce - try to produce output even if the input tree has errors\n"); + fprintf(stderr, "\t-s\n"); + fprintf(stderr, "\t\tSort nodes and properties before outputting (only useful for\n\t\tcomparing trees)\n"); fprintf(stderr, "\t-v\n"); fprintf(stderr, "\t\tPrint DTC version and exit\n"); + fprintf(stderr, "\t-H \n"); + fprintf(stderr, "\t\tphandle formats are:\n"); + fprintf(stderr, "\t\t\tlegacy - \"linux,phandle\" properties only\n"); + fprintf(stderr, "\t\t\tepapr - \"phandle\" properties only\n"); + fprintf(stderr, "\t\t\tboth - Both \"linux,phandle\" and \"phandle\" properties\n"); exit(3); } @@ -115,7 +99,7 @@ int main(int argc, char *argv[]) const char *inform = "dts"; const char *outform = "dts"; const char *outname = "-"; - int force = 0, check = 0; + int force = 0, check = 0, sort = 0; const char *arg; int opt; FILE *outf = NULL; @@ -127,7 +111,7 @@ int main(int argc, char *argv[]) minsize = 0; padsize = 0; - while ((opt = getopt(argc, argv, "hI:O:o:V:R:S:p:fcqb:v")) != EOF) { + while ((opt = getopt(argc, argv, "hI:O:o:V:R:S:p:fcqb:vH:s")) != EOF) { switch (opt) { case 'I': inform = optarg; @@ -165,6 +149,22 @@ int main(int argc, char *argv[]) case 'v': printf("Version: %s\n", DTC_VERSION); exit(0); + case 'H': + if (streq(optarg, "legacy")) + phandle_format = PHANDLE_LEGACY; + else if (streq(optarg, "epapr")) + phandle_format = PHANDLE_EPAPR; + else if (streq(optarg, "both")) + phandle_format = PHANDLE_BOTH; + else + die("Invalid argument \"%s\" to -H option\n", + optarg); + break; + + case 's': + sort = 1; + break; + case 'h': default: usage(); @@ -182,6 +182,9 @@ int main(int argc, char *argv[]) if (minsize && padsize) die("Can't set both -p and -S\n"); + if (minsize) + fprintf(stderr, "DTC: Use of \"-S\" is deprecated; it will be removed soon, use \"-p\" instead\n"); + fprintf(stderr, "DTC: %s->%s on file \"%s\"\n", inform, outform, arg); @@ -200,6 +203,8 @@ int main(int argc, char *argv[]) fill_fullpaths(bi->dt, ""); process_checks(force, bi); + if (sort) + sort_tree(bi); if (streq(outname, "-")) { outf = stdout; diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h index 08d54c87008..f37c97eb3df 100644 --- a/scripts/dtc/dtc.h +++ b/scripts/dtc/dtc.h @@ -34,7 +34,17 @@ #include #include +#include "util.h" + +#ifdef DEBUG +#define debug(fmt,args...) printf(fmt, ##args) +#else +#define debug(fmt,args...) +#endif + + #define DEFAULT_FDT_VERSION 17 + /* * Command line options */ @@ -42,36 +52,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 phandle_format; /* Use linux,phandle or phandle properties */ -static inline void __attribute__((noreturn)) die(char * str, ...) -{ - va_list ap; - - va_start(ap, str); - fprintf(stderr, "FATAL ERROR: "); - vfprintf(stderr, str, ap); - exit(1); -} - -static inline void *xmalloc(size_t len) -{ - void *new = malloc(len); - - if (! new) - die("malloc() failed\n"); - - return new; -} - -static inline void *xrealloc(void *p, size_t len) -{ - void *new = realloc(p, len); - - if (! new) - die("realloc() failed (len=%d)\n", len); - - return new; -} +#define PHANDLE_LEGACY 0x1 +#define PHANDLE_EPAPR 0x2 +#define PHANDLE_BOTH 0x3 typedef uint32_t cell_t; @@ -140,13 +125,18 @@ int data_is_one_string(struct data d); #define MAX_NODENAME_LEN 31 /* Live trees */ +struct label { + char *label; + struct label *next; +}; + struct property { char *name; struct data val; struct property *next; - char *label; + struct label *labels; }; struct node { @@ -163,22 +153,28 @@ struct node { cell_t phandle; int addr_cells, size_cells; - char *label; + struct label *labels; }; +#define for_each_label(l0, l) \ + for ((l) = (l0); (l); (l) = (l)->next) + #define for_each_property(n, p) \ for ((p) = (n)->proplist; (p); (p) = (p)->next) #define for_each_child(n, c) \ for ((c) = (n)->children; (c); (c) = (c)->next_sibling) -struct property *build_property(char *name, struct data val, char *label); +void add_label(struct label **labels, char *label); + +struct property *build_property(char *name, struct data val); struct property *chain_property(struct property *first, struct property *list); struct property *reverse_properties(struct property *first); struct node *build_node(struct property *proplist, struct node *children); -struct node *name_node(struct node *node, char *name, char *label); +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_property(struct node *node, struct property *prop); void add_child(struct node *parent, struct node *child); @@ -186,6 +182,10 @@ void add_child(struct node *parent, struct node *child); const char *get_unitname(struct node *node); struct property *get_property(struct node *node, const char *propname); cell_t propval_cell(struct property *prop); +struct property *get_property_by_label(struct node *tree, const char *label, + struct node **node); +struct marker *get_marker_label(struct node *tree, const char *label, + struct node **node, struct property **prop); struct node *get_subnode(struct node *node, const char *nodename); struct node *get_node_by_path(struct node *tree, const char *path); struct node *get_node_by_label(struct node *tree, const char *label); @@ -193,6 +193,8 @@ struct node *get_node_by_phandle(struct node *tree, cell_t phandle); struct node *get_node_by_ref(struct node *tree, const char *ref); cell_t get_node_phandle(struct node *root, struct node *node); +uint32_t guess_boot_cpuid(struct node *tree); + /* Boot info (tree plus memreserve information */ struct reserve_info { @@ -200,10 +202,10 @@ struct reserve_info { struct reserve_info *next; - char *label; + struct label *labels; }; -struct reserve_info *build_reserve_entry(uint64_t start, uint64_t len, char *label); +struct reserve_info *build_reserve_entry(uint64_t start, uint64_t len); struct reserve_info *chain_reserve_entry(struct reserve_info *first, struct reserve_info *list); struct reserve_info *add_reserve_entry(struct reserve_info *list, @@ -218,6 +220,7 @@ struct boot_info { 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); /* Checks */ @@ -239,8 +242,4 @@ struct boot_info *dt_from_source(const char *f); struct boot_info *dt_from_fs(const char *dirname); -/* misc */ - -char *join_path(const char *path, const char *name); - #endif /* _DTC_H */ diff --git a/scripts/dtc/flattree.c b/scripts/dtc/flattree.c index 76acd28c068..ead0332c87e 100644 --- a/scripts/dtc/flattree.c +++ b/scripts/dtc/flattree.c @@ -52,9 +52,9 @@ struct emitter { void (*string)(void *, char *, int); void (*align)(void *, int); void (*data)(void *, struct data); - void (*beginnode)(void *, const char *); - void (*endnode)(void *, const char *); - void (*property)(void *, const char *); + void (*beginnode)(void *, struct label *labels); + void (*endnode)(void *, struct label *labels); + void (*property)(void *, struct label *labels); }; static void bin_emit_cell(void *e, cell_t val) @@ -89,17 +89,17 @@ static void bin_emit_data(void *e, struct data d) *dtbuf = data_append_data(*dtbuf, d.val, d.len); } -static void bin_emit_beginnode(void *e, const char *label) +static void bin_emit_beginnode(void *e, struct label *labels) { bin_emit_cell(e, FDT_BEGIN_NODE); } -static void bin_emit_endnode(void *e, const char *label) +static void bin_emit_endnode(void *e, struct label *labels) { bin_emit_cell(e, FDT_END_NODE); } -static void bin_emit_property(void *e, const char *label) +static void bin_emit_property(void *e, struct label *labels) { bin_emit_cell(e, FDT_PROP); } @@ -127,11 +127,21 @@ static void emit_offset_label(FILE *f, const char *label, int offset) fprintf(f, "%s\t= . + %d\n", label, offset); } +#define ASM_EMIT_BELONG(f, fmt, ...) \ + { \ + fprintf((f), "\t.byte\t((" fmt ") >> 24) & 0xff\n", __VA_ARGS__); \ + fprintf((f), "\t.byte\t((" fmt ") >> 16) & 0xff\n", __VA_ARGS__); \ + fprintf((f), "\t.byte\t((" fmt ") >> 8) & 0xff\n", __VA_ARGS__); \ + fprintf((f), "\t.byte\t(" fmt ") & 0xff\n", __VA_ARGS__); \ + } + static void asm_emit_cell(void *e, cell_t val) { FILE *f = e; - fprintf(f, "\t.long\t0x%x\n", val); + fprintf(f, "\t.byte 0x%02x; .byte 0x%02x; .byte 0x%02x; .byte 0x%02x\n", + (val >> 24) & 0xff, (val >> 16) & 0xff, + (val >> 8) & 0xff, val & 0xff); } static void asm_emit_string(void *e, char *str, int len) @@ -156,7 +166,7 @@ static void asm_emit_align(void *e, int a) { FILE *f = e; - fprintf(f, "\t.balign\t%d\n", a); + fprintf(f, "\t.balign\t%d, 0\n", a); } static void asm_emit_data(void *e, struct data d) @@ -169,8 +179,7 @@ static void asm_emit_data(void *e, struct data d) emit_offset_label(f, m->ref, m->offset); while ((d.len - off) >= sizeof(uint32_t)) { - fprintf(f, "\t.long\t0x%x\n", - fdt32_to_cpu(*((uint32_t *)(d.val+off)))); + asm_emit_cell(e, fdt32_to_cpu(*((uint32_t *)(d.val+off)))); off += sizeof(uint32_t); } @@ -182,37 +191,43 @@ static void asm_emit_data(void *e, struct data d) assert(off == d.len); } -static void asm_emit_beginnode(void *e, const char *label) +static void asm_emit_beginnode(void *e, struct label *labels) { FILE *f = e; + struct label *l; - if (label) { - fprintf(f, "\t.globl\t%s\n", label); - fprintf(f, "%s:\n", label); + for_each_label(labels, l) { + fprintf(f, "\t.globl\t%s\n", l->label); + fprintf(f, "%s:\n", l->label); } - fprintf(f, "\t.long\tFDT_BEGIN_NODE\n"); + fprintf(f, "\t/* FDT_BEGIN_NODE */\n"); + asm_emit_cell(e, FDT_BEGIN_NODE); } -static void asm_emit_endnode(void *e, const char *label) +static void asm_emit_endnode(void *e, struct label *labels) { FILE *f = e; + struct label *l; - fprintf(f, "\t.long\tFDT_END_NODE\n"); - if (label) { - fprintf(f, "\t.globl\t%s_end\n", label); - fprintf(f, "%s_end:\n", label); + fprintf(f, "\t/* FDT_END_NODE */\n"); + asm_emit_cell(e, FDT_END_NODE); + for_each_label(labels, l) { + fprintf(f, "\t.globl\t%s_end\n", l->label); + fprintf(f, "%s_end:\n", l->label); } } -static void asm_emit_property(void *e, const char *label) +static void asm_emit_property(void *e, struct label *labels) { FILE *f = e; + struct label *l; - if (label) { - fprintf(f, "\t.globl\t%s\n", label); - fprintf(f, "%s:\n", label); + for_each_label(labels, l) { + fprintf(f, "\t.globl\t%s\n", l->label); + fprintf(f, "%s:\n", l->label); } - fprintf(f, "\t.long\tFDT_PROP\n"); + fprintf(f, "\t/* FDT_PROP */\n"); + asm_emit_cell(e, FDT_PROP); } static struct emitter asm_emitter = { @@ -248,7 +263,7 @@ static void flatten_tree(struct node *tree, struct emitter *emit, struct node *child; int seen_name_prop = 0; - emit->beginnode(etarget, tree->label); + emit->beginnode(etarget, tree->labels); if (vi->flags & FTF_FULLPATH) emit->string(etarget, tree->fullpath, 0); @@ -265,7 +280,7 @@ static void flatten_tree(struct node *tree, struct emitter *emit, nameoff = stringtable_insert(strbuf, prop->name); - emit->property(etarget, prop->label); + emit->property(etarget, prop->labels); emit->cell(etarget, prop->val.len); emit->cell(etarget, nameoff); @@ -292,7 +307,7 @@ static void flatten_tree(struct node *tree, struct emitter *emit, flatten_tree(child, emit, etarget, strbuf, vi); } - emit->endnode(etarget, tree->label); + emit->endnode(etarget, tree->labels); } static struct data flatten_reserve_list(struct reserve_info *reservelist, @@ -413,10 +428,13 @@ void dt_to_blob(FILE *f, struct boot_info *bi, int version) if (padlen > 0) blob = data_append_zeroes(blob, padlen); - fwrite(blob.val, blob.len, 1, f); - - if (ferror(f)) - die("Error writing device tree blob: %s\n", strerror(errno)); + if (fwrite(blob.val, blob.len, 1, f) != 1) { + if (ferror(f)) + die("Error writing device tree blob: %s\n", + strerror(errno)); + else + die("Short write on device tree blob\n"); + } /* * data_merge() frees the right-hand element so only the blob @@ -455,39 +473,44 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version) die("Unknown device tree blob version %d\n", version); fprintf(f, "/* autogenerated by dtc, do not edit */\n\n"); - fprintf(f, "#define FDT_MAGIC 0x%x\n", FDT_MAGIC); - fprintf(f, "#define FDT_BEGIN_NODE 0x%x\n", FDT_BEGIN_NODE); - fprintf(f, "#define FDT_END_NODE 0x%x\n", FDT_END_NODE); - fprintf(f, "#define FDT_PROP 0x%x\n", FDT_PROP); - fprintf(f, "#define FDT_END 0x%x\n", FDT_END); - fprintf(f, "\n"); emit_label(f, symprefix, "blob_start"); emit_label(f, symprefix, "header"); - fprintf(f, "\t.long\tFDT_MAGIC\t\t\t\t/* magic */\n"); - fprintf(f, "\t.long\t_%s_blob_abs_end - _%s_blob_start\t/* totalsize */\n", - symprefix, symprefix); - fprintf(f, "\t.long\t_%s_struct_start - _%s_blob_start\t/* off_dt_struct */\n", + fprintf(f, "\t/* magic */\n"); + asm_emit_cell(f, FDT_MAGIC); + fprintf(f, "\t/* totalsize */\n"); + ASM_EMIT_BELONG(f, "_%s_blob_abs_end - _%s_blob_start", + symprefix, symprefix); + fprintf(f, "\t/* off_dt_struct */\n"); + ASM_EMIT_BELONG(f, "_%s_struct_start - _%s_blob_start", symprefix, symprefix); - fprintf(f, "\t.long\t_%s_strings_start - _%s_blob_start\t/* off_dt_strings */\n", + fprintf(f, "\t/* off_dt_strings */\n"); + ASM_EMIT_BELONG(f, "_%s_strings_start - _%s_blob_start", symprefix, symprefix); - fprintf(f, "\t.long\t_%s_reserve_map - _%s_blob_start\t/* off_dt_strings */\n", + fprintf(f, "\t/* off_mem_rsvmap */\n"); + ASM_EMIT_BELONG(f, "_%s_reserve_map - _%s_blob_start", symprefix, symprefix); - fprintf(f, "\t.long\t%d\t\t\t\t\t/* version */\n", vi->version); - fprintf(f, "\t.long\t%d\t\t\t\t\t/* last_comp_version */\n", - vi->last_comp_version); - - if (vi->flags & FTF_BOOTCPUID) - fprintf(f, "\t.long\t%i\t\t\t\t\t/* boot_cpuid_phys */\n", - bi->boot_cpuid_phys); + fprintf(f, "\t/* version */\n"); + asm_emit_cell(f, vi->version); + fprintf(f, "\t/* last_comp_version */\n"); + asm_emit_cell(f, vi->last_comp_version); + + if (vi->flags & FTF_BOOTCPUID) { + fprintf(f, "\t/* boot_cpuid_phys */\n"); + asm_emit_cell(f, bi->boot_cpuid_phys); + } - if (vi->flags & FTF_STRTABSIZE) - fprintf(f, "\t.long\t_%s_strings_end - _%s_strings_start\t/* size_dt_strings */\n", - symprefix, symprefix); + if (vi->flags & FTF_STRTABSIZE) { + fprintf(f, "\t/* size_dt_strings */\n"); + ASM_EMIT_BELONG(f, "_%s_strings_end - _%s_strings_start", + symprefix, symprefix); + } - if (vi->flags & FTF_STRUCTSIZE) - fprintf(f, "\t.long\t_%s_struct_end - _%s_struct_start\t/* size_dt_struct */\n", + if (vi->flags & FTF_STRUCTSIZE) { + fprintf(f, "\t/* size_dt_struct */\n"); + ASM_EMIT_BELONG(f, "_%s_struct_end - _%s_struct_start", symprefix, symprefix); + } /* * Reserve map entries. @@ -505,16 +528,17 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version) * as it appears .quad isn't available in some assemblers. */ for (re = bi->reservelist; re; re = re->next) { - if (re->label) { - fprintf(f, "\t.globl\t%s\n", re->label); - fprintf(f, "%s:\n", re->label); + struct label *l; + + for_each_label(re->labels, l) { + fprintf(f, "\t.globl\t%s\n", l->label); + fprintf(f, "%s:\n", l->label); } - fprintf(f, "\t.long\t0x%08x, 0x%08x\n", - (unsigned int)(re->re.address >> 32), - (unsigned int)(re->re.address & 0xffffffff)); - fprintf(f, "\t.long\t0x%08x, 0x%08x\n", - (unsigned int)(re->re.size >> 32), - (unsigned int)(re->re.size & 0xffffffff)); + ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.address >> 32)); + ASM_EMIT_BELONG(f, "0x%08x", + (unsigned int)(re->re.address & 0xffffffff)); + ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.size >> 32)); + ASM_EMIT_BELONG(f, "0x%08x", (unsigned int)(re->re.size & 0xffffffff)); } for (i = 0; i < reservenum; i++) { fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n"); @@ -524,7 +548,9 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version) emit_label(f, symprefix, "struct_start"); flatten_tree(bi->dt, &asm_emitter, f, &strbuf, vi); - fprintf(f, "\t.long\tFDT_END\n"); + + fprintf(f, "\t/* FDT_END */\n"); + asm_emit_cell(f, FDT_END); emit_label(f, symprefix, "struct_end"); emit_label(f, symprefix, "strings_start"); @@ -601,7 +627,7 @@ static char *flat_read_string(struct inbuf *inb) len++; } while ((*p++) != '\0'); - str = strdup(inb->ptr); + str = xstrdup(inb->ptr); inb->ptr += len; @@ -643,7 +669,7 @@ static char *flat_read_stringtable(struct inbuf *inb, int offset) p++; } - return strdup(inb->base + offset); + return xstrdup(inb->base + offset); } static struct property *flat_read_property(struct inbuf *dtbuf, @@ -663,7 +689,7 @@ static struct property *flat_read_property(struct inbuf *dtbuf, val = flat_read_data(dtbuf, proplen); - return build_property(name, val, NULL); + return build_property(name, val); } @@ -688,7 +714,7 @@ static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb) if (re.size == 0) break; - new = build_reserve_entry(re.address, re.size, NULL); + new = build_reserve_entry(re.address, re.size); reservelist = add_reserve_entry(reservelist, new); } @@ -710,7 +736,7 @@ static char *nodename_from_path(const char *ppath, const char *cpath) if (!streq(ppath, "/")) plen++; - return strdup(cpath + plen); + return xstrdup(cpath + plen); } static struct node *unflatten_tree(struct inbuf *dtbuf, @@ -776,7 +802,7 @@ static struct node *unflatten_tree(struct inbuf *dtbuf, struct boot_info *dt_from_blob(const char *fname) { - struct dtc_file *dtcf; + FILE *f; uint32_t magic, totalsize, version, size_dt, boot_cpuid_phys; uint32_t off_dt, off_str, off_mem_rsvmap; int rc; @@ -791,14 +817,14 @@ struct boot_info *dt_from_blob(const char *fname) uint32_t val; int flags = 0; - dtcf = dtc_open_file(fname, NULL); + f = srcfile_relative_open(fname, NULL); - rc = fread(&magic, sizeof(magic), 1, dtcf->file); - if (ferror(dtcf->file)) + rc = fread(&magic, sizeof(magic), 1, f); + if (ferror(f)) die("Error reading DT blob magic number: %s\n", strerror(errno)); if (rc < 1) { - if (feof(dtcf->file)) + if (feof(f)) die("EOF reading DT blob magic number\n"); else die("Mysterious short read reading magic number\n"); @@ -808,11 +834,11 @@ struct boot_info *dt_from_blob(const char *fname) if (magic != FDT_MAGIC) die("Blob has incorrect magic number\n"); - rc = fread(&totalsize, sizeof(totalsize), 1, dtcf->file); - if (ferror(dtcf->file)) + rc = fread(&totalsize, sizeof(totalsize), 1, f); + if (ferror(f)) die("Error reading DT blob size: %s\n", strerror(errno)); if (rc < 1) { - if (feof(dtcf->file)) + if (feof(f)) die("EOF reading DT blob size\n"); else die("Mysterious short read reading blob size\n"); @@ -832,12 +858,12 @@ struct boot_info *dt_from_blob(const char *fname) p = blob + sizeof(magic) + sizeof(totalsize); while (sizeleft) { - if (feof(dtcf->file)) + if (feof(f)) die("EOF before reading %d bytes of DT blob\n", totalsize); - rc = fread(p, 1, sizeleft, dtcf->file); - if (ferror(dtcf->file)) + rc = fread(p, 1, sizeleft, f); + if (ferror(f)) die("Error reading DT blob: %s\n", strerror(errno)); @@ -900,7 +926,7 @@ struct boot_info *dt_from_blob(const char *fname) free(blob); - dtc_close_file(dtcf); + fclose(f); return build_boot_info(reservelist, tree, boot_cpuid_phys); } diff --git a/scripts/dtc/fstree.c b/scripts/dtc/fstree.c index 8fe1bdf239f..f3774530170 100644 --- a/scripts/dtc/fstree.c +++ b/scripts/dtc/fstree.c @@ -58,10 +58,9 @@ static struct node *read_fstree(const char *dirname) "WARNING: Cannot open %s: %s\n", tmpnam, strerror(errno)); } else { - prop = build_property(strdup(de->d_name), + prop = build_property(xstrdup(de->d_name), data_copy_file(pfile, - st.st_size), - NULL); + st.st_size)); add_property(tree, prop); fclose(pfile); } @@ -69,8 +68,7 @@ static struct node *read_fstree(const char *dirname) struct node *newchild; newchild = read_fstree(tmpnam); - newchild = name_node(newchild, strdup(de->d_name), - NULL); + newchild = name_node(newchild, xstrdup(de->d_name)); add_child(tree, newchild); } @@ -86,8 +84,8 @@ struct boot_info *dt_from_fs(const char *dirname) struct node *tree; tree = read_fstree(dirname); - tree = name_node(tree, "", NULL); + tree = name_node(tree, ""); - return build_boot_info(NULL, tree, 0); + return build_boot_info(NULL, tree, guess_boot_cpuid(tree)); } diff --git a/scripts/dtc/livetree.c b/scripts/dtc/livetree.c index 0ca3de550b3..c9209d5c999 100644 --- a/scripts/dtc/livetree.c +++ b/scripts/dtc/livetree.c @@ -24,17 +24,30 @@ * Tree building functions */ -struct property *build_property(char *name, struct data val, char *label) +void add_label(struct label **labels, char *label) +{ + struct label *new; + + /* Make sure the label isn't already there */ + for_each_label(*labels, new) + if (streq(new->label, label)) + return; + + new = xmalloc(sizeof(*new)); + new->label = label; + new->next = *labels; + *labels = new; +} + +struct property *build_property(char *name, struct data val) { struct property *new = xmalloc(sizeof(*new)); + memset(new, 0, sizeof(*new)); + new->name = name; new->val = val; - new->next = NULL; - - new->label = label; - return new; } @@ -78,17 +91,82 @@ struct node *build_node(struct property *proplist, struct node *children) return new; } -struct node *name_node(struct node *node, char *name, char * label) +struct node *name_node(struct node *node, char *name) { assert(node->name == NULL); node->name = name; - node->label = label; - return node; } +struct node *merge_nodes(struct node *old_node, struct node *new_node) +{ + struct property *new_prop, *old_prop; + struct node *new_child, *old_child; + struct label *l; + + /* Add new node labels to old node */ + for_each_label(new_node->labels, l) + add_label(&old_node->labels, l->label); + + /* Move properties from the new node to the old node. If there + * is a collision, replace the old value with the new */ + while (new_node->proplist) { + /* Pop the property off the list */ + new_prop = new_node->proplist; + new_node->proplist = new_prop->next; + new_prop->next = NULL; + + /* Look for a collision, set new value if there is */ + for_each_property(old_node, old_prop) { + if (streq(old_prop->name, new_prop->name)) { + /* Add new labels to old property */ + for_each_label(new_prop->labels, l) + add_label(&old_prop->labels, l->label); + + old_prop->val = new_prop->val; + free(new_prop); + new_prop = NULL; + break; + } + } + + /* if no collision occurred, add property to the old node. */ + if (new_prop) + add_property(old_node, new_prop); + } + + /* Move the override child nodes into the primary node. If + * there is a collision, then merge the nodes. */ + while (new_node->children) { + /* Pop the child node off the list */ + new_child = new_node->children; + new_node->children = new_child->next_sibling; + new_child->parent = NULL; + new_child->next_sibling = NULL; + + /* Search for a collision. Merge if there is */ + for_each_child(old_node, old_child) { + if (streq(old_child->name, new_child->name)) { + merge_nodes(old_child, new_child); + new_child = NULL; + break; + } + } + + /* if no collision occured, add child to the old node. */ + if (new_child) + add_child(old_node, new_child); + } + + /* The new node contents are now merged into the old node. Free + * the new node. */ + free(new_node); + + return old_node; +} + struct node *chain_node(struct node *first, struct node *list) { assert(first->next_sibling == NULL); @@ -124,18 +202,15 @@ void add_child(struct node *parent, struct node *child) *p = child; } -struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size, - char *label) +struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size) { struct reserve_info *new = xmalloc(sizeof(*new)); + memset(new, 0, sizeof(*new)); + new->re.address = address; new->re.size = size; - new->next = NULL; - - new->label = label; - return new; } @@ -208,6 +283,60 @@ cell_t propval_cell(struct property *prop) return fdt32_to_cpu(*((cell_t *)prop->val.val)); } +struct property *get_property_by_label(struct node *tree, const char *label, + struct node **node) +{ + struct property *prop; + struct node *c; + + *node = tree; + + for_each_property(tree, prop) { + struct label *l; + + for_each_label(prop->labels, l) + if (streq(l->label, label)) + return prop; + } + + for_each_child(tree, c) { + prop = get_property_by_label(c, label, node); + if (prop) + return prop; + } + + *node = NULL; + return NULL; +} + +struct marker *get_marker_label(struct node *tree, const char *label, + struct node **node, struct property **prop) +{ + struct marker *m; + struct property *p; + struct node *c; + + *node = tree; + + for_each_property(tree, p) { + *prop = p; + m = p->val.markers; + for_each_marker_of_type(m, LABEL) + if (streq(m->ref, label)) + return m; + } + + for_each_child(tree, c) { + m = get_marker_label(c, label, node, prop); + if (m) + return m; + } + + *prop = NULL; + *node = NULL; + return NULL; +} + struct node *get_subnode(struct node *node, const char *nodename) { struct node *child; @@ -245,11 +374,13 @@ struct node *get_node_by_path(struct node *tree, const char *path) struct node *get_node_by_label(struct node *tree, const char *label) { struct node *child, *node; + struct label *l; assert(label && (strlen(label) > 0)); - if (tree->label && streq(tree->label, label)) - return tree; + for_each_label(tree->labels, l) + if (streq(l->label, label)) + return tree; for_each_child(tree, child) { node = get_node_by_label(child, label); @@ -293,16 +424,186 @@ cell_t get_node_phandle(struct node *root, struct node *node) if ((node->phandle != 0) && (node->phandle != -1)) return node->phandle; - assert(! get_property(node, "linux,phandle")); - while (get_node_by_phandle(root, phandle)) phandle++; node->phandle = phandle; - add_property(node, - build_property("linux,phandle", - data_append_cell(empty_data, phandle), - NULL)); + + if (!get_property(node, "linux,phandle") + && (phandle_format & PHANDLE_LEGACY)) + add_property(node, + build_property("linux,phandle", + data_append_cell(empty_data, phandle))); + + if (!get_property(node, "phandle") + && (phandle_format & PHANDLE_EPAPR)) + add_property(node, + build_property("phandle", + data_append_cell(empty_data, phandle))); + + /* If the node *does* have a phandle property, we must + * be dealing with a self-referencing phandle, which will be + * fixed up momentarily in the caller */ return node->phandle; } + +uint32_t guess_boot_cpuid(struct node *tree) +{ + struct node *cpus, *bootcpu; + struct property *reg; + + cpus = get_node_by_path(tree, "/cpus"); + if (!cpus) + return 0; + + + bootcpu = cpus->children; + if (!bootcpu) + return 0; + + reg = get_property(bootcpu, "reg"); + if (!reg || (reg->val.len != sizeof(uint32_t))) + return 0; + + /* FIXME: Sanity check node? */ + + return propval_cell(reg); +} + +static int cmp_reserve_info(const void *ax, const void *bx) +{ + const struct reserve_info *a, *b; + + a = *((const struct reserve_info * const *)ax); + b = *((const struct reserve_info * const *)bx); + + if (a->re.address < b->re.address) + return -1; + else if (a->re.address > b->re.address) + return 1; + else if (a->re.size < b->re.size) + return -1; + else if (a->re.size > b->re.size) + return 1; + else + return 0; +} + +static void sort_reserve_entries(struct boot_info *bi) +{ + struct reserve_info *ri, **tbl; + int n = 0, i = 0; + + for (ri = bi->reservelist; + ri; + ri = ri->next) + n++; + + if (n == 0) + return; + + tbl = xmalloc(n * sizeof(*tbl)); + + for (ri = bi->reservelist; + ri; + ri = ri->next) + tbl[i++] = ri; + + qsort(tbl, n, sizeof(*tbl), cmp_reserve_info); + + bi->reservelist = tbl[0]; + for (i = 0; i < (n-1); i++) + tbl[i]->next = tbl[i+1]; + tbl[n-1]->next = NULL; + + free(tbl); +} + +static int cmp_prop(const void *ax, const void *bx) +{ + const struct property *a, *b; + + a = *((const struct property * const *)ax); + b = *((const struct property * const *)bx); + + return strcmp(a->name, b->name); +} + +static void sort_properties(struct node *node) +{ + int n = 0, i = 0; + struct property *prop, **tbl; + + for_each_property(node, prop) + n++; + + if (n == 0) + return; + + tbl = xmalloc(n * sizeof(*tbl)); + + for_each_property(node, prop) + tbl[i++] = prop; + + qsort(tbl, n, sizeof(*tbl), cmp_prop); + + node->proplist = tbl[0]; + for (i = 0; i < (n-1); i++) + tbl[i]->next = tbl[i+1]; + tbl[n-1]->next = NULL; + + free(tbl); +} + +static int cmp_subnode(const void *ax, const void *bx) +{ + const struct node *a, *b; + + a = *((const struct node * const *)ax); + b = *((const struct node * const *)bx); + + return strcmp(a->name, b->name); +} + +static void sort_subnodes(struct node *node) +{ + int n = 0, i = 0; + struct node *subnode, **tbl; + + for_each_child(node, subnode) + n++; + + if (n == 0) + return; + + tbl = xmalloc(n * sizeof(*tbl)); + + for_each_child(node, subnode) + tbl[i++] = subnode; + + qsort(tbl, n, sizeof(*tbl), cmp_subnode); + + node->children = tbl[0]; + for (i = 0; i < (n-1); i++) + tbl[i]->next_sibling = tbl[i+1]; + tbl[n-1]->next_sibling = NULL; + + free(tbl); +} + +static void sort_node(struct node *node) +{ + struct node *c; + + sort_properties(node); + sort_subnodes(node); + for_each_child(node, c) + sort_node(c); +} + +void sort_tree(struct boot_info *bi) +{ + sort_reserve_entries(bi); + sort_node(bi->dt); +} diff --git a/scripts/dtc/srcpos.c b/scripts/dtc/srcpos.c index 9641b7628b4..2dbc874288c 100644 --- a/scripts/dtc/srcpos.c +++ b/scripts/dtc/srcpos.c @@ -17,100 +17,232 @@ * USA */ +#define _GNU_SOURCE + +#include + #include "dtc.h" #include "srcpos.h" -/* - * Like yylineno, this is the current open file pos. - */ -struct dtc_file *srcpos_file; +static char *dirname(const char *path) +{ + const char *slash = strrchr(path, '/'); + + if (slash) { + int len = slash - path; + char *dir = xmalloc(len + 1); + + memcpy(dir, path, len); + dir[len] = '\0'; + return dir; + } + return NULL; +} + +struct srcfile_state *current_srcfile; /* = NULL */ -static int dtc_open_one(struct dtc_file *file, - const char *search, - const char *fname) +/* Detect infinite include recursion. */ +#define MAX_SRCFILE_DEPTH (100) +static int srcfile_depth; /* = 0 */ + +FILE *srcfile_relative_open(const char *fname, char **fullnamep) { + FILE *f; char *fullname; - if (search) { - fullname = xmalloc(strlen(search) + strlen(fname) + 2); - - strcpy(fullname, search); - strcat(fullname, "/"); - strcat(fullname, fname); + if (streq(fname, "-")) { + f = stdin; + fullname = xstrdup(""); } else { - fullname = strdup(fname); + if (!current_srcfile || !current_srcfile->dir + || (fname[0] == '/')) + fullname = xstrdup(fname); + else + fullname = join_path(current_srcfile->dir, fname); + + f = fopen(fullname, "r"); + if (!f) + die("Couldn't open \"%s\": %s\n", fname, + strerror(errno)); } - file->file = fopen(fullname, "r"); - if (!file->file) { + if (fullnamep) + *fullnamep = fullname; + else free(fullname); - return 0; - } - file->name = fullname; - return 1; + return f; } +void srcfile_push(const char *fname) +{ + struct srcfile_state *srcfile; + + if (srcfile_depth++ >= MAX_SRCFILE_DEPTH) + die("Includes nested too deeply"); + + srcfile = xmalloc(sizeof(*srcfile)); + + srcfile->f = srcfile_relative_open(fname, &srcfile->name); + srcfile->dir = dirname(srcfile->name); + srcfile->prev = current_srcfile; + + srcfile->lineno = 1; + srcfile->colno = 1; + + current_srcfile = srcfile; +} -struct dtc_file *dtc_open_file(const char *fname, - const struct search_path *search) +int srcfile_pop(void) { - static const struct search_path default_search = { NULL, NULL, NULL }; + struct srcfile_state *srcfile = current_srcfile; - struct dtc_file *file; - const char *slash; + assert(srcfile); - file = xmalloc(sizeof(struct dtc_file)); + current_srcfile = srcfile->prev; - slash = strrchr(fname, '/'); - if (slash) { - char *dir = xmalloc(slash - fname + 1); + if (fclose(srcfile->f)) + die("Error closing \"%s\": %s\n", srcfile->name, + strerror(errno)); - memcpy(dir, fname, slash - fname); - dir[slash - fname] = 0; - file->dir = dir; - } else { - file->dir = NULL; - } + /* FIXME: We allow the srcfile_state structure to leak, + * because it could still be referenced from a location + * variable being carried through the parser somewhere. To + * fix this we could either allocate all the files from a + * table, or use a pool allocator. */ - if (streq(fname, "-")) { - file->name = "stdin"; - file->file = stdin; - return file; - } + return current_srcfile ? 1 : 0; +} - if (fname[0] == '/') { - file->file = fopen(fname, "r"); - if (!file->file) - goto fail; +/* + * The empty source position. + */ - file->name = strdup(fname); - return file; - } +struct srcpos srcpos_empty = { + .first_line = 0, + .first_column = 0, + .last_line = 0, + .last_column = 0, + .file = NULL, +}; - if (!search) - search = &default_search; +#define TAB_SIZE 8 - while (search) { - if (dtc_open_one(file, search->dir, fname)) - return file; +void srcpos_update(struct srcpos *pos, const char *text, int len) +{ + int i; + + pos->file = current_srcfile; + + pos->first_line = current_srcfile->lineno; + pos->first_column = current_srcfile->colno; + + for (i = 0; i < len; i++) + if (text[i] == '\n') { + current_srcfile->lineno++; + current_srcfile->colno = 1; + } else if (text[i] == '\t') { + current_srcfile->colno = + ALIGN(current_srcfile->colno, TAB_SIZE); + } else { + current_srcfile->colno++; + } + + pos->last_line = current_srcfile->lineno; + pos->last_column = current_srcfile->colno; +} - if (errno != ENOENT) - goto fail; +struct srcpos * +srcpos_copy(struct srcpos *pos) +{ + struct srcpos *pos_new; - search = search->next; - } + pos_new = xmalloc(sizeof(struct srcpos)); + memcpy(pos_new, pos, sizeof(struct srcpos)); + + return pos_new; +} + + + +void +srcpos_dump(struct srcpos *pos) +{ + printf("file : \"%s\"\n", + pos->file ? (char *) pos->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); +} -fail: - die("Couldn't open \"%s\": %s\n", fname, strerror(errno)); + +char * +srcpos_string(struct srcpos *pos) +{ + const char *fname = ""; + char *pos_str; + int rc; + + if (pos) + 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); + 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); + 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"); + + return pos_str; +} + +void +srcpos_verror(struct srcpos *pos, char const *fmt, va_list va) +{ + const char *srcstr; + + srcstr = srcpos_string(pos); + + fprintf(stdout, "Error: %s ", srcstr); + vfprintf(stdout, fmt, va); + fprintf(stdout, "\n"); } -void dtc_close_file(struct dtc_file *file) +void +srcpos_error(struct srcpos *pos, char const *fmt, ...) { - if (fclose(file->file)) - die("Error closing \"%s\": %s\n", file->name, strerror(errno)); + va_list va; + + va_start(va, fmt); + srcpos_verror(pos, fmt, va); + va_end(va); +} + + +void +srcpos_warn(struct srcpos *pos, char const *fmt, ...) +{ + const char *srcstr; + va_list va; + va_start(va, fmt); + + srcstr = srcpos_string(pos); + + fprintf(stderr, "Warning: %s ", srcstr); + vfprintf(stderr, fmt, va); + fprintf(stderr, "\n"); - free(file->dir); - free(file); + va_end(va); } diff --git a/scripts/dtc/srcpos.h b/scripts/dtc/srcpos.h index e17c7c04db8..bd7966e56a5 100644 --- a/scripts/dtc/srcpos.h +++ b/scripts/dtc/srcpos.h @@ -17,69 +17,70 @@ * USA */ -/* - * Augment the standard YYLTYPE with a filenum index into an - * array of all opened filenames. - */ +#ifndef _SRCPOS_H_ +#define _SRCPOS_H_ #include -struct dtc_file { +struct srcfile_state { + FILE *f; + char *name; char *dir; - const char *name; - FILE *file; + int lineno, colno; + struct srcfile_state *prev; }; -#if ! defined(YYLTYPE) && ! defined(YYLTYPE_IS_DECLARED) -typedef struct YYLTYPE { +extern struct srcfile_state *current_srcfile; /* = NULL */ + +FILE *srcfile_relative_open(const char *fname, char **fullnamep); +void srcfile_push(const char *fname); +int srcfile_pop(void); + +struct srcpos { int first_line; int first_column; int last_line; int last_column; - struct dtc_file *file; -} YYLTYPE; - -#define YYLTYPE_IS_DECLARED 1 -#define YYLTYPE_IS_TRIVIAL 1 -#endif - -/* Cater to old parser templates. */ -#ifndef YYID -#define YYID(n) (n) -#endif + struct srcfile_state *file; +}; -#define YYLLOC_DEFAULT(Current, Rhs, N) \ - do \ - if (YYID (N)) \ - { \ - (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ - (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ - (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ - (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ - (Current).file = YYRHSLOC (Rhs, N).file; \ - } \ - else \ - { \ - (Current).first_line = (Current).last_line = \ - YYRHSLOC (Rhs, 0).last_line; \ - (Current).first_column = (Current).last_column = \ - YYRHSLOC (Rhs, 0).last_column; \ - (Current).file = YYRHSLOC (Rhs, 0).file; \ - } \ - while (YYID (0)) +#define YYLTYPE struct srcpos +#define YYLLOC_DEFAULT(Current, Rhs, N) \ + do { \ + if (N) { \ + (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC(Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC(Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + (Current).file = YYRHSLOC(Rhs, N).file; \ + } else { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC(Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC(Rhs, 0).last_column; \ + (Current).file = YYRHSLOC (Rhs, 0).file; \ + } \ + } while (0) -extern void yyerror(char const *); -extern void yyerrorf(char const *, ...) __attribute__((format(printf, 1, 2))); +/* + * Fictional source position used for IR nodes that are + * created without otherwise knowing a true source position. + * For example,constant definitions from the command line. + */ +extern struct srcpos srcpos_empty; -extern struct dtc_file *srcpos_file; +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); -struct search_path { - const char *dir; /* NULL for current directory */ - struct search_path *prev, *next; -}; +extern void srcpos_verror(struct srcpos *pos, char const *, va_list va) + __attribute__((format(printf, 2, 0))); +extern void srcpos_error(struct srcpos *pos, char const *, ...) + __attribute__((format(printf, 2, 3))); +extern void srcpos_warn(struct srcpos *pos, char const *, ...) + __attribute__((format(printf, 2, 3))); -extern struct dtc_file *dtc_open_file(const char *fname, - const struct search_path *search); -extern void dtc_close_file(struct dtc_file *file); +#endif /* _SRCPOS_H_ */ diff --git a/scripts/dtc/treesource.c b/scripts/dtc/treesource.c index 1521ff11bb9..c09aafade31 100644 --- a/scripts/dtc/treesource.c +++ b/scripts/dtc/treesource.c @@ -32,8 +32,8 @@ struct boot_info *dt_from_source(const char *fname) the_boot_info = NULL; treesource_error = 0; - srcpos_file = dtc_open_file(fname, NULL); - yyin = srcpos_file->file; + srcfile_push(fname); + yyin = current_srcfile->f; if (yyparse() != 0) die("Unable to parse input tree\n"); @@ -63,26 +63,20 @@ static void write_propval_string(FILE *f, struct data val) { const char *str = val.val; int i; - int newchunk = 1; struct marker *m = val.markers; assert(str[val.len-1] == '\0'); + while (m && (m->offset == 0)) { + if (m->type == LABEL) + fprintf(f, "%s: ", m->ref); + m = m->next; + } + fprintf(f, "\""); + for (i = 0; i < (val.len-1); i++) { char c = str[i]; - if (newchunk) { - while (m && (m->offset <= i)) { - if (m->type == LABEL) { - assert(m->offset == i); - fprintf(f, "%s: ", m->ref); - } - m = m->next; - } - fprintf(f, "\""); - newchunk = 0; - } - switch (c) { case '\a': fprintf(f, "\\a"); @@ -113,7 +107,14 @@ static void write_propval_string(FILE *f, struct data val) break; case '\0': fprintf(f, "\", "); - newchunk = 1; + while (m && (m->offset < i)) { + if (m->type == LABEL) { + assert(m->offset == (i+1)); + fprintf(f, "%s: ", m->ref); + } + m = m->next; + } + fprintf(f, "\""); break; default: if (isprint(c)) @@ -234,10 +235,11 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level) { struct property *prop; struct node *child; + struct label *l; write_prefix(f, level); - if (tree->label) - fprintf(f, "%s: ", tree->label); + for_each_label(tree->labels, l) + fprintf(f, "%s: ", l->label); if (tree->name && (*tree->name)) fprintf(f, "%s {\n", tree->name); else @@ -245,8 +247,8 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level) for_each_property(tree, prop) { write_prefix(f, level+1); - if (prop->label) - fprintf(f, "%s: ", prop->label); + for_each_label(prop->labels, l) + fprintf(f, "%s: ", l->label); fprintf(f, "%s", prop->name); write_propval(f, prop); } @@ -266,8 +268,10 @@ void dt_to_source(FILE *f, struct boot_info *bi) fprintf(f, "/dts-v1/;\n\n"); for (re = bi->reservelist; re; re = re->next) { - if (re->label) - fprintf(f, "%s: ", re->label); + struct label *l; + + for_each_label(re->labels, l) + fprintf(f, "%s: ", l->label); fprintf(f, "/memreserve/\t0x%016llx 0x%016llx;\n", (unsigned long long)re->re.address, (unsigned long long)re->re.size); diff --git a/scripts/dtc/util.c b/scripts/dtc/util.c new file mode 100644 index 00000000000..d7ac27d2ae1 --- /dev/null +++ b/scripts/dtc/util.c @@ -0,0 +1,59 @@ +/* + * Copyright 2008 Jon Loeliger, Freescale Semiconductor, 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 the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#include +#include +#include +#include + +#include "util.h" + +char *xstrdup(const char *s) +{ + int len = strlen(s) + 1; + char *dup = xmalloc(len); + + memcpy(dup, s, len); + + return dup; +} + +char *join_path(const char *path, const char *name) +{ + int lenp = strlen(path); + int lenn = strlen(name); + int len; + int needslash = 1; + char *str; + + len = lenp + lenn + 2; + if ((lenp > 0) && (path[lenp-1] == '/')) { + needslash = 0; + len--; + } + + str = xmalloc(len); + memcpy(str, path, lenp); + if (needslash) { + str[lenp] = '/'; + lenp++; + } + memcpy(str+lenp, name, lenn+1); + return str; +} diff --git a/scripts/dtc/util.h b/scripts/dtc/util.h new file mode 100644 index 00000000000..9cead842c11 --- /dev/null +++ b/scripts/dtc/util.h @@ -0,0 +1,56 @@ +#ifndef _UTIL_H +#define _UTIL_H + +/* + * Copyright 2008 Jon Loeliger, Freescale Semiconductor, 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 the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +static inline void __attribute__((noreturn)) die(char * str, ...) +{ + va_list ap; + + va_start(ap, str); + fprintf(stderr, "FATAL ERROR: "); + vfprintf(stderr, str, ap); + exit(1); +} + +static inline void *xmalloc(size_t len) +{ + void *new = malloc(len); + + if (!new) + die("malloc() failed\n"); + + return new; +} + +static inline void *xrealloc(void *p, size_t len) +{ + void *new = realloc(p, len); + + if (!new) + die("realloc() failed (len=%d)\n", len); + + return new; +} + +extern char *xstrdup(const char *s); +extern char *join_path(const char *path, const char *name); + +#endif /* _UTIL_H */ diff --git a/scripts/dtc/version_gen.h b/scripts/dtc/version_gen.h index 658ff42429d..6158b867df9 100644 --- a/scripts/dtc/version_gen.h +++ b/scripts/dtc/version_gen.h @@ -1 +1 @@ -#define DTC_VERSION "DTC 1.2.0" +#define DTC_VERSION "DTC 1.2.0-g37c0b6a0" -- cgit v1.2.3-70-g09d2 From 8484baaa5065b460e5eb18ee721d8417251f7897 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 5 Jan 2011 16:28:43 -0800 Subject: kernel-doc: code reorganization Move 'main' code vs. subroutines around so that they are not so intermixed, for better readability/understanding (relative to Perl). It was messy to follow the primary flow of code execution with the code being mixed. Now the code begins with data initialization, followed by all subroutines, then ends with the main code execution. This is almost totally source code movement, with a few changes as needed for forward declarations. Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- scripts/kernel-doc | 102 ++++++++++++++++++++++++++++------------------------- 1 file changed, 54 insertions(+), 48 deletions(-) (limited to 'scripts') diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 39580a5dc5d..9f85012acf0 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -155,6 +155,8 @@ use strict; # '@parameter' - name of a parameter # '%CONST' - name of a constant. +## init lots of data + my $errors = 0; my $warnings = 0; my $anon_struct_union = 0; @@ -218,21 +220,14 @@ my %highlights_list = ( $type_constant, "\$1", $type_param, "\$1" ); my $blankline_list = ""; -sub usage { - print "Usage: $0 [ -v ] [ -docbook | -html | -text | -man | -list ]\n"; - print " [ -no-doc-sections ]\n"; - print " [ -function funcname [ -function funcname ...] ]\n"; - print " [ -nofunction funcname [ -nofunction funcname ...] ]\n"; - print " c source file(s) > outputfile\n"; - print " -v : verbose output, more warnings & other info listed\n"; - exit 1; -} - # read arguments if ($#ARGV == -1) { usage(); } +my $kernelversion; +my $dohighlight = ""; + my $verbose = 0; my $output_mode = "man"; my $no_doc_sections = 0; @@ -245,7 +240,7 @@ my $man_date = ('January', 'February', 'March', 'April', 'May', 'June', 'November', 'December')[(localtime)[4]] . " " . ((localtime)[5]+1900); -# Essentially these are globals +# Essentially these are globals. # They probably want to be tidied up, made more localised or something. # CAVEAT EMPTOR! Some of the others I localised may not want to be, which # could cause "use of undefined value" or other bugs. @@ -353,6 +348,18 @@ while ($ARGV[0] =~ m/^-(.*)/) { } } +# continue execution near EOF; + +sub usage { + print "Usage: $0 [ -v ] [ -docbook | -html | -text | -man | -list ]\n"; + print " [ -no-doc-sections ]\n"; + print " [ -function funcname [ -function funcname ...] ]\n"; + print " [ -nofunction funcname [ -nofunction funcname ...] ]\n"; + print " c source file(s) > outputfile\n"; + print " -v : verbose output, more warnings & other info listed\n"; + exit 1; +} + # get kernel version from env sub get_kernel_version() { my $version = 'unknown kernel version'; @@ -362,15 +369,6 @@ sub get_kernel_version() { } return $version; } -my $kernelversion = get_kernel_version(); - -# generate a sequence of code that will splice in highlighting information -# using the s// operator. -my $dohighlight = ""; -foreach my $pattern (keys %highlights) { -# print STDERR "scanning pattern:$pattern, highlight:($highlights{$pattern})\n"; - $dohighlight .= "\$contents =~ s:$pattern:$highlights{$pattern}:gs;\n"; -} ## # dumps section contents to arrays/hashes intended for that purpose. @@ -1851,34 +1849,6 @@ sub dump_function($$) { }); } -sub process_file($); - -# Read the file that maps relative names to absolute names for -# separate source and object directories and for shadow trees. -if (open(SOURCE_MAP, "<.tmp_filelist.txt")) { - my ($relname, $absname); - while() { - chop(); - ($relname, $absname) = (split())[0..1]; - $relname =~ s:^/+::; - $source_map{$relname} = $absname; - } - close(SOURCE_MAP); -} - -foreach (@ARGV) { - chomp; - process_file($_); -} -if ($verbose && $errors) { - print STDERR "$errors errors\n"; -} -if ($verbose && $warnings) { - print STDERR "$warnings warnings\n"; -} - -exit($errors); - sub reset_state { $function = ""; %constants = (); @@ -2285,3 +2255,39 @@ sub process_file($) { } } } + + +$kernelversion = get_kernel_version(); + +# generate a sequence of code that will splice in highlighting information +# using the s// operator. +foreach my $pattern (keys %highlights) { +# print STDERR "scanning pattern:$pattern, highlight:($highlights{$pattern})\n"; + $dohighlight .= "\$contents =~ s:$pattern:$highlights{$pattern}:gs;\n"; +} + +# Read the file that maps relative names to absolute names for +# separate source and object directories and for shadow trees. +if (open(SOURCE_MAP, "<.tmp_filelist.txt")) { + my ($relname, $absname); + while() { + chop(); + ($relname, $absname) = (split())[0..1]; + $relname =~ s:^/+::; + $source_map{$relname} = $absname; + } + close(SOURCE_MAP); +} + +foreach (@ARGV) { + chomp; + process_file($_); +} +if ($verbose && $errors) { + print STDERR "$errors errors\n"; +} +if ($verbose && $warnings) { + print STDERR "$warnings warnings\n"; +} + +exit($errors); -- cgit v1.2.3-70-g09d2 From bc91c9f313309915f6ec767f56f78dcd0305b20f Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Fri, 17 Dec 2010 17:19:17 +0100 Subject: mkuboot.sh: Fail if mkimage is missing on building an uImage, I get: $ make uImage CHK include/linux/version.h CHK include/generated/utsrelease.h make[1]: `include/generated/mach-types.h' is up to date. CALL scripts/checksyscalls.sh CHK include/generated/compile.h Kernel: arch/arm/boot/Image is ready SHIPPED arch/arm/boot/compressed/lib1funcs.S AS arch/arm/boot/compressed/lib1funcs.o LD arch/arm/boot/compressed/vmlinux OBJCOPY arch/arm/boot/zImage Kernel: arch/arm/boot/zImage is ready UIMAGE arch/arm/boot/uImage "mkimage" command not found - U-Boot images will not be built Image arch/arm/boot/uImage is ready $ I.e. it says: "uImage is ready" even though the uImage file doesn't exist because mkimage is missing. I propose the attached patch. Signed-off-by: Roland Stigge Signed-off-by: Michal Marek --- scripts/mkuboot.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/mkuboot.sh b/scripts/mkuboot.sh index 2e3d3cd916b..446739c7843 100755 --- a/scripts/mkuboot.sh +++ b/scripts/mkuboot.sh @@ -11,7 +11,7 @@ if [ -z "${MKIMAGE}" ]; then if [ -z "${MKIMAGE}" ]; then # Doesn't exist echo '"mkimage" command not found - U-Boot images will not be built' >&2 - exit 0; + exit 1; fi fi -- cgit v1.2.3-70-g09d2 From 39177ec36236fb71257e51d0d198437b84170911 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Thu, 6 Jan 2011 16:42:45 +0100 Subject: nconf: handle comment entries within choice/endchoice Equivalent to af6c1598 (kconfig: handle comment entries within choice/endchoice), but for nconfig instead. Implement support for comment entries within choice groups. Comment entries are displayed visually distinct from normal configs, and selecting them is a no-op. Signed-off-by: Peter Korsgaard Signed-off-by: Michal Marek --- scripts/kconfig/nconf.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'scripts') diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c index eda49ffc1c8..db56377393d 100644 --- a/scripts/kconfig/nconf.c +++ b/scripts/kconfig/nconf.c @@ -1266,9 +1266,13 @@ static void conf_choice(struct menu *menu) if (child->sym == sym_get_choice_value(menu->sym)) item_make(child, ':', " %s", _(menu_get_prompt(child))); - else + else if (child->sym) item_make(child, ':', " %s", _(menu_get_prompt(child))); + else + item_make(child, ':', "*** %s ***", + _(menu_get_prompt(child))); + if (child->sym == active){ last_top_row = top_row(curses_menu); selected_index = i; @@ -1334,7 +1338,7 @@ static void conf_choice(struct menu *menu) break; child = item_data(); - if (!child || !menu_is_visible(child)) + if (!child || !menu_is_visible(child) || !child->sym) continue; switch (res) { case ' ': -- cgit v1.2.3-70-g09d2 From e68077856e599cd33d8cd5db15762df60c29d361 Mon Sep 17 00:00:00 2001 From: maximilian attems Date: Sat, 1 Jan 2011 16:44:13 +0100 Subject: deb-pkg: Make deb-pkg generate a seperate linux-libc-dev deb userland dev likes latest incarnation of that userland API. make it easy to also build it on make deb-pkg invocation: dpkg-deb: building package `linux-libc-dev' in `../linux-libc-dev_2.6.32-rc6-4_amd64.deb'. Last year patch rebased on top of latest deb-pkg changes. Signed-off-by: maximilian attems Signed-off-by: Michal Marek --- scripts/package/builddeb | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/package/builddeb b/scripts/package/builddeb index 5fc1e6f7183..8c1f8d4d156 100644 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -77,20 +77,24 @@ fi tmpdir="$objtree/debian/tmp" fwdir="$objtree/debian/fwtmp" hdrdir="$objtree/debian/hdrtmp" +headerdir="$objtree/debian/headertmp" packagename=linux-image-$version fwpackagename=linux-firmware-image hdrpackagename=linux-headers-$version +headerpackagename=linux-libc-dev if [ "$ARCH" = "um" ] ; then packagename=user-mode-linux-$version fi # Setup the directory structure -rm -rf "$tmpdir" "$fwdir" "$hdrdir" +rm -rf "$tmpdir" "$fwdir" "$hdrdir" "$headerdir" mkdir -m 755 -p "$tmpdir/DEBIAN" mkdir -p "$tmpdir/lib" "$tmpdir/boot" "$tmpdir/usr/share/doc/$packagename" mkdir -m 755 -p "$fwdir/DEBIAN" mkdir -p "$fwdir/lib" "$fwdir/usr/share/doc/$fwpackagename" +mkdir -m 755 -p "$headerdir/DEBIAN" +mkdir -p "$headerdir/usr/share/doc/$headerpackagename" if [ "$ARCH" = "um" ] ; then mkdir -p "$tmpdir/usr/lib/uml/modules/$version" "$tmpdir/usr/bin" fi @@ -121,6 +125,9 @@ if grep -q '^CONFIG_MODULES=y' .config ; then fi fi +make headers_check +make headers_install INSTALL_HDR_PATH="$headerdir/usr" + # Install the maintainer scripts # Note: hook scripts under /etc/kernel are also executed by official Debian # kernel packages, as well as kernel packages built using make-kpkg @@ -267,6 +274,18 @@ EOF create_package "$fwpackagename" "$fwdir" fi +cat <> debian/control + +Package: $headerpackagename +Section: devel +Provides: linux-kernel-headers +Architecture: any +Description: Linux support headers for userspace development + This package provides userspaces headers from the Linux kernel. These headers + are used by the installed headers for GNU glibc and other system libraries. +EOF + +create_package "$headerpackagename" "$headerdir" create_package "$packagename" "$tmpdir" exit 0 -- cgit v1.2.3-70-g09d2 From ee81b786a07f1d6062d6e14b6152f1f6cc4bc63b Mon Sep 17 00:00:00 2001 From: maximilian attems Date: Fri, 7 Jan 2011 16:13:06 +0100 Subject: deb-pkg: s/hdr/kernel_headers_/ && s/header/libc_headers_/ hdrpackage and headerpackage are not intuitive names, use proposed alternatives by Michel Marek. While touching them move the mkdir of the kernel_headers dir up and fix it for paranoid umask. CC: Theodore Ts'o Signed-off-by: maximilian attems Signed-off-by: Michal Marek --- scripts/package/builddeb | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'scripts') diff --git a/scripts/package/builddeb b/scripts/package/builddeb index 8c1f8d4d156..b0b2357aef4 100644 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -76,25 +76,27 @@ else fi tmpdir="$objtree/debian/tmp" fwdir="$objtree/debian/fwtmp" -hdrdir="$objtree/debian/hdrtmp" -headerdir="$objtree/debian/headertmp" +kernel_headers_dir="$objtree/debian/hdrtmp" +libc_headers_dir="$objtree/debian/headertmp" packagename=linux-image-$version fwpackagename=linux-firmware-image -hdrpackagename=linux-headers-$version -headerpackagename=linux-libc-dev +kernel_headers_packagename=linux-headers-$version +libc_headers_packagename=linux-libc-dev if [ "$ARCH" = "um" ] ; then packagename=user-mode-linux-$version fi # Setup the directory structure -rm -rf "$tmpdir" "$fwdir" "$hdrdir" "$headerdir" +rm -rf "$tmpdir" "$fwdir" "$kernel_headers_dir" "$libc_headers_dir" mkdir -m 755 -p "$tmpdir/DEBIAN" mkdir -p "$tmpdir/lib" "$tmpdir/boot" "$tmpdir/usr/share/doc/$packagename" mkdir -m 755 -p "$fwdir/DEBIAN" mkdir -p "$fwdir/lib" "$fwdir/usr/share/doc/$fwpackagename" -mkdir -m 755 -p "$headerdir/DEBIAN" -mkdir -p "$headerdir/usr/share/doc/$headerpackagename" +mkdir -m 755 -p "$libc_headers_dir/DEBIAN" +mkdir -p "$libc_headers_dir/usr/share/doc/$libc_headers_packagename" +mkdir -m 755 -p "$kernel_headers_dir/DEBIAN" +mkdir -p "$kernel_headers_dir/usr/share/doc/$kernel_headers_packagename" if [ "$ARCH" = "um" ] ; then mkdir -p "$tmpdir/usr/lib/uml/modules/$version" "$tmpdir/usr/bin" fi @@ -126,7 +128,7 @@ if grep -q '^CONFIG_MODULES=y' .config ; then fi make headers_check -make headers_install INSTALL_HDR_PATH="$headerdir/usr" +make headers_install INSTALL_HDR_PATH="$libc_headers_dir/usr" # Install the maintainer scripts # Note: hook scripts under /etc/kernel are also executed by official Debian @@ -239,8 +241,8 @@ fi find . -name Makefile -o -name Kconfig\* -o -name \*.pl > /tmp/files$$ find arch/x86/include include scripts -type f >> /tmp/files$$ (cd $objtree; find .config Module.symvers include scripts -type f >> /tmp/objfiles$$) -destdir=$hdrdir/usr/src/linux-headers-$version -mkdir -p "$destdir" "$hdrdir/DEBIAN" "$hdrdir/usr/share/doc/$hdrpackagename" +destdir=$kernel_headers_dir/usr/src/linux-headers-$version +mkdir -p "$destdir" tar -c -f - -T /tmp/files$$ | (cd $destdir; tar -xf -) (cd $objtree; tar -c -f - -T /tmp/objfiles$$) | (cd $destdir; tar -xf -) rm -f /tmp/files$$ /tmp/objfiles$$ @@ -248,7 +250,7 @@ arch=$(dpkg --print-architecture) cat <> debian/control -Package: $hdrpackagename +Package: $kernel_headers_packagename Provides: linux-headers, linux-headers-2.6 Architecture: $arch Description: Linux kernel headers for $KERNELRELEASE on $arch @@ -257,7 +259,7 @@ Description: Linux kernel headers for $KERNELRELEASE on $arch This is useful for people who need to build external modules EOF -create_package "$hdrpackagename" "$hdrdir" +create_package "$kernel_headers_packagename" "$kernel_headers_dir" # Do we have firmware? Move it out of the way and build it into a package. if [ -e "$tmpdir/lib/firmware" ]; then @@ -276,7 +278,7 @@ fi cat <> debian/control -Package: $headerpackagename +Package: $libc_headers_packagename Section: devel Provides: linux-kernel-headers Architecture: any @@ -285,7 +287,7 @@ Description: Linux support headers for userspace development are used by the installed headers for GNU glibc and other system libraries. EOF -create_package "$headerpackagename" "$headerdir" +create_package "$libc_headers_packagename" "$libc_headers_dir" create_package "$packagename" "$tmpdir" exit 0 -- cgit v1.2.3-70-g09d2 From 7e1863af1636b304a5f59aab6fb78d38e4079875 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 12 Jan 2011 16:59:49 -0800 Subject: scripts/get_maintainer.pl: make --rolestats the default This script now requires a user to add --norolestats to the command line so it's harder to feed the output of this script to programs that send mass emails. Update --help to correct command line defaults. Change version to 0.26. Signed-off-by: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/get_maintainer.pl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'scripts') diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index d21ec3a8960..43bace2f4ac 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -13,7 +13,7 @@ use strict; my $P = $0; -my $V = '0.26-beta6'; +my $V = '0.26'; use Getopt::Long qw(:config no_auto_abbrev); @@ -40,7 +40,7 @@ my $email_use_mailmap = 1; my $output_multiline = 1; my $output_separator = ", "; my $output_roles = 0; -my $output_rolestats = 0; +my $output_rolestats = 1; my $scm = 0; my $web = 0; my $subsystem = 0; @@ -720,7 +720,8 @@ Other options: --help => show this help information Default options: - [--email --git --m --n --l --multiline --pattern-depth=0 --remove-duplicates] + [--email --nogit --git-fallback --m --n --l --multiline -pattern-depth=0 + --remove-duplicates --rolestats] Notes: Using "-f directory" may give unexpected results: -- cgit v1.2.3-70-g09d2 From ab6c937dbadf4797484d00d2815e1e3b0ec54397 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 12 Jan 2011 16:59:50 -0800 Subject: scripts/get_maintainer.pl: use --git-fallback more often On Fri, 2010-11-05 at 13:50 -0700, Andrew Morton wrote: > z:/usr/src/git26> perl scripts/get_maintainer.pl -file mm/mempolicy.c > linux-mm@kvack.org > linux-kernel@vger.kernel.org Turns out this is an arguable defect in the script. The MAINTAINERS entry for mm is: MEMORY MANAGEMENT L: linux-mm@kvack.org W: http://www.linux-mm.org S: Maintained F: include/linux/mm.h F: mm/ There's a maintainer entry, but no named individual, so the script doesn't use git history via --git-fallback. This is also a defect for MAINTAINERS with status entries marked "Orphan" or "Odd fixes". The script now checks a section for any "M:" entry and that an "S:" entry is supported or maintained. If both those conditions are not satisified, use --git-fallback as appropriate. Signed-off-by: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/get_maintainer.pl | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index 43bace2f4ac..139e0fff8e3 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -494,6 +494,40 @@ if ($web) { exit($exit); +sub range_is_maintained { + my ($start, $end) = @_; + + for (my $i = $start; $i < $end; $i++) { + my $line = $typevalue[$i]; + if ($line =~ m/^(\C):\s*(.*)/) { + my $type = $1; + my $value = $2; + if ($type eq 'S') { + if ($value =~ /(maintain|support)/i) { + return 1; + } + } + } + } + return 0; +} + +sub range_has_maintainer { + my ($start, $end) = @_; + + for (my $i = $start; $i < $end; $i++) { + my $line = $typevalue[$i]; + if ($line =~ m/^(\C):\s*(.*)/) { + my $type = $1; + my $value = $2; + if ($type eq 'M') { + return 1; + } + } + } + return 0; +} + sub get_maintainers { %email_hash_name = (); %email_hash_address = (); @@ -556,7 +590,9 @@ sub get_maintainers { my $file_pd = ($file =~ tr@/@@); $value_pd++ if (substr($value,-1,1) ne "/"); $value_pd = -1 if ($value =~ /^\.\*/); - if ($value_pd >= $file_pd) { + if ($value_pd >= $file_pd && + range_is_maintained($start, $end) && + range_has_maintainer($start, $end)) { $exact_pattern_match_hash{$file} = 1; } if ($pattern_depth == 0 || -- cgit v1.2.3-70-g09d2 From caf2a54f101a55ec318c2a20253a1977802f7de4 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 12 Jan 2011 16:59:56 -0800 Subject: scripts/checkpatch.pl: add check for multiple terminating semicolons and casts of vmalloc Signed-off-by: Joe Perches Cc: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index e3c7fc0dca3..36d6851f97d 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2785,10 +2785,15 @@ sub process { } # check for pointless casting of kmalloc return - if ($line =~ /\*\s*\)\s*k[czm]alloc\b/) { + if ($line =~ /\*\s*\)\s*[kv][czm]alloc(_node){0,1}\b/) { WARN("unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\n" . $herecurr); } +# check for multiple semicolons + if ($line =~ /;\s*;\s*$/) { + WARN("Statements terminations use 1 semicolon\n" . $herecurr); + } + # check for gcc specific __FUNCTION__ if ($line =~ /__FUNCTION__/) { WARN("__func__ should be used instead of gcc specific __FUNCTION__\n" . $herecurr); -- cgit v1.2.3-70-g09d2 From c023e4734c3e8801e0ecb5e81b831d42a374d861 Mon Sep 17 00:00:00 2001 From: Florian Mickler Date: Wed, 12 Jan 2011 16:59:58 -0800 Subject: checkpatch.pl: fix CAST detection We should only claim that something is a cast if we did not encouter a token before, that did set av_pending. This fixes the operator * in the line below to be detected as binary (vs unary). kmalloc(sizeof(struct alphatrack_ocmd) * true_size, GFP_KERNEL); Reported-by: Audun Hoem Signed-off-by: Florian Mickler Cc: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 36d6851f97d..ddd27d8e631 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -859,7 +859,7 @@ sub annotate_values { $av_preprocessor = 0; } - } elsif ($cur =~ /^(\(\s*$Type\s*)\)/) { + } elsif ($cur =~ /^(\(\s*$Type\s*)\)/ && $av_pending eq '_') { print "CAST($1)\n" if ($dbg_values > 1); push(@av_paren_type, $type); $type = 'C'; -- cgit v1.2.3-70-g09d2 From 88f8831c055858179a7844d9dd4ddd7d3621322e Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 12 Jan 2011 16:59:59 -0800 Subject: checkpatch: check for world-writeable sysfs/debugfs files Exporting world writable sysfs/debugfs files is usually a bad thing. Warn about it. Signed-off-by: Dave Jones Cc: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'scripts') diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index ddd27d8e631..fd9560ea976 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2897,6 +2897,11 @@ sub process { ERROR("lockdep_no_validate class is reserved for device->mutex.\n" . $herecurr); } } + + if ($line =~ /debugfs_create_file.*S_IWUGO/ || + $line =~ /DEVICE_ATTR.*S_IWUGO/ ) { + WARN("Exporting world writable files is usually an error. Consider more restrictive permissions.\n" . $herecurr); + } } # If we have no input at all, then there is nothing to report on -- cgit v1.2.3-70-g09d2 From 3d130fd03e06672f7700e2cb694b29f9a98227ca Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 12 Jan 2011 17:00:00 -0800 Subject: checkpatch.pl: add "prefer __packed" check There's a __packed #define for __attribute__((packed)). Add a checkpatch to tell people about it. Signed-off-by: Joe Perches Cc: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'scripts') diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index fd9560ea976..4c0383da1c9 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2743,6 +2743,11 @@ sub process { WARN("plain inline is preferred over $1\n" . $herecurr); } +# Check for __attribute__ packed, prefer __packed + if ($line =~ /\b__attribute__\s*\(\s*\(.*\bpacked\b/) { + WARN("__packed is preferred over __attribute__((packed))\n" . $herecurr); + } + # check for sizeof(&) if ($line =~ /\bsizeof\s*\(\s*\&/) { WARN("sizeof(& should be avoided\n" . $herecurr); -- cgit v1.2.3-70-g09d2 From 24fa0402a9b6a537e87e38341e78b7da86486846 Mon Sep 17 00:00:00 2001 From: Lasse Collin Date: Wed, 12 Jan 2011 17:01:22 -0800 Subject: decompressors: add XZ decompressor module In userspace, the .lzma format has become mostly a legacy file format that got superseded by the .xz format. Similarly, LZMA Utils was superseded by XZ Utils. These patches add support for XZ decompression into the kernel. Most of the code is as is from XZ Embedded . It was written for the Linux kernel but is usable in other projects too. Advantages of XZ over the current LZMA code in the kernel: - Nice API that can be used by other kernel modules; it's not limited to kernel, initramfs, and initrd decompression. - Integrity check support (CRC32) - BCJ filters improve compression of executable code on certain architectures. These together with LZMA2 can produce a few percent smaller kernel or Squashfs images than plain LZMA without making the decompression slower. This patch: Add the main decompression code (xz_dec), testing module (xz_dec_test), wrapper script (xz_wrap.sh) for the xz command line tool, and documentation. The xz_dec module is enough to have a usable XZ decompressor e.g. for Squashfs. Signed-off-by: Lasse Collin Cc: "H. Peter Anvin" Cc: Alain Knaff Cc: Albin Tonnerre Cc: Phillip Lougher Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/xz.txt | 121 +++++ include/linux/xz.h | 264 +++++++++++ lib/Kconfig | 2 + lib/Makefile | 1 + lib/xz/Kconfig | 59 +++ lib/xz/Makefile | 5 + lib/xz/xz_crc32.c | 59 +++ lib/xz/xz_dec_bcj.c | 561 +++++++++++++++++++++++ lib/xz/xz_dec_lzma2.c | 1171 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/xz/xz_dec_stream.c | 821 +++++++++++++++++++++++++++++++++ lib/xz/xz_dec_syms.c | 26 ++ lib/xz/xz_dec_test.c | 220 +++++++++ lib/xz/xz_lzma2.h | 204 +++++++++ lib/xz/xz_private.h | 156 +++++++ lib/xz/xz_stream.h | 62 +++ scripts/Makefile.lib | 28 ++ scripts/xz_wrap.sh | 23 + 17 files changed, 3783 insertions(+) create mode 100644 Documentation/xz.txt create mode 100644 include/linux/xz.h create mode 100644 lib/xz/Kconfig create mode 100644 lib/xz/Makefile create mode 100644 lib/xz/xz_crc32.c create mode 100644 lib/xz/xz_dec_bcj.c create mode 100644 lib/xz/xz_dec_lzma2.c create mode 100644 lib/xz/xz_dec_stream.c create mode 100644 lib/xz/xz_dec_syms.c create mode 100644 lib/xz/xz_dec_test.c create mode 100644 lib/xz/xz_lzma2.h create mode 100644 lib/xz/xz_private.h create mode 100644 lib/xz/xz_stream.h create mode 100644 scripts/xz_wrap.sh (limited to 'scripts') diff --git a/Documentation/xz.txt b/Documentation/xz.txt new file mode 100644 index 00000000000..2cf3e2608de --- /dev/null +++ b/Documentation/xz.txt @@ -0,0 +1,121 @@ + +XZ data compression in Linux +============================ + +Introduction + + XZ is a general purpose data compression format with high compression + ratio and relatively fast decompression. The primary compression + algorithm (filter) is LZMA2. Additional filters can be used to improve + compression ratio even further. E.g. Branch/Call/Jump (BCJ) filters + improve compression ratio of executable data. + + The XZ decompressor in Linux is called XZ Embedded. It supports + the LZMA2 filter and optionally also BCJ filters. CRC32 is supported + for integrity checking. The home page of XZ Embedded is at + , where you can find the + latest version and also information about using the code outside + the Linux kernel. + + For userspace, XZ Utils provide a zlib-like compression library + and a gzip-like command line tool. XZ Utils can be downloaded from + . + +XZ related components in the kernel + + The xz_dec module provides XZ decompressor with single-call (buffer + to buffer) and multi-call (stateful) APIs. The usage of the xz_dec + module is documented in include/linux/xz.h. + + The xz_dec_test module is for testing xz_dec. xz_dec_test is not + useful unless you are hacking the XZ decompressor. xz_dec_test + allocates a char device major dynamically to which one can write + .xz files from userspace. The decompressed output is thrown away. + Keep an eye on dmesg to see diagnostics printed by xz_dec_test. + See the xz_dec_test source code for the details. + + For decompressing the kernel image, initramfs, and initrd, there + is a wrapper function in lib/decompress_unxz.c. Its API is the + same as in other decompress_*.c files, which is defined in + include/linux/decompress/generic.h. + + scripts/xz_wrap.sh is a wrapper for the xz command line tool found + from XZ Utils. The wrapper sets compression options to values suitable + for compressing the kernel image. + + For kernel makefiles, two commands are provided for use with + $(call if_needed). The kernel image should be compressed with + $(call if_needed,xzkern) which will use a BCJ filter and a big LZMA2 + dictionary. It will also append a four-byte trailer containing the + uncompressed size of the file, which is needed by the boot code. + Other things should be compressed with $(call if_needed,xzmisc) + which will use no BCJ filter and 1 MiB LZMA2 dictionary. + +Notes on compression options + + Since the XZ Embedded supports only streams with no integrity check or + CRC32, make sure that you don't use some other integrity check type + when encoding files that are supposed to be decoded by the kernel. With + liblzma, you need to use either LZMA_CHECK_NONE or LZMA_CHECK_CRC32 + when encoding. With the xz command line tool, use --check=none or + --check=crc32. + + Using CRC32 is strongly recommended unless there is some other layer + which will verify the integrity of the uncompressed data anyway. + Double checking the integrity would probably be waste of CPU cycles. + Note that the headers will always have a CRC32 which will be validated + by the decoder; you can only change the integrity check type (or + disable it) for the actual uncompressed data. + + In userspace, LZMA2 is typically used with dictionary sizes of several + megabytes. The decoder needs to have the dictionary in RAM, thus big + dictionaries cannot be used for files that are intended to be decoded + by the kernel. 1 MiB is probably the maximum reasonable dictionary + size for in-kernel use (maybe more is OK for initramfs). The presets + in XZ Utils may not be optimal when creating files for the kernel, + so don't hesitate to use custom settings. Example: + + xz --check=crc32 --lzma2=dict=512KiB inputfile + + An exception to above dictionary size limitation is when the decoder + is used in single-call mode. Decompressing the kernel itself is an + example of this situation. In single-call mode, the memory usage + doesn't depend on the dictionary size, and it is perfectly fine to + use a big dictionary: for maximum compression, the dictionary should + be at least as big as the uncompressed data itself. + +Future plans + + Creating a limited XZ encoder may be considered if people think it is + useful. LZMA2 is slower to compress than e.g. Deflate or LZO even at + the fastest settings, so it isn't clear if LZMA2 encoder is wanted + into the kernel. + + Support for limited random-access reading is planned for the + decompression code. I don't know if it could have any use in the + kernel, but I know that it would be useful in some embedded projects + outside the Linux kernel. + +Conformance to the .xz file format specification + + There are a couple of corner cases where things have been simplified + at expense of detecting errors as early as possible. These should not + matter in practice all, since they don't cause security issues. But + it is good to know this if testing the code e.g. with the test files + from XZ Utils. + +Reporting bugs + + Before reporting a bug, please check that it's not fixed already + at upstream. See to get the + latest code. + + Report bugs to or visit #tukaani on + Freenode and talk to Larhzu. I don't actively read LKML or other + kernel-related mailing lists, so if there's something I should know, + you should email to me personally or use IRC. + + Don't bother Igor Pavlov with questions about the XZ implementation + in the kernel or about XZ Utils. While these two implementations + include essential code that is directly based on Igor Pavlov's code, + these implementations aren't maintained nor supported by him. diff --git a/include/linux/xz.h b/include/linux/xz.h new file mode 100644 index 00000000000..64cffa6ddfc --- /dev/null +++ b/include/linux/xz.h @@ -0,0 +1,264 @@ +/* + * XZ decompressor + * + * Authors: Lasse Collin + * Igor Pavlov + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +#ifndef XZ_H +#define XZ_H + +#ifdef __KERNEL__ +# include +# include +#else +# include +# include +#endif + +/* In Linux, this is used to make extern functions static when needed. */ +#ifndef XZ_EXTERN +# define XZ_EXTERN extern +#endif + +/** + * enum xz_mode - Operation mode + * + * @XZ_SINGLE: Single-call mode. This uses less RAM than + * than multi-call modes, because the LZMA2 + * dictionary doesn't need to be allocated as + * part of the decoder state. All required data + * structures are allocated at initialization, + * so xz_dec_run() cannot return XZ_MEM_ERROR. + * @XZ_PREALLOC: Multi-call mode with preallocated LZMA2 + * dictionary buffer. All data structures are + * allocated at initialization, so xz_dec_run() + * cannot return XZ_MEM_ERROR. + * @XZ_DYNALLOC: Multi-call mode. The LZMA2 dictionary is + * allocated once the required size has been + * parsed from the stream headers. If the + * allocation fails, xz_dec_run() will return + * XZ_MEM_ERROR. + * + * It is possible to enable support only for a subset of the above + * modes at compile time by defining XZ_DEC_SINGLE, XZ_DEC_PREALLOC, + * or XZ_DEC_DYNALLOC. The xz_dec kernel module is always compiled + * with support for all operation modes, but the preboot code may + * be built with fewer features to minimize code size. + */ +enum xz_mode { + XZ_SINGLE, + XZ_PREALLOC, + XZ_DYNALLOC +}; + +/** + * enum xz_ret - Return codes + * @XZ_OK: Everything is OK so far. More input or more + * output space is required to continue. This + * return code is possible only in multi-call mode + * (XZ_PREALLOC or XZ_DYNALLOC). + * @XZ_STREAM_END: Operation finished successfully. + * @XZ_UNSUPPORTED_CHECK: Integrity check type is not supported. Decoding + * is still possible in multi-call mode by simply + * calling xz_dec_run() again. + * Note that this return value is used only if + * XZ_DEC_ANY_CHECK was defined at build time, + * which is not used in the kernel. Unsupported + * check types return XZ_OPTIONS_ERROR if + * XZ_DEC_ANY_CHECK was not defined at build time. + * @XZ_MEM_ERROR: Allocating memory failed. This return code is + * possible only if the decoder was initialized + * with XZ_DYNALLOC. The amount of memory that was + * tried to be allocated was no more than the + * dict_max argument given to xz_dec_init(). + * @XZ_MEMLIMIT_ERROR: A bigger LZMA2 dictionary would be needed than + * allowed by the dict_max argument given to + * xz_dec_init(). This return value is possible + * only in multi-call mode (XZ_PREALLOC or + * XZ_DYNALLOC); the single-call mode (XZ_SINGLE) + * ignores the dict_max argument. + * @XZ_FORMAT_ERROR: File format was not recognized (wrong magic + * bytes). + * @XZ_OPTIONS_ERROR: This implementation doesn't support the requested + * compression options. In the decoder this means + * that the header CRC32 matches, but the header + * itself specifies something that we don't support. + * @XZ_DATA_ERROR: Compressed data is corrupt. + * @XZ_BUF_ERROR: Cannot make any progress. Details are slightly + * different between multi-call and single-call + * mode; more information below. + * + * In multi-call mode, XZ_BUF_ERROR is returned when two consecutive calls + * to XZ code cannot consume any input and cannot produce any new output. + * This happens when there is no new input available, or the output buffer + * is full while at least one output byte is still pending. Assuming your + * code is not buggy, you can get this error only when decoding a compressed + * stream that is truncated or otherwise corrupt. + * + * In single-call mode, XZ_BUF_ERROR is returned only when the output buffer + * is too small or the compressed input is corrupt in a way that makes the + * decoder produce more output than the caller expected. When it is + * (relatively) clear that the compressed input is truncated, XZ_DATA_ERROR + * is used instead of XZ_BUF_ERROR. + */ +enum xz_ret { + XZ_OK, + XZ_STREAM_END, + XZ_UNSUPPORTED_CHECK, + XZ_MEM_ERROR, + XZ_MEMLIMIT_ERROR, + XZ_FORMAT_ERROR, + XZ_OPTIONS_ERROR, + XZ_DATA_ERROR, + XZ_BUF_ERROR +}; + +/** + * struct xz_buf - Passing input and output buffers to XZ code + * @in: Beginning of the input buffer. This may be NULL if and only + * if in_pos is equal to in_size. + * @in_pos: Current position in the input buffer. This must not exceed + * in_size. + * @in_size: Size of the input buffer + * @out: Beginning of the output buffer. This may be NULL if and only + * if out_pos is equal to out_size. + * @out_pos: Current position in the output buffer. This must not exceed + * out_size. + * @out_size: Size of the output buffer + * + * Only the contents of the output buffer from out[out_pos] onward, and + * the variables in_pos and out_pos are modified by the XZ code. + */ +struct xz_buf { + const uint8_t *in; + size_t in_pos; + size_t in_size; + + uint8_t *out; + size_t out_pos; + size_t out_size; +}; + +/** + * struct xz_dec - Opaque type to hold the XZ decoder state + */ +struct xz_dec; + +/** + * xz_dec_init() - Allocate and initialize a XZ decoder state + * @mode: Operation mode + * @dict_max: Maximum size of the LZMA2 dictionary (history buffer) for + * multi-call decoding. This is ignored in single-call mode + * (mode == XZ_SINGLE). LZMA2 dictionary is always 2^n bytes + * or 2^n + 2^(n-1) bytes (the latter sizes are less common + * in practice), so other values for dict_max don't make sense. + * In the kernel, dictionary sizes of 64 KiB, 128 KiB, 256 KiB, + * 512 KiB, and 1 MiB are probably the only reasonable values, + * except for kernel and initramfs images where a bigger + * dictionary can be fine and useful. + * + * Single-call mode (XZ_SINGLE): xz_dec_run() decodes the whole stream at + * once. The caller must provide enough output space or the decoding will + * fail. The output space is used as the dictionary buffer, which is why + * there is no need to allocate the dictionary as part of the decoder's + * internal state. + * + * Because the output buffer is used as the workspace, streams encoded using + * a big dictionary are not a problem in single-call mode. It is enough that + * the output buffer is big enough to hold the actual uncompressed data; it + * can be smaller than the dictionary size stored in the stream headers. + * + * Multi-call mode with preallocated dictionary (XZ_PREALLOC): dict_max bytes + * of memory is preallocated for the LZMA2 dictionary. This way there is no + * risk that xz_dec_run() could run out of memory, since xz_dec_run() will + * never allocate any memory. Instead, if the preallocated dictionary is too + * small for decoding the given input stream, xz_dec_run() will return + * XZ_MEMLIMIT_ERROR. Thus, it is important to know what kind of data will be + * decoded to avoid allocating excessive amount of memory for the dictionary. + * + * Multi-call mode with dynamically allocated dictionary (XZ_DYNALLOC): + * dict_max specifies the maximum allowed dictionary size that xz_dec_run() + * may allocate once it has parsed the dictionary size from the stream + * headers. This way excessive allocations can be avoided while still + * limiting the maximum memory usage to a sane value to prevent running the + * system out of memory when decompressing streams from untrusted sources. + * + * On success, xz_dec_init() returns a pointer to struct xz_dec, which is + * ready to be used with xz_dec_run(). If memory allocation fails, + * xz_dec_init() returns NULL. + */ +XZ_EXTERN struct xz_dec *xz_dec_init(enum xz_mode mode, uint32_t dict_max); + +/** + * xz_dec_run() - Run the XZ decoder + * @s: Decoder state allocated using xz_dec_init() + * @b: Input and output buffers + * + * The possible return values depend on build options and operation mode. + * See enum xz_ret for details. + * + * Note that if an error occurs in single-call mode (return value is not + * XZ_STREAM_END), b->in_pos and b->out_pos are not modified and the + * contents of the output buffer from b->out[b->out_pos] onward are + * undefined. This is true even after XZ_BUF_ERROR, because with some filter + * chains, there may be a second pass over the output buffer, and this pass + * cannot be properly done if the output buffer is truncated. Thus, you + * cannot give the single-call decoder a too small buffer and then expect to + * get that amount valid data from the beginning of the stream. You must use + * the multi-call decoder if you don't want to uncompress the whole stream. + */ +XZ_EXTERN enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b); + +/** + * xz_dec_reset() - Reset an already allocated decoder state + * @s: Decoder state allocated using xz_dec_init() + * + * This function can be used to reset the multi-call decoder state without + * freeing and reallocating memory with xz_dec_end() and xz_dec_init(). + * + * In single-call mode, xz_dec_reset() is always called in the beginning of + * xz_dec_run(). Thus, explicit call to xz_dec_reset() is useful only in + * multi-call mode. + */ +XZ_EXTERN void xz_dec_reset(struct xz_dec *s); + +/** + * xz_dec_end() - Free the memory allocated for the decoder state + * @s: Decoder state allocated using xz_dec_init(). If s is NULL, + * this function does nothing. + */ +XZ_EXTERN void xz_dec_end(struct xz_dec *s); + +/* + * Standalone build (userspace build or in-kernel build for boot time use) + * needs a CRC32 implementation. For normal in-kernel use, kernel's own + * CRC32 module is used instead, and users of this module don't need to + * care about the functions below. + */ +#ifndef XZ_INTERNAL_CRC32 +# ifdef __KERNEL__ +# define XZ_INTERNAL_CRC32 0 +# else +# define XZ_INTERNAL_CRC32 1 +# endif +#endif + +#if XZ_INTERNAL_CRC32 +/* + * This must be called before any other xz_* function to initialize + * the CRC32 lookup table. + */ +XZ_EXTERN void xz_crc32_init(void); + +/* + * Update CRC32 value using the polynomial from IEEE-802.3. To start a new + * calculation, the third argument must be zero. To continue the calculation, + * the previously returned value is passed as the third argument. + */ +XZ_EXTERN uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc); +#endif +#endif diff --git a/lib/Kconfig b/lib/Kconfig index 3116aa631af..2b8f8540d67 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -106,6 +106,8 @@ config LZO_COMPRESS config LZO_DECOMPRESS tristate +source "lib/xz/Kconfig" + # # These all provide a common interface (hence the apparent duplication with # ZLIB_INFLATE; DECOMPRESS_GZIP is just a wrapper.) diff --git a/lib/Makefile b/lib/Makefile index 2f59e0a1dd8..4df2d029772 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -69,6 +69,7 @@ obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/ obj-$(CONFIG_REED_SOLOMON) += reed_solomon/ obj-$(CONFIG_LZO_COMPRESS) += lzo/ obj-$(CONFIG_LZO_DECOMPRESS) += lzo/ +obj-$(CONFIG_XZ_DEC) += xz/ obj-$(CONFIG_RAID6_PQ) += raid6/ lib-$(CONFIG_DECOMPRESS_GZIP) += decompress_inflate.o diff --git a/lib/xz/Kconfig b/lib/xz/Kconfig new file mode 100644 index 00000000000..e3b6e18fdac --- /dev/null +++ b/lib/xz/Kconfig @@ -0,0 +1,59 @@ +config XZ_DEC + tristate "XZ decompression support" + select CRC32 + help + LZMA2 compression algorithm and BCJ filters are supported using + the .xz file format as the container. For integrity checking, + CRC32 is supported. See Documentation/xz.txt for more information. + +config XZ_DEC_X86 + bool "x86 BCJ filter decoder" if EMBEDDED + default y + depends on XZ_DEC + select XZ_DEC_BCJ + +config XZ_DEC_POWERPC + bool "PowerPC BCJ filter decoder" if EMBEDDED + default y + depends on XZ_DEC + select XZ_DEC_BCJ + +config XZ_DEC_IA64 + bool "IA-64 BCJ filter decoder" if EMBEDDED + default y + depends on XZ_DEC + select XZ_DEC_BCJ + +config XZ_DEC_ARM + bool "ARM BCJ filter decoder" if EMBEDDED + default y + depends on XZ_DEC + select XZ_DEC_BCJ + +config XZ_DEC_ARMTHUMB + bool "ARM-Thumb BCJ filter decoder" if EMBEDDED + default y + depends on XZ_DEC + select XZ_DEC_BCJ + +config XZ_DEC_SPARC + bool "SPARC BCJ filter decoder" if EMBEDDED + default y + depends on XZ_DEC + select XZ_DEC_BCJ + +config XZ_DEC_BCJ + bool + default n + +config XZ_DEC_TEST + tristate "XZ decompressor tester" + default n + depends on XZ_DEC + help + This allows passing .xz files to the in-kernel XZ decoder via + a character special file. It calculates CRC32 of the decompressed + data and writes diagnostics to the system log. + + Unless you are developing the XZ decoder, you don't need this + and should say N. diff --git a/lib/xz/Makefile b/lib/xz/Makefile new file mode 100644 index 00000000000..a7fa7693f0f --- /dev/null +++ b/lib/xz/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_XZ_DEC) += xz_dec.o +xz_dec-y := xz_dec_syms.o xz_dec_stream.o xz_dec_lzma2.o +xz_dec-$(CONFIG_XZ_DEC_BCJ) += xz_dec_bcj.o + +obj-$(CONFIG_XZ_DEC_TEST) += xz_dec_test.o diff --git a/lib/xz/xz_crc32.c b/lib/xz/xz_crc32.c new file mode 100644 index 00000000000..34532d14fd4 --- /dev/null +++ b/lib/xz/xz_crc32.c @@ -0,0 +1,59 @@ +/* + * CRC32 using the polynomial from IEEE-802.3 + * + * Authors: Lasse Collin + * Igor Pavlov + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +/* + * This is not the fastest implementation, but it is pretty compact. + * The fastest versions of xz_crc32() on modern CPUs without hardware + * accelerated CRC instruction are 3-5 times as fast as this version, + * but they are bigger and use more memory for the lookup table. + */ + +#include "xz_private.h" + +/* + * STATIC_RW_DATA is used in the pre-boot environment on some architectures. + * See for details. + */ +#ifndef STATIC_RW_DATA +# define STATIC_RW_DATA static +#endif + +STATIC_RW_DATA uint32_t xz_crc32_table[256]; + +XZ_EXTERN void xz_crc32_init(void) +{ + const uint32_t poly = 0xEDB88320; + + uint32_t i; + uint32_t j; + uint32_t r; + + for (i = 0; i < 256; ++i) { + r = i; + for (j = 0; j < 8; ++j) + r = (r >> 1) ^ (poly & ~((r & 1) - 1)); + + xz_crc32_table[i] = r; + } + + return; +} + +XZ_EXTERN uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc) +{ + crc = ~crc; + + while (size != 0) { + crc = xz_crc32_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8); + --size; + } + + return ~crc; +} diff --git a/lib/xz/xz_dec_bcj.c b/lib/xz/xz_dec_bcj.c new file mode 100644 index 00000000000..e51e2558ca9 --- /dev/null +++ b/lib/xz/xz_dec_bcj.c @@ -0,0 +1,561 @@ +/* + * Branch/Call/Jump (BCJ) filter decoders + * + * Authors: Lasse Collin + * Igor Pavlov + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +#include "xz_private.h" + +/* + * The rest of the file is inside this ifdef. It makes things a little more + * convenient when building without support for any BCJ filters. + */ +#ifdef XZ_DEC_BCJ + +struct xz_dec_bcj { + /* Type of the BCJ filter being used */ + enum { + BCJ_X86 = 4, /* x86 or x86-64 */ + BCJ_POWERPC = 5, /* Big endian only */ + BCJ_IA64 = 6, /* Big or little endian */ + BCJ_ARM = 7, /* Little endian only */ + BCJ_ARMTHUMB = 8, /* Little endian only */ + BCJ_SPARC = 9 /* Big or little endian */ + } type; + + /* + * Return value of the next filter in the chain. We need to preserve + * this information across calls, because we must not call the next + * filter anymore once it has returned XZ_STREAM_END. + */ + enum xz_ret ret; + + /* True if we are operating in single-call mode. */ + bool single_call; + + /* + * Absolute position relative to the beginning of the uncompressed + * data (in a single .xz Block). We care only about the lowest 32 + * bits so this doesn't need to be uint64_t even with big files. + */ + uint32_t pos; + + /* x86 filter state */ + uint32_t x86_prev_mask; + + /* Temporary space to hold the variables from struct xz_buf */ + uint8_t *out; + size_t out_pos; + size_t out_size; + + struct { + /* Amount of already filtered data in the beginning of buf */ + size_t filtered; + + /* Total amount of data currently stored in buf */ + size_t size; + + /* + * Buffer to hold a mix of filtered and unfiltered data. This + * needs to be big enough to hold Alignment + 2 * Look-ahead: + * + * Type Alignment Look-ahead + * x86 1 4 + * PowerPC 4 0 + * IA-64 16 0 + * ARM 4 0 + * ARM-Thumb 2 2 + * SPARC 4 0 + */ + uint8_t buf[16]; + } temp; +}; + +#ifdef XZ_DEC_X86 +/* + * This is used to test the most significant byte of a memory address + * in an x86 instruction. + */ +static inline int bcj_x86_test_msbyte(uint8_t b) +{ + return b == 0x00 || b == 0xFF; +} + +static size_t bcj_x86(struct xz_dec_bcj *s, uint8_t *buf, size_t size) +{ + static const bool mask_to_allowed_status[8] + = { true, true, true, false, true, false, false, false }; + + static const uint8_t mask_to_bit_num[8] = { 0, 1, 2, 2, 3, 3, 3, 3 }; + + size_t i; + size_t prev_pos = (size_t)-1; + uint32_t prev_mask = s->x86_prev_mask; + uint32_t src; + uint32_t dest; + uint32_t j; + uint8_t b; + + if (size <= 4) + return 0; + + size -= 4; + for (i = 0; i < size; ++i) { + if ((buf[i] & 0xFE) != 0xE8) + continue; + + prev_pos = i - prev_pos; + if (prev_pos > 3) { + prev_mask = 0; + } else { + prev_mask = (prev_mask << (prev_pos - 1)) & 7; + if (prev_mask != 0) { + b = buf[i + 4 - mask_to_bit_num[prev_mask]]; + if (!mask_to_allowed_status[prev_mask] + || bcj_x86_test_msbyte(b)) { + prev_pos = i; + prev_mask = (prev_mask << 1) | 1; + continue; + } + } + } + + prev_pos = i; + + if (bcj_x86_test_msbyte(buf[i + 4])) { + src = get_unaligned_le32(buf + i + 1); + while (true) { + dest = src - (s->pos + (uint32_t)i + 5); + if (prev_mask == 0) + break; + + j = mask_to_bit_num[prev_mask] * 8; + b = (uint8_t)(dest >> (24 - j)); + if (!bcj_x86_test_msbyte(b)) + break; + + src = dest ^ (((uint32_t)1 << (32 - j)) - 1); + } + + dest &= 0x01FFFFFF; + dest |= (uint32_t)0 - (dest & 0x01000000); + put_unaligned_le32(dest, buf + i + 1); + i += 4; + } else { + prev_mask = (prev_mask << 1) | 1; + } + } + + prev_pos = i - prev_pos; + s->x86_prev_mask = prev_pos > 3 ? 0 : prev_mask << (prev_pos - 1); + return i; +} +#endif + +#ifdef XZ_DEC_POWERPC +static size_t bcj_powerpc(struct xz_dec_bcj *s, uint8_t *buf, size_t size) +{ + size_t i; + uint32_t instr; + + for (i = 0; i + 4 <= size; i += 4) { + instr = get_unaligned_be32(buf + i); + if ((instr & 0xFC000003) == 0x48000001) { + instr &= 0x03FFFFFC; + instr -= s->pos + (uint32_t)i; + instr &= 0x03FFFFFC; + instr |= 0x48000001; + put_unaligned_be32(instr, buf + i); + } + } + + return i; +} +#endif + +#ifdef XZ_DEC_IA64 +static size_t bcj_ia64(struct xz_dec_bcj *s, uint8_t *buf, size_t size) +{ + static const uint8_t branch_table[32] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 6, 6, 0, 0, 7, 7, + 4, 4, 0, 0, 4, 4, 0, 0 + }; + + /* + * The local variables take a little bit stack space, but it's less + * than what LZMA2 decoder takes, so it doesn't make sense to reduce + * stack usage here without doing that for the LZMA2 decoder too. + */ + + /* Loop counters */ + size_t i; + size_t j; + + /* Instruction slot (0, 1, or 2) in the 128-bit instruction word */ + uint32_t slot; + + /* Bitwise offset of the instruction indicated by slot */ + uint32_t bit_pos; + + /* bit_pos split into byte and bit parts */ + uint32_t byte_pos; + uint32_t bit_res; + + /* Address part of an instruction */ + uint32_t addr; + + /* Mask used to detect which instructions to convert */ + uint32_t mask; + + /* 41-bit instruction stored somewhere in the lowest 48 bits */ + uint64_t instr; + + /* Instruction normalized with bit_res for easier manipulation */ + uint64_t norm; + + for (i = 0; i + 16 <= size; i += 16) { + mask = branch_table[buf[i] & 0x1F]; + for (slot = 0, bit_pos = 5; slot < 3; ++slot, bit_pos += 41) { + if (((mask >> slot) & 1) == 0) + continue; + + byte_pos = bit_pos >> 3; + bit_res = bit_pos & 7; + instr = 0; + for (j = 0; j < 6; ++j) + instr |= (uint64_t)(buf[i + j + byte_pos]) + << (8 * j); + + norm = instr >> bit_res; + + if (((norm >> 37) & 0x0F) == 0x05 + && ((norm >> 9) & 0x07) == 0) { + addr = (norm >> 13) & 0x0FFFFF; + addr |= ((uint32_t)(norm >> 36) & 1) << 20; + addr <<= 4; + addr -= s->pos + (uint32_t)i; + addr >>= 4; + + norm &= ~((uint64_t)0x8FFFFF << 13); + norm |= (uint64_t)(addr & 0x0FFFFF) << 13; + norm |= (uint64_t)(addr & 0x100000) + << (36 - 20); + + instr &= (1 << bit_res) - 1; + instr |= norm << bit_res; + + for (j = 0; j < 6; j++) + buf[i + j + byte_pos] + = (uint8_t)(instr >> (8 * j)); + } + } + } + + return i; +} +#endif + +#ifdef XZ_DEC_ARM +static size_t bcj_arm(struct xz_dec_bcj *s, uint8_t *buf, size_t size) +{ + size_t i; + uint32_t addr; + + for (i = 0; i + 4 <= size; i += 4) { + if (buf[i + 3] == 0xEB) { + addr = (uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8) + | ((uint32_t)buf[i + 2] << 16); + addr <<= 2; + addr -= s->pos + (uint32_t)i + 8; + addr >>= 2; + buf[i] = (uint8_t)addr; + buf[i + 1] = (uint8_t)(addr >> 8); + buf[i + 2] = (uint8_t)(addr >> 16); + } + } + + return i; +} +#endif + +#ifdef XZ_DEC_ARMTHUMB +static size_t bcj_armthumb(struct xz_dec_bcj *s, uint8_t *buf, size_t size) +{ + size_t i; + uint32_t addr; + + for (i = 0; i + 4 <= size; i += 2) { + if ((buf[i + 1] & 0xF8) == 0xF0 + && (buf[i + 3] & 0xF8) == 0xF8) { + addr = (((uint32_t)buf[i + 1] & 0x07) << 19) + | ((uint32_t)buf[i] << 11) + | (((uint32_t)buf[i + 3] & 0x07) << 8) + | (uint32_t)buf[i + 2]; + addr <<= 1; + addr -= s->pos + (uint32_t)i + 4; + addr >>= 1; + buf[i + 1] = (uint8_t)(0xF0 | ((addr >> 19) & 0x07)); + buf[i] = (uint8_t)(addr >> 11); + buf[i + 3] = (uint8_t)(0xF8 | ((addr >> 8) & 0x07)); + buf[i + 2] = (uint8_t)addr; + i += 2; + } + } + + return i; +} +#endif + +#ifdef XZ_DEC_SPARC +static size_t bcj_sparc(struct xz_dec_bcj *s, uint8_t *buf, size_t size) +{ + size_t i; + uint32_t instr; + + for (i = 0; i + 4 <= size; i += 4) { + instr = get_unaligned_be32(buf + i); + if ((instr >> 22) == 0x100 || (instr >> 22) == 0x1FF) { + instr <<= 2; + instr -= s->pos + (uint32_t)i; + instr >>= 2; + instr = ((uint32_t)0x40000000 - (instr & 0x400000)) + | 0x40000000 | (instr & 0x3FFFFF); + put_unaligned_be32(instr, buf + i); + } + } + + return i; +} +#endif + +/* + * Apply the selected BCJ filter. Update *pos and s->pos to match the amount + * of data that got filtered. + * + * NOTE: This is implemented as a switch statement to avoid using function + * pointers, which could be problematic in the kernel boot code, which must + * avoid pointers to static data (at least on x86). + */ +static void bcj_apply(struct xz_dec_bcj *s, + uint8_t *buf, size_t *pos, size_t size) +{ + size_t filtered; + + buf += *pos; + size -= *pos; + + switch (s->type) { +#ifdef XZ_DEC_X86 + case BCJ_X86: + filtered = bcj_x86(s, buf, size); + break; +#endif +#ifdef XZ_DEC_POWERPC + case BCJ_POWERPC: + filtered = bcj_powerpc(s, buf, size); + break; +#endif +#ifdef XZ_DEC_IA64 + case BCJ_IA64: + filtered = bcj_ia64(s, buf, size); + break; +#endif +#ifdef XZ_DEC_ARM + case BCJ_ARM: + filtered = bcj_arm(s, buf, size); + break; +#endif +#ifdef XZ_DEC_ARMTHUMB + case BCJ_ARMTHUMB: + filtered = bcj_armthumb(s, buf, size); + break; +#endif +#ifdef XZ_DEC_SPARC + case BCJ_SPARC: + filtered = bcj_sparc(s, buf, size); + break; +#endif + default: + /* Never reached but silence compiler warnings. */ + filtered = 0; + break; + } + + *pos += filtered; + s->pos += filtered; +} + +/* + * Flush pending filtered data from temp to the output buffer. + * Move the remaining mixture of possibly filtered and unfiltered + * data to the beginning of temp. + */ +static void bcj_flush(struct xz_dec_bcj *s, struct xz_buf *b) +{ + size_t copy_size; + + copy_size = min_t(size_t, s->temp.filtered, b->out_size - b->out_pos); + memcpy(b->out + b->out_pos, s->temp.buf, copy_size); + b->out_pos += copy_size; + + s->temp.filtered -= copy_size; + s->temp.size -= copy_size; + memmove(s->temp.buf, s->temp.buf + copy_size, s->temp.size); +} + +/* + * The BCJ filter functions are primitive in sense that they process the + * data in chunks of 1-16 bytes. To hide this issue, this function does + * some buffering. + */ +XZ_EXTERN enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s, + struct xz_dec_lzma2 *lzma2, + struct xz_buf *b) +{ + size_t out_start; + + /* + * Flush pending already filtered data to the output buffer. Return + * immediatelly if we couldn't flush everything, or if the next + * filter in the chain had already returned XZ_STREAM_END. + */ + if (s->temp.filtered > 0) { + bcj_flush(s, b); + if (s->temp.filtered > 0) + return XZ_OK; + + if (s->ret == XZ_STREAM_END) + return XZ_STREAM_END; + } + + /* + * If we have more output space than what is currently pending in + * temp, copy the unfiltered data from temp to the output buffer + * and try to fill the output buffer by decoding more data from the + * next filter in the chain. Apply the BCJ filter on the new data + * in the output buffer. If everything cannot be filtered, copy it + * to temp and rewind the output buffer position accordingly. + */ + if (s->temp.size < b->out_size - b->out_pos) { + out_start = b->out_pos; + memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size); + b->out_pos += s->temp.size; + + s->ret = xz_dec_lzma2_run(lzma2, b); + if (s->ret != XZ_STREAM_END + && (s->ret != XZ_OK || s->single_call)) + return s->ret; + + bcj_apply(s, b->out, &out_start, b->out_pos); + + /* + * As an exception, if the next filter returned XZ_STREAM_END, + * we can do that too, since the last few bytes that remain + * unfiltered are meant to remain unfiltered. + */ + if (s->ret == XZ_STREAM_END) + return XZ_STREAM_END; + + s->temp.size = b->out_pos - out_start; + b->out_pos -= s->temp.size; + memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size); + } + + /* + * If we have unfiltered data in temp, try to fill by decoding more + * data from the next filter. Apply the BCJ filter on temp. Then we + * hopefully can fill the actual output buffer by copying filtered + * data from temp. A mix of filtered and unfiltered data may be left + * in temp; it will be taken care on the next call to this function. + */ + if (s->temp.size > 0) { + /* Make b->out{,_pos,_size} temporarily point to s->temp. */ + s->out = b->out; + s->out_pos = b->out_pos; + s->out_size = b->out_size; + b->out = s->temp.buf; + b->out_pos = s->temp.size; + b->out_size = sizeof(s->temp.buf); + + s->ret = xz_dec_lzma2_run(lzma2, b); + + s->temp.size = b->out_pos; + b->out = s->out; + b->out_pos = s->out_pos; + b->out_size = s->out_size; + + if (s->ret != XZ_OK && s->ret != XZ_STREAM_END) + return s->ret; + + bcj_apply(s, s->temp.buf, &s->temp.filtered, s->temp.size); + + /* + * If the next filter returned XZ_STREAM_END, we mark that + * everything is filtered, since the last unfiltered bytes + * of the stream are meant to be left as is. + */ + if (s->ret == XZ_STREAM_END) + s->temp.filtered = s->temp.size; + + bcj_flush(s, b); + if (s->temp.filtered > 0) + return XZ_OK; + } + + return s->ret; +} + +XZ_EXTERN struct xz_dec_bcj *xz_dec_bcj_create(bool single_call) +{ + struct xz_dec_bcj *s = kmalloc(sizeof(*s), GFP_KERNEL); + if (s != NULL) + s->single_call = single_call; + + return s; +} + +XZ_EXTERN enum xz_ret xz_dec_bcj_reset(struct xz_dec_bcj *s, uint8_t id) +{ + switch (id) { +#ifdef XZ_DEC_X86 + case BCJ_X86: +#endif +#ifdef XZ_DEC_POWERPC + case BCJ_POWERPC: +#endif +#ifdef XZ_DEC_IA64 + case BCJ_IA64: +#endif +#ifdef XZ_DEC_ARM + case BCJ_ARM: +#endif +#ifdef XZ_DEC_ARMTHUMB + case BCJ_ARMTHUMB: +#endif +#ifdef XZ_DEC_SPARC + case BCJ_SPARC: +#endif + break; + + default: + /* Unsupported Filter ID */ + return XZ_OPTIONS_ERROR; + } + + s->type = id; + s->ret = XZ_OK; + s->pos = 0; + s->x86_prev_mask = 0; + s->temp.filtered = 0; + s->temp.size = 0; + + return XZ_OK; +} + +#endif diff --git a/lib/xz/xz_dec_lzma2.c b/lib/xz/xz_dec_lzma2.c new file mode 100644 index 00000000000..ea5fa4fe9d6 --- /dev/null +++ b/lib/xz/xz_dec_lzma2.c @@ -0,0 +1,1171 @@ +/* + * LZMA2 decoder + * + * Authors: Lasse Collin + * Igor Pavlov + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +#include "xz_private.h" +#include "xz_lzma2.h" + +/* + * Range decoder initialization eats the first five bytes of each LZMA chunk. + */ +#define RC_INIT_BYTES 5 + +/* + * Minimum number of usable input buffer to safely decode one LZMA symbol. + * The worst case is that we decode 22 bits using probabilities and 26 + * direct bits. This may decode at maximum of 20 bytes of input. However, + * lzma_main() does an extra normalization before returning, thus we + * need to put 21 here. + */ +#define LZMA_IN_REQUIRED 21 + +/* + * Dictionary (history buffer) + * + * These are always true: + * start <= pos <= full <= end + * pos <= limit <= end + * + * In multi-call mode, also these are true: + * end == size + * size <= size_max + * allocated <= size + * + * Most of these variables are size_t to support single-call mode, + * in which the dictionary variables address the actual output + * buffer directly. + */ +struct dictionary { + /* Beginning of the history buffer */ + uint8_t *buf; + + /* Old position in buf (before decoding more data) */ + size_t start; + + /* Position in buf */ + size_t pos; + + /* + * How full dictionary is. This is used to detect corrupt input that + * would read beyond the beginning of the uncompressed stream. + */ + size_t full; + + /* Write limit; we don't write to buf[limit] or later bytes. */ + size_t limit; + + /* + * End of the dictionary buffer. In multi-call mode, this is + * the same as the dictionary size. In single-call mode, this + * indicates the size of the output buffer. + */ + size_t end; + + /* + * Size of the dictionary as specified in Block Header. This is used + * together with "full" to detect corrupt input that would make us + * read beyond the beginning of the uncompressed stream. + */ + uint32_t size; + + /* + * Maximum allowed dictionary size in multi-call mode. + * This is ignored in single-call mode. + */ + uint32_t size_max; + + /* + * Amount of memory currently allocated for the dictionary. + * This is used only with XZ_DYNALLOC. (With XZ_PREALLOC, + * size_max is always the same as the allocated size.) + */ + uint32_t allocated; + + /* Operation mode */ + enum xz_mode mode; +}; + +/* Range decoder */ +struct rc_dec { + uint32_t range; + uint32_t code; + + /* + * Number of initializing bytes remaining to be read + * by rc_read_init(). + */ + uint32_t init_bytes_left; + + /* + * Buffer from which we read our input. It can be either + * temp.buf or the caller-provided input buffer. + */ + const uint8_t *in; + size_t in_pos; + size_t in_limit; +}; + +/* Probabilities for a length decoder. */ +struct lzma_len_dec { + /* Probability of match length being at least 10 */ + uint16_t choice; + + /* Probability of match length being at least 18 */ + uint16_t choice2; + + /* Probabilities for match lengths 2-9 */ + uint16_t low[POS_STATES_MAX][LEN_LOW_SYMBOLS]; + + /* Probabilities for match lengths 10-17 */ + uint16_t mid[POS_STATES_MAX][LEN_MID_SYMBOLS]; + + /* Probabilities for match lengths 18-273 */ + uint16_t high[LEN_HIGH_SYMBOLS]; +}; + +struct lzma_dec { + /* Distances of latest four matches */ + uint32_t rep0; + uint32_t rep1; + uint32_t rep2; + uint32_t rep3; + + /* Types of the most recently seen LZMA symbols */ + enum lzma_state state; + + /* + * Length of a match. This is updated so that dict_repeat can + * be called again to finish repeating the whole match. + */ + uint32_t len; + + /* + * LZMA properties or related bit masks (number of literal + * context bits, a mask dervied from the number of literal + * position bits, and a mask dervied from the number + * position bits) + */ + uint32_t lc; + uint32_t literal_pos_mask; /* (1 << lp) - 1 */ + uint32_t pos_mask; /* (1 << pb) - 1 */ + + /* If 1, it's a match. Otherwise it's a single 8-bit literal. */ + uint16_t is_match[STATES][POS_STATES_MAX]; + + /* If 1, it's a repeated match. The distance is one of rep0 .. rep3. */ + uint16_t is_rep[STATES]; + + /* + * If 0, distance of a repeated match is rep0. + * Otherwise check is_rep1. + */ + uint16_t is_rep0[STATES]; + + /* + * If 0, distance of a repeated match is rep1. + * Otherwise check is_rep2. + */ + uint16_t is_rep1[STATES]; + + /* If 0, distance of a repeated match is rep2. Otherwise it is rep3. */ + uint16_t is_rep2[STATES]; + + /* + * If 1, the repeated match has length of one byte. Otherwise + * the length is decoded from rep_len_decoder. + */ + uint16_t is_rep0_long[STATES][POS_STATES_MAX]; + + /* + * Probability tree for the highest two bits of the match + * distance. There is a separate probability tree for match + * lengths of 2 (i.e. MATCH_LEN_MIN), 3, 4, and [5, 273]. + */ + uint16_t dist_slot[DIST_STATES][DIST_SLOTS]; + + /* + * Probility trees for additional bits for match distance + * when the distance is in the range [4, 127]. + */ + uint16_t dist_special[FULL_DISTANCES - DIST_MODEL_END]; + + /* + * Probability tree for the lowest four bits of a match + * distance that is equal to or greater than 128. + */ + uint16_t dist_align[ALIGN_SIZE]; + + /* Length of a normal match */ + struct lzma_len_dec match_len_dec; + + /* Length of a repeated match */ + struct lzma_len_dec rep_len_dec; + + /* Probabilities of literals */ + uint16_t literal[LITERAL_CODERS_MAX][LITERAL_CODER_SIZE]; +}; + +struct lzma2_dec { + /* Position in xz_dec_lzma2_run(). */ + enum lzma2_seq { + SEQ_CONTROL, + SEQ_UNCOMPRESSED_1, + SEQ_UNCOMPRESSED_2, + SEQ_COMPRESSED_0, + SEQ_COMPRESSED_1, + SEQ_PROPERTIES, + SEQ_LZMA_PREPARE, + SEQ_LZMA_RUN, + SEQ_COPY + } sequence; + + /* Next position after decoding the compressed size of the chunk. */ + enum lzma2_seq next_sequence; + + /* Uncompressed size of LZMA chunk (2 MiB at maximum) */ + uint32_t uncompressed; + + /* + * Compressed size of LZMA chunk or compressed/uncompressed + * size of uncompressed chunk (64 KiB at maximum) + */ + uint32_t compressed; + + /* + * True if dictionary reset is needed. This is false before + * the first chunk (LZMA or uncompressed). + */ + bool need_dict_reset; + + /* + * True if new LZMA properties are needed. This is false + * before the first LZMA chunk. + */ + bool need_props; +}; + +struct xz_dec_lzma2 { + /* + * The order below is important on x86 to reduce code size and + * it shouldn't hurt on other platforms. Everything up to and + * including lzma.pos_mask are in the first 128 bytes on x86-32, + * which allows using smaller instructions to access those + * variables. On x86-64, fewer variables fit into the first 128 + * bytes, but this is still the best order without sacrificing + * the readability by splitting the structures. + */ + struct rc_dec rc; + struct dictionary dict; + struct lzma2_dec lzma2; + struct lzma_dec lzma; + + /* + * Temporary buffer which holds small number of input bytes between + * decoder calls. See lzma2_lzma() for details. + */ + struct { + uint32_t size; + uint8_t buf[3 * LZMA_IN_REQUIRED]; + } temp; +}; + +/************** + * Dictionary * + **************/ + +/* + * Reset the dictionary state. When in single-call mode, set up the beginning + * of the dictionary to point to the actual output buffer. + */ +static void dict_reset(struct dictionary *dict, struct xz_buf *b) +{ + if (DEC_IS_SINGLE(dict->mode)) { + dict->buf = b->out + b->out_pos; + dict->end = b->out_size - b->out_pos; + } + + dict->start = 0; + dict->pos = 0; + dict->limit = 0; + dict->full = 0; +} + +/* Set dictionary write limit */ +static void dict_limit(struct dictionary *dict, size_t out_max) +{ + if (dict->end - dict->pos <= out_max) + dict->limit = dict->end; + else + dict->limit = dict->pos + out_max; +} + +/* Return true if at least one byte can be written into the dictionary. */ +static inline bool dict_has_space(const struct dictionary *dict) +{ + return dict->pos < dict->limit; +} + +/* + * Get a byte from the dictionary at the given distance. The distance is + * assumed to valid, or as a special case, zero when the dictionary is + * still empty. This special case is needed for single-call decoding to + * avoid writing a '\0' to the end of the destination buffer. + */ +static inline uint32_t dict_get(const struct dictionary *dict, uint32_t dist) +{ + size_t offset = dict->pos - dist - 1; + + if (dist >= dict->pos) + offset += dict->end; + + return dict->full > 0 ? dict->buf[offset] : 0; +} + +/* + * Put one byte into the dictionary. It is assumed that there is space for it. + */ +static inline void dict_put(struct dictionary *dict, uint8_t byte) +{ + dict->buf[dict->pos++] = byte; + + if (dict->full < dict->pos) + dict->full = dict->pos; +} + +/* + * Repeat given number of bytes from the given distance. If the distance is + * invalid, false is returned. On success, true is returned and *len is + * updated to indicate how many bytes were left to be repeated. + */ +static bool dict_repeat(struct dictionary *dict, uint32_t *len, uint32_t dist) +{ + size_t back; + uint32_t left; + + if (dist >= dict->full || dist >= dict->size) + return false; + + left = min_t(size_t, dict->limit - dict->pos, *len); + *len -= left; + + back = dict->pos - dist - 1; + if (dist >= dict->pos) + back += dict->end; + + do { + dict->buf[dict->pos++] = dict->buf[back++]; + if (back == dict->end) + back = 0; + } while (--left > 0); + + if (dict->full < dict->pos) + dict->full = dict->pos; + + return true; +} + +/* Copy uncompressed data as is from input to dictionary and output buffers. */ +static void dict_uncompressed(struct dictionary *dict, struct xz_buf *b, + uint32_t *left) +{ + size_t copy_size; + + while (*left > 0 && b->in_pos < b->in_size + && b->out_pos < b->out_size) { + copy_size = min(b->in_size - b->in_pos, + b->out_size - b->out_pos); + if (copy_size > dict->end - dict->pos) + copy_size = dict->end - dict->pos; + if (copy_size > *left) + copy_size = *left; + + *left -= copy_size; + + memcpy(dict->buf + dict->pos, b->in + b->in_pos, copy_size); + dict->pos += copy_size; + + if (dict->full < dict->pos) + dict->full = dict->pos; + + if (DEC_IS_MULTI(dict->mode)) { + if (dict->pos == dict->end) + dict->pos = 0; + + memcpy(b->out + b->out_pos, b->in + b->in_pos, + copy_size); + } + + dict->start = dict->pos; + + b->out_pos += copy_size; + b->in_pos += copy_size; + } +} + +/* + * Flush pending data from dictionary to b->out. It is assumed that there is + * enough space in b->out. This is guaranteed because caller uses dict_limit() + * before decoding data into the dictionary. + */ +static uint32_t dict_flush(struct dictionary *dict, struct xz_buf *b) +{ + size_t copy_size = dict->pos - dict->start; + + if (DEC_IS_MULTI(dict->mode)) { + if (dict->pos == dict->end) + dict->pos = 0; + + memcpy(b->out + b->out_pos, dict->buf + dict->start, + copy_size); + } + + dict->start = dict->pos; + b->out_pos += copy_size; + return copy_size; +} + +/***************** + * Range decoder * + *****************/ + +/* Reset the range decoder. */ +static void rc_reset(struct rc_dec *rc) +{ + rc->range = (uint32_t)-1; + rc->code = 0; + rc->init_bytes_left = RC_INIT_BYTES; +} + +/* + * Read the first five initial bytes into rc->code if they haven't been + * read already. (Yes, the first byte gets completely ignored.) + */ +static bool rc_read_init(struct rc_dec *rc, struct xz_buf *b) +{ + while (rc->init_bytes_left > 0) { + if (b->in_pos == b->in_size) + return false; + + rc->code = (rc->code << 8) + b->in[b->in_pos++]; + --rc->init_bytes_left; + } + + return true; +} + +/* Return true if there may not be enough input for the next decoding loop. */ +static inline bool rc_limit_exceeded(const struct rc_dec *rc) +{ + return rc->in_pos > rc->in_limit; +} + +/* + * Return true if it is possible (from point of view of range decoder) that + * we have reached the end of the LZMA chunk. + */ +static inline bool rc_is_finished(const struct rc_dec *rc) +{ + return rc->code == 0; +} + +/* Read the next input byte if needed. */ +static __always_inline void rc_normalize(struct rc_dec *rc) +{ + if (rc->range < RC_TOP_VALUE) { + rc->range <<= RC_SHIFT_BITS; + rc->code = (rc->code << RC_SHIFT_BITS) + rc->in[rc->in_pos++]; + } +} + +/* + * Decode one bit. In some versions, this function has been splitted in three + * functions so that the compiler is supposed to be able to more easily avoid + * an extra branch. In this particular version of the LZMA decoder, this + * doesn't seem to be a good idea (tested with GCC 3.3.6, 3.4.6, and 4.3.3 + * on x86). Using a non-splitted version results in nicer looking code too. + * + * NOTE: This must return an int. Do not make it return a bool or the speed + * of the code generated by GCC 3.x decreases 10-15 %. (GCC 4.3 doesn't care, + * and it generates 10-20 % faster code than GCC 3.x from this file anyway.) + */ +static __always_inline int rc_bit(struct rc_dec *rc, uint16_t *prob) +{ + uint32_t bound; + int bit; + + rc_normalize(rc); + bound = (rc->range >> RC_BIT_MODEL_TOTAL_BITS) * *prob; + if (rc->code < bound) { + rc->range = bound; + *prob += (RC_BIT_MODEL_TOTAL - *prob) >> RC_MOVE_BITS; + bit = 0; + } else { + rc->range -= bound; + rc->code -= bound; + *prob -= *prob >> RC_MOVE_BITS; + bit = 1; + } + + return bit; +} + +/* Decode a bittree starting from the most significant bit. */ +static __always_inline uint32_t rc_bittree(struct rc_dec *rc, + uint16_t *probs, uint32_t limit) +{ + uint32_t symbol = 1; + + do { + if (rc_bit(rc, &probs[symbol])) + symbol = (symbol << 1) + 1; + else + symbol <<= 1; + } while (symbol < limit); + + return symbol; +} + +/* Decode a bittree starting from the least significant bit. */ +static __always_inline void rc_bittree_reverse(struct rc_dec *rc, + uint16_t *probs, + uint32_t *dest, uint32_t limit) +{ + uint32_t symbol = 1; + uint32_t i = 0; + + do { + if (rc_bit(rc, &probs[symbol])) { + symbol = (symbol << 1) + 1; + *dest += 1 << i; + } else { + symbol <<= 1; + } + } while (++i < limit); +} + +/* Decode direct bits (fixed fifty-fifty probability) */ +static inline void rc_direct(struct rc_dec *rc, uint32_t *dest, uint32_t limit) +{ + uint32_t mask; + + do { + rc_normalize(rc); + rc->range >>= 1; + rc->code -= rc->range; + mask = (uint32_t)0 - (rc->code >> 31); + rc->code += rc->range & mask; + *dest = (*dest << 1) + (mask + 1); + } while (--limit > 0); +} + +/******** + * LZMA * + ********/ + +/* Get pointer to literal coder probability array. */ +static uint16_t *lzma_literal_probs(struct xz_dec_lzma2 *s) +{ + uint32_t prev_byte = dict_get(&s->dict, 0); + uint32_t low = prev_byte >> (8 - s->lzma.lc); + uint32_t high = (s->dict.pos & s->lzma.literal_pos_mask) << s->lzma.lc; + return s->lzma.literal[low + high]; +} + +/* Decode a literal (one 8-bit byte) */ +static void lzma_literal(struct xz_dec_lzma2 *s) +{ + uint16_t *probs; + uint32_t symbol; + uint32_t match_byte; + uint32_t match_bit; + uint32_t offset; + uint32_t i; + + probs = lzma_literal_probs(s); + + if (lzma_state_is_literal(s->lzma.state)) { + symbol = rc_bittree(&s->rc, probs, 0x100); + } else { + symbol = 1; + match_byte = dict_get(&s->dict, s->lzma.rep0) << 1; + offset = 0x100; + + do { + match_bit = match_byte & offset; + match_byte <<= 1; + i = offset + match_bit + symbol; + + if (rc_bit(&s->rc, &probs[i])) { + symbol = (symbol << 1) + 1; + offset &= match_bit; + } else { + symbol <<= 1; + offset &= ~match_bit; + } + } while (symbol < 0x100); + } + + dict_put(&s->dict, (uint8_t)symbol); + lzma_state_literal(&s->lzma.state); +} + +/* Decode the length of the match into s->lzma.len. */ +static void lzma_len(struct xz_dec_lzma2 *s, struct lzma_len_dec *l, + uint32_t pos_state) +{ + uint16_t *probs; + uint32_t limit; + + if (!rc_bit(&s->rc, &l->choice)) { + probs = l->low[pos_state]; + limit = LEN_LOW_SYMBOLS; + s->lzma.len = MATCH_LEN_MIN; + } else { + if (!rc_bit(&s->rc, &l->choice2)) { + probs = l->mid[pos_state]; + limit = LEN_MID_SYMBOLS; + s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS; + } else { + probs = l->high; + limit = LEN_HIGH_SYMBOLS; + s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS + + LEN_MID_SYMBOLS; + } + } + + s->lzma.len += rc_bittree(&s->rc, probs, limit) - limit; +} + +/* Decode a match. The distance will be stored in s->lzma.rep0. */ +static void lzma_match(struct xz_dec_lzma2 *s, uint32_t pos_state) +{ + uint16_t *probs; + uint32_t dist_slot; + uint32_t limit; + + lzma_state_match(&s->lzma.state); + + s->lzma.rep3 = s->lzma.rep2; + s->lzma.rep2 = s->lzma.rep1; + s->lzma.rep1 = s->lzma.rep0; + + lzma_len(s, &s->lzma.match_len_dec, pos_state); + + probs = s->lzma.dist_slot[lzma_get_dist_state(s->lzma.len)]; + dist_slot = rc_bittree(&s->rc, probs, DIST_SLOTS) - DIST_SLOTS; + + if (dist_slot < DIST_MODEL_START) { + s->lzma.rep0 = dist_slot; + } else { + limit = (dist_slot >> 1) - 1; + s->lzma.rep0 = 2 + (dist_slot & 1); + + if (dist_slot < DIST_MODEL_END) { + s->lzma.rep0 <<= limit; + probs = s->lzma.dist_special + s->lzma.rep0 + - dist_slot - 1; + rc_bittree_reverse(&s->rc, probs, + &s->lzma.rep0, limit); + } else { + rc_direct(&s->rc, &s->lzma.rep0, limit - ALIGN_BITS); + s->lzma.rep0 <<= ALIGN_BITS; + rc_bittree_reverse(&s->rc, s->lzma.dist_align, + &s->lzma.rep0, ALIGN_BITS); + } + } +} + +/* + * Decode a repeated match. The distance is one of the four most recently + * seen matches. The distance will be stored in s->lzma.rep0. + */ +static void lzma_rep_match(struct xz_dec_lzma2 *s, uint32_t pos_state) +{ + uint32_t tmp; + + if (!rc_bit(&s->rc, &s->lzma.is_rep0[s->lzma.state])) { + if (!rc_bit(&s->rc, &s->lzma.is_rep0_long[ + s->lzma.state][pos_state])) { + lzma_state_short_rep(&s->lzma.state); + s->lzma.len = 1; + return; + } + } else { + if (!rc_bit(&s->rc, &s->lzma.is_rep1[s->lzma.state])) { + tmp = s->lzma.rep1; + } else { + if (!rc_bit(&s->rc, &s->lzma.is_rep2[s->lzma.state])) { + tmp = s->lzma.rep2; + } else { + tmp = s->lzma.rep3; + s->lzma.rep3 = s->lzma.rep2; + } + + s->lzma.rep2 = s->lzma.rep1; + } + + s->lzma.rep1 = s->lzma.rep0; + s->lzma.rep0 = tmp; + } + + lzma_state_long_rep(&s->lzma.state); + lzma_len(s, &s->lzma.rep_len_dec, pos_state); +} + +/* LZMA decoder core */ +static bool lzma_main(struct xz_dec_lzma2 *s) +{ + uint32_t pos_state; + + /* + * If the dictionary was reached during the previous call, try to + * finish the possibly pending repeat in the dictionary. + */ + if (dict_has_space(&s->dict) && s->lzma.len > 0) + dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0); + + /* + * Decode more LZMA symbols. One iteration may consume up to + * LZMA_IN_REQUIRED - 1 bytes. + */ + while (dict_has_space(&s->dict) && !rc_limit_exceeded(&s->rc)) { + pos_state = s->dict.pos & s->lzma.pos_mask; + + if (!rc_bit(&s->rc, &s->lzma.is_match[ + s->lzma.state][pos_state])) { + lzma_literal(s); + } else { + if (rc_bit(&s->rc, &s->lzma.is_rep[s->lzma.state])) + lzma_rep_match(s, pos_state); + else + lzma_match(s, pos_state); + + if (!dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0)) + return false; + } + } + + /* + * Having the range decoder always normalized when we are outside + * this function makes it easier to correctly handle end of the chunk. + */ + rc_normalize(&s->rc); + + return true; +} + +/* + * Reset the LZMA decoder and range decoder state. Dictionary is nore reset + * here, because LZMA state may be reset without resetting the dictionary. + */ +static void lzma_reset(struct xz_dec_lzma2 *s) +{ + uint16_t *probs; + size_t i; + + s->lzma.state = STATE_LIT_LIT; + s->lzma.rep0 = 0; + s->lzma.rep1 = 0; + s->lzma.rep2 = 0; + s->lzma.rep3 = 0; + + /* + * All probabilities are initialized to the same value. This hack + * makes the code smaller by avoiding a separate loop for each + * probability array. + * + * This could be optimized so that only that part of literal + * probabilities that are actually required. In the common case + * we would write 12 KiB less. + */ + probs = s->lzma.is_match[0]; + for (i = 0; i < PROBS_TOTAL; ++i) + probs[i] = RC_BIT_MODEL_TOTAL / 2; + + rc_reset(&s->rc); +} + +/* + * Decode and validate LZMA properties (lc/lp/pb) and calculate the bit masks + * from the decoded lp and pb values. On success, the LZMA decoder state is + * reset and true is returned. + */ +static bool lzma_props(struct xz_dec_lzma2 *s, uint8_t props) +{ + if (props > (4 * 5 + 4) * 9 + 8) + return false; + + s->lzma.pos_mask = 0; + while (props >= 9 * 5) { + props -= 9 * 5; + ++s->lzma.pos_mask; + } + + s->lzma.pos_mask = (1 << s->lzma.pos_mask) - 1; + + s->lzma.literal_pos_mask = 0; + while (props >= 9) { + props -= 9; + ++s->lzma.literal_pos_mask; + } + + s->lzma.lc = props; + + if (s->lzma.lc + s->lzma.literal_pos_mask > 4) + return false; + + s->lzma.literal_pos_mask = (1 << s->lzma.literal_pos_mask) - 1; + + lzma_reset(s); + + return true; +} + +/********* + * LZMA2 * + *********/ + +/* + * The LZMA decoder assumes that if the input limit (s->rc.in_limit) hasn't + * been exceeded, it is safe to read up to LZMA_IN_REQUIRED bytes. This + * wrapper function takes care of making the LZMA decoder's assumption safe. + * + * As long as there is plenty of input left to be decoded in the current LZMA + * chunk, we decode directly from the caller-supplied input buffer until + * there's LZMA_IN_REQUIRED bytes left. Those remaining bytes are copied into + * s->temp.buf, which (hopefully) gets filled on the next call to this + * function. We decode a few bytes from the temporary buffer so that we can + * continue decoding from the caller-supplied input buffer again. + */ +static bool lzma2_lzma(struct xz_dec_lzma2 *s, struct xz_buf *b) +{ + size_t in_avail; + uint32_t tmp; + + in_avail = b->in_size - b->in_pos; + if (s->temp.size > 0 || s->lzma2.compressed == 0) { + tmp = 2 * LZMA_IN_REQUIRED - s->temp.size; + if (tmp > s->lzma2.compressed - s->temp.size) + tmp = s->lzma2.compressed - s->temp.size; + if (tmp > in_avail) + tmp = in_avail; + + memcpy(s->temp.buf + s->temp.size, b->in + b->in_pos, tmp); + + if (s->temp.size + tmp == s->lzma2.compressed) { + memzero(s->temp.buf + s->temp.size + tmp, + sizeof(s->temp.buf) + - s->temp.size - tmp); + s->rc.in_limit = s->temp.size + tmp; + } else if (s->temp.size + tmp < LZMA_IN_REQUIRED) { + s->temp.size += tmp; + b->in_pos += tmp; + return true; + } else { + s->rc.in_limit = s->temp.size + tmp - LZMA_IN_REQUIRED; + } + + s->rc.in = s->temp.buf; + s->rc.in_pos = 0; + + if (!lzma_main(s) || s->rc.in_pos > s->temp.size + tmp) + return false; + + s->lzma2.compressed -= s->rc.in_pos; + + if (s->rc.in_pos < s->temp.size) { + s->temp.size -= s->rc.in_pos; + memmove(s->temp.buf, s->temp.buf + s->rc.in_pos, + s->temp.size); + return true; + } + + b->in_pos += s->rc.in_pos - s->temp.size; + s->temp.size = 0; + } + + in_avail = b->in_size - b->in_pos; + if (in_avail >= LZMA_IN_REQUIRED) { + s->rc.in = b->in; + s->rc.in_pos = b->in_pos; + + if (in_avail >= s->lzma2.compressed + LZMA_IN_REQUIRED) + s->rc.in_limit = b->in_pos + s->lzma2.compressed; + else + s->rc.in_limit = b->in_size - LZMA_IN_REQUIRED; + + if (!lzma_main(s)) + return false; + + in_avail = s->rc.in_pos - b->in_pos; + if (in_avail > s->lzma2.compressed) + return false; + + s->lzma2.compressed -= in_avail; + b->in_pos = s->rc.in_pos; + } + + in_avail = b->in_size - b->in_pos; + if (in_avail < LZMA_IN_REQUIRED) { + if (in_avail > s->lzma2.compressed) + in_avail = s->lzma2.compressed; + + memcpy(s->temp.buf, b->in + b->in_pos, in_avail); + s->temp.size = in_avail; + b->in_pos += in_avail; + } + + return true; +} + +/* + * Take care of the LZMA2 control layer, and forward the job of actual LZMA + * decoding or copying of uncompressed chunks to other functions. + */ +XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s, + struct xz_buf *b) +{ + uint32_t tmp; + + while (b->in_pos < b->in_size || s->lzma2.sequence == SEQ_LZMA_RUN) { + switch (s->lzma2.sequence) { + case SEQ_CONTROL: + /* + * LZMA2 control byte + * + * Exact values: + * 0x00 End marker + * 0x01 Dictionary reset followed by + * an uncompressed chunk + * 0x02 Uncompressed chunk (no dictionary reset) + * + * Highest three bits (s->control & 0xE0): + * 0xE0 Dictionary reset, new properties and state + * reset, followed by LZMA compressed chunk + * 0xC0 New properties and state reset, followed + * by LZMA compressed chunk (no dictionary + * reset) + * 0xA0 State reset using old properties, + * followed by LZMA compressed chunk (no + * dictionary reset) + * 0x80 LZMA chunk (no dictionary or state reset) + * + * For LZMA compressed chunks, the lowest five bits + * (s->control & 1F) are the highest bits of the + * uncompressed size (bits 16-20). + * + * A new LZMA2 stream must begin with a dictionary + * reset. The first LZMA chunk must set new + * properties and reset the LZMA state. + * + * Values that don't match anything described above + * are invalid and we return XZ_DATA_ERROR. + */ + tmp = b->in[b->in_pos++]; + + if (tmp >= 0xE0 || tmp == 0x01) { + s->lzma2.need_props = true; + s->lzma2.need_dict_reset = false; + dict_reset(&s->dict, b); + } else if (s->lzma2.need_dict_reset) { + return XZ_DATA_ERROR; + } + + if (tmp >= 0x80) { + s->lzma2.uncompressed = (tmp & 0x1F) << 16; + s->lzma2.sequence = SEQ_UNCOMPRESSED_1; + + if (tmp >= 0xC0) { + /* + * When there are new properties, + * state reset is done at + * SEQ_PROPERTIES. + */ + s->lzma2.need_props = false; + s->lzma2.next_sequence + = SEQ_PROPERTIES; + + } else if (s->lzma2.need_props) { + return XZ_DATA_ERROR; + + } else { + s->lzma2.next_sequence + = SEQ_LZMA_PREPARE; + if (tmp >= 0xA0) + lzma_reset(s); + } + } else { + if (tmp == 0x00) + return XZ_STREAM_END; + + if (tmp > 0x02) + return XZ_DATA_ERROR; + + s->lzma2.sequence = SEQ_COMPRESSED_0; + s->lzma2.next_sequence = SEQ_COPY; + } + + break; + + case SEQ_UNCOMPRESSED_1: + s->lzma2.uncompressed + += (uint32_t)b->in[b->in_pos++] << 8; + s->lzma2.sequence = SEQ_UNCOMPRESSED_2; + break; + + case SEQ_UNCOMPRESSED_2: + s->lzma2.uncompressed + += (uint32_t)b->in[b->in_pos++] + 1; + s->lzma2.sequence = SEQ_COMPRESSED_0; + break; + + case SEQ_COMPRESSED_0: + s->lzma2.compressed + = (uint32_t)b->in[b->in_pos++] << 8; + s->lzma2.sequence = SEQ_COMPRESSED_1; + break; + + case SEQ_COMPRESSED_1: + s->lzma2.compressed + += (uint32_t)b->in[b->in_pos++] + 1; + s->lzma2.sequence = s->lzma2.next_sequence; + break; + + case SEQ_PROPERTIES: + if (!lzma_props(s, b->in[b->in_pos++])) + return XZ_DATA_ERROR; + + s->lzma2.sequence = SEQ_LZMA_PREPARE; + + case SEQ_LZMA_PREPARE: + if (s->lzma2.compressed < RC_INIT_BYTES) + return XZ_DATA_ERROR; + + if (!rc_read_init(&s->rc, b)) + return XZ_OK; + + s->lzma2.compressed -= RC_INIT_BYTES; + s->lzma2.sequence = SEQ_LZMA_RUN; + + case SEQ_LZMA_RUN: + /* + * Set dictionary limit to indicate how much we want + * to be encoded at maximum. Decode new data into the + * dictionary. Flush the new data from dictionary to + * b->out. Check if we finished decoding this chunk. + * In case the dictionary got full but we didn't fill + * the output buffer yet, we may run this loop + * multiple times without changing s->lzma2.sequence. + */ + dict_limit(&s->dict, min_t(size_t, + b->out_size - b->out_pos, + s->lzma2.uncompressed)); + if (!lzma2_lzma(s, b)) + return XZ_DATA_ERROR; + + s->lzma2.uncompressed -= dict_flush(&s->dict, b); + + if (s->lzma2.uncompressed == 0) { + if (s->lzma2.compressed > 0 || s->lzma.len > 0 + || !rc_is_finished(&s->rc)) + return XZ_DATA_ERROR; + + rc_reset(&s->rc); + s->lzma2.sequence = SEQ_CONTROL; + + } else if (b->out_pos == b->out_size + || (b->in_pos == b->in_size + && s->temp.size + < s->lzma2.compressed)) { + return XZ_OK; + } + + break; + + case SEQ_COPY: + dict_uncompressed(&s->dict, b, &s->lzma2.compressed); + if (s->lzma2.compressed > 0) + return XZ_OK; + + s->lzma2.sequence = SEQ_CONTROL; + break; + } + } + + return XZ_OK; +} + +XZ_EXTERN struct xz_dec_lzma2 *xz_dec_lzma2_create(enum xz_mode mode, + uint32_t dict_max) +{ + struct xz_dec_lzma2 *s = kmalloc(sizeof(*s), GFP_KERNEL); + if (s == NULL) + return NULL; + + s->dict.mode = mode; + s->dict.size_max = dict_max; + + if (DEC_IS_PREALLOC(mode)) { + s->dict.buf = vmalloc(dict_max); + if (s->dict.buf == NULL) { + kfree(s); + return NULL; + } + } else if (DEC_IS_DYNALLOC(mode)) { + s->dict.buf = NULL; + s->dict.allocated = 0; + } + + return s; +} + +XZ_EXTERN enum xz_ret xz_dec_lzma2_reset(struct xz_dec_lzma2 *s, uint8_t props) +{ + /* This limits dictionary size to 3 GiB to keep parsing simpler. */ + if (props > 39) + return XZ_OPTIONS_ERROR; + + s->dict.size = 2 + (props & 1); + s->dict.size <<= (props >> 1) + 11; + + if (DEC_IS_MULTI(s->dict.mode)) { + if (s->dict.size > s->dict.size_max) + return XZ_MEMLIMIT_ERROR; + + s->dict.end = s->dict.size; + + if (DEC_IS_DYNALLOC(s->dict.mode)) { + if (s->dict.allocated < s->dict.size) { + vfree(s->dict.buf); + s->dict.buf = vmalloc(s->dict.size); + if (s->dict.buf == NULL) { + s->dict.allocated = 0; + return XZ_MEM_ERROR; + } + } + } + } + + s->lzma.len = 0; + + s->lzma2.sequence = SEQ_CONTROL; + s->lzma2.need_dict_reset = true; + + s->temp.size = 0; + + return XZ_OK; +} + +XZ_EXTERN void xz_dec_lzma2_end(struct xz_dec_lzma2 *s) +{ + if (DEC_IS_MULTI(s->dict.mode)) + vfree(s->dict.buf); + + kfree(s); +} diff --git a/lib/xz/xz_dec_stream.c b/lib/xz/xz_dec_stream.c new file mode 100644 index 00000000000..ac809b1e64f --- /dev/null +++ b/lib/xz/xz_dec_stream.c @@ -0,0 +1,821 @@ +/* + * .xz Stream decoder + * + * Author: Lasse Collin + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +#include "xz_private.h" +#include "xz_stream.h" + +/* Hash used to validate the Index field */ +struct xz_dec_hash { + vli_type unpadded; + vli_type uncompressed; + uint32_t crc32; +}; + +struct xz_dec { + /* Position in dec_main() */ + enum { + SEQ_STREAM_HEADER, + SEQ_BLOCK_START, + SEQ_BLOCK_HEADER, + SEQ_BLOCK_UNCOMPRESS, + SEQ_BLOCK_PADDING, + SEQ_BLOCK_CHECK, + SEQ_INDEX, + SEQ_INDEX_PADDING, + SEQ_INDEX_CRC32, + SEQ_STREAM_FOOTER + } sequence; + + /* Position in variable-length integers and Check fields */ + uint32_t pos; + + /* Variable-length integer decoded by dec_vli() */ + vli_type vli; + + /* Saved in_pos and out_pos */ + size_t in_start; + size_t out_start; + + /* CRC32 value in Block or Index */ + uint32_t crc32; + + /* Type of the integrity check calculated from uncompressed data */ + enum xz_check check_type; + + /* Operation mode */ + enum xz_mode mode; + + /* + * True if the next call to xz_dec_run() is allowed to return + * XZ_BUF_ERROR. + */ + bool allow_buf_error; + + /* Information stored in Block Header */ + struct { + /* + * Value stored in the Compressed Size field, or + * VLI_UNKNOWN if Compressed Size is not present. + */ + vli_type compressed; + + /* + * Value stored in the Uncompressed Size field, or + * VLI_UNKNOWN if Uncompressed Size is not present. + */ + vli_type uncompressed; + + /* Size of the Block Header field */ + uint32_t size; + } block_header; + + /* Information collected when decoding Blocks */ + struct { + /* Observed compressed size of the current Block */ + vli_type compressed; + + /* Observed uncompressed size of the current Block */ + vli_type uncompressed; + + /* Number of Blocks decoded so far */ + vli_type count; + + /* + * Hash calculated from the Block sizes. This is used to + * validate the Index field. + */ + struct xz_dec_hash hash; + } block; + + /* Variables needed when verifying the Index field */ + struct { + /* Position in dec_index() */ + enum { + SEQ_INDEX_COUNT, + SEQ_INDEX_UNPADDED, + SEQ_INDEX_UNCOMPRESSED + } sequence; + + /* Size of the Index in bytes */ + vli_type size; + + /* Number of Records (matches block.count in valid files) */ + vli_type count; + + /* + * Hash calculated from the Records (matches block.hash in + * valid files). + */ + struct xz_dec_hash hash; + } index; + + /* + * Temporary buffer needed to hold Stream Header, Block Header, + * and Stream Footer. The Block Header is the biggest (1 KiB) + * so we reserve space according to that. buf[] has to be aligned + * to a multiple of four bytes; the size_t variables before it + * should guarantee this. + */ + struct { + size_t pos; + size_t size; + uint8_t buf[1024]; + } temp; + + struct xz_dec_lzma2 *lzma2; + +#ifdef XZ_DEC_BCJ + struct xz_dec_bcj *bcj; + bool bcj_active; +#endif +}; + +#ifdef XZ_DEC_ANY_CHECK +/* Sizes of the Check field with different Check IDs */ +static const uint8_t check_sizes[16] = { + 0, + 4, 4, 4, + 8, 8, 8, + 16, 16, 16, + 32, 32, 32, + 64, 64, 64 +}; +#endif + +/* + * Fill s->temp by copying data starting from b->in[b->in_pos]. Caller + * must have set s->temp.pos to indicate how much data we are supposed + * to copy into s->temp.buf. Return true once s->temp.pos has reached + * s->temp.size. + */ +static bool fill_temp(struct xz_dec *s, struct xz_buf *b) +{ + size_t copy_size = min_t(size_t, + b->in_size - b->in_pos, s->temp.size - s->temp.pos); + + memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size); + b->in_pos += copy_size; + s->temp.pos += copy_size; + + if (s->temp.pos == s->temp.size) { + s->temp.pos = 0; + return true; + } + + return false; +} + +/* Decode a variable-length integer (little-endian base-128 encoding) */ +static enum xz_ret dec_vli(struct xz_dec *s, const uint8_t *in, + size_t *in_pos, size_t in_size) +{ + uint8_t byte; + + if (s->pos == 0) + s->vli = 0; + + while (*in_pos < in_size) { + byte = in[*in_pos]; + ++*in_pos; + + s->vli |= (vli_type)(byte & 0x7F) << s->pos; + + if ((byte & 0x80) == 0) { + /* Don't allow non-minimal encodings. */ + if (byte == 0 && s->pos != 0) + return XZ_DATA_ERROR; + + s->pos = 0; + return XZ_STREAM_END; + } + + s->pos += 7; + if (s->pos == 7 * VLI_BYTES_MAX) + return XZ_DATA_ERROR; + } + + return XZ_OK; +} + +/* + * Decode the Compressed Data field from a Block. Update and validate + * the observed compressed and uncompressed sizes of the Block so that + * they don't exceed the values possibly stored in the Block Header + * (validation assumes that no integer overflow occurs, since vli_type + * is normally uint64_t). Update the CRC32 if presence of the CRC32 + * field was indicated in Stream Header. + * + * Once the decoding is finished, validate that the observed sizes match + * the sizes possibly stored in the Block Header. Update the hash and + * Block count, which are later used to validate the Index field. + */ +static enum xz_ret dec_block(struct xz_dec *s, struct xz_buf *b) +{ + enum xz_ret ret; + + s->in_start = b->in_pos; + s->out_start = b->out_pos; + +#ifdef XZ_DEC_BCJ + if (s->bcj_active) + ret = xz_dec_bcj_run(s->bcj, s->lzma2, b); + else +#endif + ret = xz_dec_lzma2_run(s->lzma2, b); + + s->block.compressed += b->in_pos - s->in_start; + s->block.uncompressed += b->out_pos - s->out_start; + + /* + * There is no need to separately check for VLI_UNKNOWN, since + * the observed sizes are always smaller than VLI_UNKNOWN. + */ + if (s->block.compressed > s->block_header.compressed + || s->block.uncompressed + > s->block_header.uncompressed) + return XZ_DATA_ERROR; + + if (s->check_type == XZ_CHECK_CRC32) + s->crc32 = xz_crc32(b->out + s->out_start, + b->out_pos - s->out_start, s->crc32); + + if (ret == XZ_STREAM_END) { + if (s->block_header.compressed != VLI_UNKNOWN + && s->block_header.compressed + != s->block.compressed) + return XZ_DATA_ERROR; + + if (s->block_header.uncompressed != VLI_UNKNOWN + && s->block_header.uncompressed + != s->block.uncompressed) + return XZ_DATA_ERROR; + + s->block.hash.unpadded += s->block_header.size + + s->block.compressed; + +#ifdef XZ_DEC_ANY_CHECK + s->block.hash.unpadded += check_sizes[s->check_type]; +#else + if (s->check_type == XZ_CHECK_CRC32) + s->block.hash.unpadded += 4; +#endif + + s->block.hash.uncompressed += s->block.uncompressed; + s->block.hash.crc32 = xz_crc32( + (const uint8_t *)&s->block.hash, + sizeof(s->block.hash), s->block.hash.crc32); + + ++s->block.count; + } + + return ret; +} + +/* Update the Index size and the CRC32 value. */ +static void index_update(struct xz_dec *s, const struct xz_buf *b) +{ + size_t in_used = b->in_pos - s->in_start; + s->index.size += in_used; + s->crc32 = xz_crc32(b->in + s->in_start, in_used, s->crc32); +} + +/* + * Decode the Number of Records, Unpadded Size, and Uncompressed Size + * fields from the Index field. That is, Index Padding and CRC32 are not + * decoded by this function. + * + * This can return XZ_OK (more input needed), XZ_STREAM_END (everything + * successfully decoded), or XZ_DATA_ERROR (input is corrupt). + */ +static enum xz_ret dec_index(struct xz_dec *s, struct xz_buf *b) +{ + enum xz_ret ret; + + do { + ret = dec_vli(s, b->in, &b->in_pos, b->in_size); + if (ret != XZ_STREAM_END) { + index_update(s, b); + return ret; + } + + switch (s->index.sequence) { + case SEQ_INDEX_COUNT: + s->index.count = s->vli; + + /* + * Validate that the Number of Records field + * indicates the same number of Records as + * there were Blocks in the Stream. + */ + if (s->index.count != s->block.count) + return XZ_DATA_ERROR; + + s->index.sequence = SEQ_INDEX_UNPADDED; + break; + + case SEQ_INDEX_UNPADDED: + s->index.hash.unpadded += s->vli; + s->index.sequence = SEQ_INDEX_UNCOMPRESSED; + break; + + case SEQ_INDEX_UNCOMPRESSED: + s->index.hash.uncompressed += s->vli; + s->index.hash.crc32 = xz_crc32( + (const uint8_t *)&s->index.hash, + sizeof(s->index.hash), + s->index.hash.crc32); + --s->index.count; + s->index.sequence = SEQ_INDEX_UNPADDED; + break; + } + } while (s->index.count > 0); + + return XZ_STREAM_END; +} + +/* + * Validate that the next four input bytes match the value of s->crc32. + * s->pos must be zero when starting to validate the first byte. + */ +static enum xz_ret crc32_validate(struct xz_dec *s, struct xz_buf *b) +{ + do { + if (b->in_pos == b->in_size) + return XZ_OK; + + if (((s->crc32 >> s->pos) & 0xFF) != b->in[b->in_pos++]) + return XZ_DATA_ERROR; + + s->pos += 8; + + } while (s->pos < 32); + + s->crc32 = 0; + s->pos = 0; + + return XZ_STREAM_END; +} + +#ifdef XZ_DEC_ANY_CHECK +/* + * Skip over the Check field when the Check ID is not supported. + * Returns true once the whole Check field has been skipped over. + */ +static bool check_skip(struct xz_dec *s, struct xz_buf *b) +{ + while (s->pos < check_sizes[s->check_type]) { + if (b->in_pos == b->in_size) + return false; + + ++b->in_pos; + ++s->pos; + } + + s->pos = 0; + + return true; +} +#endif + +/* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */ +static enum xz_ret dec_stream_header(struct xz_dec *s) +{ + if (!memeq(s->temp.buf, HEADER_MAGIC, HEADER_MAGIC_SIZE)) + return XZ_FORMAT_ERROR; + + if (xz_crc32(s->temp.buf + HEADER_MAGIC_SIZE, 2, 0) + != get_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2)) + return XZ_DATA_ERROR; + + if (s->temp.buf[HEADER_MAGIC_SIZE] != 0) + return XZ_OPTIONS_ERROR; + + /* + * Of integrity checks, we support only none (Check ID = 0) and + * CRC32 (Check ID = 1). However, if XZ_DEC_ANY_CHECK is defined, + * we will accept other check types too, but then the check won't + * be verified and a warning (XZ_UNSUPPORTED_CHECK) will be given. + */ + s->check_type = s->temp.buf[HEADER_MAGIC_SIZE + 1]; + +#ifdef XZ_DEC_ANY_CHECK + if (s->check_type > XZ_CHECK_MAX) + return XZ_OPTIONS_ERROR; + + if (s->check_type > XZ_CHECK_CRC32) + return XZ_UNSUPPORTED_CHECK; +#else + if (s->check_type > XZ_CHECK_CRC32) + return XZ_OPTIONS_ERROR; +#endif + + return XZ_OK; +} + +/* Decode the Stream Footer field (the last 12 bytes of the .xz Stream) */ +static enum xz_ret dec_stream_footer(struct xz_dec *s) +{ + if (!memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE)) + return XZ_DATA_ERROR; + + if (xz_crc32(s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf)) + return XZ_DATA_ERROR; + + /* + * Validate Backward Size. Note that we never added the size of the + * Index CRC32 field to s->index.size, thus we use s->index.size / 4 + * instead of s->index.size / 4 - 1. + */ + if ((s->index.size >> 2) != get_le32(s->temp.buf + 4)) + return XZ_DATA_ERROR; + + if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->check_type) + return XZ_DATA_ERROR; + + /* + * Use XZ_STREAM_END instead of XZ_OK to be more convenient + * for the caller. + */ + return XZ_STREAM_END; +} + +/* Decode the Block Header and initialize the filter chain. */ +static enum xz_ret dec_block_header(struct xz_dec *s) +{ + enum xz_ret ret; + + /* + * Validate the CRC32. We know that the temp buffer is at least + * eight bytes so this is safe. + */ + s->temp.size -= 4; + if (xz_crc32(s->temp.buf, s->temp.size, 0) + != get_le32(s->temp.buf + s->temp.size)) + return XZ_DATA_ERROR; + + s->temp.pos = 2; + + /* + * Catch unsupported Block Flags. We support only one or two filters + * in the chain, so we catch that with the same test. + */ +#ifdef XZ_DEC_BCJ + if (s->temp.buf[1] & 0x3E) +#else + if (s->temp.buf[1] & 0x3F) +#endif + return XZ_OPTIONS_ERROR; + + /* Compressed Size */ + if (s->temp.buf[1] & 0x40) { + if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size) + != XZ_STREAM_END) + return XZ_DATA_ERROR; + + s->block_header.compressed = s->vli; + } else { + s->block_header.compressed = VLI_UNKNOWN; + } + + /* Uncompressed Size */ + if (s->temp.buf[1] & 0x80) { + if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size) + != XZ_STREAM_END) + return XZ_DATA_ERROR; + + s->block_header.uncompressed = s->vli; + } else { + s->block_header.uncompressed = VLI_UNKNOWN; + } + +#ifdef XZ_DEC_BCJ + /* If there are two filters, the first one must be a BCJ filter. */ + s->bcj_active = s->temp.buf[1] & 0x01; + if (s->bcj_active) { + if (s->temp.size - s->temp.pos < 2) + return XZ_OPTIONS_ERROR; + + ret = xz_dec_bcj_reset(s->bcj, s->temp.buf[s->temp.pos++]); + if (ret != XZ_OK) + return ret; + + /* + * We don't support custom start offset, + * so Size of Properties must be zero. + */ + if (s->temp.buf[s->temp.pos++] != 0x00) + return XZ_OPTIONS_ERROR; + } +#endif + + /* Valid Filter Flags always take at least two bytes. */ + if (s->temp.size - s->temp.pos < 2) + return XZ_DATA_ERROR; + + /* Filter ID = LZMA2 */ + if (s->temp.buf[s->temp.pos++] != 0x21) + return XZ_OPTIONS_ERROR; + + /* Size of Properties = 1-byte Filter Properties */ + if (s->temp.buf[s->temp.pos++] != 0x01) + return XZ_OPTIONS_ERROR; + + /* Filter Properties contains LZMA2 dictionary size. */ + if (s->temp.size - s->temp.pos < 1) + return XZ_DATA_ERROR; + + ret = xz_dec_lzma2_reset(s->lzma2, s->temp.buf[s->temp.pos++]); + if (ret != XZ_OK) + return ret; + + /* The rest must be Header Padding. */ + while (s->temp.pos < s->temp.size) + if (s->temp.buf[s->temp.pos++] != 0x00) + return XZ_OPTIONS_ERROR; + + s->temp.pos = 0; + s->block.compressed = 0; + s->block.uncompressed = 0; + + return XZ_OK; +} + +static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b) +{ + enum xz_ret ret; + + /* + * Store the start position for the case when we are in the middle + * of the Index field. + */ + s->in_start = b->in_pos; + + while (true) { + switch (s->sequence) { + case SEQ_STREAM_HEADER: + /* + * Stream Header is copied to s->temp, and then + * decoded from there. This way if the caller + * gives us only little input at a time, we can + * still keep the Stream Header decoding code + * simple. Similar approach is used in many places + * in this file. + */ + if (!fill_temp(s, b)) + return XZ_OK; + + /* + * If dec_stream_header() returns + * XZ_UNSUPPORTED_CHECK, it is still possible + * to continue decoding if working in multi-call + * mode. Thus, update s->sequence before calling + * dec_stream_header(). + */ + s->sequence = SEQ_BLOCK_START; + + ret = dec_stream_header(s); + if (ret != XZ_OK) + return ret; + + case SEQ_BLOCK_START: + /* We need one byte of input to continue. */ + if (b->in_pos == b->in_size) + return XZ_OK; + + /* See if this is the beginning of the Index field. */ + if (b->in[b->in_pos] == 0) { + s->in_start = b->in_pos++; + s->sequence = SEQ_INDEX; + break; + } + + /* + * Calculate the size of the Block Header and + * prepare to decode it. + */ + s->block_header.size + = ((uint32_t)b->in[b->in_pos] + 1) * 4; + + s->temp.size = s->block_header.size; + s->temp.pos = 0; + s->sequence = SEQ_BLOCK_HEADER; + + case SEQ_BLOCK_HEADER: + if (!fill_temp(s, b)) + return XZ_OK; + + ret = dec_block_header(s); + if (ret != XZ_OK) + return ret; + + s->sequence = SEQ_BLOCK_UNCOMPRESS; + + case SEQ_BLOCK_UNCOMPRESS: + ret = dec_block(s, b); + if (ret != XZ_STREAM_END) + return ret; + + s->sequence = SEQ_BLOCK_PADDING; + + case SEQ_BLOCK_PADDING: + /* + * Size of Compressed Data + Block Padding + * must be a multiple of four. We don't need + * s->block.compressed for anything else + * anymore, so we use it here to test the size + * of the Block Padding field. + */ + while (s->block.compressed & 3) { + if (b->in_pos == b->in_size) + return XZ_OK; + + if (b->in[b->in_pos++] != 0) + return XZ_DATA_ERROR; + + ++s->block.compressed; + } + + s->sequence = SEQ_BLOCK_CHECK; + + case SEQ_BLOCK_CHECK: + if (s->check_type == XZ_CHECK_CRC32) { + ret = crc32_validate(s, b); + if (ret != XZ_STREAM_END) + return ret; + } +#ifdef XZ_DEC_ANY_CHECK + else if (!check_skip(s, b)) { + return XZ_OK; + } +#endif + + s->sequence = SEQ_BLOCK_START; + break; + + case SEQ_INDEX: + ret = dec_index(s, b); + if (ret != XZ_STREAM_END) + return ret; + + s->sequence = SEQ_INDEX_PADDING; + + case SEQ_INDEX_PADDING: + while ((s->index.size + (b->in_pos - s->in_start)) + & 3) { + if (b->in_pos == b->in_size) { + index_update(s, b); + return XZ_OK; + } + + if (b->in[b->in_pos++] != 0) + return XZ_DATA_ERROR; + } + + /* Finish the CRC32 value and Index size. */ + index_update(s, b); + + /* Compare the hashes to validate the Index field. */ + if (!memeq(&s->block.hash, &s->index.hash, + sizeof(s->block.hash))) + return XZ_DATA_ERROR; + + s->sequence = SEQ_INDEX_CRC32; + + case SEQ_INDEX_CRC32: + ret = crc32_validate(s, b); + if (ret != XZ_STREAM_END) + return ret; + + s->temp.size = STREAM_HEADER_SIZE; + s->sequence = SEQ_STREAM_FOOTER; + + case SEQ_STREAM_FOOTER: + if (!fill_temp(s, b)) + return XZ_OK; + + return dec_stream_footer(s); + } + } + + /* Never reached */ +} + +/* + * xz_dec_run() is a wrapper for dec_main() to handle some special cases in + * multi-call and single-call decoding. + * + * In multi-call mode, we must return XZ_BUF_ERROR when it seems clear that we + * are not going to make any progress anymore. This is to prevent the caller + * from calling us infinitely when the input file is truncated or otherwise + * corrupt. Since zlib-style API allows that the caller fills the input buffer + * only when the decoder doesn't produce any new output, we have to be careful + * to avoid returning XZ_BUF_ERROR too easily: XZ_BUF_ERROR is returned only + * after the second consecutive call to xz_dec_run() that makes no progress. + * + * In single-call mode, if we couldn't decode everything and no error + * occurred, either the input is truncated or the output buffer is too small. + * Since we know that the last input byte never produces any output, we know + * that if all the input was consumed and decoding wasn't finished, the file + * must be corrupt. Otherwise the output buffer has to be too small or the + * file is corrupt in a way that decoding it produces too big output. + * + * If single-call decoding fails, we reset b->in_pos and b->out_pos back to + * their original values. This is because with some filter chains there won't + * be any valid uncompressed data in the output buffer unless the decoding + * actually succeeds (that's the price to pay of using the output buffer as + * the workspace). + */ +XZ_EXTERN enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b) +{ + size_t in_start; + size_t out_start; + enum xz_ret ret; + + if (DEC_IS_SINGLE(s->mode)) + xz_dec_reset(s); + + in_start = b->in_pos; + out_start = b->out_pos; + ret = dec_main(s, b); + + if (DEC_IS_SINGLE(s->mode)) { + if (ret == XZ_OK) + ret = b->in_pos == b->in_size + ? XZ_DATA_ERROR : XZ_BUF_ERROR; + + if (ret != XZ_STREAM_END) { + b->in_pos = in_start; + b->out_pos = out_start; + } + + } else if (ret == XZ_OK && in_start == b->in_pos + && out_start == b->out_pos) { + if (s->allow_buf_error) + ret = XZ_BUF_ERROR; + + s->allow_buf_error = true; + } else { + s->allow_buf_error = false; + } + + return ret; +} + +XZ_EXTERN struct xz_dec *xz_dec_init(enum xz_mode mode, uint32_t dict_max) +{ + struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL); + if (s == NULL) + return NULL; + + s->mode = mode; + +#ifdef XZ_DEC_BCJ + s->bcj = xz_dec_bcj_create(DEC_IS_SINGLE(mode)); + if (s->bcj == NULL) + goto error_bcj; +#endif + + s->lzma2 = xz_dec_lzma2_create(mode, dict_max); + if (s->lzma2 == NULL) + goto error_lzma2; + + xz_dec_reset(s); + return s; + +error_lzma2: +#ifdef XZ_DEC_BCJ + xz_dec_bcj_end(s->bcj); +error_bcj: +#endif + kfree(s); + return NULL; +} + +XZ_EXTERN void xz_dec_reset(struct xz_dec *s) +{ + s->sequence = SEQ_STREAM_HEADER; + s->allow_buf_error = false; + s->pos = 0; + s->crc32 = 0; + memzero(&s->block, sizeof(s->block)); + memzero(&s->index, sizeof(s->index)); + s->temp.pos = 0; + s->temp.size = STREAM_HEADER_SIZE; +} + +XZ_EXTERN void xz_dec_end(struct xz_dec *s) +{ + if (s != NULL) { + xz_dec_lzma2_end(s->lzma2); +#ifdef XZ_DEC_BCJ + xz_dec_bcj_end(s->bcj); +#endif + kfree(s); + } +} diff --git a/lib/xz/xz_dec_syms.c b/lib/xz/xz_dec_syms.c new file mode 100644 index 00000000000..32eb3c03aed --- /dev/null +++ b/lib/xz/xz_dec_syms.c @@ -0,0 +1,26 @@ +/* + * XZ decoder module information + * + * Author: Lasse Collin + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +#include +#include + +EXPORT_SYMBOL(xz_dec_init); +EXPORT_SYMBOL(xz_dec_reset); +EXPORT_SYMBOL(xz_dec_run); +EXPORT_SYMBOL(xz_dec_end); + +MODULE_DESCRIPTION("XZ decompressor"); +MODULE_VERSION("1.0"); +MODULE_AUTHOR("Lasse Collin and Igor Pavlov"); + +/* + * This code is in the public domain, but in Linux it's simplest to just + * say it's GPL and consider the authors as the copyright holders. + */ +MODULE_LICENSE("GPL"); diff --git a/lib/xz/xz_dec_test.c b/lib/xz/xz_dec_test.c new file mode 100644 index 00000000000..da28a19d6c9 --- /dev/null +++ b/lib/xz/xz_dec_test.c @@ -0,0 +1,220 @@ +/* + * XZ decoder tester + * + * Author: Lasse Collin + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +#include +#include +#include +#include +#include +#include + +/* Maximum supported dictionary size */ +#define DICT_MAX (1 << 20) + +/* Device name to pass to register_chrdev(). */ +#define DEVICE_NAME "xz_dec_test" + +/* Dynamically allocated device major number */ +static int device_major; + +/* + * We reuse the same decoder state, and thus can decode only one + * file at a time. + */ +static bool device_is_open; + +/* XZ decoder state */ +static struct xz_dec *state; + +/* + * Return value of xz_dec_run(). We need to avoid calling xz_dec_run() after + * it has returned XZ_STREAM_END, so we make this static. + */ +static enum xz_ret ret; + +/* + * Input and output buffers. The input buffer is used as a temporary safe + * place for the data coming from the userspace. + */ +static uint8_t buffer_in[1024]; +static uint8_t buffer_out[1024]; + +/* + * Structure to pass the input and output buffers to the XZ decoder. + * A few of the fields are never modified so we initialize them here. + */ +static struct xz_buf buffers = { + .in = buffer_in, + .out = buffer_out, + .out_size = sizeof(buffer_out) +}; + +/* + * CRC32 of uncompressed data. This is used to give the user a simple way + * to check that the decoder produces correct output. + */ +static uint32_t crc; + +static int xz_dec_test_open(struct inode *i, struct file *f) +{ + if (device_is_open) + return -EBUSY; + + device_is_open = true; + + xz_dec_reset(state); + ret = XZ_OK; + crc = 0xFFFFFFFF; + + buffers.in_pos = 0; + buffers.in_size = 0; + buffers.out_pos = 0; + + printk(KERN_INFO DEVICE_NAME ": opened\n"); + return 0; +} + +static int xz_dec_test_release(struct inode *i, struct file *f) +{ + device_is_open = false; + + if (ret == XZ_OK) + printk(KERN_INFO DEVICE_NAME ": input was truncated\n"); + + printk(KERN_INFO DEVICE_NAME ": closed\n"); + return 0; +} + +/* + * Decode the data given to us from the userspace. CRC32 of the uncompressed + * data is calculated and is printed at the end of successful decoding. The + * uncompressed data isn't stored anywhere for further use. + * + * The .xz file must have exactly one Stream and no Stream Padding. The data + * after the first Stream is considered to be garbage. + */ +static ssize_t xz_dec_test_write(struct file *file, const char __user *buf, + size_t size, loff_t *pos) +{ + size_t remaining; + + if (ret != XZ_OK) { + if (size > 0) + printk(KERN_INFO DEVICE_NAME ": %zu bytes of " + "garbage at the end of the file\n", + size); + + return -ENOSPC; + } + + printk(KERN_INFO DEVICE_NAME ": decoding %zu bytes of input\n", + size); + + remaining = size; + while ((remaining > 0 || buffers.out_pos == buffers.out_size) + && ret == XZ_OK) { + if (buffers.in_pos == buffers.in_size) { + buffers.in_pos = 0; + buffers.in_size = min(remaining, sizeof(buffer_in)); + if (copy_from_user(buffer_in, buf, buffers.in_size)) + return -EFAULT; + + buf += buffers.in_size; + remaining -= buffers.in_size; + } + + buffers.out_pos = 0; + ret = xz_dec_run(state, &buffers); + crc = crc32(crc, buffer_out, buffers.out_pos); + } + + switch (ret) { + case XZ_OK: + printk(KERN_INFO DEVICE_NAME ": XZ_OK\n"); + return size; + + case XZ_STREAM_END: + printk(KERN_INFO DEVICE_NAME ": XZ_STREAM_END, " + "CRC32 = 0x%08X\n", ~crc); + return size - remaining - (buffers.in_size - buffers.in_pos); + + case XZ_MEMLIMIT_ERROR: + printk(KERN_INFO DEVICE_NAME ": XZ_MEMLIMIT_ERROR\n"); + break; + + case XZ_FORMAT_ERROR: + printk(KERN_INFO DEVICE_NAME ": XZ_FORMAT_ERROR\n"); + break; + + case XZ_OPTIONS_ERROR: + printk(KERN_INFO DEVICE_NAME ": XZ_OPTIONS_ERROR\n"); + break; + + case XZ_DATA_ERROR: + printk(KERN_INFO DEVICE_NAME ": XZ_DATA_ERROR\n"); + break; + + case XZ_BUF_ERROR: + printk(KERN_INFO DEVICE_NAME ": XZ_BUF_ERROR\n"); + break; + + default: + printk(KERN_INFO DEVICE_NAME ": Bug detected!\n"); + break; + } + + return -EIO; +} + +/* Allocate the XZ decoder state and register the character device. */ +static int __init xz_dec_test_init(void) +{ + static const struct file_operations fileops = { + .owner = THIS_MODULE, + .open = &xz_dec_test_open, + .release = &xz_dec_test_release, + .write = &xz_dec_test_write + }; + + state = xz_dec_init(XZ_PREALLOC, DICT_MAX); + if (state == NULL) + return -ENOMEM; + + device_major = register_chrdev(0, DEVICE_NAME, &fileops); + if (device_major < 0) { + xz_dec_end(state); + return device_major; + } + + printk(KERN_INFO DEVICE_NAME ": module loaded\n"); + printk(KERN_INFO DEVICE_NAME ": Create a device node with " + "'mknod " DEVICE_NAME " c %d 0' and write .xz files " + "to it.\n", device_major); + return 0; +} + +static void __exit xz_dec_test_exit(void) +{ + unregister_chrdev(device_major, DEVICE_NAME); + xz_dec_end(state); + printk(KERN_INFO DEVICE_NAME ": module unloaded\n"); +} + +module_init(xz_dec_test_init); +module_exit(xz_dec_test_exit); + +MODULE_DESCRIPTION("XZ decompressor tester"); +MODULE_VERSION("1.0"); +MODULE_AUTHOR("Lasse Collin "); + +/* + * This code is in the public domain, but in Linux it's simplest to just + * say it's GPL and consider the authors as the copyright holders. + */ +MODULE_LICENSE("GPL"); diff --git a/lib/xz/xz_lzma2.h b/lib/xz/xz_lzma2.h new file mode 100644 index 00000000000..071d67bee9f --- /dev/null +++ b/lib/xz/xz_lzma2.h @@ -0,0 +1,204 @@ +/* + * LZMA2 definitions + * + * Authors: Lasse Collin + * Igor Pavlov + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +#ifndef XZ_LZMA2_H +#define XZ_LZMA2_H + +/* Range coder constants */ +#define RC_SHIFT_BITS 8 +#define RC_TOP_BITS 24 +#define RC_TOP_VALUE (1 << RC_TOP_BITS) +#define RC_BIT_MODEL_TOTAL_BITS 11 +#define RC_BIT_MODEL_TOTAL (1 << RC_BIT_MODEL_TOTAL_BITS) +#define RC_MOVE_BITS 5 + +/* + * Maximum number of position states. A position state is the lowest pb + * number of bits of the current uncompressed offset. In some places there + * are different sets of probabilities for different position states. + */ +#define POS_STATES_MAX (1 << 4) + +/* + * This enum is used to track which LZMA symbols have occurred most recently + * and in which order. This information is used to predict the next symbol. + * + * Symbols: + * - Literal: One 8-bit byte + * - Match: Repeat a chunk of data at some distance + * - Long repeat: Multi-byte match at a recently seen distance + * - Short repeat: One-byte repeat at a recently seen distance + * + * The symbol names are in from STATE_oldest_older_previous. REP means + * either short or long repeated match, and NONLIT means any non-literal. + */ +enum lzma_state { + STATE_LIT_LIT, + STATE_MATCH_LIT_LIT, + STATE_REP_LIT_LIT, + STATE_SHORTREP_LIT_LIT, + STATE_MATCH_LIT, + STATE_REP_LIT, + STATE_SHORTREP_LIT, + STATE_LIT_MATCH, + STATE_LIT_LONGREP, + STATE_LIT_SHORTREP, + STATE_NONLIT_MATCH, + STATE_NONLIT_REP +}; + +/* Total number of states */ +#define STATES 12 + +/* The lowest 7 states indicate that the previous state was a literal. */ +#define LIT_STATES 7 + +/* Indicate that the latest symbol was a literal. */ +static inline void lzma_state_literal(enum lzma_state *state) +{ + if (*state <= STATE_SHORTREP_LIT_LIT) + *state = STATE_LIT_LIT; + else if (*state <= STATE_LIT_SHORTREP) + *state -= 3; + else + *state -= 6; +} + +/* Indicate that the latest symbol was a match. */ +static inline void lzma_state_match(enum lzma_state *state) +{ + *state = *state < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH; +} + +/* Indicate that the latest state was a long repeated match. */ +static inline void lzma_state_long_rep(enum lzma_state *state) +{ + *state = *state < LIT_STATES ? STATE_LIT_LONGREP : STATE_NONLIT_REP; +} + +/* Indicate that the latest symbol was a short match. */ +static inline void lzma_state_short_rep(enum lzma_state *state) +{ + *state = *state < LIT_STATES ? STATE_LIT_SHORTREP : STATE_NONLIT_REP; +} + +/* Test if the previous symbol was a literal. */ +static inline bool lzma_state_is_literal(enum lzma_state state) +{ + return state < LIT_STATES; +} + +/* Each literal coder is divided in three sections: + * - 0x001-0x0FF: Without match byte + * - 0x101-0x1FF: With match byte; match bit is 0 + * - 0x201-0x2FF: With match byte; match bit is 1 + * + * Match byte is used when the previous LZMA symbol was something else than + * a literal (that is, it was some kind of match). + */ +#define LITERAL_CODER_SIZE 0x300 + +/* Maximum number of literal coders */ +#define LITERAL_CODERS_MAX (1 << 4) + +/* Minimum length of a match is two bytes. */ +#define MATCH_LEN_MIN 2 + +/* Match length is encoded with 4, 5, or 10 bits. + * + * Length Bits + * 2-9 4 = Choice=0 + 3 bits + * 10-17 5 = Choice=1 + Choice2=0 + 3 bits + * 18-273 10 = Choice=1 + Choice2=1 + 8 bits + */ +#define LEN_LOW_BITS 3 +#define LEN_LOW_SYMBOLS (1 << LEN_LOW_BITS) +#define LEN_MID_BITS 3 +#define LEN_MID_SYMBOLS (1 << LEN_MID_BITS) +#define LEN_HIGH_BITS 8 +#define LEN_HIGH_SYMBOLS (1 << LEN_HIGH_BITS) +#define LEN_SYMBOLS (LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS + LEN_HIGH_SYMBOLS) + +/* + * Maximum length of a match is 273 which is a result of the encoding + * described above. + */ +#define MATCH_LEN_MAX (MATCH_LEN_MIN + LEN_SYMBOLS - 1) + +/* + * Different sets of probabilities are used for match distances that have + * very short match length: Lengths of 2, 3, and 4 bytes have a separate + * set of probabilities for each length. The matches with longer length + * use a shared set of probabilities. + */ +#define DIST_STATES 4 + +/* + * Get the index of the appropriate probability array for decoding + * the distance slot. + */ +static inline uint32_t lzma_get_dist_state(uint32_t len) +{ + return len < DIST_STATES + MATCH_LEN_MIN + ? len - MATCH_LEN_MIN : DIST_STATES - 1; +} + +/* + * The highest two bits of a 32-bit match distance are encoded using six bits. + * This six-bit value is called a distance slot. This way encoding a 32-bit + * value takes 6-36 bits, larger values taking more bits. + */ +#define DIST_SLOT_BITS 6 +#define DIST_SLOTS (1 << DIST_SLOT_BITS) + +/* Match distances up to 127 are fully encoded using probabilities. Since + * the highest two bits (distance slot) are always encoded using six bits, + * the distances 0-3 don't need any additional bits to encode, since the + * distance slot itself is the same as the actual distance. DIST_MODEL_START + * indicates the first distance slot where at least one additional bit is + * needed. + */ +#define DIST_MODEL_START 4 + +/* + * Match distances greater than 127 are encoded in three pieces: + * - distance slot: the highest two bits + * - direct bits: 2-26 bits below the highest two bits + * - alignment bits: four lowest bits + * + * Direct bits don't use any probabilities. + * + * The distance slot value of 14 is for distances 128-191. + */ +#define DIST_MODEL_END 14 + +/* Distance slots that indicate a distance <= 127. */ +#define FULL_DISTANCES_BITS (DIST_MODEL_END / 2) +#define FULL_DISTANCES (1 << FULL_DISTANCES_BITS) + +/* + * For match distances greater than 127, only the highest two bits and the + * lowest four bits (alignment) is encoded using probabilities. + */ +#define ALIGN_BITS 4 +#define ALIGN_SIZE (1 << ALIGN_BITS) +#define ALIGN_MASK (ALIGN_SIZE - 1) + +/* Total number of all probability variables */ +#define PROBS_TOTAL (1846 + LITERAL_CODERS_MAX * LITERAL_CODER_SIZE) + +/* + * LZMA remembers the four most recent match distances. Reusing these + * distances tends to take less space than re-encoding the actual + * distance value. + */ +#define REPS 4 + +#endif diff --git a/lib/xz/xz_private.h b/lib/xz/xz_private.h new file mode 100644 index 00000000000..a65633e0696 --- /dev/null +++ b/lib/xz/xz_private.h @@ -0,0 +1,156 @@ +/* + * Private includes and definitions + * + * Author: Lasse Collin + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +#ifndef XZ_PRIVATE_H +#define XZ_PRIVATE_H + +#ifdef __KERNEL__ +# include +# include +# include + /* XZ_PREBOOT may be defined only via decompress_unxz.c. */ +# ifndef XZ_PREBOOT +# include +# include +# include +# ifdef CONFIG_XZ_DEC_X86 +# define XZ_DEC_X86 +# endif +# ifdef CONFIG_XZ_DEC_POWERPC +# define XZ_DEC_POWERPC +# endif +# ifdef CONFIG_XZ_DEC_IA64 +# define XZ_DEC_IA64 +# endif +# ifdef CONFIG_XZ_DEC_ARM +# define XZ_DEC_ARM +# endif +# ifdef CONFIG_XZ_DEC_ARMTHUMB +# define XZ_DEC_ARMTHUMB +# endif +# ifdef CONFIG_XZ_DEC_SPARC +# define XZ_DEC_SPARC +# endif +# define memeq(a, b, size) (memcmp(a, b, size) == 0) +# define memzero(buf, size) memset(buf, 0, size) +# endif +# define get_le32(p) le32_to_cpup((const uint32_t *)(p)) +#else + /* + * For userspace builds, use a separate header to define the required + * macros and functions. This makes it easier to adapt the code into + * different environments and avoids clutter in the Linux kernel tree. + */ +# include "xz_config.h" +#endif + +/* If no specific decoding mode is requested, enable support for all modes. */ +#if !defined(XZ_DEC_SINGLE) && !defined(XZ_DEC_PREALLOC) \ + && !defined(XZ_DEC_DYNALLOC) +# define XZ_DEC_SINGLE +# define XZ_DEC_PREALLOC +# define XZ_DEC_DYNALLOC +#endif + +/* + * The DEC_IS_foo(mode) macros are used in "if" statements. If only some + * of the supported modes are enabled, these macros will evaluate to true or + * false at compile time and thus allow the compiler to omit unneeded code. + */ +#ifdef XZ_DEC_SINGLE +# define DEC_IS_SINGLE(mode) ((mode) == XZ_SINGLE) +#else +# define DEC_IS_SINGLE(mode) (false) +#endif + +#ifdef XZ_DEC_PREALLOC +# define DEC_IS_PREALLOC(mode) ((mode) == XZ_PREALLOC) +#else +# define DEC_IS_PREALLOC(mode) (false) +#endif + +#ifdef XZ_DEC_DYNALLOC +# define DEC_IS_DYNALLOC(mode) ((mode) == XZ_DYNALLOC) +#else +# define DEC_IS_DYNALLOC(mode) (false) +#endif + +#if !defined(XZ_DEC_SINGLE) +# define DEC_IS_MULTI(mode) (true) +#elif defined(XZ_DEC_PREALLOC) || defined(XZ_DEC_DYNALLOC) +# define DEC_IS_MULTI(mode) ((mode) != XZ_SINGLE) +#else +# define DEC_IS_MULTI(mode) (false) +#endif + +/* + * If any of the BCJ filter decoders are wanted, define XZ_DEC_BCJ. + * XZ_DEC_BCJ is used to enable generic support for BCJ decoders. + */ +#ifndef XZ_DEC_BCJ +# if defined(XZ_DEC_X86) || defined(XZ_DEC_POWERPC) \ + || defined(XZ_DEC_IA64) || defined(XZ_DEC_ARM) \ + || defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) \ + || defined(XZ_DEC_SPARC) +# define XZ_DEC_BCJ +# endif +#endif + +/* + * Allocate memory for LZMA2 decoder. xz_dec_lzma2_reset() must be used + * before calling xz_dec_lzma2_run(). + */ +XZ_EXTERN struct xz_dec_lzma2 *xz_dec_lzma2_create(enum xz_mode mode, + uint32_t dict_max); + +/* + * Decode the LZMA2 properties (one byte) and reset the decoder. Return + * XZ_OK on success, XZ_MEMLIMIT_ERROR if the preallocated dictionary is not + * big enough, and XZ_OPTIONS_ERROR if props indicates something that this + * decoder doesn't support. + */ +XZ_EXTERN enum xz_ret xz_dec_lzma2_reset(struct xz_dec_lzma2 *s, + uint8_t props); + +/* Decode raw LZMA2 stream from b->in to b->out. */ +XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s, + struct xz_buf *b); + +/* Free the memory allocated for the LZMA2 decoder. */ +XZ_EXTERN void xz_dec_lzma2_end(struct xz_dec_lzma2 *s); + +#ifdef XZ_DEC_BCJ +/* + * Allocate memory for BCJ decoders. xz_dec_bcj_reset() must be used before + * calling xz_dec_bcj_run(). + */ +XZ_EXTERN struct xz_dec_bcj *xz_dec_bcj_create(bool single_call); + +/* + * Decode the Filter ID of a BCJ filter. This implementation doesn't + * support custom start offsets, so no decoding of Filter Properties + * is needed. Returns XZ_OK if the given Filter ID is supported. + * Otherwise XZ_OPTIONS_ERROR is returned. + */ +XZ_EXTERN enum xz_ret xz_dec_bcj_reset(struct xz_dec_bcj *s, uint8_t id); + +/* + * Decode raw BCJ + LZMA2 stream. This must be used only if there actually is + * a BCJ filter in the chain. If the chain has only LZMA2, xz_dec_lzma2_run() + * must be called directly. + */ +XZ_EXTERN enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s, + struct xz_dec_lzma2 *lzma2, + struct xz_buf *b); + +/* Free the memory allocated for the BCJ filters. */ +#define xz_dec_bcj_end(s) kfree(s) +#endif + +#endif diff --git a/lib/xz/xz_stream.h b/lib/xz/xz_stream.h new file mode 100644 index 00000000000..66cb5a7055e --- /dev/null +++ b/lib/xz/xz_stream.h @@ -0,0 +1,62 @@ +/* + * Definitions for handling the .xz file format + * + * Author: Lasse Collin + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +#ifndef XZ_STREAM_H +#define XZ_STREAM_H + +#if defined(__KERNEL__) && !XZ_INTERNAL_CRC32 +# include +# undef crc32 +# define xz_crc32(buf, size, crc) \ + (~crc32_le(~(uint32_t)(crc), buf, size)) +#endif + +/* + * See the .xz file format specification at + * http://tukaani.org/xz/xz-file-format.txt + * to understand the container format. + */ + +#define STREAM_HEADER_SIZE 12 + +#define HEADER_MAGIC "\3757zXZ" +#define HEADER_MAGIC_SIZE 6 + +#define FOOTER_MAGIC "YZ" +#define FOOTER_MAGIC_SIZE 2 + +/* + * Variable-length integer can hold a 63-bit unsigned integer or a special + * value indicating that the value is unknown. + * + * Experimental: vli_type can be defined to uint32_t to save a few bytes + * in code size (no effect on speed). Doing so limits the uncompressed and + * compressed size of the file to less than 256 MiB and may also weaken + * error detection slightly. + */ +typedef uint64_t vli_type; + +#define VLI_MAX ((vli_type)-1 / 2) +#define VLI_UNKNOWN ((vli_type)-1) + +/* Maximum encoded size of a VLI */ +#define VLI_BYTES_MAX (sizeof(vli_type) * 8 / 7) + +/* Integrity Check types */ +enum xz_check { + XZ_CHECK_NONE = 0, + XZ_CHECK_CRC32 = 1, + XZ_CHECK_CRC64 = 4, + XZ_CHECK_SHA256 = 10 +}; + +/* Maximum possible Check ID */ +#define XZ_CHECK_MAX 15 + +#endif diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 396da16aabf..1c702ca8aac 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -262,6 +262,34 @@ cmd_lzo = (cat $(filter-out FORCE,$^) | \ lzop -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ (rm -f $@ ; false) +# XZ +# --------------------------------------------------------------------------- +# Use xzkern to compress the kernel image and xzmisc to compress other things. +# +# xzkern uses a big LZMA2 dictionary since it doesn't increase memory usage +# of the kernel decompressor. A BCJ filter is used if it is available for +# the target architecture. xzkern also appends uncompressed size of the data +# using size_append. The .xz format has the size information available at +# the end of the file too, but it's in more complex format and it's good to +# avoid changing the part of the boot code that reads the uncompressed size. +# Note that the bytes added by size_append will make the xz tool think that +# the file is corrupt. This is expected. +# +# xzmisc doesn't use size_append, so it can be used to create normal .xz +# files. xzmisc uses smaller LZMA2 dictionary than xzkern, because a very +# big dictionary would increase the memory usage too much in the multi-call +# decompression mode. A BCJ filter isn't used either. +quiet_cmd_xzkern = XZKERN $@ +cmd_xzkern = (cat $(filter-out FORCE,$^) | \ + sh $(srctree)/scripts/xz_wrap.sh && \ + $(call size_append, $(filter-out FORCE,$^))) > $@ || \ + (rm -f $@ ; false) + +quiet_cmd_xzmisc = XZMISC $@ +cmd_xzmisc = (cat $(filter-out FORCE,$^) | \ + xz --check=crc32 --lzma2=dict=1MiB) > $@ || \ + (rm -f $@ ; false) + # misc stuff # --------------------------------------------------------------------------- quote:=" diff --git a/scripts/xz_wrap.sh b/scripts/xz_wrap.sh new file mode 100644 index 00000000000..17a5798c29d --- /dev/null +++ b/scripts/xz_wrap.sh @@ -0,0 +1,23 @@ +#!/bin/sh +# +# This is a wrapper for xz to compress the kernel image using appropriate +# compression options depending on the architecture. +# +# Author: Lasse Collin +# +# This file has been put into the public domain. +# You can do whatever you want with this file. +# + +BCJ= +LZMA2OPTS= + +case $ARCH in + x86|x86_64) BCJ=--x86 ;; + powerpc) BCJ=--powerpc ;; + ia64) BCJ=--ia64; LZMA2OPTS=pb=4 ;; + arm) BCJ=--arm ;; + sparc) BCJ=--sparc ;; +esac + +exec xz --check=crc32 $BCJ --lzma2=$LZMA2OPTS,dict=32MiB -- cgit v1.2.3-70-g09d2 From 3ebe12439ba7fc62e1d6ecb569b7287771716ca1 Mon Sep 17 00:00:00 2001 From: Lasse Collin Date: Wed, 12 Jan 2011 17:01:23 -0800 Subject: decompressors: add boot-time XZ support This implements the API defined in which is used for kernel, initramfs, and initrd decompression. This patch together with the first patch is enough for XZ-compressed initramfs and initrd; XZ-compressed kernel will need arch-specific changes. The buffering requirements described in decompress_unxz.c are stricter than with gzip, so the relevant changes should be done to the arch-specific code when adding support for XZ-compressed kernel. Similarly, the heap size in arch-specific pre-boot code may need to be increased (30 KiB is enough). The XZ decompressor needs memmove(), memeq() (memcmp() == 0), and memzero() (memset(ptr, 0, size)), which aren't available in all arch-specific pre-boot environments. I'm including simple versions in decompress_unxz.c, but a cleaner solution would naturally be nicer. Signed-off-by: Lasse Collin Cc: "H. Peter Anvin" Cc: Alain Knaff Cc: Albin Tonnerre Cc: Phillip Lougher Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/decompress/unxz.h | 19 ++ init/Kconfig | 20 +- lib/Kconfig | 4 + lib/Makefile | 1 + lib/decompress.c | 5 + lib/decompress_unxz.c | 397 ++++++++++++++++++++++++++++++++++++++++ scripts/gen_initramfs_list.sh | 2 + usr/Kconfig | 18 ++ usr/Makefile | 5 +- 9 files changed, 469 insertions(+), 2 deletions(-) create mode 100644 include/linux/decompress/unxz.h create mode 100644 lib/decompress_unxz.c (limited to 'scripts') diff --git a/include/linux/decompress/unxz.h b/include/linux/decompress/unxz.h new file mode 100644 index 00000000000..41728fc6c8a --- /dev/null +++ b/include/linux/decompress/unxz.h @@ -0,0 +1,19 @@ +/* + * Wrapper for decompressing XZ-compressed kernel, initramfs, and initrd + * + * Author: Lasse Collin + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +#ifndef DECOMPRESS_UNXZ_H +#define DECOMPRESS_UNXZ_H + +int unxz(unsigned char *in, int in_size, + int (*fill)(void *dest, unsigned int size), + int (*flush)(void *src, unsigned int size), + unsigned char *out, int *in_used, + void (*error)(char *x)); + +#endif diff --git a/init/Kconfig b/init/Kconfig index 8dfd094e687..ea176e8edbd 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -130,13 +130,16 @@ config HAVE_KERNEL_BZIP2 config HAVE_KERNEL_LZMA bool +config HAVE_KERNEL_XZ + bool + config HAVE_KERNEL_LZO bool choice prompt "Kernel compression mode" default KERNEL_GZIP - depends on HAVE_KERNEL_GZIP || HAVE_KERNEL_BZIP2 || HAVE_KERNEL_LZMA || HAVE_KERNEL_LZO + depends on HAVE_KERNEL_GZIP || HAVE_KERNEL_BZIP2 || HAVE_KERNEL_LZMA || HAVE_KERNEL_XZ || HAVE_KERNEL_LZO help The linux kernel is a kind of self-extracting executable. Several compression algorithms are available, which differ @@ -181,6 +184,21 @@ config KERNEL_LZMA two. Compression is slowest. The kernel size is about 33% smaller with LZMA in comparison to gzip. +config KERNEL_XZ + bool "XZ" + depends on HAVE_KERNEL_XZ + help + XZ uses the LZMA2 algorithm and instruction set specific + BCJ filters which can improve compression ratio of executable + code. The size of the kernel is about 30% smaller with XZ in + comparison to gzip. On architectures for which there is a BCJ + filter (i386, x86_64, ARM, IA-64, PowerPC, and SPARC), XZ + will create a few percent smaller kernel than plain LZMA. + + The speed is about the same as with LZMA: The decompression + speed of XZ is better than that of bzip2 but worse than gzip + and LZO. Compression is slow. + config KERNEL_LZO bool "LZO" depends on HAVE_KERNEL_LZO diff --git a/lib/Kconfig b/lib/Kconfig index 2b8f8540d67..0ee67e08ad3 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -122,6 +122,10 @@ config DECOMPRESS_BZIP2 config DECOMPRESS_LZMA tristate +config DECOMPRESS_XZ + select XZ_DEC + tristate + config DECOMPRESS_LZO select LZO_DECOMPRESS tristate diff --git a/lib/Makefile b/lib/Makefile index 4df2d029772..cbb774f7d41 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -75,6 +75,7 @@ obj-$(CONFIG_RAID6_PQ) += raid6/ lib-$(CONFIG_DECOMPRESS_GZIP) += decompress_inflate.o lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o lib-$(CONFIG_DECOMPRESS_LZMA) += decompress_unlzma.o +lib-$(CONFIG_DECOMPRESS_XZ) += decompress_unxz.o lib-$(CONFIG_DECOMPRESS_LZO) += decompress_unlzo.o obj-$(CONFIG_TEXTSEARCH) += textsearch.o diff --git a/lib/decompress.c b/lib/decompress.c index a7606815541..3d766b7f60a 100644 --- a/lib/decompress.c +++ b/lib/decompress.c @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -23,6 +24,9 @@ #ifndef CONFIG_DECOMPRESS_LZMA # define unlzma NULL #endif +#ifndef CONFIG_DECOMPRESS_XZ +# define unxz NULL +#endif #ifndef CONFIG_DECOMPRESS_LZO # define unlzo NULL #endif @@ -36,6 +40,7 @@ static const struct compress_format { { {037, 0236}, "gzip", gunzip }, { {0x42, 0x5a}, "bzip2", bunzip2 }, { {0x5d, 0x00}, "lzma", unlzma }, + { {0xfd, 0x37}, "xz", unxz }, { {0x89, 0x4c}, "lzo", unlzo }, { {0, 0}, NULL, NULL } }; diff --git a/lib/decompress_unxz.c b/lib/decompress_unxz.c new file mode 100644 index 00000000000..cecd23df2b9 --- /dev/null +++ b/lib/decompress_unxz.c @@ -0,0 +1,397 @@ +/* + * Wrapper for decompressing XZ-compressed kernel, initramfs, and initrd + * + * Author: Lasse Collin + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +/* + * Important notes about in-place decompression + * + * At least on x86, the kernel is decompressed in place: the compressed data + * is placed to the end of the output buffer, and the decompressor overwrites + * most of the compressed data. There must be enough safety margin to + * guarantee that the write position is always behind the read position. + * + * The safety margin for XZ with LZMA2 or BCJ+LZMA2 is calculated below. + * Note that the margin with XZ is bigger than with Deflate (gzip)! + * + * The worst case for in-place decompression is that the beginning of + * the file is compressed extremely well, and the rest of the file is + * uncompressible. Thus, we must look for worst-case expansion when the + * compressor is encoding uncompressible data. + * + * The structure of the .xz file in case of a compresed kernel is as follows. + * Sizes (as bytes) of the fields are in parenthesis. + * + * Stream Header (12) + * Block Header: + * Block Header (8-12) + * Compressed Data (N) + * Block Padding (0-3) + * CRC32 (4) + * Index (8-20) + * Stream Footer (12) + * + * Normally there is exactly one Block, but let's assume that there are + * 2-4 Blocks just in case. Because Stream Header and also Block Header + * of the first Block don't make the decompressor produce any uncompressed + * data, we can ignore them from our calculations. Block Headers of possible + * additional Blocks have to be taken into account still. With these + * assumptions, it is safe to assume that the total header overhead is + * less than 128 bytes. + * + * Compressed Data contains LZMA2 or BCJ+LZMA2 encoded data. Since BCJ + * doesn't change the size of the data, it is enough to calculate the + * safety margin for LZMA2. + * + * LZMA2 stores the data in chunks. Each chunk has a header whose size is + * a maximum of 6 bytes, but to get round 2^n numbers, let's assume that + * the maximum chunk header size is 8 bytes. After the chunk header, there + * may be up to 64 KiB of actual payload in the chunk. Often the payload is + * quite a bit smaller though; to be safe, let's assume that an average + * chunk has only 32 KiB of payload. + * + * The maximum uncompressed size of the payload is 2 MiB. The minimum + * uncompressed size of the payload is in practice never less than the + * payload size itself. The LZMA2 format would allow uncompressed size + * to be less than the payload size, but no sane compressor creates such + * files. LZMA2 supports storing uncompressible data in uncompressed form, + * so there's never a need to create payloads whose uncompressed size is + * smaller than the compressed size. + * + * The assumption, that the uncompressed size of the payload is never + * smaller than the payload itself, is valid only when talking about + * the payload as a whole. It is possible that the payload has parts where + * the decompressor consumes more input than it produces output. Calculating + * the worst case for this would be tricky. Instead of trying to do that, + * let's simply make sure that the decompressor never overwrites any bytes + * of the payload which it is currently reading. + * + * Now we have enough information to calculate the safety margin. We need + * - 128 bytes for the .xz file format headers; + * - 8 bytes per every 32 KiB of uncompressed size (one LZMA2 chunk header + * per chunk, each chunk having average payload size of 32 KiB); and + * - 64 KiB (biggest possible LZMA2 chunk payload size) to make sure that + * the decompressor never overwrites anything from the LZMA2 chunk + * payload it is currently reading. + * + * We get the following formula: + * + * safety_margin = 128 + uncompressed_size * 8 / 32768 + 65536 + * = 128 + (uncompressed_size >> 12) + 65536 + * + * For comparision, according to arch/x86/boot/compressed/misc.c, the + * equivalent formula for Deflate is this: + * + * safety_margin = 18 + (uncompressed_size >> 12) + 32768 + * + * Thus, when updating Deflate-only in-place kernel decompressor to + * support XZ, the fixed overhead has to be increased from 18+32768 bytes + * to 128+65536 bytes. + */ + +/* + * STATIC is defined to "static" if we are being built for kernel + * decompression (pre-boot code). will define + * STATIC to empty if it wasn't already defined. Since we will need to + * know later if we are being used for kernel decompression, we define + * XZ_PREBOOT here. + */ +#ifdef STATIC +# define XZ_PREBOOT +#endif +#ifdef __KERNEL__ +# include +#endif +#define XZ_EXTERN STATIC + +#ifndef XZ_PREBOOT +# include +# include +#else +/* + * Use the internal CRC32 code instead of kernel's CRC32 module, which + * is not available in early phase of booting. + */ +#define XZ_INTERNAL_CRC32 1 + +/* + * For boot time use, we enable only the BCJ filter of the current + * architecture or none if no BCJ filter is available for the architecture. + */ +#ifdef CONFIG_X86 +# define XZ_DEC_X86 +#endif +#ifdef CONFIG_PPC +# define XZ_DEC_POWERPC +#endif +#ifdef CONFIG_ARM +# define XZ_DEC_ARM +#endif +#ifdef CONFIG_IA64 +# define XZ_DEC_IA64 +#endif +#ifdef CONFIG_SPARC +# define XZ_DEC_SPARC +#endif + +/* + * This will get the basic headers so that memeq() and others + * can be defined. + */ +#include "xz/xz_private.h" + +/* + * Replace the normal allocation functions with the versions from + * . vfree() needs to support vfree(NULL) + * when XZ_DYNALLOC is used, but the pre-boot free() doesn't support it. + * Workaround it here because the other decompressors don't need it. + */ +#undef kmalloc +#undef kfree +#undef vmalloc +#undef vfree +#define kmalloc(size, flags) malloc(size) +#define kfree(ptr) free(ptr) +#define vmalloc(size) malloc(size) +#define vfree(ptr) do { if (ptr != NULL) free(ptr); } while (0) + +/* + * FIXME: Not all basic memory functions are provided in architecture-specific + * files (yet). We define our own versions here for now, but this should be + * only a temporary solution. + * + * memeq and memzero are not used much and any remotely sane implementation + * is fast enough. memcpy/memmove speed matters in multi-call mode, but + * the kernel image is decompressed in single-call mode, in which only + * memcpy speed can matter and only if there is a lot of uncompressible data + * (LZMA2 stores uncompressible chunks in uncompressed form). Thus, the + * functions below should just be kept small; it's probably not worth + * optimizing for speed. + */ + +#ifndef memeq +static bool memeq(const void *a, const void *b, size_t size) +{ + const uint8_t *x = a; + const uint8_t *y = b; + size_t i; + + for (i = 0; i < size; ++i) + if (x[i] != y[i]) + return false; + + return true; +} +#endif + +#ifndef memzero +static void memzero(void *buf, size_t size) +{ + uint8_t *b = buf; + uint8_t *e = b + size; + + while (b != e) + *b++ = '\0'; +} +#endif + +#ifndef memmove +/* Not static to avoid a conflict with the prototype in the Linux headers. */ +void *memmove(void *dest, const void *src, size_t size) +{ + uint8_t *d = dest; + const uint8_t *s = src; + size_t i; + + if (d < s) { + for (i = 0; i < size; ++i) + d[i] = s[i]; + } else if (d > s) { + i = size; + while (i-- > 0) + d[i] = s[i]; + } + + return dest; +} +#endif + +/* + * Since we need memmove anyway, would use it as memcpy too. + * Commented out for now to avoid breaking things. + */ +/* +#ifndef memcpy +# define memcpy memmove +#endif +*/ + +#include "xz/xz_crc32.c" +#include "xz/xz_dec_stream.c" +#include "xz/xz_dec_lzma2.c" +#include "xz/xz_dec_bcj.c" + +#endif /* XZ_PREBOOT */ + +/* Size of the input and output buffers in multi-call mode */ +#define XZ_IOBUF_SIZE 4096 + +/* + * This function implements the API defined in . + * + * This wrapper will automatically choose single-call or multi-call mode + * of the native XZ decoder API. The single-call mode can be used only when + * both input and output buffers are available as a single chunk, i.e. when + * fill() and flush() won't be used. + */ +STATIC int INIT unxz(unsigned char *in, int in_size, + int (*fill)(void *dest, unsigned int size), + int (*flush)(void *src, unsigned int size), + unsigned char *out, int *in_used, + void (*error)(char *x)) +{ + struct xz_buf b; + struct xz_dec *s; + enum xz_ret ret; + bool must_free_in = false; + +#if XZ_INTERNAL_CRC32 + xz_crc32_init(); +#endif + + if (in_used != NULL) + *in_used = 0; + + if (fill == NULL && flush == NULL) + s = xz_dec_init(XZ_SINGLE, 0); + else + s = xz_dec_init(XZ_DYNALLOC, (uint32_t)-1); + + if (s == NULL) + goto error_alloc_state; + + if (flush == NULL) { + b.out = out; + b.out_size = (size_t)-1; + } else { + b.out_size = XZ_IOBUF_SIZE; + b.out = malloc(XZ_IOBUF_SIZE); + if (b.out == NULL) + goto error_alloc_out; + } + + if (in == NULL) { + must_free_in = true; + in = malloc(XZ_IOBUF_SIZE); + if (in == NULL) + goto error_alloc_in; + } + + b.in = in; + b.in_pos = 0; + b.in_size = in_size; + b.out_pos = 0; + + if (fill == NULL && flush == NULL) { + ret = xz_dec_run(s, &b); + } else { + do { + if (b.in_pos == b.in_size && fill != NULL) { + if (in_used != NULL) + *in_used += b.in_pos; + + b.in_pos = 0; + + in_size = fill(in, XZ_IOBUF_SIZE); + if (in_size < 0) { + /* + * This isn't an optimal error code + * but it probably isn't worth making + * a new one either. + */ + ret = XZ_BUF_ERROR; + break; + } + + b.in_size = in_size; + } + + ret = xz_dec_run(s, &b); + + if (flush != NULL && (b.out_pos == b.out_size + || (ret != XZ_OK && b.out_pos > 0))) { + /* + * Setting ret here may hide an error + * returned by xz_dec_run(), but probably + * it's not too bad. + */ + if (flush(b.out, b.out_pos) != (int)b.out_pos) + ret = XZ_BUF_ERROR; + + b.out_pos = 0; + } + } while (ret == XZ_OK); + + if (must_free_in) + free(in); + + if (flush != NULL) + free(b.out); + } + + if (in_used != NULL) + *in_used += b.in_pos; + + xz_dec_end(s); + + switch (ret) { + case XZ_STREAM_END: + return 0; + + case XZ_MEM_ERROR: + /* This can occur only in multi-call mode. */ + error("XZ decompressor ran out of memory"); + break; + + case XZ_FORMAT_ERROR: + error("Input is not in the XZ format (wrong magic bytes)"); + break; + + case XZ_OPTIONS_ERROR: + error("Input was encoded with settings that are not " + "supported by this XZ decoder"); + break; + + case XZ_DATA_ERROR: + case XZ_BUF_ERROR: + error("XZ-compressed data is corrupt"); + break; + + default: + error("Bug in the XZ decompressor"); + break; + } + + return -1; + +error_alloc_in: + if (flush != NULL) + free(b.out); + +error_alloc_out: + xz_dec_end(s); + +error_alloc_state: + error("XZ decompressor ran out of memory"); + return -1; +} + +/* + * This macro is used by architecture-specific files to decompress + * the kernel image. + */ +#define decompress unxz diff --git a/scripts/gen_initramfs_list.sh b/scripts/gen_initramfs_list.sh index 5958fffb211..55caecdad99 100644 --- a/scripts/gen_initramfs_list.sh +++ b/scripts/gen_initramfs_list.sh @@ -243,6 +243,8 @@ case "$arg" in echo "$output_file" | grep -q "\.gz$" && compr="gzip -9 -f" echo "$output_file" | grep -q "\.bz2$" && compr="bzip2 -9 -f" echo "$output_file" | grep -q "\.lzma$" && compr="lzma -9 -f" + echo "$output_file" | grep -q "\.xz$" && \ + compr="xz --check=crc32 --lzma2=dict=1MiB" echo "$output_file" | grep -q "\.lzo$" && compr="lzop -9 -f" echo "$output_file" | grep -q "\.cpio$" && compr="cat" shift diff --git a/usr/Kconfig b/usr/Kconfig index c2c7fe2f717..4780deac597 100644 --- a/usr/Kconfig +++ b/usr/Kconfig @@ -72,6 +72,15 @@ config RD_LZMA Support loading of a LZMA encoded initial ramdisk or cpio buffer If unsure, say N. +config RD_XZ + bool "Support initial ramdisks compressed using XZ" if EMBEDDED + default !EMBEDDED + depends on BLK_DEV_INITRD + select DECOMPRESS_XZ + help + Support loading of a XZ encoded initial ramdisk or cpio buffer. + If unsure, say N. + config RD_LZO bool "Support initial ramdisks compressed using LZO" if EMBEDDED default !EMBEDDED @@ -139,6 +148,15 @@ config INITRAMFS_COMPRESSION_LZMA three. Compression is slowest. The initramfs size is about 33% smaller with LZMA in comparison to gzip. +config INITRAMFS_COMPRESSION_XZ + bool "XZ" + depends on RD_XZ + help + XZ uses the LZMA2 algorithm. The initramfs size is about 30% + smaller with XZ in comparison to gzip. Decompression speed + is better than that of bzip2 but worse than gzip and LZO. + Compression is slow. + config INITRAMFS_COMPRESSION_LZO bool "LZO" depends on RD_LZO diff --git a/usr/Makefile b/usr/Makefile index 6faa444b708..029ffe6cd0d 100644 --- a/usr/Makefile +++ b/usr/Makefile @@ -15,6 +15,9 @@ suffix_$(CONFIG_INITRAMFS_COMPRESSION_BZIP2) = .bz2 # Lzma suffix_$(CONFIG_INITRAMFS_COMPRESSION_LZMA) = .lzma +# XZ +suffix_$(CONFIG_INITRAMFS_COMPRESSION_XZ) = .xz + # Lzo suffix_$(CONFIG_INITRAMFS_COMPRESSION_LZO) = .lzo @@ -50,7 +53,7 @@ endif quiet_cmd_initfs = GEN $@ cmd_initfs = $(initramfs) -o $@ $(ramfs-args) $(ramfs-input) -targets := initramfs_data.cpio.gz initramfs_data.cpio.bz2 initramfs_data.cpio.lzma initramfs_data.cpio.lzo initramfs_data.cpio +targets := initramfs_data.cpio.gz initramfs_data.cpio.bz2 initramfs_data.cpio.lzma initramfs_data.cpio.xz initramfs_data.cpio.lzo initramfs_data.cpio # do not try to update files included in initramfs $(deps_initramfs): ; -- cgit v1.2.3-70-g09d2 From 1b9a50d931a04ba007cc1a926fead3ff4b5afa9b Mon Sep 17 00:00:00 2001 From: maximilian attems Date: Thu, 13 Jan 2011 15:34:20 +0100 Subject: deb-pkg: Use $SRCARCH for include path Fix x86 centric path to allow building kernel-header packages for other architecture. Signed-off-by: maximilian attems Signed-off-by: Michal Marek --- scripts/package/builddeb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/package/builddeb b/scripts/package/builddeb index b0b2357aef4..ebc6d6e9d77 100644 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -239,7 +239,7 @@ fi # Build header package find . -name Makefile -o -name Kconfig\* -o -name \*.pl > /tmp/files$$ -find arch/x86/include include scripts -type f >> /tmp/files$$ +find arch/$SRCARCH/include include scripts -type f >> /tmp/files$$ (cd $objtree; find .config Module.symvers include scripts -type f >> /tmp/objfiles$$) destdir=$kernel_headers_dir/usr/src/linux-headers-$version mkdir -p "$destdir" -- cgit v1.2.3-70-g09d2 From 9b4ce7bce5f30712fd926ab4599a803314a07719 Mon Sep 17 00:00:00 2001 From: Nicolas de Pesloüan Date: Mon, 24 Jan 2011 14:41:41 +0100 Subject: deb-pkg: Fix building outside of source tree (O=...). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When building linux-headers package using deb-pkg, builddeb erroneously assume current directory is the source tree. This is not true if building in another directory, using make O=... deb-pkg. This patch fix this problem. Signed-off-by: Nicolas de Pesloüan Tested-by: Nikolai Kondrashov Acked-by: maximilian attems Signed-off-by: Michal Marek --- scripts/package/builddeb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'scripts') diff --git a/scripts/package/builddeb b/scripts/package/builddeb index ebc6d6e9d77..f6cbc3ddb68 100644 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -238,12 +238,12 @@ EOF fi # Build header package -find . -name Makefile -o -name Kconfig\* -o -name \*.pl > /tmp/files$$ -find arch/$SRCARCH/include include scripts -type f >> /tmp/files$$ +(cd $srctree; find . -name Makefile -o -name Kconfig\* -o -name \*.pl > /tmp/files$$) +(cd $srctree; find arch/$SRCARCH/include include scripts -type f >> /tmp/files$$) (cd $objtree; find .config Module.symvers include scripts -type f >> /tmp/objfiles$$) destdir=$kernel_headers_dir/usr/src/linux-headers-$version mkdir -p "$destdir" -tar -c -f - -T /tmp/files$$ | (cd $destdir; tar -xf -) +(cd $srctree; tar -c -f - -T /tmp/files$$) | (cd $destdir; tar -xf -) (cd $objtree; tar -c -f - -T /tmp/objfiles$$) | (cd $destdir; tar -xf -) rm -f /tmp/files$$ /tmp/objfiles$$ arch=$(dpkg --print-architecture) -- cgit v1.2.3-70-g09d2 From b7bd182176960fdd139486cadb9962b39f8a2b50 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Thu, 17 Feb 2011 15:13:54 +0100 Subject: fixdep: Do not record dependency on the source file itself The dependency is already expressed by the Makefiles, storing it in the .cmd file breaks build if a .c file is replaced by .S or vice versa, because the .cmd file contains foo/bar.o: foo/bar.c ... foo/bar.c ... : so the foo/bar.c -> foo/bar.o rule triggers even if there is no foo/bar.c anymore. Acked-by: Stephen Rothwell Signed-off-by: Michal Marek --- scripts/basic/fixdep.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c index c9a16abacab..6c94c6ce292 100644 --- a/scripts/basic/fixdep.c +++ b/scripts/basic/fixdep.c @@ -315,6 +315,7 @@ static void parse_dep_file(void *map, size_t len) char *end = m + len; char *p; char s[PATH_MAX]; + int first; p = strchr(m, ':'); if (!p) { @@ -327,6 +328,7 @@ static void parse_dep_file(void *map, size_t len) clear_config(); + first = 1; while (m < end) { while (m < end && (*m == ' ' || *m == '\\' || *m == '\n')) m++; @@ -340,9 +342,17 @@ static void parse_dep_file(void *map, size_t len) if (strrcmp(s, "include/generated/autoconf.h") && strrcmp(s, "arch/um/include/uml-config.h") && strrcmp(s, ".ver")) { - printf(" %s \\\n", s); + /* + * Do not output the first dependency (the + * source file), so that kbuild is not confused + * if a .c file is rewritten into .S or vice + * versa. + */ + if (!first) + printf(" %s \\\n", s); do_config_file(s); } + first = 0; m = p + 1; } printf("\n%s: $(deps_%s)\n\n", target, target); -- cgit v1.2.3-70-g09d2