@@ -837,14 +837,25 @@ quiet_cmd_kallsyms = KSYM $@
.tmp_kallsyms%.S: .tmp_vmlinux% $(KALLSYMS)
$(call cmd,kallsyms)
+quiet_cmd_cond_sections_bis = CONDSECS $@
+ cmd_cond_sections_bis = $(NM) -n $< | \
+ grep -E "cond_(data|text)_start" | \
+ scripts/cond-sections --s-file > $@
+
+.tmp_condsecs.o: %.o: %.S FORCE
+ $(call if_changed_dep,as_o_S)
+
+.tmp_condsecs.S: .tmp_vmlinux1 scripts/cond-sections
+ $(call cmd,cond_sections_bis)
+
# .tmp_vmlinux1 must be complete except kallsyms, so update vmlinux version
.tmp_vmlinux1: $(vmlinux-lds) $(vmlinux-all) FORCE
$(call if_changed_rule,ksym_ld)
-.tmp_vmlinux2: $(vmlinux-lds) $(vmlinux-all) .tmp_kallsyms1.o FORCE
+.tmp_vmlinux2: $(vmlinux-lds) $(vmlinux-all) .tmp_kallsyms1.o .tmp_condsecs.o FORCE
$(call if_changed,vmlinux__)
-.tmp_vmlinux3: $(vmlinux-lds) $(vmlinux-all) .tmp_kallsyms2.o FORCE
+.tmp_vmlinux3: $(vmlinux-lds) $(vmlinux-all) .tmp_kallsyms2.o .tmp_condsecs.o FORCE
$(call if_changed,vmlinux__)
# Needs to visit scripts/ before $(KALLSYMS) can be used.
@@ -876,7 +887,7 @@ define rule_vmlinux-modpost
endef
# vmlinux image - including updated kernel symbols
-vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o) FORCE
+vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o $(kallsyms.o) .tmp_condsecs.o FORCE
ifdef CONFIG_HEADERS_CHECK
$(Q)$(MAKE) -f $(srctree)/Makefile headers_check
endif
@@ -105,6 +105,7 @@ SECTIONS
SCHED_TEXT
LOCK_TEXT
KPROBES_TEXT
+ CONDITIONAL_TEXT
#ifdef CONFIG_MMU
*(.fixup)
#endif
@@ -168,6 +169,8 @@ SECTIONS
NOSAVE_DATA
CACHELINE_ALIGNED_DATA(32)
+ CONDITIONAL_DATA
+
/*
* The exception fixup table (might need resorting at runtime)
*/
new file mode 100644
@@ -0,0 +1,19 @@
+/*
+ * Conditional section management
+ *
+ * Copyright (C) 2010 Thomas Petazzoni <t-petazzoni@ti.com>
+ */
+
+#ifndef __CONDSECTIONS_H__
+#define __CONDSECTIONS_H__
+
+/*
+ * Use these macros to define other macros to put code or data into
+ * specific conditional sections.
+ */
+#define cond_data_section(__secname__) __section(.data.conditional.__secname__)
+#define cond_text_section(__secname__) __section(.text.conditional.__secname__)
+
+void free_unused_cond_section(const char *name);
+
+#endif /* __CONDSECTIONS_H__ */
@@ -10,7 +10,7 @@ obj-y = sched.o fork.o exec_domain.o panic.o printk.o \
kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \
notifier.o ksysfs.o pm_qos_params.o sched_clock.o cred.o \
- async.o range.o jump_label.o
+ async.o range.o jump_label.o condsections.o
obj-y += groups.o
ifdef CONFIG_FUNCTION_TRACER
new file mode 100644
@@ -0,0 +1,57 @@
+/*
+ * Conditional section management
+ *
+ * Copyright (C) 2010 Thomas Petazzoni <t-petazzoni@ti.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+
+/*
+ * This structure must be in sync with the assembly code generated by
+ * scripts/cond-sections.
+ */
+struct cond_section_desc {
+ unsigned long start;
+ unsigned long end;
+ unsigned long type;
+ const char *name;
+};
+
+/*
+ * Symbol defined by assembly code generated in
+ * scripts/cond-sections. Declared as weak because it appears only at
+ * late stage of the link process.
+ */
+extern struct cond_section_desc cond_section_descs[] __attribute__((weak));
+
+static void free_unused_cond_section_area(unsigned long pfn, unsigned long end)
+{
+ for (; pfn < end; pfn++) {
+ struct page *page = pfn_to_page(pfn);
+ ClearPageReserved(page);
+ init_page_count(page);
+ __free_page(page);
+ totalram_pages += 1;
+ }
+}
+
+/*
+ * Free the text and data conditional sections associated to the given
+ * name
+ */
+void free_unused_cond_section(const char *name)
+{
+ struct cond_section_desc *sec;
+
+ for (sec = cond_section_descs; sec->name; sec++) {
+ if (strcmp(sec->name, name))
+ continue;
+ printk(KERN_INFO "Freeing unused conditional section: %s %s 0x%lx -> 0%lx (sz=%ld)\n",
+ sec->name, (sec->type ? "data" : "text"),
+ sec->start, sec->end, (sec->end - sec->start));
+ memset((void*) sec->start, POISON_FREE_INITMEM, sec->end - sec->start);
+ free_unused_cond_section_area(__phys_to_pfn(__pa(sec->start)),
+ __phys_to_pfn(__pa(sec->end)));
+ }
+}
@@ -285,10 +285,11 @@ targets += $(extra-y) $(MAKECMDGOALS) $(always)
# Linker scripts preprocessor (.lds.S -> .lds)
# ---------------------------------------------------------------------------
quiet_cmd_cpp_lds_S = LDS $@
- cmd_cpp_lds_S = $(CPP) $(cpp_flags) -P -C -U$(ARCH) \
- -D__ASSEMBLY__ -DLINKER_SCRIPT -o $@ $<
+ cmd_cpp_lds_S = cat $< | scripts/cond-sections --lds $(OBJDUMP) | \
+ $(CPP) $(cpp_flags) -P -C -U$(ARCH) \
+ -D__ASSEMBLY__ -DLINKER_SCRIPT -o $@ -
-$(obj)/%.lds: $(src)/%.lds.S FORCE
+$(obj)/%.lds: $(src)/%.lds.S scripts/cond-sections FORCE
$(call if_changed_dep,cpp_lds_S)
# Build the compiled-in targets
new file mode 100755
@@ -0,0 +1,93 @@
+#!/bin/sh
+#
+# Conditional section link script and assembly code generation
+#
+# Copyright (C) 2010 Thomas Petazzoni <t-petazzoni@ti.com>
+#
+# This script is used:
+#
+# *) with a --lds path-to-objdump argument, with the vmlinux.lds.S
+# file on its standard input, in order to generate the linker
+# script fragments corresponding to the different conditional
+# sections included in the kernel image.
+#
+# *) with a --s-file argument, with the result of a
+# $(CROSS_COMPILE)nm -n as its standard input, in order to
+# generate some assembly code that will compile into an array of
+# structures representing each conditional section.
+
+if [ $# -lt 1 ] ; then
+ echo "Incorrect number of arguments"
+ exit 1
+fi
+
+if [ x$1 = x"--lds" ] ; then
+ OBJDUMP=$(which $2)
+ if [ ! -x $OBJDUMP ] ; then
+ echo "Invalid objdump executable"
+ exit 1
+ fi
+
+ # Get the list of conditional data sections
+ CONDITIONAL_DATA_SECTIONS=$($OBJDUMP -w -h vmlinux.o | \
+ grep "\.data\.conditional\." | cut -f3 -d' ' | tr "\n" " ")
+
+ # Get the list of conditional text sections
+ CONDITIONAL_TEXT_SECTIONS=$($OBJDUMP -w -h vmlinux.o | \
+ grep "\.text\.conditional\." | cut -f3 -d' ' | tr "\n" " ")
+
+ while read line ; do
+ if echo $line | grep -q "CONDITIONAL_TEXT" ; then
+ for s in $CONDITIONAL_TEXT_SECTIONS ; do
+ sym=$(echo $s | sed 's/\.data\.conditional\.//')
+ echo ". = ALIGN(PAGE_SIZE);"
+ echo "VMLINUX_SYMBOL(__${sym}_cond_text_start) = .;"
+ echo "*(.text.conditional.${sym})"
+ echo ". = ALIGN(PAGE_SIZE);"
+ echo "VMLINUX_SYMBOL(__${sym}_cond_text_end) = .;"
+ done
+ elif echo $line | grep -q "CONDITIONAL_DATA" ; then
+ for s in $CONDITIONAL_DATA_SECTIONS ; do
+ sym=$(echo $s | sed 's/\.data\.conditional\.//')
+ echo ". = ALIGN(PAGE_SIZE);"
+ echo "VMLINUX_SYMBOL(__${sym}_cond_data_start) = .;"
+ echo "*(.data.conditional.${sym})"
+ echo ". = ALIGN(PAGE_SIZE);"
+ echo "VMLINUX_SYMBOL(__${sym}_cond_data_end) = .;"
+ done
+ else
+ echo "$line"
+ fi
+ done
+elif [ x$1 = x"--s-file" ] ; then
+ echo ".section .rodata, \"a\""
+ echo ".globl cond_section_descs"
+ echo ".align 8"
+ echo "cond_section_descs:"
+ seclist=""
+ while read line ; do
+ sym=$(echo $line | cut -f3 -d' ')
+ secname=$(echo $sym | sed 's/^__\(.*\)_cond_.*/\1/')
+ sectype=$(echo $sym | sed 's/^.*_cond_\([a-z]*\)_start/\1/')
+ echo ".long __${secname}_cond_${sectype}_start"
+ echo ".long __${secname}_cond_${sectype}_end"
+ if [ $sectype = "text" ] ; then
+ echo ".long 0"
+ else
+ echo ".long 1"
+ fi
+ echo ".long __${secname}_cond_str"
+ seclist="$seclist $secname"
+ done
+ echo ".long 0"
+ echo ".long 0"
+ echo ".long 0"
+ echo ".long 0"
+ for sec in $seclist ; do
+ echo "__${sec}_cond_str:"
+ echo ".asciz \"${sec}\""
+ done
+else
+ echo "Invalid option"
+ exit 1
+fi