From patchwork Sun Jul 15 02:44:12 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Domenico Andreoli X-Patchwork-Id: 1198341 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork2.kernel.org (Postfix) with ESMTP id 40D1EDF28C for ; Sun, 15 Jul 2012 02:54:45 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1SqEta-0000Bc-MH; Sun, 15 Jul 2012 02:49:18 +0000 Received: from mail-wi0-f171.google.com ([209.85.212.171]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1SqEqd-0008VN-0h for linux-arm-kernel@lists.infradead.org; Sun, 15 Jul 2012 02:46:27 +0000 Received: by wibhq4 with SMTP id hq4so1332942wib.0 for ; Sat, 14 Jul 2012 19:46:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:message-id:user-agent:date:from:to:cc:subject:references :content-disposition; bh=urlhwKp6MOLZbZgONA5NC3dTw/2hE2cNU4B+INJH/cA=; b=g3D9jEmSdg+zNoSdyIhzoxd3AuQP6URVtMsfTZJjfY+slvl/25S95ffMJHFNEMH3/O fHLBeGYbFjaUG8tCvrULJ3RNtUfGz3njBXUXg6/0NwUBratSZMX3grzZA7LDtsbJoY4C 2q35EtyfAwnOTubh3ZodaWf76CAhFQdviryUiIrNE4VD0cuu+RSX+SgWDC7LK5XEmlOT cLk1Q1p8IZrvcmnjqgttJl1WFF//T6kBYRYelZrs5Sp74EwvW6JNYOXJcutO51JkXDbO tzyds6vqQVBtK1AfjLpd/qhSqnWlQkYq4RMX9k2QowtcaZPdBkHfKALZsrrXi5qEkqCS lMBw== Received: by 10.216.27.21 with SMTP id d21mr3140924wea.152.1342320370601; Sat, 14 Jul 2012 19:46:10 -0700 (PDT) Received: from raptus.dandreoli.com (178-85-163-250.dynamic.upc.nl. [178.85.163.250]) by mx.google.com with ESMTPS id fr4sm19280446wib.8.2012.07.14.19.46.09 (version=TLSv1/SSLv3 cipher=OTHER); Sat, 14 Jul 2012 19:46:09 -0700 (PDT) Received: by raptus.dandreoli.com (Postfix, from userid 1000) id 785F137BA01; Sun, 15 Jul 2012 04:46:09 +0200 (CEST) Message-Id: <20120715024609.213083179@gmail.com> User-Agent: quilt/0.60-1 Date: Sun, 15 Jul 2012 04:44:12 +0200 From: Domenico Andreoli To: linux-arm-kernel@lists.infradead.org Subject: [RFC PATCH 04/12] ARM: Add architecture specific decompressor tags References: <20120715024408.747946928@gmail.com> Content-Disposition: inline; filename=decomp-arch.patch X-Spam-Note: CRM114 invocation failed X-Spam-Score: -2.7 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (cavokz[at]gmail.com) -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [209.85.212.171 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature Cc: Domenico Andreoli , Russell King - ARM Linux , Arnd Bergmann X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org From: Domenico Andreoli Main concept here is the "decompressor tag" defined by struct: struct decomp_tag_hdr { unsigned int arch_id; unsigned short type; unsigned short size; }; Each tag is associated to an architecture, has a type to identify it among the different kind of tags (see enum decomp_tag_type) and a size to easily walk heterogeneous piles of tags. Secondary concept (but primary for the patchset) is the "architecture tag" defined by struct: struct decomp_arch_tag { struct decomp_tag_hdr hdr; void (*setup)(void); void (*error)(char *msg); }; So here we have the first user of the decompressor tags who adds some arch specific ops (setup and error) to a tag and ships everything to the decompressor. The rest of the patch is exactly what implements that "ships everything to the decompressor" and what the decompressor does with that "everything". So, in order to ship stuff to the decopressor, each tag (and respective pointed-to code/data) needs to be stored in the proper ELF sections. Such sections are relocated (*) to the decompressor during the build. Almost all of this is taken care by some type saving (but not too scary) macros and some help from the linker. Next, the decompressor at boot walks the shipped tags and looks for a match of the machine id passed by the boot loader. The first matching architecture tag provides the possibly NULL pointers to the specific ops. In case of not matching machid (and not in case of NULL ops), fallback functions are used instead. All of this is implemented in file arch.c, which also takes care of some stuff previously in misc.c and cleaning decompress_kernel(). The new key function arch_setup() is invoked right before decompress_kernel(). (*) such relocation brings in some difficulties with strings and pointers used in the shipped ops. Also invoking functions from there can be from trivial (inline functions) to impossible (we don't relocate the whole kernel into the decompressor...). Signed-off-by: Domenico Andreoli --- arch/arm/boot/compressed/arch.c | 53 +++++++++++++++++++++++++++++++++++++ arch/arm/boot/compressed/arch.h | 10 +++++++ arch/arm/boot/compressed/head.S | 14 +++++----- arch/arm/boot/compressed/misc.c | 23 ++++++---------- include/linux/decompress/arch.h | 58 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 136 insertions(+), 22 deletions(-) Index: b/include/linux/decompress/arch.h =================================================================== --- /dev/null +++ b/include/linux/decompress/arch.h @@ -0,0 +1,58 @@ +/* + * Handling of arch specific bits in the decompressor + * + * Copyright (C) 2012 Domenico Andreoli + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#ifndef LINUX_DECOMP_ARCH_H +#define LINUX_DECOMP_ARCH_H + +#include + +enum decomp_tag_type { + DECOMP_TAG_ARCH = 0, +}; + +struct decomp_tag_hdr { + unsigned int arch_id; + unsigned short type; + unsigned short size; +}; + +#define DECOMP_TAG_START(_struct, _name, _tagtype, _machid) \ +static const _struct _name __used \ + __attribute__((__section__(".arch.tags.decomp"))) = { \ + .hdr = { \ + .arch_id = _machid, \ + .type = _tagtype, \ + .size = sizeof(_struct), \ + }, + +#define DECOMP_TAG_END \ +}; + +struct decomp_arch_tag { + struct decomp_tag_hdr hdr; + void (*setup)(void); + void (*error)(char *msg); +}; + +#define DECOMP_ARCH_START(_machid) \ +DECOMP_TAG_START(struct decomp_arch_tag, __decomp_arch_##_machid, \ + DECOMP_TAG_ARCH, MACH_TYPE_##_machid) + +#define DECOMP_ARCH_END DECOMP_TAG_END + +#define __decomp_arch __section(.arch.text.decomp) +#define __decomp_archdata __section(.arch.data.decomp) + +#endif /* LINUX_DECOMP_ARCH_H */ Index: b/arch/arm/boot/compressed/misc.c =================================================================== --- a/arch/arm/boot/compressed/misc.c +++ b/arch/arm/boot/compressed/misc.c @@ -16,8 +16,6 @@ * This allows for a much quicker boot time. */ -unsigned int __machine_arch_type; - #include /* for inline */ #include #include @@ -29,6 +27,10 @@ void error(char *x); #include #endif +#include + +#include "arch.h" + #ifdef CONFIG_DEBUG_ICEDCC #if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V6K) || defined(CONFIG_CPU_V7) @@ -134,12 +136,10 @@ extern char input_data_end[]; unsigned char *output_data; -unsigned long free_mem_ptr; -unsigned long free_mem_end_ptr; - void error(char *x) { - fallback_arch_error(x); + if (arch_error_p) + arch_error_p(x); putstr("\n\n"); putstr(x); @@ -157,18 +157,11 @@ extern int do_decompress(u8 *input, int void -decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p, - unsigned long free_mem_ptr_end_p, - int arch_id) +decompress_kernel(unsigned long output_start) { int ret; - output_data = (unsigned char *)output_start; - free_mem_ptr = free_mem_ptr_p; - free_mem_end_ptr = free_mem_ptr_end_p; - __machine_arch_type = arch_id; - - fallback_arch_setup(); + output_data = (unsigned char *)output_start; putstr("Uncompressing Linux..."); ret = do_decompress(input_data, input_data_end - input_data, Index: b/arch/arm/boot/compressed/head.S =================================================================== --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -447,14 +447,14 @@ not_relocated: mov r0, #0 /* * The C runtime environment should now be setup sufficiently. * Set up some pointers, and start decompressing. - * r4 = kernel execution address - * r7 = architecture ID - * r8 = atags pointer */ - mov r0, r4 - mov r1, sp @ malloc space above stack - add r2, sp, #0x10000 @ 64k max - mov r3, r7 + + mov r0, r7 @ architecture id + mov r1, r8 @ atags or devicetree + mov r2, sp @ malloc space above stack + add r3, sp, #0x10000 @ 64k max + bl arch_setup + mov r0, r4 @ kernel execution address bl decompress_kernel bl cache_clean_flush bl cache_off Index: b/arch/arm/boot/compressed/arch.c =================================================================== --- a/arch/arm/boot/compressed/arch.c +++ b/arch/arm/boot/compressed/arch.c @@ -13,10 +13,22 @@ * GNU General Public License for more details. */ +unsigned int __machine_arch_type; + +#include #include +#include +#include + +#include #include "arch.h" +unsigned long free_mem_ptr; +unsigned long free_mem_end_ptr; + +void (*arch_error_p)(char *x); + /* defined in the linker script */ extern void *__decomp_text_begin; extern void *__decomp_data_begin; @@ -36,3 +48,44 @@ const void *fix_data_ptr(const void *p) return ((void *) &__decomp_data_begin) + (p - __decomp_data_begin); } + +extern const struct decomp_tag_hdr __decomp_tags_begin[]; +extern const struct decomp_tag_hdr __decomp_tags_end[]; + +#define for_each_decomp_tag(p) \ + for ((p) = __decomp_tags_begin; \ + (p) < __decomp_tags_end; \ + p = ((void *) p) + (p)->size) + +void arch_setup(unsigned int arch_id, void *atag_fdt, + unsigned long free_mem_ptr_p, + unsigned long free_mem_ptr_end_p) +{ + struct decomp_arch_tag *arch_tag = NULL; + const struct decomp_tag_hdr *hdr; + void (*arch_setup_p)(void); + + __machine_arch_type = arch_id; + + arch_setup_p = fallback_arch_setup; + arch_error_p = fallback_arch_error; + + free_mem_ptr = free_mem_ptr_p; + free_mem_end_ptr = free_mem_ptr_end_p; + + for_each_decomp_tag(hdr) { + if (hdr->arch_id != arch_id) + continue; + + if (hdr->type == DECOMP_TAG_ARCH) { + arch_tag = (struct decomp_arch_tag *) hdr; + arch_setup_p = fix_text_ptr(arch_tag->setup); + arch_error_p = fix_text_ptr(arch_tag->error); + break; + } + } + + /* archs without decompressor setup have NULL here */ + if (arch_setup_p) + arch_setup_p(); +} Index: b/arch/arm/boot/compressed/arch.h =================================================================== --- a/arch/arm/boot/compressed/arch.h +++ b/arch/arm/boot/compressed/arch.h @@ -16,6 +16,16 @@ #ifndef ARM_BOOT_COMPRESSED_ARCH_H #define ARM_BOOT_COMPRESSED_ARCH_H +extern unsigned int __machine_arch_type; + +extern unsigned long free_mem_ptr; +extern unsigned long free_mem_end_ptr; + +extern void (*arch_error_p)(char *x); + +void fallback_arch_setup(void); +void fallback_arch_error(char *x); + const void *fix_text_ptr(const void *p); const void *fix_data_ptr(const void *p);