From patchwork Mon Jul 21 15:16:22 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 33986 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-oi0-f71.google.com (mail-oi0-f71.google.com [209.85.218.71]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 3CB2620672 for ; Mon, 21 Jul 2014 15:37:49 +0000 (UTC) Received: by mail-oi0-f71.google.com with SMTP id e131sf14969924oig.10 for ; Mon, 21 Jul 2014 08:37:47 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:subject:date:message-id :in-reply-to:references:cc:precedence:list-id:list-unsubscribe :list-archive:list-post:list-help:list-subscribe:mime-version:sender :errors-to:x-original-sender:x-original-authentication-results :mailing-list:content-type:content-transfer-encoding; bh=j0Y4G3vaiQPqkQWBwhyklAcCP0QiDwlPv4AzE+WrOmM=; b=HeG9tD/9pwVbrYNeY6mtxokLwwZ/tyDLidHSZQsIonb7461npMWcx9s2A8WLtEZjzj y/FwEVhytU1WYuN+K1FCN/VQkGpDp1u4PhsMlrsiIc0TZmvIMV1q0fyTcVTmBGlKAESk ZPsOQc0QFBRrrvFpcKjE03hlwOUA4XQse3j/wd4A0JreRU+5wUIn0V3mV3nO9BzC54lv fFHSiGlHVRYdZf60/iTZTTldZqVonsoIZ2bR23kzxjwkEZVGi7MFdpAl43wZu2WQq20r 14ZcSG0cYIEC/SK7H02nBjsEZ+khJAFLB5N3X+hqFaiBfrkoy3TdyOr3HIv6Aqz0FKnJ HBpA== X-Gm-Message-State: ALoCoQkapAVleX/y5u6nCVafo1FWAkxk4eoEaKi5IU/GYmx45cpUz2RMC6LsTpc4RC6P0rXLL8sI X-Received: by 10.42.25.17 with SMTP id y17mr4378242icb.11.1405957067417; Mon, 21 Jul 2014 08:37:47 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.29.55 with SMTP id a52ls1983653qga.14.gmail; Mon, 21 Jul 2014 08:37:47 -0700 (PDT) X-Received: by 10.52.232.200 with SMTP id tq8mr25902915vdc.32.1405957067064; Mon, 21 Jul 2014 08:37:47 -0700 (PDT) Received: from mail-vc0-f179.google.com (mail-vc0-f179.google.com [209.85.220.179]) by mx.google.com with ESMTPS id z8si11620018ven.51.2014.07.21.08.37.44 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 21 Jul 2014 08:37:44 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.220.179 as permitted sender) client-ip=209.85.220.179; Received: by mail-vc0-f179.google.com with SMTP id hq11so10794906vcb.38 for ; Mon, 21 Jul 2014 08:37:44 -0700 (PDT) X-Received: by 10.221.26.10 with SMTP id rk10mr30672141vcb.0.1405957064254; Mon, 21 Jul 2014 08:37:44 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.221.37.5 with SMTP id tc5csp122509vcb; Mon, 21 Jul 2014 08:37:43 -0700 (PDT) X-Received: by 10.68.114.65 with SMTP id je1mr9236638pbb.124.1405957063156; Mon, 21 Jul 2014 08:37:43 -0700 (PDT) Received: from bombadil.infradead.org (bombadil.infradead.org. [2001:1868:205::9]) by mx.google.com with ESMTPS id rn6si14599940pab.179.2014.07.21.08.37.42 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 21 Jul 2014 08:37:43 -0700 (PDT) Received-SPF: none (google.com: linux-arm-kernel-bounces+patch=linaro.org@lists.infradead.org does not designate permitted sender hosts) client-ip=2001:1868:205::9; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1X9Fcx-0002RJ-3q; Mon, 21 Jul 2014 15:35:47 +0000 Received: from casper.infradead.org ([2001:770:15f::2]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1X9Fco-0002NR-OQ for linux-arm-kernel@bombadil.infradead.org; Mon, 21 Jul 2014 15:35:38 +0000 Received: from mail-we0-f181.google.com ([74.125.82.181]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1X9FLT-0003tT-Sq for linux-arm-kernel@lists.infradead.org; Mon, 21 Jul 2014 15:17:47 +0000 Received: by mail-we0-f181.google.com with SMTP id k48so6456503wev.26 for ; Mon, 21 Jul 2014 08:17:18 -0700 (PDT) X-Received: by 10.180.189.210 with SMTP id gk18mr5399659wic.82.1405955837846; Mon, 21 Jul 2014 08:17:17 -0700 (PDT) Received: from ards-macbook-pro.local ([212.91.105.246]) by mx.google.com with ESMTPSA id ft17sm38327602wjc.14.2014.07.21.08.17.14 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 21 Jul 2014 08:17:17 -0700 (PDT) From: Ard Biesheuvel To: matt.fleming@intel.com, linux-efi@vger.kernel.org, linux-arm-kernel@lists.infradead.org, will.deacon@arm.com, leif.lindholm@linaro.org Subject: [RFC PATCH 07/10] arm64/efi: efistub: add support for booting a BE kernel Date: Mon, 21 Jul 2014 17:16:22 +0200 Message-Id: <1405955785-13477-8-git-send-email-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 1.8.3.2 In-Reply-To: <1405955785-13477-1-git-send-email-ard.biesheuvel@linaro.org> References: <1405955785-13477-1-git-send-email-ard.biesheuvel@linaro.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140721_161743_962016_E9F269EE X-CRM114-Status: GOOD ( 26.88 ) X-Spam-Score: -2.6 (--) X-Spam-Report: SpamAssassin version 3.4.0 on casper.infradead.org summary: Content analysis details: (-2.6 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_MSPIKE_H3 RBL: Good reputation (+3) [74.125.82.181 listed in wl.mailspike.net] -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [74.125.82.181 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.0 RCVD_IN_MSPIKE_WL Mailspike good senders Cc: roy.franz@linaro.org, victor.kamensky@linaro.org, steve.capper@linaro.org, Ard Biesheuvel , msalter@redhat.com X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: , List-Help: , List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patch=linaro.org@lists.infradead.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: ard.biesheuvel@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.220.179 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 This adds support to boot a big endian kernel from UEFI firmware, which is always little endian. The EFI stub itself is built as little endian, and embedded into a big endian kernel image. To enable this, we need to build all the stub's dependencies as little endian, including FDT parsing code and string functions. This is accomplished by building little endian versions of those support files and link them into a static library which is used by the inner stub build. Signed-off-by: Ard Biesheuvel --- arch/arm64/kernel/Makefile | 7 +++- arch/arm64/kernel/efi-entry.S | 42 +++++++++++++++++------ arch/arm64/kernel/efistub-le/Makefile | 52 +++++++++++++++++++++++++++++ arch/arm64/kernel/efistub-le/efi-le-entry.S | 13 ++++++++ arch/arm64/kernel/efistub-le/efistub-le.lds | 35 +++++++++++++++++++ arch/arm64/kernel/efistub-le/le.h | 12 +++++++ arch/arm64/kernel/efistub-le/strstr.c | 20 +++++++++++ drivers/firmware/efi/libstub/fdt.c | 4 +++ 8 files changed, 173 insertions(+), 12 deletions(-) create mode 100644 arch/arm64/kernel/efistub-le/Makefile create mode 100644 arch/arm64/kernel/efistub-le/efi-le-entry.S create mode 100644 arch/arm64/kernel/efistub-le/efistub-le.lds create mode 100644 arch/arm64/kernel/efistub-le/le.h create mode 100644 arch/arm64/kernel/efistub-le/strstr.c diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index afaeb734295a..942cd042e93e 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -27,7 +27,12 @@ arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o arm64-obj-$(CONFIG_KGDB) += kgdb.o -arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o + +arm64-efi-obj-y := efi.o +arm64-efi-obj-$(CONFIG_EFI_STUB) += efi-stub.o efi-entry.o +arm64-efi-obj-$(CONFIG_EFI_LE_STUB) += efistub-le/ +arm64-efi-obj-$(CONFIG_CPU_BIG_ENDIAN) += efi-be-runtime.o efi-be-call.o +arm64-obj-$(CONFIG_EFI) += $(arm64-efi-obj-y) obj-y += $(arm64-obj-y) vdso/ obj-m += $(arm64-obj-m) diff --git a/arch/arm64/kernel/efi-entry.S b/arch/arm64/kernel/efi-entry.S index a0016d3a17da..89f34bb86cfd 100644 --- a/arch/arm64/kernel/efi-entry.S +++ b/arch/arm64/kernel/efi-entry.S @@ -34,8 +34,34 @@ ENTRY(efi_stub_entry) * Create a stack frame to save FP/LR with extra space * for image_addr variable passed to efi_entry(). */ - stp x29, x30, [sp, #-32]! + stp x29, x30, [sp, #-48]! + stp x22, x23, [sp, #32] +#ifdef CONFIG_EFI_LE_STUB + adr x4, efi_stub_entry + ldp w8, w9, [x4, #-32] +STUB_BE(rev w8, w8 ) +STUB_BE(rev w9, w9 ) + add x8, x4, w8, sxtw // x8: base of Image + add x9, x4, w9, sxtw // x9: offset of linux_banner + + ldp x22, x23, [x4, #-24] // x22: size of Image +STUB_BE(rev x23, x23 ) // x23: stext offset + + /* + * Get a pointer to linux_banner in the outer image and store it + * in this image. + */ + adrp x4, le_linux_banner + str x9, [x4, #:lo12:le_linux_banner] +#else + adrp x8, _text + add x8, x8, #:lo12:_text // x8: base of Image + adrp x9, _edata + add x9, x9, #:lo12:_edata + sub x22, x9, x8 // x22: size of Image + ldr x23, =stext_offset // x23: stext offset +#endif /* * Call efi_entry to do the real work. * x0 and x1 are already set up by firmware. Current runtime @@ -45,8 +71,6 @@ ENTRY(efi_stub_entry) * efi_system_table_t *sys_table, * unsigned long *image_addr) ; */ - adrp x8, _text - add x8, x8, #:lo12:_text add x2, sp, 16 str x8, [x2] bl efi_entry @@ -61,18 +85,13 @@ ENTRY(efi_stub_entry) */ mov x20, x0 // DTB address ldr x0, [sp, #16] // relocated _text address - ldr x21, =stext_offset - add x21, x0, x21 + add x21, x0, x23 /* * Flush dcache covering current runtime addresses * of kernel text/data. Then flush all of icache. */ - adrp x1, _text - add x1, x1, #:lo12:_text - adrp x2, _edata - add x2, x2, #:lo12:_edata - sub x1, x2, x1 + mov x1, x22 bl __flush_dcache_area ic ialluis @@ -103,7 +122,8 @@ ENTRY(efi_stub_entry) efi_load_fail: mov x0, #EFI_LOAD_ERROR - ldp x29, x30, [sp], #32 + ldp x22, x23, [sp, #32] + ldp x29, x30, [sp], #48 ret ENDPROC(efi_stub_entry) diff --git a/arch/arm64/kernel/efistub-le/Makefile b/arch/arm64/kernel/efistub-le/Makefile new file mode 100644 index 000000000000..38347b0633c8 --- /dev/null +++ b/arch/arm64/kernel/efistub-le/Makefile @@ -0,0 +1,52 @@ + +# +# Build a little endian EFI stub and wrap it into a single .o +# + +# the LE objects making up the LE efi stub +le-objs := efi-entry.o efi-stub.o strstr.o cache.o \ + lib-memchr.o lib-memcmp.o lib-memcpy.o lib-memmove.o \ + lib-memset.o lib-strchr.o lib-strlen.o lib-strncmp.o \ + fdt-fdt.o fdt-fdt_ro.o fdt-fdt_rw.o fdt-fdt_sw.o \ + fdt-fdt_wip.o fdt-fdt_empty_tree.o \ + libstub-fdt.o libstub-arm-stub.o libstub-efi-stub-helper.o + +extra-y := efi-le-stub.bin efi-le-stub.elf $(le-objs) + +KBUILD_CFLAGS := $(subst -pg,,$(KBUILD_CFLAGS)) -fno-stack-protector \ + -mlittle-endian -I$(srctree)/scripts/dtc/libfdt + +le-targets := $(addprefix $(obj)/, $(le-objs)) +$(le-targets): KBUILD_AFLAGS += -mlittle-endian -include $(srctree)/$(src)/le.h + +$(obj)/efi-entry.o: $(obj)/../efi-entry.S FORCE + $(call if_changed_dep,as_o_S) + +CFLAGS_efi-stub.o += -DTEXT_OFFSET=$(TEXT_OFFSET) +$(obj)/efi-stub.o: $(obj)/../efi-stub.c FORCE + $(call if_changed_dep,cc_o_c) + +$(obj)/cache.o: $(src)/../../mm/cache.S FORCE + $(call if_changed_dep,as_o_S) + +$(obj)/lib-%.o: $(src)/../../lib/%.S FORCE + $(call if_changed_dep,as_o_S) + +$(obj)/fdt-%.o: $(srctree)/lib/%.c FORCE + $(call if_changed_dep,cc_o_c) + +$(obj)/libstub-%.o: $(srctree)/drivers/firmware/efi/libstub/%.c FORCE + $(call if_changed_dep,cc_o_c) + +$(obj)/efi-le-stub.elf: LDFLAGS=-EL -Map $@.map -T +$(obj)/efi-le-stub.elf: $(src)/efistub-le.lds $(le-targets) FORCE + $(call if_changed,ld) + +$(obj)/efi-le-stub.bin: OBJCOPYFLAGS=-O binary +$(obj)/efi-le-stub.bin: $(obj)/efi-le-stub.elf FORCE + $(call if_changed,objcopy) + +# the BE object containing the entire LE stub +obj-y := efi-le-entry.o + +$(obj)/efi-le-entry.o: $(obj)/efi-le-stub.bin diff --git a/arch/arm64/kernel/efistub-le/efi-le-entry.S b/arch/arm64/kernel/efistub-le/efi-le-entry.S new file mode 100644 index 000000000000..f615430209e5 --- /dev/null +++ b/arch/arm64/kernel/efistub-le/efi-le-entry.S @@ -0,0 +1,13 @@ + +#include + + .text + .align 12 + .long _text - efi_stub_entry + .long linux_banner - efi_stub_entry + .quad _kernel_size_le + .quad stext_offset + .quad 0 +ENTRY(efi_stub_entry) + .incbin "arch/arm64/kernel/efistub-le/efi-le-stub.bin" +ENDPROC(efi_stub_entry) diff --git a/arch/arm64/kernel/efistub-le/efistub-le.lds b/arch/arm64/kernel/efistub-le/efistub-le.lds new file mode 100644 index 000000000000..20361c43aa2e --- /dev/null +++ b/arch/arm64/kernel/efistub-le/efistub-le.lds @@ -0,0 +1,35 @@ + +ENTRY(efi_stub_entry) + +SECTIONS { + /* + * The inner and outer alignment of this chunk of code need to be the + * same so that PC relative references using adrp/add or adrp/ldr pairs + * will work correctly. + * Skip 32 bytes here, so we can put the binary blob at an offset of + * 4k + 0x20 in the outer image, and use the gap to share constants + * emitted by the outer linker but required in the stub. + */ + .text 0x20 : { + arch/arm64/kernel/efistub-le/efi-entry.o(.init.text) + *(.init.text) + *(.text) + *(.text*) + } + .rodata : { + . = ALIGN(16); + *(.rodata) + *(.rodata*) + *(.init.rodata) + } + .data : { + . = ALIGN(16); + *(.data) + *(.data*) + le_linux_banner = .; + . += 8; + } + /DISCARD/ : { + *(__ex_table) + } +} diff --git a/arch/arm64/kernel/efistub-le/le.h b/arch/arm64/kernel/efistub-le/le.h new file mode 100644 index 000000000000..f4a28a5f6815 --- /dev/null +++ b/arch/arm64/kernel/efistub-le/le.h @@ -0,0 +1,12 @@ + +/* + * This is a bit of a hack, but it is necessary to correctly compile .S files + * that contain CPU_LE()/CPU_BE() statements, as these are defined to depend on + * CONFIG_ symbols and not on the endianness of the compiler. + */ +#ifdef CONFIG_CPU_BIG_ENDIAN +#define STUB_BE(code...) code +#else +#define STUB_BE(code...) +#endif +#undef CONFIG_CPU_BIG_ENDIAN diff --git a/arch/arm64/kernel/efistub-le/strstr.c b/arch/arm64/kernel/efistub-le/strstr.c new file mode 100644 index 000000000000..daed0bbcc0c6 --- /dev/null +++ b/arch/arm64/kernel/efistub-le/strstr.c @@ -0,0 +1,20 @@ + +#include +#include + +char *strstr(const char *s1, const char *s2) +{ + size_t l1, l2; + + l2 = strlen(s2); + if (!l2) + return (char *)s1; + l1 = strlen(s1); + while (l1 >= l2) { + l1--; + if (!memcmp(s1, s2, l2)) + return (char *)s1; + s1++; + } + return NULL; +} diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c index a56bb3528755..651c639a8a18 100644 --- a/drivers/firmware/efi/libstub/fdt.c +++ b/drivers/firmware/efi/libstub/fdt.c @@ -22,6 +22,10 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, unsigned long map_size, unsigned long desc_size, u32 desc_ver) { +#ifdef CONFIG_EFI_LE_STUB + extern char const *le_linux_banner; + char const *linux_banner = le_linux_banner; +#endif int node, prev; int status; u32 fdt_val32;