summaryrefslogtreecommitdiff
path: root/arch/arm
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2017-11-08 19:42:47 +0000
committerRussell King <rmk+kernel@armlinux.org.uk>2017-11-08 19:42:47 +0000
commit02196144a0a0ad71fb75bd4a5a4785ab36c3b78e (patch)
treeb87fe75626250a456604a331faf3594b4f3925a8 /arch/arm
parent7f3d1f984336377074ebf804ff53869ef1906fbe (diff)
parentfe9c0589eeef4b3edbaad9f7500679a2eeafe951 (diff)
downloadlinux-02196144a0a0ad71fb75bd4a5a4785ab36c3b78e.tar.gz
linux-02196144a0a0ad71fb75bd4a5a4785ab36c3b78e.tar.bz2
linux-02196144a0a0ad71fb75bd4a5a4785ab36c3b78e.zip
Merge branch 'devel-stable' into for-next
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/Kconfig20
-rw-r--r--arch/arm/Kconfig-nommu4
-rw-r--r--arch/arm/boot/Makefile13
-rwxr-xr-xarch/arm/boot/deflate_xip_data.sh64
-rw-r--r--arch/arm/include/asm/cputype.h10
-rw-r--r--arch/arm/include/asm/elf.h16
-rw-r--r--arch/arm/include/asm/mmu.h8
-rw-r--r--arch/arm/include/asm/mpu.h26
-rw-r--r--arch/arm/include/asm/processor.h22
-rw-r--r--arch/arm/include/asm/smp.h2
-rw-r--r--arch/arm/include/asm/ucontext.h1
-rw-r--r--arch/arm/include/asm/v7m.h10
-rw-r--r--arch/arm/include/uapi/asm/ptrace.h4
-rw-r--r--arch/arm/include/uapi/asm/unistd.h1
-rw-r--r--arch/arm/kernel/Makefile5
-rw-r--r--arch/arm/kernel/asm-offsets.c15
-rw-r--r--arch/arm/kernel/elf.c24
-rw-r--r--arch/arm/kernel/head-common.S86
-rw-r--r--arch/arm/kernel/head-inflate-data.c62
-rw-r--r--arch/arm/kernel/head-nommu.S148
-rw-r--r--arch/arm/kernel/signal.c53
-rw-r--r--arch/arm/kernel/signal.h11
-rw-r--r--arch/arm/kernel/sigreturn_codes.S56
-rw-r--r--arch/arm/kernel/smp.c2
-rw-r--r--arch/arm/kernel/traps.c3
-rw-r--r--arch/arm/kernel/vmlinux-xip.lds.S115
-rw-r--r--arch/arm/kernel/vmlinux.lds.S40
-rw-r--r--arch/arm/mm/Makefile1
-rw-r--r--arch/arm/mm/nommu.c254
-rw-r--r--arch/arm/mm/pmsa-v7.c484
30 files changed, 1111 insertions, 449 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 979aac3e2fbf..631e61bc7ac4 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -240,15 +240,6 @@ config NEED_RET_TO_USER
config ARCH_MTD_XIP
bool
-config VECTORS_BASE
- hex
- default 0xffff0000 if MMU || CPU_HIGH_VECTOR
- default DRAM_BASE if REMAP_VECTORS_TO_RAM
- default 0x00000000
- help
- The base address of exception vectors. This must be two pages
- in size.
-
config ARM_PATCH_PHYS_VIRT
bool "Patch physical to virtual translations at runtime" if EMBEDDED
default y
@@ -2006,6 +1997,17 @@ config XIP_PHYS_ADDR
be linked for and stored to. This address is dependent on your
own flash usage.
+config XIP_DEFLATED_DATA
+ bool "Store kernel .data section compressed in ROM"
+ depends on XIP_KERNEL
+ select ZLIB_INFLATE
+ help
+ Before the kernel is actually executed, its .data section has to be
+ copied to RAM from ROM. This option allows for storing that data
+ in compressed form and decompressed to RAM rather than merely being
+ copied, saving some precious ROM space. A possible drawback is a
+ slightly longer boot delay.
+
config KEXEC
bool "Kexec system call (EXPERIMENTAL)"
depends on (!SMP || PM_SLEEP_SMP)
diff --git a/arch/arm/Kconfig-nommu b/arch/arm/Kconfig-nommu
index b7576349528c..0fad7d943630 100644
--- a/arch/arm/Kconfig-nommu
+++ b/arch/arm/Kconfig-nommu
@@ -52,8 +52,8 @@ config REMAP_VECTORS_TO_RAM
config ARM_MPU
bool 'Use the ARM v7 PMSA Compliant MPU'
- depends on CPU_V7
- default y
+ depends on CPU_V7 || CPU_V7M
+ default y if CPU_V7
help
Some ARM systems without an MMU have instead a Memory Protection
Unit (MPU) that defines the type and permissions for regions of
diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
index 50f8d1be7fcb..a3af4dc08c3e 100644
--- a/arch/arm/boot/Makefile
+++ b/arch/arm/boot/Makefile
@@ -31,8 +31,19 @@ targets := Image zImage xipImage bootpImage uImage
ifeq ($(CONFIG_XIP_KERNEL),y)
+cmd_deflate_xip_data = $(CONFIG_SHELL) -c \
+ '$(srctree)/$(src)/deflate_xip_data.sh $< $@ || { rm -f $@; false; }'
+
+ifeq ($(CONFIG_XIP_DEFLATED_DATA),y)
+quiet_cmd_mkxip = XIPZ $@
+cmd_mkxip = $(cmd_objcopy) && $(cmd_deflate_xip_data)
+else
+quiet_cmd_mkxip = $(quiet_cmd_objcopy)
+cmd_mkxip = $(cmd_objcopy)
+endif
+
$(obj)/xipImage: vmlinux FORCE
- $(call if_changed,objcopy)
+ $(call if_changed,mkxip)
@$(kecho) ' Physical Address of xipImage: $(CONFIG_XIP_PHYS_ADDR)'
$(obj)/Image $(obj)/zImage: FORCE
diff --git a/arch/arm/boot/deflate_xip_data.sh b/arch/arm/boot/deflate_xip_data.sh
new file mode 100755
index 000000000000..1189598a25eb
--- /dev/null
+++ b/arch/arm/boot/deflate_xip_data.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+
+# XIP kernel .data segment compressor
+#
+# Created by: Nicolas Pitre, August 2017
+# Copyright: (C) 2017 Linaro Limited
+#
+# 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.
+
+# This script locates the start of the .data section in xipImage and
+# substitutes it with a compressed version. The needed offsets are obtained
+# from symbol addresses in vmlinux. It is expected that .data extends to
+# the end of xipImage.
+
+set -e
+
+VMLINUX="$1"
+XIPIMAGE="$2"
+
+DD="dd status=none"
+
+# Use "make V=1" to debug this script.
+case "$KBUILD_VERBOSE" in
+*1*)
+ set -x
+ ;;
+esac
+
+sym_val() {
+ # extract hex value for symbol in $1
+ local val=$($NM "$VMLINUX" | sed -n "/ $1$/{s/ .*$//p;q}")
+ [ "$val" ] || { echo "can't find $1 in $VMLINUX" 1>&2; exit 1; }
+ # convert from hex to decimal
+ echo $((0x$val))
+}
+
+__data_loc=$(sym_val __data_loc)
+_edata_loc=$(sym_val _edata_loc)
+base_offset=$(sym_val _xiprom)
+
+# convert to file based offsets
+data_start=$(($__data_loc - $base_offset))
+data_end=$(($_edata_loc - $base_offset))
+
+# Make sure data occupies the last part of the file.
+file_end=$(stat -c "%s" "$XIPIMAGE")
+if [ "$file_end" != "$data_end" ]; then
+ printf "end of xipImage doesn't match with _edata_loc (%#x vs %#x)\n" \
+ $(($file_end + $base_offset)) $_edata_loc 2>&1
+ exit 1;
+fi
+
+# be ready to clean up
+trap 'rm -f "$XIPIMAGE.tmp"' 0 1 2 3
+
+# substitute the data section by a compressed version
+$DD if="$XIPIMAGE" count=$data_start iflag=count_bytes of="$XIPIMAGE.tmp"
+$DD if="$XIPIMAGE" skip=$data_start iflag=skip_bytes |
+gzip -9 >> "$XIPIMAGE.tmp"
+
+# replace kernel binary
+mv -f "$XIPIMAGE.tmp" "$XIPIMAGE"
diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h
index b62eaeb147aa..abaac5e07b80 100644
--- a/arch/arm/include/asm/cputype.h
+++ b/arch/arm/include/asm/cputype.h
@@ -173,6 +173,11 @@ static inline unsigned int __attribute_const__ read_cpuid_cachetype(void)
return read_cpuid(CPUID_CACHETYPE);
}
+static inline unsigned int __attribute_const__ read_cpuid_mputype(void)
+{
+ return read_cpuid(CPUID_MPUIR);
+}
+
#elif defined(CONFIG_CPU_V7M)
static inline unsigned int __attribute_const__ read_cpuid_id(void)
@@ -185,6 +190,11 @@ static inline unsigned int __attribute_const__ read_cpuid_cachetype(void)
return readl(BASEADDR_V7M_SCB + V7M_SCB_CTR);
}
+static inline unsigned int __attribute_const__ read_cpuid_mputype(void)
+{
+ return readl(BASEADDR_V7M_SCB + MPU_TYPE);
+}
+
#else /* ifdef CONFIG_CPU_CP15 / elif defined(CONFIG_CPU_V7M) */
static inline unsigned int __attribute_const__ read_cpuid_id(void)
diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h
index f13ae153fb24..ad0ca4f2ba13 100644
--- a/arch/arm/include/asm/elf.h
+++ b/arch/arm/include/asm/elf.h
@@ -100,10 +100,15 @@ struct elf32_hdr;
extern int elf_check_arch(const struct elf32_hdr *);
#define elf_check_arch elf_check_arch
+#define ELFOSABI_ARM_FDPIC 65 /* ARM FDPIC platform */
+#define elf_check_fdpic(x) ((x)->e_ident[EI_OSABI] == ELFOSABI_ARM_FDPIC)
+#define elf_check_const_displacement(x) ((x)->e_flags & EF_ARM_PIC)
+#define ELF_FDPIC_CORE_EFLAGS 0
+
#define vmcore_elf64_check_arch(x) (0)
-extern int arm_elf_read_implies_exec(const struct elf32_hdr *, int);
-#define elf_read_implies_exec(ex,stk) arm_elf_read_implies_exec(&(ex), stk)
+extern int arm_elf_read_implies_exec(int);
+#define elf_read_implies_exec(ex,stk) arm_elf_read_implies_exec(stk)
struct task_struct;
int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs);
@@ -120,6 +125,13 @@ int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs);
have no such handler. */
#define ELF_PLAT_INIT(_r, load_addr) (_r)->ARM_r0 = 0
+#define ELF_FDPIC_PLAT_INIT(_r, _exec_map_addr, _interp_map_addr, dynamic_addr) \
+ do { \
+ (_r)->ARM_r7 = _exec_map_addr; \
+ (_r)->ARM_r8 = _interp_map_addr; \
+ (_r)->ARM_r9 = dynamic_addr; \
+ } while(0)
+
extern void elf_set_personality(const struct elf32_hdr *);
#define SET_PERSONALITY(ex) elf_set_personality(&(ex))
diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h
index a5b47421059d..bdec37c6ac35 100644
--- a/arch/arm/include/asm/mmu.h
+++ b/arch/arm/include/asm/mmu.h
@@ -14,6 +14,10 @@ typedef struct {
#ifdef CONFIG_VDSO
unsigned long vdso;
#endif
+#ifdef CONFIG_BINFMT_ELF_FDPIC
+ unsigned long exec_fdpic_loadmap;
+ unsigned long interp_fdpic_loadmap;
+#endif
} mm_context_t;
#ifdef CONFIG_CPU_HAS_ASID
@@ -33,6 +37,10 @@ typedef struct {
*/
typedef struct {
unsigned long end_brk;
+#ifdef CONFIG_BINFMT_ELF_FDPIC
+ unsigned long exec_fdpic_loadmap;
+ unsigned long interp_fdpic_loadmap;
+#endif
} mm_context_t;
#endif
diff --git a/arch/arm/include/asm/mpu.h b/arch/arm/include/asm/mpu.h
index c3247cc2fe08..56ec02617f58 100644
--- a/arch/arm/include/asm/mpu.h
+++ b/arch/arm/include/asm/mpu.h
@@ -1,8 +1,6 @@
#ifndef __ARM_MPU_H
#define __ARM_MPU_H
-#ifdef CONFIG_ARM_MPU
-
/* MPUIR layout */
#define MPUIR_nU 1
#define MPUIR_DREGION 8
@@ -17,6 +15,11 @@
/* MPU D/I Size Register fields */
#define MPU_RSR_SZ 1
#define MPU_RSR_EN 0
+#define MPU_RSR_SD 8
+
+/* Number of subregions (SD) */
+#define MPU_NR_SUBREGS 8
+#define MPU_MIN_SUBREG_SIZE 256
/* The D/I RSR value for an enabled region spanning the whole of memory */
#define MPU_RSR_ALL_MEM 63
@@ -38,6 +41,7 @@
#endif
/* Access permission bits of ACR (only define those that we use)*/
+#define MPU_AP_PL1RO_PL0NA (0x5 << 8)
#define MPU_AP_PL1RW_PL0RW (0x3 << 8)
#define MPU_AP_PL1RW_PL0R0 (0x2 << 8)
#define MPU_AP_PL1RW_PL0NA (0x1 << 8)
@@ -46,7 +50,7 @@
#define MPU_PROBE_REGION 0
#define MPU_BG_REGION 1
#define MPU_RAM_REGION 2
-#define MPU_VECTORS_REGION 3
+#define MPU_ROM_REGION 3
/* Maximum number of regions Linux is interested in */
#define MPU_MAX_REGIONS 16
@@ -64,13 +68,23 @@ struct mpu_rgn {
};
struct mpu_rgn_info {
- u32 mpuir;
+ unsigned int used;
struct mpu_rgn rgns[MPU_MAX_REGIONS];
};
extern struct mpu_rgn_info mpu_rgn_info;
-#endif /* __ASSEMBLY__ */
+#ifdef CONFIG_ARM_MPU
+
+extern void __init adjust_lowmem_bounds_mpu(void);
+extern void __init mpu_setup(void);
-#endif /* CONFIG_ARM_MPU */
+#else
+
+static inline void adjust_lowmem_bounds_mpu(void) {}
+static inline void mpu_setup(void) {}
+
+#endif /* !CONFIG_ARM_MPU */
+
+#endif /* __ASSEMBLY__ */
#endif
diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h
index c3d5fc124a05..338cbe0a18ef 100644
--- a/arch/arm/include/asm/processor.h
+++ b/arch/arm/include/asm/processor.h
@@ -47,15 +47,24 @@ struct thread_struct {
#define INIT_THREAD { }
-#ifdef CONFIG_MMU
-#define nommu_start_thread(regs) do { } while (0)
-#else
-#define nommu_start_thread(regs) regs->ARM_r10 = current->mm->start_data
-#endif
-
#define start_thread(regs,pc,sp) \
({ \
+ unsigned long r7, r8, r9; \
+ \
+ if (IS_ENABLED(CONFIG_BINFMT_ELF_FDPIC)) { \
+ r7 = regs->ARM_r7; \
+ r8 = regs->ARM_r8; \
+ r9 = regs->ARM_r9; \
+ } \
memset(regs->uregs, 0, sizeof(regs->uregs)); \
+ if (IS_ENABLED(CONFIG_BINFMT_ELF_FDPIC) && \
+ current->personality & FDPIC_FUNCPTRS) { \
+ regs->ARM_r7 = r7; \
+ regs->ARM_r8 = r8; \
+ regs->ARM_r9 = r9; \
+ regs->ARM_r10 = current->mm->start_data; \
+ } else if (!IS_ENABLED(CONFIG_MMU)) \
+ regs->ARM_r10 = current->mm->start_data; \
if (current->personality & ADDR_LIMIT_32BIT) \
regs->ARM_cpsr = USR_MODE; \
else \
@@ -65,7 +74,6 @@ struct thread_struct {
regs->ARM_cpsr |= PSR_ENDSTATE; \
regs->ARM_pc = pc & ~1; /* pc */ \
regs->ARM_sp = sp; /* sp */ \
- nommu_start_thread(regs); \
})
/* Forward declaration, a strange C thing */
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 3d6dc8b460e4..709a55989cb0 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -60,7 +60,7 @@ asmlinkage void secondary_start_kernel(void);
*/
struct secondary_data {
union {
- unsigned long mpu_rgn_szr;
+ struct mpu_rgn_info *mpu_rgn_info;
u64 pgdir;
};
unsigned long swapper_pg_dir;
diff --git a/arch/arm/include/asm/ucontext.h b/arch/arm/include/asm/ucontext.h
index 921d8274855c..b42c75ae0d19 100644
--- a/arch/arm/include/asm/ucontext.h
+++ b/arch/arm/include/asm/ucontext.h
@@ -2,6 +2,7 @@
#define _ASMARM_UCONTEXT_H
#include <asm/fpstate.h>
+#include <asm/user.h>
/*
* struct sigcontext only has room for the basic registers, but struct
diff --git a/arch/arm/include/asm/v7m.h b/arch/arm/include/asm/v7m.h
index 1fd775c1bc5d..5de776c81382 100644
--- a/arch/arm/include/asm/v7m.h
+++ b/arch/arm/include/asm/v7m.h
@@ -57,6 +57,16 @@
#define V7M_SCB_CCSIDR 0x80 /* Cache size ID register */
#define V7M_SCB_CSSELR 0x84 /* Cache size selection register */
+/* Memory-mapped MPU registers for M-class */
+#define MPU_TYPE 0x90
+#define MPU_CTRL 0x94
+#define MPU_CTRL_ENABLE 1
+#define MPU_CTRL_PRIVDEFENA (1 << 2)
+
+#define MPU_RNR 0x98
+#define MPU_RBAR 0x9c
+#define MPU_RASR 0xa0
+
/* Cache opeartions */
#define V7M_SCB_ICIALLU 0x250 /* I-cache invalidate all to PoU */
#define V7M_SCB_ICIMVAU 0x258 /* I-cache invalidate by MVA to PoU */
diff --git a/arch/arm/include/uapi/asm/ptrace.h b/arch/arm/include/uapi/asm/ptrace.h
index 5af0ed1b825a..3173eb9751fd 100644
--- a/arch/arm/include/uapi/asm/ptrace.h
+++ b/arch/arm/include/uapi/asm/ptrace.h
@@ -31,6 +31,10 @@
#define PTRACE_SETVFPREGS 28
#define PTRACE_GETHBPREGS 29
#define PTRACE_SETHBPREGS 30
+#define PTRACE_GETFDPIC 31
+
+#define PTRACE_GETFDPIC_EXEC 0
+#define PTRACE_GETFDPIC_INTERP 1
/*
* PSR bits
diff --git a/arch/arm/include/uapi/asm/unistd.h b/arch/arm/include/uapi/asm/unistd.h
index 28bd456494a3..575b25fc29c6 100644
--- a/arch/arm/include/uapi/asm/unistd.h
+++ b/arch/arm/include/uapi/asm/unistd.h
@@ -35,5 +35,6 @@
#define __ARM_NR_usr26 (__ARM_NR_BASE+3)
#define __ARM_NR_usr32 (__ARM_NR_BASE+4)
#define __ARM_NR_set_tls (__ARM_NR_BASE+5)
+#define __ARM_NR_get_tls (__ARM_NR_BASE+6)
#endif /* _UAPI__ASM_ARM_UNISTD_H */
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index ad325a8c7e1e..52f437997cc6 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -87,6 +87,11 @@ head-y := head$(MMUEXT).o
obj-$(CONFIG_DEBUG_LL) += debug.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+# This is executed very early using a temporary stack when no memory allocator
+# nor global data is available. Everything has to be allocated on the stack.
+CFLAGS_head-inflate-data.o := $(call cc-option,-Wframe-larger-than=10240)
+obj-$(CONFIG_XIP_DEFLATED_DATA) += head-inflate-data.o
+
obj-$(CONFIG_ARM_VIRT_EXT) += hyp-stub.o
AFLAGS_hyp-stub.o :=-Wa,-march=armv7-a
ifeq ($(CONFIG_ARM_PSCI),y)
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
index 608008229c7d..f369ece99958 100644
--- a/arch/arm/kernel/asm-offsets.c
+++ b/arch/arm/kernel/asm-offsets.c
@@ -23,11 +23,13 @@
#include <asm/mach/arch.h>
#include <asm/thread_info.h>
#include <asm/memory.h>
+#include <asm/mpu.h>
#include <asm/procinfo.h>
#include <asm/suspend.h>
#include <asm/vdso_datapage.h>
#include <asm/hardware/cache-l2x0.h>
#include <linux/kbuild.h>
+#include "signal.h"
/*
* Make sure that the compiler and target are compatible.
@@ -112,6 +114,9 @@ int main(void)
DEFINE(SVC_ADDR_LIMIT, offsetof(struct svc_pt_regs, addr_limit));
DEFINE(SVC_REGS_SIZE, sizeof(struct svc_pt_regs));
BLANK();
+ DEFINE(SIGFRAME_RC3_OFFSET, offsetof(struct sigframe, retcode[3]));
+ DEFINE(RT_SIGFRAME_RC3_OFFSET, offsetof(struct rt_sigframe, sig.retcode[3]));
+ BLANK();
#ifdef CONFIG_CACHE_L2X0
DEFINE(L2X0_R_PHY_BASE, offsetof(struct l2x0_regs, phy_base));
DEFINE(L2X0_R_AUX_CTRL, offsetof(struct l2x0_regs, aux_ctrl));
@@ -183,5 +188,15 @@ int main(void)
#ifdef CONFIG_VDSO
DEFINE(VDSO_DATA_SIZE, sizeof(union vdso_data_store));
#endif
+ BLANK();
+#ifdef CONFIG_ARM_MPU
+ DEFINE(MPU_RNG_INFO_RNGS, offsetof(struct mpu_rgn_info, rgns));
+ DEFINE(MPU_RNG_INFO_USED, offsetof(struct mpu_rgn_info, used));
+
+ DEFINE(MPU_RNG_SIZE, sizeof(struct mpu_rgn));
+ DEFINE(MPU_RGN_DRBAR, offsetof(struct mpu_rgn, drbar));
+ DEFINE(MPU_RGN_DRSR, offsetof(struct mpu_rgn, drsr));
+ DEFINE(MPU_RGN_DRACR, offsetof(struct mpu_rgn, dracr));
+#endif
return 0;
}
diff --git a/arch/arm/kernel/elf.c b/arch/arm/kernel/elf.c
index d0d1e83150c9..569e69ece5ca 100644
--- a/arch/arm/kernel/elf.c
+++ b/arch/arm/kernel/elf.c
@@ -3,6 +3,7 @@
#include <linux/personality.h>
#include <linux/binfmts.h>
#include <linux/elf.h>
+#include <linux/elf-fdpic.h>
#include <asm/system_info.h>
int elf_check_arch(const struct elf32_hdr *x)
@@ -80,7 +81,7 @@ EXPORT_SYMBOL(elf_set_personality);
* - the binary requires an executable stack
* - we're running on a CPU which doesn't support NX.
*/
-int arm_elf_read_implies_exec(const struct elf32_hdr *x, int executable_stack)
+int arm_elf_read_implies_exec(int executable_stack)
{
if (executable_stack != EXSTACK_DISABLE_X)
return 1;
@@ -89,3 +90,24 @@ int arm_elf_read_implies_exec(const struct elf32_hdr *x, int executable_stack)
return 0;
}
EXPORT_SYMBOL(arm_elf_read_implies_exec);
+
+#if defined(CONFIG_MMU) && defined(CONFIG_BINFMT_ELF_FDPIC)
+
+void elf_fdpic_arch_lay_out_mm(struct elf_fdpic_params *exec_params,
+ struct elf_fdpic_params *interp_params,
+ unsigned long *start_stack,
+ unsigned long *start_brk)
+{
+ elf_set_personality(&exec_params->hdr);
+
+ exec_params->load_addr = 0x8000;
+ interp_params->load_addr = ELF_ET_DYN_BASE;
+ *start_stack = TASK_SIZE - SZ_16M;
+
+ if ((exec_params->flags & ELF_FDPIC_FLAG_ARRANGEMENT) == ELF_FDPIC_FLAG_INDEPENDENT) {
+ exec_params->flags &= ~ELF_FDPIC_FLAG_ARRANGEMENT;
+ exec_params->flags |= ELF_FDPIC_FLAG_CONSTDISP;
+ }
+}
+
+#endif
diff --git a/arch/arm/kernel/head-common.S b/arch/arm/kernel/head-common.S
index 8733012d231f..21dde771a7dd 100644
--- a/arch/arm/kernel/head-common.S
+++ b/arch/arm/kernel/head-common.S
@@ -79,47 +79,69 @@ ENDPROC(__vet_atags)
*/
__INIT
__mmap_switched:
- adr r3, __mmap_switched_data
-
- ldmia r3!, {r4, r5, r6, r7}
- cmp r4, r5 @ Copy data segment if needed
-1: cmpne r5, r6
- ldrne fp, [r4], #4
- strne fp, [r5], #4
- bne 1b
-
- mov fp, #0 @ Clear BSS (and zero fp)
-1: cmp r6, r7
- strcc fp, [r6],#4
- bcc 1b
-
- ARM( ldmia r3, {r4, r5, r6, r7, sp})
- THUMB( ldmia r3, {r4, r5, r6, r7} )
- THUMB( ldr sp, [r3, #16] )
- str r9, [r4] @ Save processor ID
- str r1, [r5] @ Save machine type
- str r2, [r6] @ Save atags pointer
- cmp r7, #0
- strne r0, [r7] @ Save control register values
+
+ mov r7, r1
+ mov r8, r2
+ mov r10, r0
+
+ adr r4, __mmap_switched_data
+ mov fp, #0
+
+#if defined(CONFIG_XIP_DEFLATED_DATA)
+ ARM( ldr sp, [r4], #4 )
+ THUMB( ldr sp, [r4] )
+ THUMB( add r4, #4 )
+ bl __inflate_kernel_data @ decompress .data to RAM
+ teq r0, #0
+ bne __error
+#elif defined(CONFIG_XIP_KERNEL)
+ ARM( ldmia r4!, {r0, r1, r2, sp} )
+ THUMB( ldmia r4!, {r0, r1, r2, r3} )
+ THUMB( mov sp, r3 )
+ sub r2, r2, r1
+ bl memcpy @ copy .data to RAM
+#endif
+
+ ARM( ldmia r4!, {r0, r1, sp} )
+ THUMB( ldmia r4!, {r0, r1, r3} )
+ THUMB( mov sp, r3 )
+ sub r1, r1, r0
+ bl __memzero @ clear .bss
+
+ ldmia r4, {r0, r1, r2, r3}
+ str r9, [r0] @ Save processor ID
+ str r7, [r1] @ Save machine type
+ str r8, [r2] @ Save atags pointer
+ cmp r3, #0
+ strne r10, [r3] @ Save control register values
+ mov lr, #0
b start_kernel
ENDPROC(__mmap_switched)
.align 2
.type __mmap_switched_data, %object
__mmap_switched_data:
- .long __data_loc @ r4
- .long _sdata @ r5
- .long __bss_start @ r6
- .long _end @ r7
- .long processor_id @ r4
- .long __machine_arch_type @ r5
- .long __atags_pointer @ r6
+#ifdef CONFIG_XIP_KERNEL
+#ifndef CONFIG_XIP_DEFLATED_DATA
+ .long _sdata @ r0
+ .long __data_loc @ r1
+ .long _edata_loc @ r2
+#endif
+ .long __bss_stop @ sp (temporary stack in .bss)
+#endif
+
+ .long __bss_start @ r0
+ .long __bss_stop @ r1
+ .long init_thread_union + THREAD_START_SP @ sp
+
+ .long processor_id @ r0
+ .long __machine_arch_type @ r1
+ .long __atags_pointer @ r2
#ifdef CONFIG_CPU_CP15
- .long cr_alignment @ r7
+ .long cr_alignment @ r3
#else
- .long 0 @ r7
+ .long 0 @ r3
#endif
- .long init_thread_union + THREAD_START_SP @ sp
.size __mmap_switched_data, . - __mmap_switched_data
/*
diff --git a/arch/arm/kernel/head-inflate-data.c b/arch/arm/kernel/head-inflate-data.c
new file mode 100644
index 000000000000..6dd0ce5e6058
--- /dev/null
+++ b/arch/arm/kernel/head-inflate-data.c
@@ -0,0 +1,62 @@
+/*
+ * XIP kernel .data segment decompressor
+ *
+ * Created by: Nicolas Pitre, August 2017
+ * Copyright: (C) 2017 Linaro Limited
+ *
+ * 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/init.h>
+#include <linux/zutil.h>
+
+/* for struct inflate_state */
+#include "../../../lib/zlib_inflate/inftrees.h"
+#include "../../../lib/zlib_inflate/inflate.h"
+#include "../../../lib/zlib_inflate/infutil.h"
+
+extern char __data_loc[];
+extern char _edata_loc[];
+extern char _sdata[];
+
+/*
+ * This code is called very early during the boot process to decompress
+ * the .data segment stored compressed in ROM. Therefore none of the global
+ * variables are valid yet, hence no kernel services such as memory
+ * allocation is available. Everything must be allocated on the stack and
+ * we must avoid any global data access. We use a temporary stack located
+ * in the .bss area. The linker script makes sure the .bss is big enough
+ * to hold our stack frame plus some room for called functions.
+ *
+ * We mimic the code in lib/decompress_inflate.c to use the smallest work
+ * area possible. And because everything is statically allocated on the
+ * stack then there is no need to clean up before returning.
+ */
+
+int __init __inflate_kernel_data(void)
+{
+ struct z_stream_s stream, *strm = &stream;
+ struct inflate_state state;
+ char *in = __data_loc;
+ int rc;
+
+ /* Check and skip gzip header (assume no filename) */
+ if (in[0] != 0x1f || in[1] != 0x8b || in[2] != 0x08 || in[3] & ~3)
+ return -1;
+ in += 10;
+
+ strm->workspace = &state;
+ strm->next_in = in;
+ strm->avail_in = _edata_loc - __data_loc; /* upper bound */
+ strm->next_out = _sdata;
+ strm->avail_out = _edata_loc - __data_loc;
+ zlib_inflateInit2(strm, -MAX_WBITS);
+ WS(strm)->inflate_state.wsize = 0;
+ WS(strm)->inflate_state.window = NULL;
+ rc = zlib_inflate(strm, Z_FINISH);
+ if (rc == Z_OK || rc == Z_STREAM_END)
+ rc = strm->avail_out; /* should be 0 */
+ return rc;
+}
diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S
index 2e21e08de747..2e38f85b757a 100644
--- a/arch/arm/kernel/head-nommu.S
+++ b/arch/arm/kernel/head-nommu.S
@@ -13,6 +13,7 @@
*/
#include <linux/linkage.h>
#include <linux/init.h>
+#include <linux/errno.h>
#include <asm/assembler.h>
#include <asm/ptrace.h>
@@ -110,8 +111,8 @@ ENTRY(secondary_startup)
#ifdef CONFIG_ARM_MPU
/* Use MPU region info supplied by __cpu_up */
- ldr r6, [r7] @ get secondary_data.mpu_szr
- bl __setup_mpu @ Initialize the MPU
+ ldr r6, [r7] @ get secondary_data.mpu_rgn_info
+ bl __secondary_setup_mpu @ Initialize the MPU
#endif
badr lr, 1f @ return (PIC) address
@@ -175,19 +176,33 @@ ENDPROC(__after_proc_init)
#ifdef CONFIG_ARM_MPU
+#ifndef CONFIG_CPU_V7M
/* Set which MPU region should be programmed */
-.macro set_region_nr tmp, rgnr
+.macro set_region_nr tmp, rgnr, unused
mov \tmp, \rgnr @ Use static region numbers
mcr p15, 0, \tmp, c6, c2, 0 @ Write RGNR
.endm
/* Setup a single MPU region, either D or I side (D-side for unified) */
-.macro setup_region bar, acr, sr, side = MPU_DATA_SIDE
+.macro setup_region bar, acr, sr, side = MPU_DATA_SIDE, unused
mcr p15, 0, \bar, c6, c1, (0 + \side) @ I/DRBAR
mcr p15, 0, \acr, c6, c1, (4 + \side) @ I/DRACR
mcr p15, 0, \sr, c6, c1, (2 + \side) @ I/DRSR
.endm
+#else
+.macro set_region_nr tmp, rgnr, base
+ mov \tmp, \rgnr
+ str \tmp, [\base, #MPU_RNR]
+.endm
+
+.macro setup_region bar, acr, sr, unused, base
+ lsl \acr, \acr, #16
+ orr \acr, \acr, \sr
+ str \bar, [\base, #MPU_RBAR]
+ str \acr, [\base, #MPU_RASR]
+.endm
+#endif
/*
* Setup the MPU and initial MPU Regions. We create the following regions:
* Region 0: Use this for probing the MPU details, so leave disabled.
@@ -201,64 +216,137 @@ ENDPROC(__after_proc_init)
ENTRY(__setup_mpu)
/* Probe for v7 PMSA compliance */
- mrc p15, 0, r0, c0, c1, 4 @ Read ID_MMFR0
+M_CLASS(movw r12, #:lower16:BASEADDR_V7M_SCB)
+M_CLASS(movt r12, #:upper16:BASEADDR_V7M_SCB)
+
+AR_CLASS(mrc p15, 0, r0, c0, c1, 4) @ Read ID_MMFR0
+M_CLASS(ldr r0, [r12, 0x50])
and r0, r0, #(MMFR0_PMSA) @ PMSA field
teq r0, #(MMFR0_PMSAv7) @ PMSA v7
- bne __error_p @ Fail: ARM_MPU on NOT v7 PMSA
+ bxne lr
/* Determine whether the D/I-side memory map is unified. We set the
* flags here and continue to use them for the rest of this function */
- mrc p15, 0, r0, c0, c0, 4 @ MPUIR
+AR_CLASS(mrc p15, 0, r0, c0, c0, 4) @ MPUIR
+M_CLASS(ldr r0, [r12, #MPU_TYPE])
ands r5, r0, #MPUIR_DREGION_SZMASK @ 0 size d region => No MPU
- beq __error_p @ Fail: ARM_MPU and no MPU
+ bxeq lr
tst r0, #MPUIR_nU @ MPUIR_nU = 0 for unified
/* Setup second region first to free up r6 */
- set_region_nr r0, #MPU_RAM_REGION
+ set_region_nr r0, #MPU_RAM_REGION, r12
isb
/* Full access from PL0, PL1, shared for CONFIG_SMP, cacheable */
ldr r0, =PLAT_PHYS_OFFSET @ RAM starts at PHYS_OFFSET
ldr r5,=(MPU_AP_PL1RW_PL0RW | MPU_RGN_NORMAL)