From patchwork Tue Dec 21 18:19:59 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Petazzoni X-Patchwork-Id: 424841 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id oBLIKPC1026904 for ; Tue, 21 Dec 2010 18:20:25 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752498Ab0LUSUX (ORCPT ); Tue, 21 Dec 2010 13:20:23 -0500 Received: from mail.free-electrons.com ([88.190.12.23]:44881 "EHLO mail.free-electrons.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752479Ab0LUSUV (ORCPT ); Tue, 21 Dec 2010 13:20:21 -0500 Received: by mail.free-electrons.com (Postfix, from userid 106) id 5A0E614F; Tue, 21 Dec 2010 19:20:20 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.free-electrons.com X-Spam-Level: X-Spam-Status: No, score=-2.9 required=5.0 tests=ALL_TRUSTED,BAYES_00 autolearn=ham version=3.3.1 Received: from localhost (humanoidz.org [82.247.183.72]) by mail.free-electrons.com (Postfix) with ESMTPSA id 9DE8A16A; Tue, 21 Dec 2010 19:20:11 +0100 (CET) From: Thomas Petazzoni To: linux-omap@vger.kernel.org Cc: Thomas Petazzoni , Thomas Petazzoni Subject: [PATCH 1/6] Add infrastructure for conditional code and data sections Date: Tue, 21 Dec 2010 19:19:59 +0100 Message-Id: <1292955604-8809-2-git-send-email-thomas.petazzoni@free-electrons.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <1292955604-8809-1-git-send-email-thomas.petazzoni@free-electrons.com> References: <1292955604-8809-1-git-send-email-thomas.petazzoni@free-electrons.com> Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Tue, 21 Dec 2010 18:20:25 +0000 (UTC) diff --git a/Makefile b/Makefile index 6619720..57bb824 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index cead889..aa0282f 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -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) */ diff --git a/include/linux/condsections.h b/include/linux/condsections.h new file mode 100644 index 0000000..d657be6 --- /dev/null +++ b/include/linux/condsections.h @@ -0,0 +1,19 @@ +/* + * Conditional section management + * + * Copyright (C) 2010 Thomas Petazzoni + */ + +#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__ */ diff --git a/kernel/Makefile b/kernel/Makefile index 0b5ff08..58b0435 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -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 diff --git a/kernel/condsections.c b/kernel/condsections.c new file mode 100644 index 0000000..b568549 --- /dev/null +++ b/kernel/condsections.c @@ -0,0 +1,57 @@ +/* + * Conditional section management + * + * Copyright (C) 2010 Thomas Petazzoni + */ + +#include +#include + +/* + * 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))); + } +} diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 5ad25e1..3822751 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -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 diff --git a/scripts/cond-sections b/scripts/cond-sections new file mode 100755 index 0000000..c72e932 --- /dev/null +++ b/scripts/cond-sections @@ -0,0 +1,93 @@ +#!/bin/sh +# +# Conditional section link script and assembly code generation +# +# Copyright (C) 2010 Thomas Petazzoni +# +# 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