* [PATCH] mvebu : pcie: dt: potential issue in range parsing
From: Jason Cooper @ 2014-02-05 17:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140205164710.082f689e@skate>
+ Bjorn, linux-pci
Bjorn,
It looks like this didn't get Cc'd to linux-pci. Here's a link:
http://www.spinics.net/lists/arm-kernel/msg299721.html
On Wed, Feb 05, 2014 at 04:47:10PM +0100, Thomas Petazzoni wrote:
> Dear Jean-Jacques Hiblot,
>
> On Fri, 10 Jan 2014 11:23:51 +0100, Jean-Jacques Hiblot wrote:
> > The second parameter of of_read_number is not the index, but a size.
> > As it happens, in this case it may work just fine because of the the conversion
> > to u32 and the favorable endianness on this architecture.
> >
> > Signed-off-by: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
> > ---
> > drivers/pci/host/pci-mvebu.c | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c
> > index c269e43..877e8ce 100644
> > --- a/drivers/pci/host/pci-mvebu.c
> > +++ b/drivers/pci/host/pci-mvebu.c
> > @@ -768,7 +768,7 @@ static int mvebu_get_tgt_attr(struct device_node *np, int devfn,
> >
> > for (i = 0; i < nranges; i++) {
> > u32 flags = of_read_number(range, 1);
> > - u32 slot = of_read_number(range, 2);
> > + u32 slot = of_read_number(range + 1, 1);
> > u64 cpuaddr = of_read_number(range + na, pna);
> > unsigned long rtype;
> >
>
> Sorry for the long delay, and thanks for the fix!
>
> Acked-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
> Tested-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
>
> (on Armada 370, with PCIe cards plugged in)
Fixes: 11be65472a427 ("PCI: mvebu: Adapt to the new device tree layout")
Cc: <stable@vger.kernel.org> # v3.12+
Acked-by: Jason Cooper <jason@lakedaemon.net>
thx,
Jason.
^ permalink raw reply
* [PATCH] ARM: config: enable ams AS3722 power reset driver
From: Stephen Warren @ 2014-02-05 17:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1389084000-17033-1-git-send-email-ldewangan@nvidia.com>
On 01/07/2014 01:39 AM, Laxman Dewangan wrote:
> ams AS3722 is used as system PMIC for Tegra124 based Venice2.
> Enable ams AS3722 power reset driver for enabling power off
> system using PMIC.
Applied to Tegra's for-3.15/defconfig branch.
^ permalink raw reply
* [PATCH] ARM: tegra: add system-power-controller property for PMIC node
From: Stephen Warren @ 2014-02-05 17:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1389265308-26405-1-git-send-email-ldewangan@nvidia.com>
On 01/09/2014 04:01 AM, Laxman Dewangan wrote:
> Add system-power-controller property to system PMIC, ams AS3722,
> node to enable power off functionality through PMIC.
Applied to Tegra's for-3.15/dt branch.
^ permalink raw reply
* [PATCH v3 0/7] ARM: sunxi: Add driver for SD/MMC hosts found on allwinner sunxi SOCs
From: David Lanzendörfer @ 2014-02-05 17:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140205134741.3027.50207.stgit@dizzy-6.o2s.ch>
As Maxime has pointed out, I've forgotten to add a changelog
in my coverletter.
Here is, what has changed in this revision:
Changes since v1:
-Using mmc_of_parse instead of diy dt parsing
-Adding nodes for all mmc controller to the dtsi files, including sofar unused
controllers
-Using generic GPIO slot library
-Adding additional MMC device nodes into DTSI files
Changes since v2:
-Add missing Signed-off-by tags
-Stop using __raw_readl / __raw_writel so that barriers are properly used
-Adding missing new lines
-Adding missing patch for automatic reparenting of clocks
cheers
david
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140205/e80036de/attachment.sig>
^ permalink raw reply
* [PATCH] ARM: tegra: document which Dalmore revisions are supported
From: Stephen Warren @ 2014-02-05 17:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1389035749-15261-1-git-send-email-swarren@wwwdotorg.org>
On 01/06/2014 12:15 PM, Stephen Warren wrote:
> From: Stephen Warren <swarren@nvidia.com>
>
> There are a number of revisions of the Dalmore board, each with a variety
> of incompatible SW-visible HW changes. The Dalmore DT file in the kernel
> only supports HW revision A04. Document this in the DT file.
Applied to Tegra's for-3.15/dt branch.
^ permalink raw reply
* [PATCH] ARM: tegra: Properly sort clocks property
From: Stephen Warren @ 2014-02-05 17:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1389021642-5516-1-git-send-email-treding@nvidia.com>
On 01/06/2014 08:20 AM, Thierry Reding wrote:
> Other files and nodes list the resets property after the clocks property
> so do the same here for consistency.
Applied to Tegra's for-3.15/dt branch.
^ permalink raw reply
* [PATCH 2/2] ARM: tegra: paz00: Add LVDS support to device tree
From: Stephen Warren @ 2014-02-05 17:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <bcf12ecec69ef4e38e74a9be9c45e8bd2bd9ffcc.1387656959.git.marvin24@gmx.de>
On 12/21/2013 01:38 PM, Marc Dietrich wrote:
> Add backlight and panel nodes for the PAZ00 TFT LCD panel.
Applied to Tegra's for-3.15/dt branch.
^ permalink raw reply
* [PATCH v2 4/4] arm64: add Crypto Extensions based synchronous core AES cipher
From: Ard Biesheuvel @ 2014-02-05 17:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391620418-3999-1-git-send-email-ard.biesheuvel@linaro.org>
This implements the core AES cipher using the Crypto Extensions,
using only NEON registers q0 - q3.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/Makefile | 1 +
arch/arm64/crypto/Makefile | 13 ++++
arch/arm64/crypto/aes-ce-cipher.c | 134 ++++++++++++++++++++++++++++++++++++++
crypto/Kconfig | 6 ++
4 files changed, 154 insertions(+)
create mode 100644 arch/arm64/crypto/Makefile
create mode 100644 arch/arm64/crypto/aes-ce-cipher.c
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index 2fceb71ac3b7..8185a913c5ed 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -45,6 +45,7 @@ export TEXT_OFFSET GZFLAGS
core-y += arch/arm64/kernel/ arch/arm64/mm/
core-$(CONFIG_KVM) += arch/arm64/kvm/
core-$(CONFIG_XEN) += arch/arm64/xen/
+core-$(CONFIG_CRYPTO) += arch/arm64/crypto/
libs-y := arch/arm64/lib/ $(libs-y)
libs-y += $(LIBGCC)
diff --git a/arch/arm64/crypto/Makefile b/arch/arm64/crypto/Makefile
new file mode 100644
index 000000000000..ac58945c50b3
--- /dev/null
+++ b/arch/arm64/crypto/Makefile
@@ -0,0 +1,13 @@
+#
+# linux/arch/arm64/crypto/Makefile
+#
+# Copyright (C) 2013 Linaro Ltd <ard.biesheuvel@linaro.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+
+obj-$(CONFIG_CRYPTO_AES_ARM64_CE) += aes-ce-cipher.o
+
+CFLAGS_aes-ce-cipher.o += -march=armv8-a+crypto
diff --git a/arch/arm64/crypto/aes-ce-cipher.c b/arch/arm64/crypto/aes-ce-cipher.c
new file mode 100644
index 000000000000..6dd64106923f
--- /dev/null
+++ b/arch/arm64/crypto/aes-ce-cipher.c
@@ -0,0 +1,134 @@
+/*
+ * linux/arch/arm64/crypto/aes-ce-cipher.c
+ *
+ * Copyright (C) 2013 Linaro Ltd <ard.biesheuvel@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <asm/hwcap.h>
+#include <asm/neon.h>
+#include <crypto/aes.h>
+#include <linux/crypto.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+
+MODULE_DESCRIPTION("Synchronous AES cipher using ARMv8 Crypto Extensions");
+MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
+MODULE_LICENSE("GPL");
+
+static int num_rounds(struct crypto_aes_ctx *ctx)
+{
+ /*
+ * # of rounds specified by AES:
+ * 128 bit key 10 rounds
+ * 192 bit key 12 rounds
+ * 256 bit key 14 rounds
+ * => n byte key => 6 + (n/4) rounds
+ */
+ return 6 + ctx->key_length / 4;
+}
+
+static void aes_cipher_encrypt(struct crypto_tfm *tfm, u8 dst[], u8 const src[])
+{
+ struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ kernel_neon_begin_partial(4);
+
+ __asm__(" ld1 {v0.16b}, [%[in]] ;"
+ " cmp %[rounds], #10 ;"
+ " bmi 0f ;"
+ " bne 3f ;"
+ " ld1 {v3.2d}, [%[key]], #16 ;"
+ " b 2f ;"
+ "0: ld1 {v2.2d-v3.2d}, [%[key]], #32 ;"
+ "1: aese v0.16b, v2.16b ;"
+ " aesmc v0.16b, v0.16b ;"
+ "2: aese v0.16b, v3.16b ;"
+ " aesmc v0.16b, v0.16b ;"
+ "3: ld1 {v1.2d-v3.2d}, [%[key]], #48 ;"
+ " subs %[rounds], %[rounds], #3 ;"
+ " aese v0.16b, v1.16b ;"
+ " aesmc v0.16b, v0.16b ;"
+ " bpl 1b ;"
+ " aese v0.16b, v2.16b ;"
+ " eor v0.16b, v0.16b, v3.16b ;"
+ " st1 {v0.16b}, [%[out]] ;"
+ : :
+ [out] "r"(dst),
+ [in] "r"(src),
+ [rounds] "r"(num_rounds(ctx) - 2),
+ [key] "r"(ctx->key_enc)
+ : "cc", "memory");
+
+ kernel_neon_end();
+}
+
+static void aes_cipher_decrypt(struct crypto_tfm *tfm, u8 dst[], u8 const src[])
+{
+ struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ kernel_neon_begin_partial(4);
+
+ __asm__(" ld1 {v0.16b}, [%[in]] ;"
+ " cmp %[rounds], #10 ;"
+ " bmi 0f ;"
+ " bne 3f ;"
+ " ld1 {v3.2d}, [%[key]], #16 ;"
+ " b 2f ;"
+ "0: ld1 {v2.2d-v3.2d}, [%[key]], #32 ;"
+ "1: aesd v0.16b, v2.16b ;"
+ " aesimc v0.16b, v0.16b ;"
+ "2: aesd v0.16b, v3.16b ;"
+ " aesimc v0.16b, v0.16b ;"
+ "3: ld1 {v1.2d-v3.2d}, [%[key]], #48 ;"
+ " subs %[rounds], %[rounds], #3 ;"
+ " aesd v0.16b, v1.16b ;"
+ " aesimc v0.16b, v0.16b ;"
+ " bpl 1b ;"
+ " aesd v0.16b, v2.16b ;"
+ " eor v0.16b, v0.16b, v3.16b ;"
+ " st1 {v0.16b}, [%[out]] ;"
+ : :
+ [out] "r"(dst),
+ [in] "r"(src),
+ [rounds] "r"(num_rounds(ctx) - 2),
+ [key] "r"(ctx->key_dec)
+ : "cc", "memory");
+
+ kernel_neon_end();
+}
+
+static struct crypto_alg aes_alg = {
+ .cra_name = "aes",
+ .cra_driver_name = "aes-ce",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct crypto_aes_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_cipher = {
+ .cia_min_keysize = AES_MIN_KEY_SIZE,
+ .cia_max_keysize = AES_MAX_KEY_SIZE,
+ .cia_setkey = crypto_aes_set_key,
+ .cia_encrypt = aes_cipher_encrypt,
+ .cia_decrypt = aes_cipher_decrypt
+ }
+};
+
+static int __init aes_mod_init(void)
+{
+ if (!(elf_hwcap & HWCAP_AES))
+ return -ENODEV;
+ return crypto_register_alg(&aes_alg);
+}
+
+static void __exit aes_mod_exit(void)
+{
+ crypto_unregister_alg(&aes_alg);
+}
+
+module_init(aes_mod_init);
+module_exit(aes_mod_exit);
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 7bcb70d216e1..f1d98bc346b6 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -791,6 +791,12 @@ config CRYPTO_AES_ARM_BS
This implementation does not rely on any lookup tables so it is
believed to be invulnerable to cache timing attacks.
+config CRYPTO_AES_ARM64_CE
+ tristate "Synchronous AES cipher using ARMv8 Crypto Extensions"
+ depends on ARM64 && KERNEL_MODE_NEON
+ select CRYPTO_ALGAPI
+ select CRYPTO_AES
+
config CRYPTO_ANUBIS
tristate "Anubis cipher algorithm"
select CRYPTO_ALGAPI
--
1.8.3.2
^ permalink raw reply related
* [PATCH v2 3/4] arm64: add support for kernel mode NEON in interrupt context
From: Ard Biesheuvel @ 2014-02-05 17:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391620418-3999-1-git-send-email-ard.biesheuvel@linaro.org>
This patch modifies kernel_neon_begin() and kernel_neon_end(), so
they may be called from any context. To address the case where only
a couple of registers are needed, kernel_neon_begin_partial(u32) is
introduced which takes as a parameter the number of bottom 'n' NEON
q-registers required. To mark the end of such a partial section, the
regular kernel_neon_end() should be used.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/include/asm/fpsimd.h | 17 ++++++++++++++
arch/arm64/include/asm/fpsimdmacros.h | 37 ++++++++++++++++++++++++++++++
arch/arm64/include/asm/neon.h | 6 ++++-
arch/arm64/kernel/entry-fpsimd.S | 24 +++++++++++++++++++
arch/arm64/kernel/fpsimd.c | 43 +++++++++++++++++++++++------------
5 files changed, 112 insertions(+), 15 deletions(-)
diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index f7e70f3f1eb7..8c0f8d332528 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -41,6 +41,19 @@ struct fpsimd_state {
unsigned int last_cpu;
};
+/*
+ * Struct for stacking the bottom 'n' FP/SIMD registers.
+ * Mainly intended for kernel use of v8 Crypto Extensions which only
+ * needs a few registers and may need to execute in atomic context.
+ */
+struct fpsimd_partial_state {
+ u32 num_regs;
+ u32 fpsr;
+ u32 fpcr;
+ __uint128_t vregs[32] __aligned(16);
+} __aligned(16);
+
+
#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
/* Masks for extracting the FPSR and FPCR from the FPSCR */
#define VFP_FPSCR_STAT_MASK 0xf800009f
@@ -65,6 +78,10 @@ void fpsimd_set_user_state(struct task_struct *t, struct user_fpsimd_state *st);
void fpsimd_reload_fpstate(void);
+extern void fpsimd_save_partial_state(struct fpsimd_partial_state *state,
+ u32 num_regs);
+extern void fpsimd_load_partial_state(struct fpsimd_partial_state *state);
+
#endif
#endif
diff --git a/arch/arm64/include/asm/fpsimdmacros.h b/arch/arm64/include/asm/fpsimdmacros.h
index bbec599c96bd..42990a82c671 100644
--- a/arch/arm64/include/asm/fpsimdmacros.h
+++ b/arch/arm64/include/asm/fpsimdmacros.h
@@ -62,3 +62,40 @@
ldr w\tmpnr, [\state, #16 * 2 + 4]
msr fpcr, x\tmpnr
.endm
+
+.altmacro
+.macro q2op, op, q1, q2, state
+ \op q\q1, q\q2, [\state, # -16 * \q1 - 16]
+.endm
+
+.macro fpsimd_save_partial state, numnr, tmpnr1, tmpnr2
+ mrs x\tmpnr1, fpsr
+ str w\numnr, [\state]
+ mrs x\tmpnr2, fpcr
+ stp w\tmpnr1, w\tmpnr2, [\state, #4]
+ adr x\tmpnr1, 0f
+ add \state, \state, x\numnr, lsl #4
+ sub x\tmpnr1, x\tmpnr1, x\numnr, lsl #1
+ br x\tmpnr1
+ .irp qa, 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 0
+ qb = \qa + 1
+ q2op stp, \qa, %qb, \state
+ .endr
+0:
+.endm
+
+.macro fpsimd_restore_partial state, tmpnr1, tmpnr2
+ ldp w\tmpnr1, w\tmpnr2, [\state, #4]
+ msr fpsr, x\tmpnr1
+ msr fpcr, x\tmpnr2
+ adr x\tmpnr1, 0f
+ ldr w\tmpnr2, [\state]
+ add \state, \state, x\tmpnr2, lsl #4
+ sub x\tmpnr1, x\tmpnr1, x\tmpnr2, lsl #1
+ br x\tmpnr1
+ .irp qa, 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 0
+ qb = \qa + 1
+ q2op ldp, \qa, %qb, \state
+ .endr
+0:
+.endm
diff --git a/arch/arm64/include/asm/neon.h b/arch/arm64/include/asm/neon.h
index b0cc58a97780..13ce4cc18e26 100644
--- a/arch/arm64/include/asm/neon.h
+++ b/arch/arm64/include/asm/neon.h
@@ -8,7 +8,11 @@
* published by the Free Software Foundation.
*/
+#include <linux/types.h>
+
#define cpu_has_neon() (1)
-void kernel_neon_begin(void);
+#define kernel_neon_begin() kernel_neon_begin_partial(32)
+
+void kernel_neon_begin_partial(u32 num_regs);
void kernel_neon_end(void);
diff --git a/arch/arm64/kernel/entry-fpsimd.S b/arch/arm64/kernel/entry-fpsimd.S
index 6a27cd6dbfa6..d358ccacfc00 100644
--- a/arch/arm64/kernel/entry-fpsimd.S
+++ b/arch/arm64/kernel/entry-fpsimd.S
@@ -41,3 +41,27 @@ ENTRY(fpsimd_load_state)
fpsimd_restore x0, 8
ret
ENDPROC(fpsimd_load_state)
+
+#ifdef CONFIG_KERNEL_MODE_NEON
+
+/*
+ * Save the bottom n FP registers.
+ *
+ * x0 - pointer to struct fpsimd_partial_state
+ */
+ENTRY(fpsimd_save_partial_state)
+ fpsimd_save_partial x0, 1, 8, 9
+ ret
+ENDPROC(fpsimd_load_partial_state)
+
+/*
+ * Load the bottom n FP registers.
+ *
+ * x0 - pointer to struct fpsimd_partial_state
+ */
+ENTRY(fpsimd_load_partial_state)
+ fpsimd_restore_partial x0, 8, 9
+ ret
+ENDPROC(fpsimd_load_partial_state)
+
+#endif
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 239c8162473f..2ed92976ac16 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -188,29 +188,44 @@ void fpsimd_set_user_state(struct task_struct *t, struct user_fpsimd_state *st)
#ifdef CONFIG_KERNEL_MODE_NEON
+static DEFINE_PER_CPU(struct fpsimd_partial_state, hardirq_fpsimdstate);
+static DEFINE_PER_CPU(struct fpsimd_partial_state, softirq_fpsimdstate);
+
/*
* Kernel-side NEON support functions
*/
-void kernel_neon_begin(void)
+void kernel_neon_begin_partial(u32 num_regs)
{
- /* Avoid using the NEON in interrupt context */
- BUG_ON(in_interrupt());
- preempt_disable();
+ if (in_interrupt()) {
+ struct fpsimd_partial_state *s = this_cpu_ptr(
+ in_irq() ? &hardirq_fpsimdstate : &softirq_fpsimdstate);
- /*
- * Save the userland FPSIMD state if we have one and if we haven't done
- * so already. Clear fpsimd_last_task to indicate that there is no
- * longer userland context in the registers.
- */
- if (current->mm && !test_and_set_thread_flag(TIF_FOREIGN_FPSTATE))
- fpsimd_save_state(¤t->thread.fpsimd_state);
- __get_cpu_var(fpsimd_last_task) = NULL;
+ BUG_ON(num_regs > 32);
+ fpsimd_save_partial_state(s, roundup(num_regs, 2));
+ } else {
+ /*
+ * Save the userland FPSIMD state if we have one and if we
+ * haven't done so already. Clear fpsimd_last_task to indicate
+ * that there is no longer userland context in the registers.
+ */
+ preempt_disable();
+ if (current->mm &&
+ !test_and_set_thread_flag(TIF_FOREIGN_FPSTATE))
+ fpsimd_save_state(¤t->thread.fpsimd_state);
+ __get_cpu_var(fpsimd_last_task) = NULL;
+ }
}
-EXPORT_SYMBOL(kernel_neon_begin);
+EXPORT_SYMBOL(kernel_neon_begin_partial);
void kernel_neon_end(void)
{
- preempt_enable();
+ if (in_interrupt()) {
+ struct fpsimd_partial_state *s = this_cpu_ptr(
+ in_irq() ? &hardirq_fpsimdstate : &softirq_fpsimdstate);
+ fpsimd_load_partial_state(s);
+ } else {
+ preempt_enable();
+ }
}
EXPORT_SYMBOL(kernel_neon_end);
--
1.8.3.2
^ permalink raw reply related
* [PATCH v2 2/4] arm64: defer reloading a task's FPSIMD state to userland resume
From: Ard Biesheuvel @ 2014-02-05 17:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391620418-3999-1-git-send-email-ard.biesheuvel@linaro.org>
If a task gets scheduled out and back in again and nothing has touched
its FPSIMD state in the mean time, there is really no reason to reload
it from memory. Similarly, repeated calls to kernel_neon_begin() and
kernel_neon_end() will preserve and restore the FPSIMD state every time.
This patch defers the FPSIMD state restore to the last possible moment,
i.e., right before the task re-enters userland. If a task does not enter
userland at all (for any reason), the existing FPSIMD state is preserved
and may be reused by the owning task if it gets scheduled in again on the
same CPU.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/include/asm/fpsimd.h | 4 ++
arch/arm64/include/asm/thread_info.h | 4 +-
arch/arm64/kernel/entry.S | 2 +-
arch/arm64/kernel/fpsimd.c | 102 +++++++++++++++++++++++++++++------
arch/arm64/kernel/signal.c | 4 ++
5 files changed, 98 insertions(+), 18 deletions(-)
diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index 7807974b49ee..f7e70f3f1eb7 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -37,6 +37,8 @@ struct fpsimd_state {
u32 fpcr;
};
};
+ /* the id of the last cpu to have restored this state */
+ unsigned int last_cpu;
};
#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
@@ -61,6 +63,8 @@ void fpsimd_set_task_state(struct fpsimd_state *state);
struct user_fpsimd_state *fpsimd_get_user_state(struct task_struct *t);
void fpsimd_set_user_state(struct task_struct *t, struct user_fpsimd_state *st);
+void fpsimd_reload_fpstate(void);
+
#endif
#endif
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index 720e70b66ffd..4a1ca1cfb2f8 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -100,6 +100,7 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_SIGPENDING 0
#define TIF_NEED_RESCHED 1
#define TIF_NOTIFY_RESUME 2 /* callback before returning to user */
+#define TIF_FOREIGN_FPSTATE 3 /* CPU's FP state is not current's */
#define TIF_SYSCALL_TRACE 8
#define TIF_POLLING_NRFLAG 16
#define TIF_MEMDIE 18 /* is terminating due to OOM killer */
@@ -112,10 +113,11 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
+#define _TIF_FOREIGN_FPSTATE (1 << TIF_FOREIGN_FPSTATE)
#define _TIF_32BIT (1 << TIF_32BIT)
#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \
- _TIF_NOTIFY_RESUME)
+ _TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE)
#endif /* __KERNEL__ */
#endif /* __ASM_THREAD_INFO_H */
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 39ac630d83de..80464e2fb1a5 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -576,7 +576,7 @@ fast_work_pending:
str x0, [sp, #S_X0] // returned x0
work_pending:
tbnz x1, #TIF_NEED_RESCHED, work_resched
- /* TIF_SIGPENDING or TIF_NOTIFY_RESUME case */
+ /* TIF_SIGPENDING, TIF_NOTIFY_RESUME or TIF_FOREIGN_FPSTATE case */
ldr x2, [sp, #S_PSTATE]
mov x0, sp // 'regs'
tst x2, #PSR_MODE_MASK // user mode regs?
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index eeb003f54ad0..239c8162473f 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -39,6 +39,23 @@ void fpsimd_save_state(struct fpsimd_state *state);
void fpsimd_load_state(struct fpsimd_state *state);
/*
+ * In order to reduce the number of times the fpsimd state is needlessly saved
+ * and restored, keep track here of which task's userland owns the current state
+ * of the FPSIMD register file.
+ *
+ * This percpu variable points to the fpsimd_state.last_cpu field of the task
+ * whose FPSIMD state was most recently loaded onto this cpu. The last_cpu field
+ * itself contains the id of the cpu onto which the task's FPSIMD state was
+ * loaded most recently. So, to decide whether we can skip reloading the FPSIMD
+ * state, we need to check
+ * (a) whether this task was the last one to have its FPSIMD state loaded onto
+ * this cpu
+ * (b) whether this task may have manipulated its FPSIMD state on another cpu in
+ * the meantime
+ */
+static DEFINE_PER_CPU(unsigned int *, fpsimd_last_task);
+
+/*
* Trapped FP/ASIMD access.
*/
void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs)
@@ -76,36 +93,84 @@ void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs)
void fpsimd_thread_switch(struct task_struct *next)
{
- /* check if not kernel threads */
- if (current->mm)
+ /*
+ * The thread flag TIF_FOREIGN_FPSTATE conveys that the userland FPSIMD
+ * state belonging to the current task is not present in the registers
+ * but has (already) been saved to memory in order for the kernel to be
+ * able to go off and use the registers for something else. Therefore,
+ * we must not (re)save the register contents if this flag is set.
+ */
+ if (current->mm && !test_thread_flag(TIF_FOREIGN_FPSTATE))
fpsimd_save_state(¤t->thread.fpsimd_state);
- if (next->mm)
- fpsimd_load_state(&next->thread.fpsimd_state);
+
+ if (next->mm) {
+ /*
+ * If we are switching to a task whose most recent userland
+ * FPSIMD contents are already in the registers of *this* cpu,
+ * we can skip loading the state from memory. Otherwise, set
+ * the TIF_FOREIGN_FPSTATE flag so the state will be loaded
+ * upon the next entry of userland.
+ */
+ struct fpsimd_state *st = &next->thread.fpsimd_state;
+
+ if (__get_cpu_var(fpsimd_last_task) == &st->last_cpu
+ && st->last_cpu == smp_processor_id())
+ clear_ti_thread_flag(task_thread_info(next),
+ TIF_FOREIGN_FPSTATE);
+ else
+ set_ti_thread_flag(task_thread_info(next),
+ TIF_FOREIGN_FPSTATE);
+ }
}
void fpsimd_flush_thread(void)
{
- preempt_disable();
memset(¤t->thread.fpsimd_state, 0, sizeof(struct fpsimd_state));
- fpsimd_load_state(¤t->thread.fpsimd_state);
+ set_thread_flag(TIF_FOREIGN_FPSTATE);
+}
+
+/*
+ * Sync the FPSIMD register file with the saved FPSIMD context (if necessary)
+ */
+void fpsimd_reload_fpstate(void)
+{
+ preempt_disable();
+ if (test_and_clear_thread_flag(TIF_FOREIGN_FPSTATE)) {
+ struct fpsimd_state *st = ¤t->thread.fpsimd_state;
+
+ fpsimd_load_state(st);
+ __get_cpu_var(fpsimd_last_task) = &st->last_cpu;
+ st->last_cpu = smp_processor_id();
+ }
preempt_enable();
}
/*
- * Sync the saved FPSIMD context with the FPSIMD register file
+ * Sync the saved FPSIMD context with the FPSIMD register file (if necessary)
*/
struct fpsimd_state *fpsimd_get_task_state(void)
{
- fpsimd_save_state(¤t->thread.fpsimd_state);
+ preempt_disable();
+ if (!test_thread_flag(TIF_FOREIGN_FPSTATE))
+ fpsimd_save_state(¤t->thread.fpsimd_state);
+ preempt_enable();
return ¤t->thread.fpsimd_state;
}
/*
- * Load a new FPSIMD state into the FPSIMD register file.
+ * Load a new FPSIMD state into the FPSIMD register file, and clear the
+ * TIF_FOREIGN_FPSTATE flag to convey that the register content is now
+ * owned by 'current'. To be called with preemption disabled.
*/
void fpsimd_set_task_state(struct fpsimd_state *state)
{
fpsimd_load_state(state);
+ if (test_and_clear_thread_flag(TIF_FOREIGN_FPSTATE)) {
+ struct fpsimd_state *st = ¤t->thread.fpsimd_state;
+
+ __get_cpu_var(fpsimd_last_task) = &st->last_cpu;
+ st->last_cpu = smp_processor_id();
+ }
}
struct user_fpsimd_state *fpsimd_get_user_state(struct task_struct *t)
@@ -116,6 +181,9 @@ struct user_fpsimd_state *fpsimd_get_user_state(struct task_struct *t)
void fpsimd_set_user_state(struct task_struct *t, struct user_fpsimd_state *st)
{
t->thread.fpsimd_state.user_fpsimd = *st;
+
+ /* invalidate potential live copies of this FPSIMD state */
+ t->thread.fpsimd_state.last_cpu = NR_CPUS;
}
#ifdef CONFIG_KERNEL_MODE_NEON
@@ -129,16 +197,19 @@ void kernel_neon_begin(void)
BUG_ON(in_interrupt());
preempt_disable();
- if (current->mm)
+ /*
+ * Save the userland FPSIMD state if we have one and if we haven't done
+ * so already. Clear fpsimd_last_task to indicate that there is no
+ * longer userland context in the registers.
+ */
+ if (current->mm && !test_and_set_thread_flag(TIF_FOREIGN_FPSTATE))
fpsimd_save_state(¤t->thread.fpsimd_state);
+ __get_cpu_var(fpsimd_last_task) = NULL;
}
EXPORT_SYMBOL(kernel_neon_begin);
void kernel_neon_end(void)
{
- if (current->mm)
- fpsimd_load_state(¤t->thread.fpsimd_state);
-
preempt_enable();
}
EXPORT_SYMBOL(kernel_neon_end);
@@ -151,12 +222,11 @@ static int fpsimd_cpu_pm_notifier(struct notifier_block *self,
{
switch (cmd) {
case CPU_PM_ENTER:
- if (current->mm)
+ if (current->mm && !test_thread_flag(TIF_FOREIGN_FPSTATE))
fpsimd_save_state(¤t->thread.fpsimd_state);
break;
case CPU_PM_EXIT:
- if (current->mm)
- fpsimd_load_state(¤t->thread.fpsimd_state);
+ set_thread_flag(TIF_FOREIGN_FPSTATE);
break;
case CPU_PM_ENTER_FAILED:
default:
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 54e1092c5b4c..68d2957e5ebe 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -416,4 +416,8 @@ asmlinkage void do_notify_resume(struct pt_regs *regs,
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(regs);
}
+
+ if (thread_flags & _TIF_FOREIGN_FPSTATE)
+ fpsimd_reload_fpstate();
+
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH v2 1/4] arm64: add abstractions for FPSIMD state manipulation
From: Ard Biesheuvel @ 2014-02-05 17:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391620418-3999-1-git-send-email-ard.biesheuvel@linaro.org>
This is a preparatory patch that replaces code that saves or restores the
on-CPU or preserved FPSIMD state directly with wrapper functions, resulting
in all direct manipulation of the FPSIMD state to be concentrated in fpsimd.c
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/include/asm/fpsimd.h | 9 ++++++---
arch/arm64/kernel/fpsimd.c | 31 +++++++++++++++++++++++++++++++
arch/arm64/kernel/process.c | 2 +-
arch/arm64/kernel/ptrace.c | 22 +++++++++++++---------
arch/arm64/kernel/signal.c | 6 +++---
arch/arm64/kernel/signal32.c | 6 +++---
6 files changed, 57 insertions(+), 19 deletions(-)
diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index c43b4ac13008..7807974b49ee 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -52,12 +52,15 @@ struct fpsimd_state {
struct task_struct;
-extern void fpsimd_save_state(struct fpsimd_state *state);
-extern void fpsimd_load_state(struct fpsimd_state *state);
-
extern void fpsimd_thread_switch(struct task_struct *next);
extern void fpsimd_flush_thread(void);
+struct fpsimd_state *fpsimd_get_task_state(void);
+void fpsimd_set_task_state(struct fpsimd_state *state);
+
+struct user_fpsimd_state *fpsimd_get_user_state(struct task_struct *t);
+void fpsimd_set_user_state(struct task_struct *t, struct user_fpsimd_state *st);
+
#endif
#endif
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 4aef42a04bdc..eeb003f54ad0 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -34,6 +34,10 @@
#define FPEXC_IXF (1 << 4)
#define FPEXC_IDF (1 << 7)
+/* defined in entry-fpsimd.S but only used in this unit */
+void fpsimd_save_state(struct fpsimd_state *state);
+void fpsimd_load_state(struct fpsimd_state *state);
+
/*
* Trapped FP/ASIMD access.
*/
@@ -87,6 +91,33 @@ void fpsimd_flush_thread(void)
preempt_enable();
}
+/*
+ * Sync the saved FPSIMD context with the FPSIMD register file
+ */
+struct fpsimd_state *fpsimd_get_task_state(void)
+{
+ fpsimd_save_state(¤t->thread.fpsimd_state);
+ return ¤t->thread.fpsimd_state;
+}
+
+/*
+ * Load a new FPSIMD state into the FPSIMD register file.
+ */
+void fpsimd_set_task_state(struct fpsimd_state *state)
+{
+ fpsimd_load_state(state);
+}
+
+struct user_fpsimd_state *fpsimd_get_user_state(struct task_struct *t)
+{
+ return &t->thread.fpsimd_state.user_fpsimd;
+}
+
+void fpsimd_set_user_state(struct task_struct *t, struct user_fpsimd_state *st)
+{
+ t->thread.fpsimd_state.user_fpsimd = *st;
+}
+
#ifdef CONFIG_KERNEL_MODE_NEON
/*
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index 1c0a9be2ffa8..bfa8214f92d1 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -199,7 +199,7 @@ void release_thread(struct task_struct *dead_task)
int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
{
- fpsimd_save_state(¤t->thread.fpsimd_state);
+ fpsimd_get_task_state();
*dst = *src;
return 0;
}
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 6a8928bba03c..d0b35af14539 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -500,8 +500,7 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
{
- struct user_fpsimd_state *uregs;
- uregs = &target->thread.fpsimd_state.user_fpsimd;
+ struct user_fpsimd_state *uregs = fpsimd_get_user_state(target);
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, -1);
}
@@ -516,7 +515,7 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset,
if (ret)
return ret;
- target->thread.fpsimd_state.user_fpsimd = newstate;
+ fpsimd_set_user_state(target, &newstate);
return ret;
}
@@ -723,7 +722,7 @@ static int compat_vfp_get(struct task_struct *target,
compat_ulong_t fpscr;
int ret;
- uregs = &target->thread.fpsimd_state.user_fpsimd;
+ uregs = fpsimd_get_user_state(target);
/*
* The VFP registers are packed into the fpsimd_state, so they all sit
@@ -746,24 +745,29 @@ static int compat_vfp_set(struct task_struct *target,
unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
{
- struct user_fpsimd_state *uregs;
+ struct user_fpsimd_state newstate;
compat_ulong_t fpscr;
int ret;
if (pos + count > VFP_STATE_SIZE)
return -EIO;
- uregs = &target->thread.fpsimd_state.user_fpsimd;
+ /*
+ * We will not overwrite the entire FPSIMD state, so we need to
+ * initialize 'newstate' with sane values.
+ */
+ newstate = *fpsimd_get_user_state(target);
- ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0,
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newstate, 0,
VFP_STATE_SIZE - sizeof(compat_ulong_t));
if (count && !ret) {
ret = get_user(fpscr, (compat_ulong_t *)ubuf);
- uregs->fpsr = fpscr & VFP_FPSCR_STAT_MASK;
- uregs->fpcr = fpscr & VFP_FPSCR_CTRL_MASK;
+ newstate.fpsr = fpscr & VFP_FPSCR_STAT_MASK;
+ newstate.fpcr = fpscr & VFP_FPSCR_CTRL_MASK;
}
+ fpsimd_set_user_state(target, &newstate);
return ret;
}
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 890a591f75dd..54e1092c5b4c 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -47,11 +47,11 @@ struct rt_sigframe {
static int preserve_fpsimd_context(struct fpsimd_context __user *ctx)
{
- struct fpsimd_state *fpsimd = ¤t->thread.fpsimd_state;
+ struct fpsimd_state *fpsimd;
int err;
/* dump the hardware registers to the fpsimd_state structure */
- fpsimd_save_state(fpsimd);
+ fpsimd = fpsimd_get_task_state();
/* copy the FP and status/control registers */
err = __copy_to_user(ctx->vregs, fpsimd->vregs, sizeof(fpsimd->vregs));
@@ -88,7 +88,7 @@ static int restore_fpsimd_context(struct fpsimd_context __user *ctx)
/* load the hardware registers from the fpsimd_state structure */
if (!err) {
preempt_disable();
- fpsimd_load_state(&fpsimd);
+ fpsimd_set_task_state(&fpsimd);
preempt_enable();
}
diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
index b3fc9f5ec6d3..88e4535c3a45 100644
--- a/arch/arm64/kernel/signal32.c
+++ b/arch/arm64/kernel/signal32.c
@@ -208,7 +208,7 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
*/
static int compat_preserve_vfp_context(struct compat_vfp_sigframe __user *frame)
{
- struct fpsimd_state *fpsimd = ¤t->thread.fpsimd_state;
+ struct fpsimd_state *fpsimd;
compat_ulong_t magic = VFP_MAGIC;
compat_ulong_t size = VFP_STORAGE_SIZE;
compat_ulong_t fpscr, fpexc;
@@ -219,7 +219,7 @@ static int compat_preserve_vfp_context(struct compat_vfp_sigframe __user *frame)
* Note that this also saves V16-31, which aren't visible
* in AArch32.
*/
- fpsimd_save_state(fpsimd);
+ fpsimd = fpsimd_get_task_state();
/* Place structure header on the stack */
__put_user_error(magic, &frame->magic, err);
@@ -284,7 +284,7 @@ static int compat_restore_vfp_context(struct compat_vfp_sigframe __user *frame)
*/
if (!err) {
preempt_disable();
- fpsimd_load_state(&fpsimd);
+ fpsimd_set_task_state(&fpsimd);
preempt_enable();
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH v2 0/4] kernel mode NEON optimizations
From: Ard Biesheuvel @ 2014-02-05 17:13 UTC (permalink / raw)
To: linux-arm-kernel
The main purpose of this series is to allow Crypto Extensions instructions to be
used in interrupt context. For instance, the WPA2 CCMP handling (i.e., AES-128
in CCM mode) in the mac80211 layer runs entirely in softirq context.
Patch #1 does some preparatory work so all code external to kernel/fpsimd.c uses
accessor functions to manipulate both the on-CPU and preserved FPSIMD states
rather than poking them directly.
Patch #2 implements an optimization that reduces the number of times the
userland FPSIMD state is needlessly preserved and restored.
Patch #3 modifies kernel_neon_begin() and kernel_neon_end() so they may be
called from interrupt context.
Patch #4 contains the actual AES implementation, updated to reflect some recent
feedback I received when I posted it separately from this series.
Changes since previous version:
- added preparatory patch #1
- based on feedback from Will Deacon, make sure ptrace() and return from signal
handler cases are covered.
Mildly but not yet thoroughly tested.
All feedback highly appreciated.
Ard Biesheuvel (4):
arm64: add abstractions for FPSIMD state manipulation
arm64: defer reloading a task's FPSIMD state to userland resume
arm64: add support for kernel mode NEON in interrupt context
arm64: add Crypto Extensions based synchronous core AES cipher
arch/arm64/Makefile | 1 +
arch/arm64/crypto/Makefile | 13 +++
arch/arm64/crypto/aes-ce-cipher.c | 134 +++++++++++++++++++++++++++++
arch/arm64/include/asm/fpsimd.h | 30 ++++++-
arch/arm64/include/asm/fpsimdmacros.h | 37 ++++++++
arch/arm64/include/asm/neon.h | 6 +-
arch/arm64/include/asm/thread_info.h | 4 +-
arch/arm64/kernel/entry-fpsimd.S | 24 ++++++
arch/arm64/kernel/entry.S | 2 +-
arch/arm64/kernel/fpsimd.c | 156 +++++++++++++++++++++++++++++-----
arch/arm64/kernel/process.c | 2 +-
arch/arm64/kernel/ptrace.c | 22 +++--
arch/arm64/kernel/signal.c | 10 ++-
arch/arm64/kernel/signal32.c | 6 +-
crypto/Kconfig | 6 ++
15 files changed, 411 insertions(+), 42 deletions(-)
create mode 100644 arch/arm64/crypto/Makefile
create mode 100644 arch/arm64/crypto/aes-ce-cipher.c
--
1.8.3.2
^ permalink raw reply
* [GIT PULL] clk: socfpga: Clock updates for v3.15
From: dinguyen at altera.com @ 2014-02-05 17:12 UTC (permalink / raw)
To: linux-arm-kernel
Hi Mike,
Please consider pull these patch for v3.15.
Thanks,
Dinh
The following changes since commit 38dbfb59d1175ef458d006556061adeaa8751b72:
Linus 3.14-rc1 (2014-02-02 16:42:13 -0800)
are available in the git repository at:
git://git.rocketboards.org/linux-socfpga-next.git tags/socfpga-clk-for-3.15
for you to fetch changes up to 5d81b6fc5ee1d904f9e3faab3a80cee36d267136:
clk: socfpga: Add a clk-phase property to the "altr,socfpga-gate-clk" (2014-02-05 11:05:09 -0600)
----------------------------------------------------------------
SOCFPGA clk updates for v3.15
----------------------------------------------------------------
Dinh Nguyen (4):
clk: socfpga: Map the clk manager base address in the clock driver
clk: socfpga: Look for the GPIO_DB_CLK by its offset
clk: socfpga: Remove socfpga_init_clocks
clk: socfpga: Add a clk-phase property to the "altr,socfpga-gate-clk"
Steffen Trumtrar (3):
clk: socfpga: remove unused field
clk: socfpga: fix define typo
clk: socfpga: split clk code
.../devicetree/bindings/clock/altr_socfpga.txt | 5 +
arch/arm/boot/dts/socfpga.dtsi | 1 +
arch/arm/mach-socfpga/socfpga.c | 5 -
drivers/clk/socfpga/Makefile | 3 +
drivers/clk/socfpga/clk-gate.c | 263 ++++++++++++++++
drivers/clk/socfpga/clk-periph.c | 94 ++++++
drivers/clk/socfpga/clk-pll.c | 111 +++++++
drivers/clk/socfpga/clk.c | 326 +-------------------
drivers/clk/socfpga/clk.h | 57 ++++
9 files changed, 546 insertions(+), 319 deletions(-)
create mode 100644 drivers/clk/socfpga/clk-gate.c
create mode 100644 drivers/clk/socfpga/clk-periph.c
create mode 100644 drivers/clk/socfpga/clk-pll.c
create mode 100644 drivers/clk/socfpga/clk.h
^ permalink raw reply
* How to support SDIO wifi/bt in DT
From: Mark Brown @ 2014-02-05 17:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140117104423.GR17530@lunn.ch>
On Fri, Jan 17, 2014 at 11:44:23AM +0100, Andrew Lunn wrote:
> I've not looked at regulators, but i would hope it also does reference
> counting of a regulators users.
Yes, it does.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140205/3a80d2b9/attachment.sig>
^ permalink raw reply
* [PATCH] ARM: OMAP4: hwmod: Fix SOFTRESET logic for OMAP4
From: Grygorii Strashko @ 2014-02-05 17:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391612769-27890-1-git-send-email-illia.smyrnov@globallogic.com>
Hi All,
On 02/05/2014 05:06 PM, Illia Smyrnov wrote:
> Commit 313a76e (ARM: OMAP2+: hwmod: Fix SOFTRESET logic) introduced
> softreset bit cleaning right after set one. It is caused L3 error for
> OMAP4 ISS because ISS register write occurs when ISS reset process is in
> progress. Avoid this situation by cleaning softreset bit later, when reset
> process is successfully finished.
I'd like to mention that this issue has been caught while upgrading
custom Linux Kernel 3.4 to the last Stable Kernel linux-3.4.y.
So, the same OMAP4+ functionality can be broken in all Stable trees
where commit "ARM: OMAP2+: hwmod: Fix SOFTRESET logic" was merged to.
On OMAP4+ we should always try to wait until IP reset is finished before proceed.
Reviewed-by: "Grygorii Strashko <grygorii.strashko@ti.com>"
Error log example (k3.4):
[ 5766.575347] ------------[ cut here ]------------
[ 5766.580749] WARNING: at arch/arm/mach-omap2/omap_l3_noc.c:97 l3_interrupt_handler+0xc0/0x170()
[ 5766.590209] L3 standard error: TARGET:ISS at address 0x10
[ 5766.596435] Modules linked in: wlcore_sdio(O) wl18xx(O) wl12xx(O) wlcore(O) mac80211(O) pvrsrvkm_sgx544_112(O) cfg80211(O) compat(O)
[ 5766.611022] Backtrace:
[ 5766.614013] [<c00180ec>] (dump_backtrace+0x0/0x10c) from [<c065d448>] (dump_stack+0x18/0x1c)
[ 5766.623413] r6:c003a19c r5:00000009 r4:c0921d80 r3:c0982f10
[ 5766.630340] [<c065d430>] (dump_stack+0x0/0x1c) from [<c0046cf4>] (warn_slowpath_common+0x54/0x6c)
[ 5766.640258] [<c0046ca0>] (warn_slowpath_common+0x0/0x6c) from [<c0046db0>] (warn_slowpath_fmt+0x38/0x40)
[ 5766.650787] r8:00000000 r7:00000018 r6:c06712c4 r5:80080001 r4:e08f4400
[ 5766.658630] r3:00000009
[ 5766.661926] [<c0046d78>] (warn_slowpath_fmt+0x0/0x40) from [<c003a19c>] (l3_interrupt_handler+0xc0/0x170)
[ 5766.672546] r3:c080790c r2:c0807858
[ 5766.676910] [<c003a0dc>] (l3_interrupt_handler+0x0/0x170) from [<c00a8bc0>] (handle_irq_event_percpu+0x64/0x2b0)
[ 5766.688201] r8:00000000 r7:0000002a r6:0000002a r5:c0924190 r4:d6cbeac0
[ 5766.696533] [<c00a8b5c>] (handle_irq_event_percpu+0x0/0x2b0) from [<c00a8e50>] (handle_irq_event+0x44/0x64)
[ 5766.707244] [<c00a8e0c>] (handle_irq_event+0x0/0x64) from [<c00abb80>] (handle_fasteoi_irq+0xa0/0x160)
[ 5766.717620] r6:c0920000 r5:c0924190 r4:c0924140 r3:00000000
[ 5766.724639] [<c00abae0>] (handle_fasteoi_irq+0x0/0x160) from [<c00a83ac>] (generic_handle_irq+0x30/0x44)
[ 5766.735198] r5:c091e538 r4:c0946d40
[ 5766.739562] [<c00a837c>] (generic_handle_irq+0x0/0x44) from [<c0014b88>] (handle_IRQ+0x54/0xb8)
[ 5766.749267] [<c0014b34>] (handle_IRQ+0x0/0xb8) from [<c00084d0>] (gic_handle_irq+0x2c/0x60)
[ 5766.758453] r8:00000000 r7:c0921ed4 r6:c0921ea0 r5:c0945a00 r4:e0802100
[ 5766.766448] r3:c008aeb8
[ 5766.769744] [<c00084a4>] (gic_handle_irq+0x0/0x60) from [<c06678c0>] (__irq_svc+0x40/0x70)
[ 5766.778991] Exception stack(0xc0921ea0 to 0xc0921ee8)
[ 5766.784637] 1ea0: c0921ee8 000be65e a237f8b7 0000053e a2378182 0000053e c1858498 00000000
[ 5766.793762] 1ec0: 00000000 c095645c c0a3350c c0921f14 00001686 c0921ee8 c008aeb8 c042e5b4
[ 5766.802886] 1ee0: 60070013 ffffffff
[ 5766.806823] r6:ffffffff r5:60070013 r4:c042e5b4 r3:c008aeb8
[ 5766.813903] [<c042e564>] (cpuidle_wrap_enter+0x0/0x9c) from [<c042db94>] (cpuidle_enter_tk+0x18/0x1c)
[ 5766.824035] r7:c09c35b4 r6:c1858498 r5:00000000 r4:c1858498
[ 5766.830963] [<c042db7c>] (cpuidle_enter_tk+0x0/0x1c) from [<c042e0b0>] (cpuidle_enter_state+0x1c/0x78)
[ 5766.841339] [<c042e094>] (cpuidle_enter_state+0x0/0x78) from [<c042e1ec>] (cpuidle_idle_call+0xe0/0x31c)
[ 5766.851898] r6:c0920000 r5:00000000 r4:c1858498 r3:0000004c
[ 5766.858825] [<c042e10c>] (cpuidle_idle_call+0x0/0x31c) from [<c00152b4>] (cpu_idle+0xa4/0x10c)
[ 5766.868438] [<c0015210>] (cpu_idle+0x0/0x10c) from [<c063ce50>] (rest_init+0x74/0x8c)
[ 5766.877227] [<c063cddc>] (rest_init+0x0/0x8c) from [<c08c7864>] (start_kernel+0x2b4/0x304)
[ 5766.886352] r4:c0946b20 r3:c0982f10
[ 5766.890808] [<c08c75b0>] (start_kernel+0x0/0x304) from [<80008044>] (0x80008044)
[ 5766.898986] Board Information:
[ 5766.898986] Revision : 20edb4
[ 5766.899017] Serial : 0000000000000000
[ 5766.899017] SoC Information:
[ 5766.899017] CPU : OMAP4470
[ 5766.899017] Rev : ES1.0
[ 5766.899047] Type : HS
[ 5766.899047] Production ID: 0002B975-000000CC
[ 5766.899047] Die ID : 76080000-30002FFF-01518C70-0D00F007
[ 5766.899047]
[ 5766.935028] ---[ end trace 5f7d6da5db258915 ]---
[ 5766.948150] virtio_rpmsg_bus virtio1: destroying channel rpmsg-resmgr addr 0x66
[ 5767.098541] virtio_rpmsg_bus virtio1: creating channel rpmsg-resmgr addr 0x66
[ 5769.519683] ------------[ cut here ]------------
[ 5769.524749] WARNING: at arch/arm/mach-omap2/omap_l3_noc.c:97 l3_interrupt_handler+0xc0/0x170()
[ 5769.534149] L3 standard error: TARGET:ISS at address 0x10
[ 5769.540100] Modules linked in: wlcore_sdio(O) wl18xx(O) wl12xx(O) wlcore(O) mac80211(O) pvrsrvkm_sgx544_112(O) cfg80211(O) compat(O)
[ 5769.553802] Backtrace:
[ 5769.556610] [<c00180ec>] (dump_backtrace+0x0/0x10c) from [<c065d448>] (dump_stack+0x18/0x1c)
[ 5769.565734] r6:c003a19c r5:00000009 r4:ca453a68 r3:c0982f10
[ 5769.572296] [<c065d430>] (dump_stack+0x0/0x1c) from [<c0046cf4>] (warn_slowpath_common+0x54/0x6c)
[ 5769.581970] [<c0046ca0>] (warn_slowpath_common+0x0/0x6c) from [<c0046db0>] (warn_slowpath_fmt+0x38/0x40)
[ 5769.592285] r8:00000000 r7:00000018 r6:c06712c4 r5:80080001 r4:e08f4400
[ 5769.599700] r3:00000009
[ 5769.602783] [<c0046d78>] (warn_slowpath_fmt+0x0/0x40) from [<c003a19c>] (l3_interrupt_handler+0xc0/0x170)
[ 5769.613189] r3:c080790c r2:c0807858
[ 5769.617340] [<c003a0dc>] (l3_interrupt_handler+0x0/0x170) from [<c00a8bc0>] (handle_irq_event_percpu+0x64/0x2b0)
[ 5769.628356] r8:00000000 r7:0000002a r6:0000002a r5:c0924190 r4:d6cbeac0
[ 5769.636108] [<c00a8b5c>] (handle_irq_event_percpu+0x0/0x2b0) from [<c00a8e50>] (handle_irq_event+0x44/0x64)
[ 5769.646728] [<c00a8e0c>] (handle_irq_event+0x0/0x64) from [<c00abb80>] (handle_fasteoi_irq+0xa0/0x160)
[ 5769.656860] r6:ca452000 r5:c0924190 r4:c0924140 r3:00000000
[ 5769.663360] [<c00abae0>] (handle_fasteoi_irq+0x0/0x160) from [<c00a83ac>] (generic_handle_irq+0x30/0x44)
[ 5769.673675] r5:c091e538 r4:c0946d40
[ 5769.677764] [<c00a837c>] (generic_handle_irq+0x0/0x44) from [<c0014b88>] (handle_IRQ+0x54/0xb8)
[ 5769.687255] [<c0014b34>] (handle_IRQ+0x0/0xb8) from [<c00084d0>] (gic_handle_irq+0x2c/0x60)
[ 5769.696380] r8:d6cf3f40 r7:ca453bbc r6:ca453b88 r5:c0945a00 r4:e0802100
[ 5769.703857] r3:c0029070
[ 5769.706909] [<c00084a4>] (gic_handle_irq+0x0/0x60) from [<c06678c0>] (__irq_svc+0x40/0x70)
[ 5769.715881] Exception stack(0xca453b88 to 0xca453bd0)
[ 5769.721435] 3b80: c0964d98 a0000013 00000010 00000000 00000000 c0964d98
[ 5769.730377] 3ba0: a0000013 d6cf3f40 d6cf3f40 3b9aca00 00000000 ca453bdc ca453be0 ca453bd0
[ 5769.739227] 3bc0: c0029070 c0666d68 60000013 ffffffff
[ 5769.744781] r6:ffffffff r5:60000013 r4:c0666d68 r3:c0029070
[ 5769.751281] [<c0666d44>] (_raw_spin_unlock_irqrestore+0x0/0x50) from [<c0029070>] (omap_hwmod_reset+0x3c/0x4c)
[ 5769.762176] [<c0029034>] (omap_hwmod_reset+0x0/0x4c) from [<c0024d30>] (omap_cam_deactivate+0x30/0x48)
[ 5769.772308] r6:d6cf3fc0 r5:d6cf3fc0 r4:00000001 r3:d6cf3f80
[ 5769.778869] [<c0024d00>] (omap_cam_deactivate+0x0/0x48) from [<c0040bc4>] (_omap_device_deactivate+0xb4/0x14c)
[ 5769.789703] r5:d6cf1608 r4:d6cf3fc0
[ 5769.793853] [<c0040b10>] (_omap_device_deactivate+0x0/0x14c) from [<c0041434>] (omap_device_idle+0x30/0x5c)
[ 5769.804473] [<c0041404>] (omap_device_idle+0x0/0x5c) from [<c0041520>] (omap_device_runtime_suspend+0x24/0x2c)
[ 5769.815277] r4:00000000 r3:00000000
[ 5769.819396] [<c00414fc>] (omap_device_runtime_suspend+0x0/0x2c) from [<c02f1d5c>] (__rpm_callback+0x3c/0x78)
[ 5769.830078] r5:d6cf1668 r4:d6cf1608
[ 5769.834167] [<c02f1d20>] (__rpm_callback+0x0/0x78) from [<c02f2270>] (rpm_suspend+0x254/0x728)
[ 5769.843566] r6:00000000 r5:00000000 r4:d6cf1608 r3:c09827ec
[ 5769.850067] [<c02f201c>] (rpm_suspend+0x0/0x728) from [<c02f385c>] (__pm_runtime_suspend+0x60/0x84)
[ 5769.859924] [<c02f37fc>] (__pm_runtime_suspend+0x0/0x84) from [<c02eea28>] (pm_generic_runtime_idle+0x4c/0x58)
[ 5769.870819] r7:60000013 r6:c0040978 r5:d6cf1668 r4:d6cf1608
[ 5769.877319] [<c02ee9dc>] (pm_generic_runtime_idle+0x0/0x58) from [<c0040988>] (_od_runtime_idle+0x10/0x14)
[ 5769.887817] r4:d6cf1608 r3:00000000
[ 5769.891967] [<c0040978>] (_od_runtime_idle+0x0/0x14) from [<c02f1d5c>] (__rpm_callback+0x3c/0x78)
[ 5769.901580] [<c02f1d20>] (__rpm_callback+0x0/0x78) from [<c02f28c0>] (rpm_idle+0x100/0x290)
[ 5769.910675] r6:00000000 r5:00000004 r4:d6cf1608 r3:00000088
[ 5769.917236] [<c02f27c0>] (rpm_idle+0x0/0x290) from [<c02f2b2c>] (__pm_runtime_idle+0x60/0x84)
[ 5769.926452] r8:ce7b2c00 r7:60000013 r6:d6cf1668 r5:00000004 r4:d6cf1608
[ 5769.933959] r3:d6cf16ec
[ 5769.937042] [<c02f2acc>] (__pm_runtime_idle+0x0/0x84) from [<c0473100>] (_device_release+0x34/0x38)
[ 5769.946899] r7:cf2a3288 r6:ce7b2c08 r5:d6cf1608 r4:d5f9b440
[ 5769.953460] [<c04730cc>] (_device_release+0x0/0x38) from [<c0473b74>] (rprm_iss_release+0x10/0x38)
[ 5769.963165] r5:ce7b2c08 r4:cf2a32c0
[ 5769.967315] [<c0473b64>] (rprm_iss_release+0x0/0x38) from [<c0471f90>] (_resource_release+0x40/0xdc)
[ 5769.977172] r4:cf2a32c0 r3:c0473b64
[ 5769.981323] [<c0471f50>] (_resource_release+0x0/0xdc) from [<c04722f8>] (rprm_cb+0x270/0x680)
[ 5769.990631] r6:00000000 r5:ce7b2c08 r4:cf2a32a0 r3:00000000
[ 5769.997131] [<c0472088>] (rprm_cb+0x0/0x680) from [<c0470e50>] (rpmsg_recv_done+0x108/0x220)
[ 5770.006347] [<c0470d48>] (rpmsg_recv_done+0x0/0x220) from [<c02ab2f8>] (vring_interrupt+0x40/0x58)
[ 5770.016113] [<c02ab2b8>] (vring_interrupt+0x0/0x58) from [<c046f728>] (rproc_vq_interrupt+0x3c/0x50)
[ 5770.026000] [<c046f6ec>] (rproc_vq_interrupt+0x0/0x50) from [<c04707c4>] (_vq_interrupt_thread+0x1c/0x44)
[ 5770.036437] [<c04707a8>] (_vq_interrupt_thread+0x0/0x44) from [<c0066764>] (kthread+0x90/0x9c)
[ 5770.045806] r5:cf2e9cc0 r4:cf937e44
[ 5770.049896] [<c00666d4>] (kthread+0x0/0x9c) from [<c004ac04>] (do_exit+0x0/0x7b4)
[ 5770.058074] r6:c004ac04 r5:c00666d4 r4:cf937e44
[ 5770.063385] Board Information:
[ 5770.063385] Revision : 20edb4
[ 5770.063385] Serial : 0000000000000000
[ 5770.063385] SoC Information:
[ 5770.063385] CPU : OMAP4470
[ 5770.063385] Rev : ES1.0
[ 5770.063415] Type : HS
[ 5770.063415] Production ID: 0002B975-000000CC
[ 5770.063415] Die ID : 76080000-30002FFF-01518C70-0D00F007
[ 5770.063415]
[ 5770.098297] ---[ end trace 5f7d6da5db258916 ]---
[ 5770.110778] virtio_rpmsg_bus virtio1: destroying channel rpmsg-resmgr addr 0x66
[ 5770.266723] virtio_rpmsg_bus virtio1: creating channel rpmsg-resmgr addr 0x66
^ permalink raw reply
* [PATCH 22/22] arm: update boot/compressed/.gitignore
From: Leif Lindholm @ 2014-02-05 17:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391619853-10601-1-git-send-email-leif.lindholm@linaro.org>
Add bswapsdi2.S, fdt_empty_tree.c and fdt_sw.c to ignore list.
Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
---
arch/arm/boot/compressed/.gitignore | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/arm/boot/compressed/.gitignore b/arch/arm/boot/compressed/.gitignore
index 47279aa..cc3487e 100644
--- a/arch/arm/boot/compressed/.gitignore
+++ b/arch/arm/boot/compressed/.gitignore
@@ -1,4 +1,5 @@
ashldi3.S
+bswapsdi2.S
font.c
lib1funcs.S
hyp-stub.S
@@ -13,8 +14,10 @@ vmlinux.lds
# borrowed libfdt files
fdt.c
fdt.h
+fdt_empty_tree.c
fdt_ro.c
fdt_rw.c
+fdt_sw.c
fdt_wip.c
libfdt.h
libfdt_internal.h
--
1.7.10.4
^ permalink raw reply related
* [PATCH 21/22] arm: efistub: ignore dtb= when UEFI SecureBoot is enabled
From: Leif Lindholm @ 2014-02-05 17:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391619853-10601-1-git-send-email-leif.lindholm@linaro.org>
From: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Loading unauthenticated FDT blobs directly from storage is a security hazard,
so this should only be allowed when running with UEFI Secure Boot disabled.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
---
drivers/firmware/efi/arm-stub.c | 4 +++-
drivers/firmware/efi/efi-stub-helper.c | 24 ++++++++++++++++++++++++
2 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/drivers/firmware/efi/arm-stub.c b/drivers/firmware/efi/arm-stub.c
index b505fde..c651082 100644
--- a/drivers/firmware/efi/arm-stub.c
+++ b/drivers/firmware/efi/arm-stub.c
@@ -95,7 +95,9 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
/* Load a device tree from the configuration table, if present. */
fdt_addr = (uintptr_t)get_fdt(sys_table);
- if (!fdt_addr) {
+ if (efi_secureboot_enabled(sys_table))
+ pr_efi(sys_table, "UEFI Secure Boot is enabled, ignoring dtb= commandline option.\n");
+ else if (!fdt_addr) {
status = handle_cmdline_files(sys_table, image, cmdline_ptr,
"dtb=",
~0UL, (unsigned long *)&fdt_addr,
diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
index 2ee69ea..6221be7 100644
--- a/drivers/firmware/efi/efi-stub-helper.c
+++ b/drivers/firmware/efi/efi-stub-helper.c
@@ -721,3 +721,27 @@ static char *efi_convert_cmdline(efi_system_table_t *sys_table_arg,
*cmd_line_len = options_bytes;
return (char *)cmdline_addr;
}
+
+static int __init efi_secureboot_enabled(efi_system_table_t *sys_table_arg)
+{
+ static efi_guid_t const var_guid __initconst = EFI_GLOBAL_VARIABLE_GUID;
+ static efi_char16_t const var_name[] __initconst = {
+ 'S', 'e', 'c', 'u', 'r', 'e', 'B', 'o', 'o', 't', 0 };
+
+ efi_get_variable_t *f_getvar = sys_table_arg->runtime->get_variable;
+ unsigned long size = sizeof(u8);
+ efi_status_t status;
+ u8 val;
+
+ status = efi_call_phys5(f_getvar, (efi_char16_t *)var_name,
+ (efi_guid_t *)&var_guid, NULL, &size, &val);
+
+ switch (status) {
+ case EFI_SUCCESS:
+ return val;
+ case EFI_NOT_FOUND:
+ return 0;
+ default:
+ return 1;
+ }
+}
--
1.7.10.4
^ permalink raw reply related
* [PATCH 20/22] Improve cmdline conversion
From: Leif Lindholm @ 2014-02-05 17:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391619853-10601-1-git-send-email-leif.lindholm@linaro.org>
From: "H. Peter Anvin" <hpa@zytor.com>
Improve the conversion of the UTF-16 EFI command line
to UTF-8 for passing to the kernel.
Signed-off-by: Roy Franz <roy.franz@linaro.org>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
---
arch/x86/boot/compressed/eboot.c | 3 +-
drivers/firmware/efi/arm-stub.c | 3 +-
drivers/firmware/efi/efi-stub-helper.c | 89 ++++++++++++++++++++++++--------
3 files changed, 70 insertions(+), 25 deletions(-)
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index a7677ba..feca05f 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -488,8 +488,7 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)
hdr->type_of_loader = 0x21;
/* Convert unicode cmdline to ascii */
- cmdline_ptr = efi_convert_cmdline_to_ascii(sys_table, image,
- &options_size);
+ cmdline_ptr = efi_convert_cmdline(sys_table, image, &options_size);
if (!cmdline_ptr)
goto fail;
hdr->cmd_line_ptr = (unsigned long)cmdline_ptr;
diff --git a/drivers/firmware/efi/arm-stub.c b/drivers/firmware/efi/arm-stub.c
index aefe963..b505fde 100644
--- a/drivers/firmware/efi/arm-stub.c
+++ b/drivers/firmware/efi/arm-stub.c
@@ -87,8 +87,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
* protocol. We are going to copy the command line into the
* device tree, so this can be allocated anywhere.
*/
- cmdline_ptr = efi_convert_cmdline_to_ascii(sys_table, image,
- &cmdline_size);
+ cmdline_ptr = efi_convert_cmdline(sys_table, image, &cmdline_size);
if (!cmdline_ptr) {
pr_efi_err(sys_table, "getting command line via LOADED_IMAGE_PROTOCOL\n");
goto fail_free_image;
diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
index 8477a72..2ee69ea 100644
--- a/drivers/firmware/efi/efi-stub-helper.c
+++ b/drivers/firmware/efi/efi-stub-helper.c
@@ -625,52 +625,99 @@ static efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg,
}
/*
- * Convert the unicode UEFI command line to ASCII to pass to kernel.
+ * Get the number of UTF-8 bytes corresponding to an UTF-16 character.
+ * This overestimates for surrogates, but that is okay.
+ */
+static int efi_utf8_bytes(u16 c)
+{
+ return 1 + (c >= 0x80) + (c >= 0x800);
+}
+
+/*
+ * Convert an UTF-16 string, not necessarily null terminated, to UTF-8.
+ */
+static u8 *efi_utf16_to_utf8(u8 *dst, const u16 *src, int n)
+{
+ unsigned int c;
+
+ while (n--) {
+ c = *src++;
+ if (n && c >= 0xd800 && c <= 0xdbff &&
+ *src >= 0xdc00 && *src <= 0xdfff) {
+ c = 0x10000 + ((c & 0x3ff) << 10) + (*src & 0x3ff);
+ src++;
+ n--;
+ }
+ if (c >= 0xd800 && c <= 0xdfff)
+ c = 0xfffd; /* Unmatched surrogate */
+ if (c < 0x80) {
+ *dst++ = c;
+ continue;
+ }
+ if (c < 0x800) {
+ *dst++ = 0xc0 + (c >> 6);
+ goto t1;
+ }
+ if (c < 0x10000) {
+ *dst++ = 0xe0 + (c >> 12);
+ goto t2;
+ }
+ *dst++ = 0xf0 + (c >> 18);
+ *dst++ = 0x80 + ((c >> 12) & 0x3f);
+t2:
+ *dst++ = 0x80 + ((c >> 6) & 0x3f);
+t1:
+ *dst++ = 0x80 + (c & 0x3f);
+ }
+
+ return dst;
+}
+
+/*
+ * Do proper conversion from UTF-16 to UTF-8
* Size of memory allocated return in *cmd_line_len.
* Returns NULL on error.
*/
-static char *efi_convert_cmdline_to_ascii(efi_system_table_t *sys_table_arg,
- efi_loaded_image_t *image,
- int *cmd_line_len)
+static char *efi_convert_cmdline(efi_system_table_t *sys_table_arg,
+ efi_loaded_image_t *image,
+ int *cmd_line_len)
{
- u16 *s2;
+ const u16 *s2;
u8 *s1 = NULL;
unsigned long cmdline_addr = 0;
- int load_options_size = image->load_options_size / 2; /* ASCII */
- void *options = image->load_options;
- int options_size = 0;
+ int load_options_chars = image->load_options_size / 2; /* UTF-16 */
+ const u16 *options = image->load_options;
+ int options_bytes = 0; /* UTF-8 bytes */
+ int options_chars = 0; /* UTF-16 chars */
efi_status_t status;
- int i;
u16 zero = 0;
if (options) {
s2 = options;
- while (*s2 && *s2 != '\n' && options_size < load_options_size) {
- s2++;
- options_size++;
+ while (options_chars < load_options_chars
+ && *s2 && *s2 != '\n') {
+ options_bytes += efi_utf8_bytes(*s2++);
+ options_chars++;
}
}
- if (options_size == 0) {
- /* No command line options, so return empty string*/
- options_size = 1;
+ if (!options_chars) {
+ /* No command line options, so return empty string */
options = &zero;
}
- options_size++; /* NULL termination */
+ options_bytes++; /* NUL termination */
status = efi_low_alloc(sys_table_arg, options_bytes, 0, &cmdline_addr);
if (status != EFI_SUCCESS)
return NULL;
s1 = (u8 *)cmdline_addr;
- s2 = (u16 *)options;
-
- for (i = 0; i < options_size - 1; i++)
- *s1++ = *s2++;
+ s2 = (const u16 *)options;
+ s1 = efi_utf16_to_utf8(s1, s2, options_chars);
*s1 = '\0';
- *cmd_line_len = options_size;
+ *cmd_line_len = options_bytes;
return (char *)cmdline_addr;
}
--
1.7.10.4
^ permalink raw reply related
* [PATCH 19/22] arm64: add EFI runtime services
From: Leif Lindholm @ 2014-02-05 17:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391619853-10601-1-git-send-email-leif.lindholm@linaro.org>
From: Mark Salter <msalter@redhat.com>
This patch adds EFI runtime support for arm64. The runtime support allows
the kernel to access various EFI runtime services provided by EFI firmware.
Things like reboot, real time clock, EFI boot variables, and others.
Signed-off-by: Mark Salter <msalter@redhat.com>
Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
---
arch/arm64/Kconfig | 16 ++
arch/arm64/include/asm/efi.h | 12 ++
arch/arm64/kernel/Makefile | 1 +
arch/arm64/kernel/efi.c | 462 ++++++++++++++++++++++++++++++++++++++++++
arch/arm64/kernel/setup.c | 3 +
init/main.c | 3 +-
6 files changed, 496 insertions(+), 1 deletion(-)
create mode 100644 arch/arm64/include/asm/efi.h
create mode 100644 arch/arm64/kernel/efi.c
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 355f87c..636df8b 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -258,6 +258,20 @@ config CMDLINE_FORCE
This is useful if you cannot or don't want to change the
command-line options your boot loader passes to the kernel.
+config EFI
+ bool "EFI runtime service support"
+ depends on OF
+ select UCS2_STRING
+ select LIBFDT
+ select UEFI_PARAMS_FROM_FDT
+ help
+ This enables the kernel to use UEFI runtime services that are
+ available (such as the UEFI variable services).
+
+ This option is only useful on systems that have UEFI firmware.
+ However, even with this option, the resultant kernel should
+ continue to boot on existing non-UEFI platforms.
+
config EFI_STUB
bool "EFI stub support"
depends on OF
@@ -317,6 +331,8 @@ source "net/Kconfig"
source "drivers/Kconfig"
+source "drivers/firmware/Kconfig"
+
source "fs/Kconfig"
source "arch/arm64/kvm/Kconfig"
diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h
new file mode 100644
index 0000000..a835b2c
--- /dev/null
+++ b/arch/arm64/include/asm/efi.h
@@ -0,0 +1,12 @@
+#ifndef _ASM_ARM64_EFI_H
+#define _ASM_ARM64_EFI_H
+
+#include <asm/io.h>
+
+#ifdef CONFIG_EFI
+extern void efi_init(void);
+#else
+#define efi_init()
+#endif
+
+#endif /* _ASM_ARM64_EFI_H */
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 0f60b45..4c5a797 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -23,6 +23,7 @@ arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o
arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o
arm64-obj-$(CONFIG_EFI_STUB) += efi-stub.o efi-entry.o
+arm64-obj-$(CONFIG_EFI) += efi.o
obj-y += $(arm64-obj-y) vdso/
obj-m += $(arm64-obj-m)
diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c
new file mode 100644
index 0000000..90ca3d1
--- /dev/null
+++ b/arch/arm64/kernel/efi.c
@@ -0,0 +1,462 @@
+/*
+ * Extensible Firmware Interface
+ *
+ * Based on Extensible Firmware Interface Specification version 2.4
+ *
+ * Copyright (C) 2013 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/efi.h>
+#include <linux/export.h>
+#include <linux/memblock.h>
+#include <linux/bootmem.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include <asm/cacheflush.h>
+#include <asm/efi.h>
+#include <asm/tlbflush.h>
+#include <asm/mmu_context.h>
+
+struct efi_memory_map memmap;
+
+static efi_runtime_services_t *runtime;
+
+static u64 efi_system_table;
+
+static int uefi_debug __initdata;
+static int __init uefi_debug_setup(char *str)
+{
+ uefi_debug = 1;
+
+ return 0;
+}
+early_param("uefi_debug", uefi_debug_setup);
+
+static int __init is_normal_ram(efi_memory_desc_t *md)
+{
+ if (md->attribute & EFI_MEMORY_WB)
+ return 1;
+ return 0;
+}
+
+static void __init efi_setup_idmap(void)
+{
+ struct memblock_region *r;
+ efi_memory_desc_t *md;
+ u64 paddr, npages, size;
+
+ for_each_memblock(memory, r)
+ create_id_mapping(r->base, r->size, 0);
+
+ /* map runtime io spaces */
+ for_each_efi_memory_desc(&memmap, md) {
+ if (!(md->attribute & EFI_MEMORY_RUNTIME) || is_normal_ram(md))
+ continue;
+ paddr = md->phys_addr;
+ npages = md->num_pages;
+ memrange_efi_to_native(&paddr, &npages);
+ size = npages << PAGE_SHIFT;
+ create_id_mapping(paddr, size, 1);
+ }
+}
+
+static int __init uefi_init(void)
+{
+ efi_char16_t *c16;
+ char vendor[100] = "unknown";
+ int i, retval;
+
+ efi.systab = early_memremap(efi_system_table,
+ sizeof(efi_system_table_t));
+ if (efi.systab == NULL) {
+ pr_warn("Unable to map EFI system table.\n");
+ return -ENOMEM;
+ }
+
+ set_bit(EFI_BOOT, &efi.flags);
+ set_bit(EFI_64BIT, &efi.flags);
+
+ /*
+ * Verify the EFI Table
+ */
+ if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) {
+ pr_err("System table signature incorrect\n");
+ return -EINVAL;
+ }
+ if ((efi.systab->hdr.revision >> 16) < 2)
+ pr_warn("Warning: EFI system table version %d.%02d, expected 2.00 or greater\n",
+ efi.systab->hdr.revision >> 16,
+ efi.systab->hdr.revision & 0xffff);
+
+ /* Show what we know for posterity */
+ c16 = early_memremap(efi.systab->fw_vendor,
+ sizeof(vendor));
+ if (c16) {
+ for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i)
+ vendor[i] = c16[i];
+ vendor[i] = '\0';
+ }
+
+ pr_info("EFI v%u.%.02u by %s\n",
+ efi.systab->hdr.revision >> 16,
+ efi.systab->hdr.revision & 0xffff, vendor);
+
+ retval = efi_config_init(NULL);
+ if (retval == 0)
+ set_bit(EFI_CONFIG_TABLES, &efi.flags);
+
+ early_memunmap(c16, sizeof(vendor));
+ early_memunmap(efi.systab, sizeof(efi_system_table_t));
+
+ return retval;
+}
+
+static __initdata char memory_type_name[][32] = {
+ {"Reserved"},
+ {"Loader Code"},
+ {"Loader Data"},
+ {"Boot Code"},
+ {"Boot Data"},
+ {"Runtime Code"},
+ {"Runtime Data"},
+ {"Conventional Memory"},
+ {"Unusable Memory"},
+ {"ACPI Reclaim Memory"},
+ {"ACPI Memory NVS"},
+ {"Memory Mapped I/O"},
+ {"MMIO Port Space"},
+ {"PAL Code"},
+};
+
+/*
+ * Return true for RAM regions we want to permanently reserve.
+ */
+static __init int is_reserve_region(efi_memory_desc_t *md)
+{
+ if (!is_normal_ram(md))
+ return 0;
+
+ if (md->attribute & EFI_MEMORY_RUNTIME)
+ return 1;
+
+ if (md->type == EFI_ACPI_RECLAIM_MEMORY)
+ return 1;
+
+ return 0;
+}
+
+static __init void reserve_regions(void)
+{
+ efi_memory_desc_t *md;
+ u64 paddr, npages, size;
+
+ if (uefi_debug)
+ pr_info("Processing EFI memory map:\n");
+
+ for_each_efi_memory_desc(&memmap, md) {
+ paddr = md->phys_addr;
+ npages = md->num_pages;
+
+ if (uefi_debug)
+ pr_info(" 0x%012llx-0x%012llx [%s]",
+ paddr, paddr + (npages << EFI_PAGE_SHIFT) - 1,
+ memory_type_name[md->type]);
+
+ memrange_efi_to_native(&paddr, &npages);
+ size = npages << PAGE_SHIFT;
+
+ if (is_normal_ram(md))
+ early_init_dt_add_memory_arch(paddr, size);
+
+ if (is_reserve_region(md) ||
+ md->type == EFI_BOOT_SERVICES_CODE ||
+ md->type == EFI_BOOT_SERVICES_DATA) {
+ memblock_reserve(paddr, size);
+ if (uefi_debug)
+ pr_cont("*");
+ }
+
+ if (uefi_debug)
+ pr_cont("\n");
+ }
+}
+
+
+static u64 __init free_one_region(u64 start, u64 end)
+{
+ u64 size = end - start;
+
+ if (uefi_debug)
+ pr_info(" EFI freeing: 0x%012llx-0x%012llx\n", start, end - 1);
+
+ free_bootmem_late(start, size);
+ return size;
+}
+
+static u64 __init free_region(u64 start, u64 end)
+{
+ u64 map_start, map_end, total = 0;
+
+ if (end <= start)
+ return total;
+
+ map_start = (u64)memmap.phys_map;
+ map_end = PAGE_ALIGN(map_start + (memmap.map_end - memmap.map));
+ map_start &= PAGE_MASK;
+
+ if (start < map_end && end > map_start) {
+ /* region overlaps UEFI memmap */
+ if (start < map_start)
+ total += free_one_region(start, map_start);
+
+ if (map_end < end)
+ total += free_one_region(map_end, end);
+ } else
+ total += free_one_region(start, end);
+
+ return total;
+}
+
+static void __init free_boot_services(void)
+{
+ u64 total_freed = 0;
+ u64 keep_end, free_start, free_end;
+ efi_memory_desc_t *md;
+
+ /*
+ * If kernel uses larger pages than UEFI, we have to be careful
+ * not to inadvertantly free memory we want to keep if there is
+ * overlap@the kernel page size alignment. We do not want to
+ * free is_reserve_region() memory nor the UEFI memmap itself.
+ *
+ * The memory map is sorted, so we keep track of the end of
+ * any previous region we want to keep, remember any region
+ * we want to free and defer freeing it until we encounter
+ * the next region we want to keep. This way, before freeing
+ * it, we can clip it as needed to avoid freeing memory we
+ * want to keep for UEFI.
+ */
+
+ keep_end = 0;
+ free_start = 0;
+
+ for_each_efi_memory_desc(&memmap, md) {
+ u64 paddr, npages, size;
+
+ if (is_reserve_region(md)) {
+ /*
+ * We don't want to free any memory from this region.
+ */
+ if (free_start) {
+ /* adjust free_end then free region */
+ if (free_end > md->phys_addr)
+ free_end -= PAGE_SIZE;
+ total_freed += free_region(free_start, free_end);
+ free_start = 0;
+ }
+ keep_end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
+ continue;
+ }
+
+ if (md->type != EFI_BOOT_SERVICES_CODE &&
+ md->type != EFI_BOOT_SERVICES_DATA) {
+ /* no need to free this region */
+ continue;
+ }
+
+ /*
+ * We want to free memory from this region.
+ */
+ paddr = md->phys_addr;
+ npages = md->num_pages;
+ memrange_efi_to_native(&paddr, &npages);
+ size = npages << PAGE_SHIFT;
+
+ if (free_start) {
+ if (paddr <= free_end)
+ free_end = paddr + size;
+ else {
+ total_freed += free_region(free_start, free_end);
+ free_start = paddr;
+ free_end = paddr + size;
+ }
+ } else {
+ free_start = paddr;
+ free_end = paddr + size;
+ }
+ if (free_start < keep_end) {
+ free_start += PAGE_SIZE;
+ if (free_start >= free_end)
+ free_start = 0;
+ }
+ }
+ if (free_start)
+ total_freed += free_region(free_start, free_end);
+
+ if (total_freed)
+ pr_info("Freed 0x%llx bytes of EFI boot services memory",
+ total_freed);
+}
+
+void __init efi_init(void)
+{
+ struct efi_fdt_params params;
+
+ /* Grab UEFI information placed in FDT by stub */
+ if (!efi_get_fdt_params(¶ms, uefi_debug))
+ return;
+
+ efi_system_table = params.system_table;
+
+ memblock_reserve(params.mmap & PAGE_MASK,
+ PAGE_ALIGN(params.mmap_size + (params.mmap & ~PAGE_MASK)));
+ memmap.phys_map = (void *)params.mmap;
+ memmap.map = early_memremap(params.mmap, params.mmap_size);
+ memmap.map_end = memmap.map + params.mmap_size;
+ memmap.desc_size = params.desc_size;
+ memmap.desc_version = params.desc_ver;
+
+ if (uefi_init() < 0)
+ return;
+
+ reserve_regions();
+}
+
+static int __init remap_region(efi_memory_desc_t *md, void **new)
+{
+ u64 paddr, vaddr, npages, size;
+
+ paddr = md->phys_addr;
+ npages = md->num_pages;
+ memrange_efi_to_native(&paddr, &npages);
+ size = npages << PAGE_SHIFT;
+
+ if (is_normal_ram(md))
+ vaddr = (__force u64)ioremap_cache(paddr, size);
+ else
+ vaddr = (__force u64)ioremap(paddr, size);
+
+ if (!vaddr) {
+ pr_err("Unable to remap 0x%llx pages @ %p\n",
+ npages, (void *)paddr);
+ return 0;
+ }
+
+ /* adjust for any rounding when EFI and system pagesize differs */
+ md->virt_addr = vaddr + (md->phys_addr - paddr);
+
+ if (uefi_debug)
+ pr_info(" EFI remap 0x%012llx => %p\n",
+ md->phys_addr, (void *)md->virt_addr);
+
+ memcpy(*new, md, memmap.desc_size);
+ *new += memmap.desc_size;
+
+ return 1;
+}
+
+/*
+ * Called from setup_arch with interrupts disabled.
+ */
+void __init efi_enter_virtual_mode(void)
+{
+ efi_memory_desc_t *md;
+ phys_addr_t virtmap_phys;
+ void *virtmap, *virt_md;
+ efi_status_t status;
+ u64 mapsize;
+ int count = 0;
+ unsigned long flags;
+
+ if (!efi_enabled(EFI_BOOT)) {
+ pr_info("EFI services will not be available.\n");
+ return;
+ }
+
+ pr_info("Remapping and enabling EFI services.\n");
+
+ /* replace early memmap mapping with permanent mapping */
+ mapsize = memmap.map_end - memmap.map;
+ early_memunmap(memmap.map, mapsize);
+ memmap.map = (__force void *)ioremap_cache((phys_addr_t)memmap.phys_map,
+ mapsize);
+ memmap.map_end = memmap.map + mapsize;
+
+ efi.memmap = &memmap;
+
+ /* Map the runtime regions */
+ virtmap = kmalloc(mapsize, GFP_KERNEL);
+ if (!virtmap) {
+ pr_err("Failed to allocate EFI virtual memmap\n");
+ return;
+ }
+ virtmap_phys = virt_to_phys(virtmap);
+ virt_md = virtmap;
+
+ for_each_efi_memory_desc(&memmap, md) {
+ if (!(md->attribute & EFI_MEMORY_RUNTIME))
+ continue;
+ if (remap_region(md, &virt_md))
+ ++count;
+ }
+
+ efi.systab = (__force void *)efi_lookup_mapped_addr(efi_system_table);
+ if (efi.systab)
+ set_bit(EFI_SYSTEM_TABLES, &efi.flags);
+
+ /* boot time idmap_pg_dir is incomplete, so fill in missing parts */
+ efi_setup_idmap();
+
+ local_irq_save(flags);
+ cpu_switch_mm(idmap_pg_dir, &init_mm);
+ flush_tlb_all();
+ flush_cache_all();
+
+ /* Call SetVirtualAddressMap with the physical address of the map */
+ runtime = efi.systab->runtime;
+ efi.set_virtual_address_map = runtime->set_virtual_address_map;
+
+ status = efi.set_virtual_address_map(count * memmap.desc_size,
+ memmap.desc_size,
+ memmap.desc_version,
+ (efi_memory_desc_t *)virtmap_phys);
+ cpu_set_reserved_ttbr0();
+ flush_tlb_all();
+ flush_cache_all();
+ local_irq_restore(flags);
+
+ kfree(virtmap);
+
+ free_boot_services();
+
+ if (status != EFI_SUCCESS) {
+ pr_err("Failed to set EFI virtual address map! [%lx]\n",
+ status);
+ return;
+ }
+
+ /* Set up runtime services function pointers */
+ runtime = efi.systab->runtime;
+ efi.get_time = runtime->get_time;
+ efi.set_time = runtime->set_time;
+ efi.get_wakeup_time = runtime->get_wakeup_time;
+ efi.set_wakeup_time = runtime->set_wakeup_time;
+ efi.get_variable = runtime->get_variable;
+ efi.get_next_variable = runtime->get_next_variable;
+ efi.set_variable = runtime->set_variable;
+ efi.query_variable_info = runtime->query_variable_info;
+ efi.update_capsule = runtime->update_capsule;
+ efi.query_capsule_caps = runtime->query_capsule_caps;
+ efi.get_next_high_mono_count = runtime->get_next_high_mono_count;
+ efi.reset_system = runtime->reset_system;
+
+ set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+}
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 4d2ac74..7314460 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -41,6 +41,7 @@
#include <linux/memblock.h>
#include <linux/of_fdt.h>
#include <linux/of_platform.h>
+#include <linux/efi.h>
#include <asm/fixmap.h>
#include <asm/cputype.h>
@@ -55,6 +56,7 @@
#include <asm/traps.h>
#include <asm/memblock.h>
#include <asm/psci.h>
+#include <asm/efi.h>
unsigned int processor_id;
EXPORT_SYMBOL(processor_id);
@@ -333,6 +335,7 @@ void __init setup_arch(char **cmdline_p)
parse_early_param();
+ efi_init();
arm64_memblock_init();
paging_init();
diff --git a/init/main.c b/init/main.c
index 0325962..387b5b2 100644
--- a/init/main.c
+++ b/init/main.c
@@ -903,7 +903,8 @@ static noinline void __init kernel_init_freeable(void)
do_pre_smp_initcalls();
- if (IS_ENABLED(CONFIG_ARM) && efi_enabled(EFI_BOOT))
+ if ((IS_ENABLED(CONFIG_ARM) || IS_ENABLED(CONFIG_ARM64)) &&
+ efi_enabled(EFI_BOOT))
efi_enter_virtual_mode();
lockup_detector_init();
--
1.7.10.4
^ permalink raw reply related
* [PATCH 18/22] doc: arm64: add description of EFI stub support
From: Leif Lindholm @ 2014-02-05 17:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391619853-10601-1-git-send-email-leif.lindholm@linaro.org>
From: Mark Salter <msalter@redhat.com>
Add explanation of arm64 EFI stub and kernel image header changes
needed to masquerade as a PE/COFF application.
Signed-off-by: Mark Salter <msalter@redhat.com>
Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
Acked-by: Grant Likely <grant.likely@linaro.org>
CC: linux-doc at vger.kernel.org
CC: Rob Landley <rob@landley.net>
---
Documentation/arm64/booting.txt | 4 ++++
Documentation/efi-stub.txt | 12 +++++++++---
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/Documentation/arm64/booting.txt b/Documentation/arm64/booting.txt
index a9691cc..aa95d38c 100644
--- a/Documentation/arm64/booting.txt
+++ b/Documentation/arm64/booting.txt
@@ -85,6 +85,10 @@ The decompressed kernel image contains a 64-byte header as follows:
Header notes:
- code0/code1 are responsible for branching to stext.
+- when booting through EFI, code0/code1 are initially skipped.
+ res5 is an offset to the PE header and the PE header has the EFI
+ entry point (efi_stub_entry). When the stub has done its work, it
+ jumps to code0 to resume the normal boot process.
The image must be placed at the specified offset (currently 0x80000)
from the start of the system RAM and called there. The start of the
diff --git a/Documentation/efi-stub.txt b/Documentation/efi-stub.txt
index 26be7b0..7747024 100644
--- a/Documentation/efi-stub.txt
+++ b/Documentation/efi-stub.txt
@@ -12,6 +12,11 @@ arch/arm/boot/compressed/efi-header.S and
arch/arm/boot/compressed/efi-stub.c. EFI stub code that is shared
between architectures is in drivers/firmware/efi/efi-stub-helper.c.
+For arm64, there is no compressed kernel support, so the Image itself
+masquerades as a PE/COFF image and the EFI stub is linked into the
+kernel. The arm64 EFI stub lives in arch/arm64/kernel/efi-entry.S
+and arch/arm64/kernel/efi-stub.c.
+
By using the EFI boot stub it's possible to boot a Linux kernel
without the use of a conventional EFI boot loader, such as grub or
elilo. Since the EFI boot stub performs the jobs of a boot loader, in
@@ -28,7 +33,8 @@ the extension the EFI firmware loader will refuse to execute it. It's
not possible to execute bzImage.efi from the usual Linux file systems
because EFI firmware doesn't have support for them. For ARM the
arch/arm/boot/zImage should be copied to the system partition, and it
-may not need to be renamed.
+may not need to be renamed. Similarly for arm64, arch/arm64/boot/Image
+should be copied but not necessarily renamed.
**** Passing kernel parameters from the EFI shell
@@ -72,7 +78,7 @@ is passed to bzImage.efi.
**** The "dtb=" option
-For the ARM architecture, we also need to be able to provide a device
-tree to the kernel. This is done with the "dtb=" command line option,
+For the ARM and arm64 architectures, we also need to be able to provide a
+device tree to the kernel. This is done with the "dtb=" command line option,
and is processed in the same manner as the "initrd=" option that is
described above.
--
1.7.10.4
^ permalink raw reply related
* [PATCH 17/22] arm64: add EFI stub
From: Leif Lindholm @ 2014-02-05 17:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391619853-10601-1-git-send-email-leif.lindholm@linaro.org>
From: Mark Salter <msalter@redhat.com>
This patch adds PE/COFF header fields to the start of the Image
so that it appears as an EFI application to EFI firmware. An EFI
stub is included to allow direct booting of the kernel Image.
Support in the COFF header for signed images was provided by
Ard Biesheuvel.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Mark Salter <msalter@redhat.com>
Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
---
arch/arm64/Kconfig | 10 ++++
arch/arm64/kernel/Makefile | 3 ++
arch/arm64/kernel/efi-entry.S | 93 ++++++++++++++++++++++++++++++++++
arch/arm64/kernel/efi-stub.c | 67 ++++++++++++++++++++++++
arch/arm64/kernel/head.S | 112 +++++++++++++++++++++++++++++++++++++++++
5 files changed, 285 insertions(+)
create mode 100644 arch/arm64/kernel/efi-entry.S
create mode 100644 arch/arm64/kernel/efi-stub.c
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 0e7b443..355f87c 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -258,6 +258,16 @@ config CMDLINE_FORCE
This is useful if you cannot or don't want to change the
command-line options your boot loader passes to the kernel.
+config EFI_STUB
+ bool "EFI stub support"
+ depends on OF
+ select LIBFDT
+ default y
+ help
+ This kernel feature allows an Image to be loaded directly
+ by EFI firmware without the use of a bootloader.
+ See Documentation/efi-stub.txt for more information.
+
endmenu
menu "Userspace binary formats"
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 2d4554b..0f60b45 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -4,6 +4,8 @@
CPPFLAGS_vmlinux.lds := -DTEXT_OFFSET=$(TEXT_OFFSET)
AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
+CFLAGS_efi-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) \
+ -I$(src)/../../../scripts/dtc/libfdt
# Object file lists.
arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \
@@ -20,6 +22,7 @@ arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o
arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o
arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o
+arm64-obj-$(CONFIG_EFI_STUB) += efi-stub.o efi-entry.o
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
new file mode 100644
index 0000000..83bfb72
--- /dev/null
+++ b/arch/arm64/kernel/efi-entry.S
@@ -0,0 +1,93 @@
+/*
+ * EFI entry point.
+ *
+ * Copyright (C) 2013 Red Hat, Inc.
+ * Author: Mark Salter <msalter@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+#include <asm/assembler.h>
+
+#define EFI_LOAD_ERROR 0x8000000000000001
+
+ __INIT
+
+ /*
+ * We arrive here from the EFI boot manager with:
+ *
+ * * MMU on with identity-mapped RAM.
+ * * Icache and Dcache on
+ *
+ * We will most likely be running from some place other than where
+ * we want to be. The kernel image wants to be placed at TEXT_OFFSET
+ * from start of RAM.
+ */
+ENTRY(efi_stub_entry)
+ stp x29, x30, [sp, #-32]!
+
+ /*
+ * Call efi_entry to do the real work.
+ * x0 and x1 are already set up by firmware. Current runtime
+ * address of image is calculated and passed via *image_addr.
+ *
+ * unsigned long efi_entry(void *handle,
+ * 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
+ cmn x0, #1
+ b.eq efi_load_fail
+
+ /*
+ * efi_entry() will have relocated the kernel image if necessary
+ * and we return here with device tree address in x0 and the kernel
+ * entry point stored at *image_addr. Save those values in registers
+ * which are preserved by __flush_dcache_all.
+ */
+ ldr x1, [sp, #16]
+ mov x20, x0
+ mov x21, x1
+
+ /* Turn off Dcache and MMU */
+ mrs x0, CurrentEL
+ cmp x0, #PSR_MODE_EL2t
+ ccmp x0, #PSR_MODE_EL2h, #0x4, ne
+ b.ne 1f
+ mrs x0, sctlr_el2
+ bic x0, x0, #1 << 0 // clear SCTLR.M
+ bic x0, x0, #1 << 2 // clear SCTLR.C
+ msr sctlr_el2, x0
+ isb
+ b 2f
+1:
+ mrs x0, sctlr_el1
+ bic x0, x0, #1 << 0 // clear SCTLR.M
+ bic x0, x0, #1 << 2 // clear SCTLR.C
+ msr sctlr_el1, x0
+ isb
+2:
+ bl __flush_dcache_all
+
+ /* Jump to real entry point */
+ mov x0, x20
+ mov x1, xzr
+ mov x2, xzr
+ mov x3, xzr
+ br x21
+
+efi_load_fail:
+ mov x0, #EFI_LOAD_ERROR
+ ldp x29, x30, [sp], #32
+ ret
+
+ENDPROC(efi_stub_entry)
diff --git a/arch/arm64/kernel/efi-stub.c b/arch/arm64/kernel/efi-stub.c
new file mode 100644
index 0000000..17f5cc3
--- /dev/null
+++ b/arch/arm64/kernel/efi-stub.c
@@ -0,0 +1,67 @@
+/*
+ * linux/arch/arm/boot/compressed/efi-stub.c
+ *
+ * Copyright (C) 2013, 2014 Linaro Ltd; <roy.franz@linaro.org>
+ *
+ * This file implements the EFI boot stub for the arm64 kernel.
+ * Adapted from ARM version by Mark Salter <msalter@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/efi.h>
+#include <linux/libfdt.h>
+#include <asm/sections.h>
+#include <generated/compile.h>
+#include <generated/utsrelease.h>
+
+/*
+ * AArch64 requires the DTB to be 8-byte aligned in the first 512MiB from
+ * start of kernel and may not cross a 2MiB boundary. We set alignment to
+ * 2MiB so we know it won't cross a 2MiB boundary.
+ */
+#define EFI_FDT_ALIGN SZ_2M /* used by allocate_new_fdt_and_exit_boot() */
+#define MAX_FDT_OFFSET SZ_512M
+
+/* Include shared EFI stub code */
+#include "../../../drivers/firmware/efi/efi-stub-helper.c"
+#include "../../../drivers/firmware/efi/fdt.c"
+#include "../../../drivers/firmware/efi/arm-stub.c"
+
+
+static efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
+ unsigned long *image_addr,
+ unsigned long *image_size,
+ unsigned long *reserve_addr,
+ unsigned long *reserve_size,
+ unsigned long dram_base,
+ efi_loaded_image_t *image)
+{
+ efi_status_t status;
+ unsigned long kernel_size, kernel_memsize = 0;
+
+ /* Relocate the image, if required. */
+ kernel_size = _edata - _text;
+ if (*image_addr != (dram_base + TEXT_OFFSET)) {
+ kernel_memsize = kernel_size + (_end - _edata);
+ status = efi_relocate_kernel(sys_table, image_addr,
+ kernel_size, kernel_memsize,
+ dram_base + TEXT_OFFSET,
+ PAGE_SIZE);
+ if (status != EFI_SUCCESS) {
+ pr_efi_err(sys_table, "Failed to relocate kernel\n");
+ return status;
+ }
+ if (*image_addr != (dram_base + TEXT_OFFSET)) {
+ pr_efi_err(sys_table, "Failed to alloc kernel memory\n");
+ efi_free(sys_table, kernel_memsize, *image_addr);
+ return EFI_ERROR;
+ }
+ *image_size = kernel_memsize;
+ }
+
+
+ return EFI_SUCCESS;
+}
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index c86bfdf..2f07979 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -107,8 +107,18 @@
/*
* DO NOT MODIFY. Image header expected by Linux boot-loaders.
*/
+#ifdef CONFIG_EFI_STUB
+ /*
+ * Magic "MZ" signature for PE/COFF
+ * Little Endian: add x13, x18, #0x16
+ */
+efi_head:
+ .long 0x91005a4d
+ b stext
+#else
b stext // branch to kernel start, magic
.long 0 // reserved
+#endif
.quad TEXT_OFFSET // Image load offset from start of RAM
.quad 0 // reserved
.quad 0 // reserved
@@ -119,7 +129,109 @@
.byte 0x52
.byte 0x4d
.byte 0x64
+#ifdef CONFIG_EFI_STUB
+ .long pe_header - efi_head // Offset to the PE header.
+#else
.word 0 // reserved
+#endif
+
+#ifdef CONFIG_EFI_STUB
+ .align 3
+pe_header:
+ .ascii "PE"
+ .short 0
+coff_header:
+ .short 0xaa64 // AArch64
+ .short 2 // nr_sections
+ .long 0 // TimeDateStamp
+ .long 0 // PointerToSymbolTable
+ .long 1 // NumberOfSymbols
+ .short section_table - optional_header // SizeOfOptionalHeader
+ .short 0x206 // Characteristics.
+ // IMAGE_FILE_DEBUG_STRIPPED |
+ // IMAGE_FILE_EXECUTABLE_IMAGE |
+ // IMAGE_FILE_LINE_NUMS_STRIPPED
+optional_header:
+ .short 0x20b // PE32+ format
+ .byte 0x02 // MajorLinkerVersion
+ .byte 0x14 // MinorLinkerVersion
+ .long _edata - stext // SizeOfCode
+ .long 0 // SizeOfInitializedData
+ .long 0 // SizeOfUninitializedData
+ .long efi_stub_entry - efi_head // AddressOfEntryPoint
+ .long stext - efi_head // BaseOfCode
+
+extra_header_fields:
+ .quad 0 // ImageBase
+ .long 0x20 // SectionAlignment
+ .long 0x8 // FileAlignment
+ .short 0 // MajorOperatingSystemVersion
+ .short 0 // MinorOperatingSystemVersion
+ .short 0 // MajorImageVersion
+ .short 0 // MinorImageVersion
+ .short 0 // MajorSubsystemVersion
+ .short 0 // MinorSubsystemVersion
+ .long 0 // Win32VersionValue
+
+ .long _edata - efi_head // SizeOfImage
+
+ // Everything before the kernel image is considered part of the header
+ .long stext - efi_head // SizeOfHeaders
+ .long 0 // CheckSum
+ .short 0xa // Subsystem (EFI application)
+ .short 0 // DllCharacteristics
+ .quad 0 // SizeOfStackReserve
+ .quad 0 // SizeOfStackCommit
+ .quad 0 // SizeOfHeapReserve
+ .quad 0 // SizeOfHeapCommit
+ .long 0 // LoaderFlags
+ .long 0x6 // NumberOfRvaAndSizes
+
+ .quad 0 // ExportTable
+ .quad 0 // ImportTable
+ .quad 0 // ResourceTable
+ .quad 0 // ExceptionTable
+ .quad 0 // CertificationTable
+ .quad 0 // BaseRelocationTable
+
+ // Section table
+section_table:
+
+ /*
+ * The EFI application loader requires a relocation section
+ * because EFI applications must be relocatable. This is a
+ * dummy section as far as we are concerned.
+ */
+ .ascii ".reloc"
+ .byte 0
+ .byte 0 // end of 0 padding of section name
+ .long 0
+ .long 0
+ .long 0 // SizeOfRawData
+ .long 0 // PointerToRawData
+ .long 0 // PointerToRelocations
+ .long 0 // PointerToLineNumbers
+ .short 0 // NumberOfRelocations
+ .short 0 // NumberOfLineNumbers
+ .long 0x42100040 // Characteristics (section flags)
+
+
+ .ascii ".text"
+ .byte 0
+ .byte 0
+ .byte 0 // end of 0 padding of section name
+ .long _edata - stext // VirtualSize
+ .long stext - efi_head // VirtualAddress
+ .long _edata - stext // SizeOfRawData
+ .long stext - efi_head // PointerToRawData
+
+ .long 0 // PointerToRelocations (0 for executables)
+ .long 0 // PointerToLineNumbers (0 for executables)
+ .short 0 // NumberOfRelocations (0 for executables)
+ .short 0 // NumberOfLineNumbers (0 for executables)
+ .long 0xe0500020 // Characteristics (section flags)
+ .align 5
+#endif
ENTRY(stext)
mov x21, x0 // x21=FDT
--
1.7.10.4
^ permalink raw reply related
* [PATCH 16/22] arm64: Add function to create identity mappings
From: Leif Lindholm @ 2014-02-05 17:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391619853-10601-1-git-send-email-leif.lindholm@linaro.org>
From: Mark Salter <msalter@redhat.com>
At boot time, before switching to a virtual UEFI memory map, firmware
expects UEFI memory and IO regions to be identity mapped whenever
kernel makes runtime services calls. The exisitng early boot code
creates an identity map of kernel text/data but this is not sufficient
for UEFI. This patch adds a create_id_mapping() function which reuses
the core code of the existing create_mapping().
Signed-off-by: Mark Salter <msalter@redhat.com>
Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
---
arch/arm64/include/asm/mmu.h | 2 ++
arch/arm64/mm/mmu.c | 66 ++++++++++++++++++++++++++++++------------
2 files changed, 50 insertions(+), 18 deletions(-)
diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h
index f600d40..29ed1d8 100644
--- a/arch/arm64/include/asm/mmu.h
+++ b/arch/arm64/include/asm/mmu.h
@@ -28,5 +28,7 @@ extern void paging_init(void);
extern void setup_mm_for_reboot(void);
extern void __iomem *early_io_map(phys_addr_t phys, unsigned long virt);
extern void init_mem_pgprot(void);
+/* create an identity mapping for memory (or io if map_io is true) */
+extern void create_id_mapping(phys_addr_t addr, phys_addr_t size, int map_io);
#endif
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 7b345e3..2eeebd1 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -168,7 +168,8 @@ static void __init *early_alloc(unsigned long sz)
}
static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,
- unsigned long end, unsigned long pfn)
+ unsigned long end, unsigned long pfn,
+ pgprot_t prot)
{
pte_t *pte;
@@ -180,16 +181,28 @@ static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,
pte = pte_offset_kernel(pmd, addr);
do {
- set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC));
+ set_pte(pte, pfn_pte(pfn, prot));
pfn++;
} while (pte++, addr += PAGE_SIZE, addr != end);
}
static void __init alloc_init_pmd(pud_t *pud, unsigned long addr,
- unsigned long end, phys_addr_t phys)
+ unsigned long end, phys_addr_t phys,
+ int map_io)
{
pmd_t *pmd;
unsigned long next;
+ pmdval_t prot_sect;
+ pgprot_t prot_pte;
+
+ if (map_io) {
+ prot_sect = PMD_TYPE_SECT | PMD_SECT_AF |
+ PMD_ATTRINDX(MT_DEVICE_nGnRE);
+ prot_pte = __pgprot(PROT_DEVICE_nGnRE);
+ } else {
+ prot_sect = prot_sect_kernel;
+ prot_pte = PAGE_KERNEL_EXEC;
+ }
/*
* Check for initial section mappings in the pgd/pud and remove them.
@@ -204,22 +217,24 @@ static void __init alloc_init_pmd(pud_t *pud, unsigned long addr,
next = pmd_addr_end(addr, end);
/* try section mapping first */
if (((addr | next | phys) & ~SECTION_MASK) == 0)
- set_pmd(pmd, __pmd(phys | prot_sect_kernel));
+ set_pmd(pmd, __pmd(phys | prot_sect));
else
- alloc_init_pte(pmd, addr, next, __phys_to_pfn(phys));
+ alloc_init_pte(pmd, addr, next, __phys_to_pfn(phys),
+ prot_pte);
phys += next - addr;
} while (pmd++, addr = next, addr != end);
}
static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
- unsigned long end, unsigned long phys)
+ unsigned long end, unsigned long phys,
+ int map_io)
{
pud_t *pud = pud_offset(pgd, addr);
unsigned long next;
do {
next = pud_addr_end(addr, end);
- alloc_init_pmd(pud, addr, next, phys);
+ alloc_init_pmd(pud, addr, next, phys, map_io);
phys += next - addr;
} while (pud++, addr = next, addr != end);
}
@@ -228,30 +243,45 @@ static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
* Create the page directory entries and any necessary page tables for the
* mapping specified by 'md'.
*/
-static void __init create_mapping(phys_addr_t phys, unsigned long virt,
- phys_addr_t size)
+static void __init __create_mapping(pgd_t *pgd, phys_addr_t phys,
+ unsigned long virt, phys_addr_t size,
+ int map_io)
{
unsigned long addr, length, end, next;
- pgd_t *pgd;
-
- if (virt < VMALLOC_START) {
- pr_warning("BUG: not creating mapping for 0x%016llx at 0x%016lx - outside kernel range\n",
- phys, virt);
- return;
- }
addr = virt & PAGE_MASK;
length = PAGE_ALIGN(size + (virt & ~PAGE_MASK));
- pgd = pgd_offset_k(addr);
end = addr + length;
do {
next = pgd_addr_end(addr, end);
- alloc_init_pud(pgd, addr, next, phys);
+ alloc_init_pud(pgd, addr, next, phys, map_io);
phys += next - addr;
} while (pgd++, addr = next, addr != end);
}
+static void __init create_mapping(phys_addr_t phys, unsigned long virt,
+ phys_addr_t size)
+{
+ if (virt < VMALLOC_START) {
+ pr_warn("BUG: not creating mapping for 0x%016llx@0x%016lx - outside kernel range\n",
+ phys, virt);
+ return;
+ }
+ __create_mapping(pgd_offset_k(virt & PAGE_MASK), phys, virt, size, 0);
+}
+
+void __init create_id_mapping(phys_addr_t addr, phys_addr_t size, int map_io)
+{
+ pgd_t *pgd = &idmap_pg_dir[pgd_index(addr)];
+
+ if (pgd >= &idmap_pg_dir[ARRAY_SIZE(idmap_pg_dir)]) {
+ pr_warn("BUG: not creating id mapping for 0x%016llx\n", addr);
+ return;
+ }
+ __create_mapping(pgd, addr, addr, size, map_io);
+}
+
static void __init map_mem(void)
{
struct memblock_region *reg;
--
1.7.10.4
^ permalink raw reply related
* [PATCH 15/22] lib: add fdt_empty_tree.c
From: Leif Lindholm @ 2014-02-05 17:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391619853-10601-1-git-send-email-leif.lindholm@linaro.org>
From: Mark Salter <msalter@redhat.com>
CONFIG_LIBFDT support does not include fdt_empty_tree.c which is
needed by arm64 EFI stub. Add it to libfdt_files.
Signed-off-by: Mark Salter <msalter@redhat.com>
Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
---
lib/Makefile | 3 ++-
lib/fdt_empty_tree.c | 2 ++
2 files changed, 4 insertions(+), 1 deletion(-)
create mode 100644 lib/fdt_empty_tree.c
diff --git a/lib/Makefile b/lib/Makefile
index 126b34f..ce085d2 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -146,7 +146,8 @@ obj-$(CONFIG_GENERIC_NET_UTILS) += net_utils.o
obj-$(CONFIG_STMP_DEVICE) += stmp_device.o
-libfdt_files = fdt.o fdt_ro.o fdt_wip.o fdt_rw.o fdt_sw.o fdt_strerror.o
+libfdt_files = fdt.o fdt_ro.o fdt_wip.o fdt_rw.o fdt_sw.o fdt_strerror.o \
+ fdt_empty_tree.o
$(foreach file, $(libfdt_files), \
$(eval CFLAGS_$(file) = -I$(src)/../scripts/dtc/libfdt))
lib-$(CONFIG_LIBFDT) += $(libfdt_files)
diff --git a/lib/fdt_empty_tree.c b/lib/fdt_empty_tree.c
new file mode 100644
index 0000000..5d30c58
--- /dev/null
+++ b/lib/fdt_empty_tree.c
@@ -0,0 +1,2 @@
+#include <linux/libfdt_env.h>
+#include "../scripts/dtc/libfdt/fdt_empty_tree.c"
--
1.7.10.4
^ permalink raw reply related
* [PATCH 14/22] init: efi: arm: enable (U)EFI runtime services on arm
From: Leif Lindholm @ 2014-02-05 17:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391619853-10601-1-git-send-email-leif.lindholm@linaro.org>
Since the efi_set_virtual_address_map call has strict init ordering
requirements, add an explicit hook in the required place.
Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
Acked-by: Grant Likely <grant.likely@linaro.org>
---
init/main.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/init/main.c b/init/main.c
index 2fd9cef..0325962 100644
--- a/init/main.c
+++ b/init/main.c
@@ -902,6 +902,10 @@ static noinline void __init kernel_init_freeable(void)
smp_prepare_cpus(setup_max_cpus);
do_pre_smp_initcalls();
+
+ if (IS_ENABLED(CONFIG_ARM) && efi_enabled(EFI_BOOT))
+ efi_enter_virtual_mode();
+
lockup_detector_init();
smp_init();
--
1.7.10.4
^ permalink raw reply related
* [PATCH 13/22] arm: Add [U]EFI runtime services support
From: Leif Lindholm @ 2014-02-05 17:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1391619853-10601-1-git-send-email-leif.lindholm@linaro.org>
This patch implements basic support for UEFI runtime services in the
ARM architecture - a requirement for using efibootmgr to read and update
the system boot configuration.
It uses the generic configuration table scanning to populate ACPI and
SMBIOS pointers.
Changes since v2:
- Updated FDT bindings.
- Preserve regions marked RESERVED (but don't map them).
- Rename 'efi' -> 'uefi' within this new port (leaving core code as is).
Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org>
Reviewed-by: Grant Likely <grant.likely@linaro.org>
---
arch/arm/Kconfig | 16 ++
arch/arm/include/asm/uefi.h | 28 +++
arch/arm/kernel/Makefile | 2 +
arch/arm/kernel/setup.c | 7 +-
arch/arm/kernel/uefi.c | 413 +++++++++++++++++++++++++++++++++++++++++++
arch/arm/kernel/uefi_phys.S | 69 ++++++++
6 files changed, 533 insertions(+), 2 deletions(-)
create mode 100644 arch/arm/include/asm/uefi.h
create mode 100644 arch/arm/kernel/uefi.c
create mode 100644 arch/arm/kernel/uefi_phys.S
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index a693921..1e1273d 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1885,6 +1885,20 @@ config EARLY_IOREMAP
the same virtual memory range as kmap so all early mappings must
be unapped before paging_init() is called.
+config EFI
+ bool "UEFI runtime service support"
+ depends on OF && !CPU_BIG_ENDIAN
+ select UCS2_STRING
+ select EARLY_IOREMAP
+ select UEFI_PARAMS_FROM_FDT
+ ---help---
+ This enables the kernel to use UEFI runtime services that are
+ available (such as the UEFI variable services).
+
+ This option is only useful on systems that have UEFI firmware.
+ However, even with this option, the resultant kernel will
+ continue to boot on non-UEFI platforms.
+
config EFI_STUB
bool "EFI stub support"
depends on EFI && !CPU_BIG_ENDIAN
@@ -2304,6 +2318,8 @@ source "net/Kconfig"
source "drivers/Kconfig"
+source "drivers/firmware/Kconfig"
+
source "fs/Kconfig"
source "arch/arm/Kconfig.debug"
diff --git a/arch/arm/include/asm/uefi.h b/arch/arm/include/asm/uefi.h
new file mode 100644
index 0000000..3bc4c60
--- /dev/null
+++ b/arch/arm/include/asm/uefi.h
@@ -0,0 +1,28 @@
+#ifndef _ASM_ARM_EFI_H
+#define _ASM_ARM_EFI_H
+
+#ifdef CONFIG_EFI
+#include <asm/mach/map.h>
+
+extern void uefi_init(void);
+
+typedef efi_status_t uefi_phys_call_t(efi_set_virtual_address_map_t *f,
+ u32 virt_phys_offset,
+ u32 memory_map_size,
+ u32 descriptor_size,
+ u32 descriptor_version,
+ efi_memory_desc_t *dsc);
+
+extern efi_status_t uefi_phys_call(u32, u32, u32, efi_memory_desc_t *,
+ efi_set_virtual_address_map_t *);
+
+#define uefi_remap(cookie, size) __arm_ioremap((cookie), (size), MT_MEMORY_RWX)
+#define uefi_ioremap(cookie, size) __arm_ioremap((cookie), (size), MT_DEVICE)
+#define uefi_unmap(cookie) __arm_iounmap((cookie))
+#define uefi_iounmap(cookie) __arm_iounmap((cookie))
+
+#else
+#define uefi_init()
+#endif /* CONFIG_EFI */
+
+#endif /* _ASM_ARM_EFI_H */
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index a30fc9b..736cce4 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -98,4 +98,6 @@ obj-y += psci.o
obj-$(CONFIG_SMP) += psci_smp.o
endif
+obj-$(CONFIG_EFI) += uefi.o uefi_phys.o
+
extra-y := $(head-y) vmlinux.lds
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index b074ef5..71b8839 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -30,6 +30,7 @@
#include <linux/bug.h>
#include <linux/compiler.h>
#include <linux/sort.h>
+#include <linux/efi.h>
#include <asm/unified.h>
#include <asm/cp15.h>
@@ -57,6 +58,7 @@
#include <asm/unwind.h>
#include <asm/memblock.h>
#include <asm/virt.h>
+#include <asm/uefi.h>
#include "atags.h"
@@ -878,6 +880,9 @@ void __init setup_arch(char **cmdline_p)
if (mdesc->reboot_mode != REBOOT_HARD)
reboot_mode = mdesc->reboot_mode;
+ early_ioremap_init();
+ uefi_init();
+
init_mm.start_code = (unsigned long) _text;
init_mm.end_code = (unsigned long) _etext;
init_mm.end_data = (unsigned long) _edata;
@@ -889,8 +894,6 @@ void __init setup_arch(char **cmdline_p)
parse_early_param();
- early_ioremap_init();
-
early_paging_init(mdesc, lookup_processor_type(read_cpuid_id()));
setup_dma_zone(mdesc);
sanity_check_meminfo();
diff --git a/arch/arm/kernel/uefi.c b/arch/arm/kernel/uefi.c
new file mode 100644
index 0000000..77c18b6
--- /dev/null
+++ b/arch/arm/kernel/uefi.c
@@ -0,0 +1,413 @@
+/*
+ * Based on Unified Extensible Firmware Interface Specification version 2.3.1
+ *
+ * Copyright (C) 2013-2014 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/efi.h>
+#include <linux/export.h>
+#include <linux/memblock.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include <asm/cacheflush.h>
+#include <asm/idmap.h>
+#include <asm/setup.h>
+#include <asm/tlbflush.h>
+#include <asm/uefi.h>
+
+struct efi_memory_map memmap;
+
+static efi_runtime_services_t *runtime;
+
+static phys_addr_t uefi_system_table;
+static phys_addr_t uefi_boot_mmap;
+static u32 uefi_boot_mmap_size;
+static u32 uefi_mmap_desc_size;
+static u32 uefi_mmap_desc_ver;
+
+/*
+ * If you want to wire up a debugger and debug the UEFI side, set to 0.
+ */
+#define DISCARD_UNUSED_REGIONS 1
+
+/*
+ * If you need to (temporarily) support buggy firmware, set to 0.
+ */
+#define DISCARD_BOOT_SERVICES_REGIONS 1
+
+static int uefi_debug __initdata;
+static int __init uefi_debug_setup(char *str)
+{
+ uefi_debug = 1;
+
+ return 0;
+}
+early_param("uefi_debug", uefi_debug_setup);
+
+static int __init uefi_systab_init(void)
+{
+ efi_char16_t *c16;
+ char vendor[100] = "unknown";
+ int i, retval;
+
+ efi.systab = early_memremap(uefi_system_table,
+ sizeof(efi_system_table_t));
+
+ /*
+ * Verify the UEFI System Table
+ */
+ if (efi.systab == NULL)
+ panic("Whoa! Can't find UEFI system table.\n");
+ if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
+ panic("Whoa! UEFI system table signature incorrect\n");
+ if ((efi.systab->hdr.revision >> 16) == 0)
+ pr_warn("Warning: UEFI system table version %d.%02d, expected 2.30 or greater\n",
+ efi.systab->hdr.revision >> 16,
+ efi.systab->hdr.revision & 0xffff);
+
+ /* Show what we know for posterity */
+ c16 = early_memremap(efi.systab->fw_vendor, sizeof(vendor));
+ if (c16) {
+ for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i)
+ vendor[i] = c16[i];
+ vendor[i] = '\0';
+ }
+
+ pr_info("UEFI v%u.%.02u by %s\n",
+ efi.systab->hdr.revision >> 16,
+ efi.systab->hdr.revision & 0xffff, vendor);
+
+ retval = efi_config_init(NULL);
+ if (retval == 0)
+ set_bit(EFI_CONFIG_TABLES, &efi.flags);
+
+ early_memunmap(c16, sizeof(vendor));
+ early_memunmap(efi.systab, sizeof(efi_system_table_t));
+
+ return retval;
+}
+
+static __init int is_discardable_region(efi_memory_desc_t *md)
+{
+ if (md->attribute & EFI_MEMORY_RUNTIME)
+ return 0;
+
+ switch (md->type) {
+ case EFI_CONVENTIONAL_MEMORY:
+ return 1;
+ case EFI_BOOT_SERVICES_CODE:
+ case EFI_BOOT_SERVICES_DATA:
+ return DISCARD_BOOT_SERVICES_REGIONS;
+ /* Keep tables around for any future kexec operations */
+ case EFI_ACPI_MEMORY_NVS:
+ case EFI_ACPI_RECLAIM_MEMORY:
+ return 0;
+ /* Preserve */
+ case EFI_RESERVED_TYPE:
+ return 0;
+ }
+
+ return DISCARD_UNUSED_REGIONS;
+}
+
+static __initdata struct {
+ u32 type;
+ const char *name;
+} memory_type_name_map[] = {
+ {EFI_RESERVED_TYPE, "reserved"},
+ {EFI_LOADER_CODE, "loader code"},
+ {EFI_LOADER_DATA, "loader data"},
+ {EFI_BOOT_SERVICES_CODE, "boot services code"},
+ {EFI_BOOT_SERVICES_DATA, "boot services data"},
+ {EFI_RUNTIME_SERVICES_CODE, "runtime services code"},
+ {EFI_RUNTIME_SERVICES_DATA, "runtime services data"},
+ {EFI_CONVENTIONAL_MEMORY, "conventional memory"},
+ {EFI_UNUSABLE_MEMORY, "unusable memory"},
+ {EFI_ACPI_RECLAIM_MEMORY, "ACPI reclaim memory"},
+ {EFI_ACPI_MEMORY_NVS, "ACPI memory nvs"},
+ {EFI_MEMORY_MAPPED_IO, "memory mapped I/O"},
+ {EFI_MEMORY_MAPPED_IO_PORT_SPACE, "memory mapped I/O port space"},
+ {EFI_PAL_CODE, "pal code"},
+ {EFI_MAX_MEMORY_TYPE, NULL},
+};
+
+static __init void remove_sections(phys_addr_t addr, unsigned long size)
+{
+ unsigned long section_offset;
+ unsigned long num_sections;
+
+ section_offset = addr - (addr & SECTION_MASK);
+ num_sections = size / SECTION_SIZE;
+ if (size % SECTION_SIZE)
+ num_sections++;
+
+ memblock_remove(addr - section_offset, num_sections * SECTION_SIZE);
+}
+
+static void memmap_init(void)
+{
+ efi_memory_desc_t *md;
+ int i = 0;
+
+ if (uefi_debug)
+ pr_info("Processing UEFI memory map:\n");
+
+ memmap.map = early_memremap(uefi_boot_mmap, uefi_boot_mmap_size);
+ if (!memmap.map)
+ return;
+
+ memmap.map_end = memmap.map + uefi_boot_mmap_size;
+ memmap.nr_map = 0;
+
+ for_each_efi_memory_desc(&memmap, md) {
+ pr_info(" %8llu pages @ %016llx (%s)\n",
+ md->num_pages, md->phys_addr,
+ memory_type_name_map[md->type].name);
+ if (md->attribute & EFI_MEMORY_WB) {
+ if (is_discardable_region(md)) {
+ arm_add_memory(md->phys_addr,
+ md->num_pages * EFI_PAGE_SIZE);
+ i++;
+ }
+ }
+ memmap.nr_map++;
+ }
+
+ if (uefi_debug)
+ pr_info("%d memory regions added.\n", i);
+
+ remove_sections(uefi_boot_mmap, uefi_boot_mmap_size);
+
+ early_memunmap(memmap.map, uefi_boot_mmap_size);
+
+ set_bit(EFI_MEMMAP, &efi.flags);
+}
+
+void __init uefi_init(void)
+{
+ struct efi_fdt_params params;
+
+ uefi_debug = 1;
+
+ /* Grab UEFI information placed in FDT by stub */
+ if (!efi_get_fdt_params(¶ms, uefi_debug))
+ return;
+
+ uefi_system_table = params.system_table;
+
+ uefi_boot_mmap = params.mmap;
+ uefi_boot_mmap_size = params.mmap_size;
+ uefi_mmap_desc_size = params.desc_size;
+ uefi_mmap_desc_ver = params.desc_ver;
+ memmap.desc_size = uefi_mmap_desc_size;
+ memmap.map_end = memmap.map + params.mmap_size;
+ if (uefi_boot_mmap > UINT_MAX) {
+ pr_err("UEFI memory map located above 4GB - unusable!");
+ return;
+ }
+
+ if (uefi_systab_init() < 0)
+ return;
+
+ memmap_init();
+
+ set_bit(EFI_BOOT, &efi.flags);
+}
+
+/*
+ * Disable instrrupts, enable idmap and disable caches.
+ */
+static void __init phys_call_prologue(void)
+{
+ local_irq_disable();
+
+ outer_disable();
+
+ idmap_prepare();
+}
+
+/*
+ * Restore original memory map and re-enable interrupts.
+ */
+static void __init phys_call_epilogue(void)
+{
+ static struct mm_struct *mm = &init_mm;
+
+ /* Restore original memory mapping */
+ cpu_switch_mm(mm->pgd, mm);
+
+ local_flush_bp_all();
+ local_flush_tlb_all();
+
+ outer_resume();
+
+ local_irq_enable();
+}
+
+static int __init remap_region(efi_memory_desc_t *md, int entry)
+{
+ efi_memory_desc_t *region;
+ u32 va;
+ u64 paddr;
+ u64 size;
+
+ region = memmap.map + entry * memmap.desc_size;
+ *region = *md;
+ paddr = region->phys_addr;
+ size = region->num_pages << EFI_PAGE_SHIFT;
+
+ /*
+ * Map everything writeback-capable as coherent memory,
+ * anything else as device.
+ */
+ if (md->attribute & EFI_MEMORY_WB)
+ va = (u32)uefi_remap(paddr, size);
+ else
+ va = (u32)uefi_ioremap(paddr, size);
+ if (!va)
+ return 0;
+ region->virt_addr = va;
+
+ if (uefi_debug)
+ pr_info(" %016llx-%016llx => 0x%08x : (%s)\n",
+ paddr, paddr + size - 1, va,
+ md->attribute & EFI_MEMORY_WB ? "WB" : "I/O");
+
+ return 1;
+}
+
+static int __init remap_regions(void)
+{
+ void *p;
+ efi_memory_desc_t *md;
+ int mapped_regions;
+
+ memmap.phys_map = uefi_remap(uefi_boot_mmap, uefi_boot_mmap_size);
+ if (!memmap.phys_map)
+ return 0;
+
+ memmap.map_end = memmap.phys_map + uefi_boot_mmap_size;
+ memmap.desc_size = uefi_mmap_desc_size;
+ memmap.desc_version = uefi_mmap_desc_ver;
+
+ /* Allocate space for the physical region map */
+ memmap.map = kzalloc(memmap.nr_map * memmap.desc_size, GFP_ATOMIC);
+ if (!memmap.map)
+ return 0;
+
+ mapped_regions = 0;
+ for (p = memmap.phys_map; p < memmap.map_end; p += memmap.desc_size) {
+ md = p;
+ if (is_discardable_region(md))
+ continue;
+
+ if (!remap_region(p, mapped_regions++))
+ return 0;
+ }
+
+ memmap.map_end = memmap.map + mapped_regions * memmap.desc_size;
+ efi.memmap = &memmap;
+
+ uefi_unmap(memmap.phys_map);
+ memmap.phys_map = efi_lookup_mapped_addr(uefi_boot_mmap);
+ efi.systab = efi_lookup_mapped_addr(uefi_system_table);
+ if (efi.systab)
+ set_bit(EFI_SYSTEM_TABLES, &efi.flags);
+ /*
+ * efi.systab->runtime is a 32-bit pointer to something guaranteed by
+ * the UEFI specification to be 1:1 mapped in a 4GB address space.
+ */
+ runtime = efi_lookup_mapped_addr((u32)efi.systab->runtime);
+
+ return 1;
+}
+
+
+/*
+ * This function switches the UEFI runtime services to virtual mode.
+ * This operation must be performed only once in the system's lifetime,
+ * including any kecec calls.
+ *
+ * This must be done with a 1:1 mapping. The current implementation
+ * resolves this by disabling the MMU.
+ */
+efi_status_t __init phys_set_virtual_address_map(u32 memory_map_size,
+ u32 descriptor_size,
+ u32 descriptor_version,
+ efi_memory_desc_t *dsc)
+{
+ uefi_phys_call_t *phys_set_map;
+ efi_status_t status;
+
+ phys_call_prologue();
+
+ phys_set_map = (void *)(unsigned long)virt_to_phys(uefi_phys_call);
+
+ /* Called with caches disabled, returns with caches enabled */
+ status = phys_set_map(efi.set_virtual_address_map,
+ PAGE_OFFSET - PHYS_OFFSET,
+ memory_map_size, descriptor_size,
+ descriptor_version, dsc);
+
+ phys_call_epilogue();
+
+ return status;
+}
+
+/*
+ * Called explicitly from init/mm.c
+ */
+void __init efi_enter_virtual_mode(void)
+{
+ efi_status_t status;
+ u32 mmap_phys_addr;
+
+ if (!efi_enabled(EFI_BOOT)) {
+ pr_info("UEFI services will not be available.\n");
+ return;
+ }
+
+ pr_info("Remapping and enabling UEFI services.\n");
+
+ /* Map the regions we memblock_remove:d earlier into kernel
+ address space */
+ if (!remap_regions()) {
+ pr_info("Failed to remap UEFI regions - runtime services will not be available.\n");
+ return;
+ }
+
+ /* Call SetVirtualAddressMap with the physical address of the map */
+ efi.set_virtual_address_map = runtime->set_virtual_address_map;
+
+ /*
+ * __virt_to_phys() takes an unsigned long and returns a phys_addr_t
+ * memmap.phys_map is a void *
+ * The gymnastics below makes this compile validly with/without LPAE.
+ */
+ mmap_phys_addr = __virt_to_phys((u32)memmap.map);
+ memmap.phys_map = (void *)mmap_phys_addr;
+
+ status = phys_set_virtual_address_map(memmap.nr_map * memmap.desc_size,
+ memmap.desc_size,
+ memmap.desc_version,
+ memmap.phys_map);
+ if (status != EFI_SUCCESS) {
+ pr_info("Failed to set UEFI virtual address map!\n");
+ return;
+ }
+
+ /* Set up function pointers for efivars */
+ efi.get_variable = runtime->get_variable;
+ efi.get_next_variable = runtime->get_next_variable;
+ efi.set_variable = runtime->set_variable;
+ efi.set_virtual_address_map = NULL;
+
+ set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+}
diff --git a/arch/arm/kernel/uefi_phys.S b/arch/arm/kernel/uefi_phys.S
new file mode 100644
index 0000000..a999626
--- /dev/null
+++ b/arch/arm/kernel/uefi_phys.S
@@ -0,0 +1,69 @@
+/*
+ * arch/arm/kernel/uefi_phys.S
+ *
+ * Copyright (C) 2013 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <asm/assembler.h>
+#include <asm/cp15.h>
+#include <linux/linkage.h>
+#define PAR_MASK 0xfff
+
+ .text
+@ uefi_phys_call(*f, virt_phys_offset, a, b, c, d, ...)
+ .align 5
+ .pushsection .idmap.text, "ax"
+ENTRY(uefi_phys_call)
+ @ Save physical context
+ mov r12, sp
+ ldr sp, =tmpstack
+ stmfd sp, {r4-r5, r12, lr} @ push is redefined by asm/assembler.h
+
+ mov r4, r1
+
+ @ Extract function pointer (don't write lr again before call)
+ mov lr, r0
+
+ @ Shift arguments down
+ mov r0, r2
+ mov r1, r3
+ ldr r2, [r12], #4
+ ldr r3, [r12], #4
+
+ @ Convert sp to physical
+ sub r12, r12, r4
+ mov sp, r12
+
+ @ Disable MMU
+ ldr r5, =(CR_M)
+ update_sctlr r12, , r5
+ isb
+
+ @ Make call
+ blx lr
+
+ @ Enable MMU + Caches
+ ldr r4, =(CR_I | CR_C | CR_M)
+ update_sctlr r12, r4
+ isb
+
+ ldr sp, =tmpstack_top
+ ldmfd sp, {r4-r5, r12, lr}
+
+ @ Restore virtual sp and return
+ mov sp, r12
+ bx lr
+
+ .align 3
+tmpstack_top:
+ .long 0 @ r4
+ .long 0 @ r5
+ .long 0 @ r12
+ .long 0 @ lr
+tmpstack:
+ENDPROC(uefi_phys_call)
+ .popsection
--
1.7.10.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox