mirror of
https://github.com/ukui/kernel.git
synced 2026-03-09 10:07:04 -07:00
Merge branches 'arnd-fixes', 'clk', 'misc', 'v7' and 'fixes' into for-next
This commit is contained in:
@@ -67,6 +67,11 @@ Optional properties:
|
||||
disable if zero.
|
||||
- arm,prefetch-offset : Override prefetch offset value. Valid values are
|
||||
0-7, 15, 23, and 31.
|
||||
- prefetch-data : Data prefetch. Value: <0> (forcibly disable), <1>
|
||||
(forcibly enable), property absent (retain settings set by firmware)
|
||||
- prefetch-instr : Instruction prefetch. Value: <0> (forcibly disable),
|
||||
<1> (forcibly enable), property absent (retain settings set by
|
||||
firmware)
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
@@ -856,6 +856,10 @@ address which can extend beyond that limit.
|
||||
name may clash with standard defined ones, you prefix them with your
|
||||
vendor name and a comma.
|
||||
|
||||
Additional properties for the root node:
|
||||
|
||||
- serial-number : a string representing the device's serial number
|
||||
|
||||
b) The /cpus node
|
||||
|
||||
This node is the parent of all individual CPU nodes. It doesn't
|
||||
|
||||
@@ -60,7 +60,7 @@ config ARM
|
||||
select HAVE_KPROBES if !XIP_KERNEL && !CPU_ENDIAN_BE32 && !CPU_V7M
|
||||
select HAVE_KRETPROBES if (HAVE_KPROBES)
|
||||
select HAVE_MEMBLOCK
|
||||
select HAVE_MOD_ARCH_SPECIFIC if ARM_UNWIND
|
||||
select HAVE_MOD_ARCH_SPECIFIC
|
||||
select HAVE_OPROFILE if (HAVE_PERF_EVENTS)
|
||||
select HAVE_OPTPROBES if !THUMB2_KERNEL
|
||||
select HAVE_PERF_EVENTS
|
||||
@@ -975,11 +975,6 @@ config PLAT_PXA
|
||||
config PLAT_VERSATILE
|
||||
bool
|
||||
|
||||
config ARM_TIMER_SP804
|
||||
bool
|
||||
select CLKSRC_MMIO
|
||||
select CLKSRC_OF if OF
|
||||
|
||||
source "arch/arm/firmware/Kconfig"
|
||||
|
||||
source arch/arm/mm/Kconfig
|
||||
@@ -1682,6 +1677,21 @@ config HAVE_ARCH_TRANSPARENT_HUGEPAGE
|
||||
config ARCH_WANT_GENERAL_HUGETLB
|
||||
def_bool y
|
||||
|
||||
config ARM_MODULE_PLTS
|
||||
bool "Use PLTs to allow module memory to spill over into vmalloc area"
|
||||
depends on MODULES
|
||||
help
|
||||
Allocate PLTs when loading modules so that jumps and calls whose
|
||||
targets are too far away for their relative offsets to be encoded
|
||||
in the instructions themselves can be bounced via veneers in the
|
||||
module's PLT. This allows modules to be allocated in the generic
|
||||
vmalloc area after the dedicated module memory area has been
|
||||
exhausted. The modules will use slightly more memory, but after
|
||||
rounding up to page size, the actual memory footprint is usually
|
||||
the same.
|
||||
|
||||
Say y if you are getting out of memory errors while loading modules
|
||||
|
||||
source "mm/Kconfig"
|
||||
|
||||
config FORCE_MAX_ZONEORDER
|
||||
|
||||
@@ -19,6 +19,10 @@ LDFLAGS_vmlinux += --be8
|
||||
LDFLAGS_MODULE += --be8
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARM_MODULE_PLTS),y)
|
||||
LDFLAGS_MODULE += -T $(srctree)/arch/arm/kernel/module.lds
|
||||
endif
|
||||
|
||||
OBJCOPYFLAGS :=-O binary -R .comment -S
|
||||
GZFLAGS :=-9
|
||||
#KBUILD_CFLAGS +=-pipe
|
||||
|
||||
@@ -11,7 +11,6 @@ obj-$(CONFIG_SHARP_LOCOMO) += locomo.o
|
||||
obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o
|
||||
obj-$(CONFIG_SHARP_SCOOP) += scoop.o
|
||||
obj-$(CONFIG_PCI_HOST_ITE8152) += it8152.o
|
||||
obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp.o
|
||||
obj-$(CONFIG_MCPM) += mcpm_head.o mcpm_entry.o mcpm_platsmp.o vlock.o
|
||||
CFLAGS_REMOVE_mcpm_entry.o = -pg
|
||||
AFLAGS_mcpm_head.o := -march=armv7-a
|
||||
|
||||
@@ -94,6 +94,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* Cause a link-time error, the xchg() size is not supported */
|
||||
__bad_xchg(ptr, size), ret = 0;
|
||||
break;
|
||||
}
|
||||
@@ -102,8 +103,10 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define xchg(ptr,x) \
|
||||
((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
|
||||
#define xchg(ptr, x) ({ \
|
||||
(__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), \
|
||||
sizeof(*(ptr))); \
|
||||
})
|
||||
|
||||
#include <asm-generic/cmpxchg-local.h>
|
||||
|
||||
@@ -118,14 +121,16 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
|
||||
* cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
|
||||
* them available.
|
||||
*/
|
||||
#define cmpxchg_local(ptr, o, n) \
|
||||
((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
|
||||
(unsigned long)(n), sizeof(*(ptr))))
|
||||
#define cmpxchg_local(ptr, o, n) ({ \
|
||||
(__typeof(*ptr))__cmpxchg_local_generic((ptr), \
|
||||
(unsigned long)(o), \
|
||||
(unsigned long)(n), \
|
||||
sizeof(*(ptr))); \
|
||||
})
|
||||
|
||||
#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
|
||||
|
||||
#ifndef CONFIG_SMP
|
||||
#include <asm-generic/cmpxchg.h>
|
||||
#endif
|
||||
|
||||
#else /* min ARCH >= ARMv6 */
|
||||
|
||||
@@ -201,11 +206,12 @@ static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define cmpxchg(ptr,o,n) \
|
||||
((__typeof__(*(ptr)))__cmpxchg_mb((ptr), \
|
||||
(unsigned long)(o), \
|
||||
(unsigned long)(n), \
|
||||
sizeof(*(ptr))))
|
||||
#define cmpxchg(ptr,o,n) ({ \
|
||||
(__typeof__(*(ptr)))__cmpxchg_mb((ptr), \
|
||||
(unsigned long)(o), \
|
||||
(unsigned long)(n), \
|
||||
sizeof(*(ptr))); \
|
||||
})
|
||||
|
||||
static inline unsigned long __cmpxchg_local(volatile void *ptr,
|
||||
unsigned long old,
|
||||
@@ -227,6 +233,13 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define cmpxchg_local(ptr, o, n) ({ \
|
||||
(__typeof(*ptr))__cmpxchg_local((ptr), \
|
||||
(unsigned long)(o), \
|
||||
(unsigned long)(n), \
|
||||
sizeof(*(ptr))); \
|
||||
})
|
||||
|
||||
static inline unsigned long long __cmpxchg64(unsigned long long *ptr,
|
||||
unsigned long long old,
|
||||
unsigned long long new)
|
||||
@@ -252,6 +265,14 @@ static inline unsigned long long __cmpxchg64(unsigned long long *ptr,
|
||||
return oldval;
|
||||
}
|
||||
|
||||
#define cmpxchg64_relaxed(ptr, o, n) ({ \
|
||||
(__typeof__(*(ptr)))__cmpxchg64((ptr), \
|
||||
(unsigned long long)(o), \
|
||||
(unsigned long long)(n)); \
|
||||
})
|
||||
|
||||
#define cmpxchg64_local(ptr, o, n) cmpxchg64_relaxed((ptr), (o), (n))
|
||||
|
||||
static inline unsigned long long __cmpxchg64_mb(unsigned long long *ptr,
|
||||
unsigned long long old,
|
||||
unsigned long long new)
|
||||
@@ -265,23 +286,11 @@ static inline unsigned long long __cmpxchg64_mb(unsigned long long *ptr,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define cmpxchg_local(ptr,o,n) \
|
||||
((__typeof__(*(ptr)))__cmpxchg_local((ptr), \
|
||||
(unsigned long)(o), \
|
||||
(unsigned long)(n), \
|
||||
sizeof(*(ptr))))
|
||||
|
||||
#define cmpxchg64(ptr, o, n) \
|
||||
((__typeof__(*(ptr)))__cmpxchg64_mb((ptr), \
|
||||
(unsigned long long)(o), \
|
||||
(unsigned long long)(n)))
|
||||
|
||||
#define cmpxchg64_relaxed(ptr, o, n) \
|
||||
((__typeof__(*(ptr)))__cmpxchg64((ptr), \
|
||||
(unsigned long long)(o), \
|
||||
(unsigned long long)(n)))
|
||||
|
||||
#define cmpxchg64_local(ptr, o, n) cmpxchg64_relaxed((ptr), (o), (n))
|
||||
#define cmpxchg64(ptr, o, n) ({ \
|
||||
(__typeof__(*(ptr)))__cmpxchg64_mb((ptr), \
|
||||
(unsigned long long)(o), \
|
||||
(unsigned long long)(n)); \
|
||||
})
|
||||
|
||||
#endif /* __LINUX_ARM_ARCH__ >= 6 */
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ struct dma_iommu_mapping {
|
||||
};
|
||||
|
||||
struct dma_iommu_mapping *
|
||||
arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size);
|
||||
arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, u64 size);
|
||||
|
||||
void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping);
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/blk_types.h>
|
||||
#include <asm/byteorder.h>
|
||||
@@ -73,17 +74,16 @@ void __raw_readsl(const volatile void __iomem *addr, void *data, int longlen);
|
||||
static inline void __raw_writew(u16 val, volatile void __iomem *addr)
|
||||
{
|
||||
asm volatile("strh %1, %0"
|
||||
: "+Q" (*(volatile u16 __force *)addr)
|
||||
: "r" (val));
|
||||
: : "Q" (*(volatile u16 __force *)addr), "r" (val));
|
||||
}
|
||||
|
||||
#define __raw_readw __raw_readw
|
||||
static inline u16 __raw_readw(const volatile void __iomem *addr)
|
||||
{
|
||||
u16 val;
|
||||
asm volatile("ldrh %1, %0"
|
||||
: "+Q" (*(volatile u16 __force *)addr),
|
||||
"=r" (val));
|
||||
asm volatile("ldrh %0, %1"
|
||||
: "=r" (val)
|
||||
: "Q" (*(volatile u16 __force *)addr));
|
||||
return val;
|
||||
}
|
||||
#endif
|
||||
@@ -92,25 +92,23 @@ static inline u16 __raw_readw(const volatile void __iomem *addr)
|
||||
static inline void __raw_writeb(u8 val, volatile void __iomem *addr)
|
||||
{
|
||||
asm volatile("strb %1, %0"
|
||||
: "+Qo" (*(volatile u8 __force *)addr)
|
||||
: "r" (val));
|
||||
: : "Qo" (*(volatile u8 __force *)addr), "r" (val));
|
||||
}
|
||||
|
||||
#define __raw_writel __raw_writel
|
||||
static inline void __raw_writel(u32 val, volatile void __iomem *addr)
|
||||
{
|
||||
asm volatile("str %1, %0"
|
||||
: "+Qo" (*(volatile u32 __force *)addr)
|
||||
: "r" (val));
|
||||
: : "Qo" (*(volatile u32 __force *)addr), "r" (val));
|
||||
}
|
||||
|
||||
#define __raw_readb __raw_readb
|
||||
static inline u8 __raw_readb(const volatile void __iomem *addr)
|
||||
{
|
||||
u8 val;
|
||||
asm volatile("ldrb %1, %0"
|
||||
: "+Qo" (*(volatile u8 __force *)addr),
|
||||
"=r" (val));
|
||||
asm volatile("ldrb %0, %1"
|
||||
: "=r" (val)
|
||||
: "Qo" (*(volatile u8 __force *)addr));
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -118,9 +116,9 @@ static inline u8 __raw_readb(const volatile void __iomem *addr)
|
||||
static inline u32 __raw_readl(const volatile void __iomem *addr)
|
||||
{
|
||||
u32 val;
|
||||
asm volatile("ldr %1, %0"
|
||||
: "+Qo" (*(volatile u32 __force *)addr),
|
||||
"=r" (val));
|
||||
asm volatile("ldr %0, %1"
|
||||
: "=r" (val)
|
||||
: "Qo" (*(volatile u32 __force *)addr));
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -319,9 +317,33 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
|
||||
#define writesw(p,d,l) __raw_writesw(p,d,l)
|
||||
#define writesl(p,d,l) __raw_writesl(p,d,l)
|
||||
|
||||
#ifndef __ARMBE__
|
||||
static inline void memset_io(volatile void __iomem *dst, unsigned c,
|
||||
size_t count)
|
||||
{
|
||||
memset((void __force *)dst, c, count);
|
||||
}
|
||||
#define memset_io(dst,c,count) memset_io(dst,c,count)
|
||||
|
||||
static inline void memcpy_fromio(void *to, const volatile void __iomem *from,
|
||||
size_t count)
|
||||
{
|
||||
memcpy(to, (const void __force *)from, count);
|
||||
}
|
||||
#define memcpy_fromio(to,from,count) memcpy_fromio(to,from,count)
|
||||
|
||||
static inline void memcpy_toio(volatile void __iomem *to, const void *from,
|
||||
size_t count)
|
||||
{
|
||||
memcpy((void __force *)to, from, count);
|
||||
}
|
||||
#define memcpy_toio(to,from,count) memcpy_toio(to,from,count)
|
||||
|
||||
#else
|
||||
#define memset_io(c,v,l) _memset_io(c,(v),(l))
|
||||
#define memcpy_fromio(a,c,l) _memcpy_fromio((a),c,(l))
|
||||
#define memcpy_toio(c,a,l) _memcpy_toio(c,(a),(l))
|
||||
#endif
|
||||
|
||||
#endif /* readl */
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ struct machine_desc {
|
||||
bool (*smp_init)(void);
|
||||
void (*fixup)(struct tag *, char **);
|
||||
void (*dt_fixup)(void);
|
||||
void (*init_meminfo)(void);
|
||||
long long (*pv_fixup)(void);
|
||||
void (*reserve)(void);/* reserve mem blocks */
|
||||
void (*map_io)(void);/* IO mapping function */
|
||||
void (*init_early)(void);
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/sizes.h>
|
||||
|
||||
#include <asm/cache.h>
|
||||
|
||||
#ifdef CONFIG_NEED_MACH_MEMORY_H
|
||||
#include <mach/memory.h>
|
||||
#endif
|
||||
@@ -132,20 +130,6 @@
|
||||
#define page_to_phys(page) (__pfn_to_phys(page_to_pfn(page)))
|
||||
#define phys_to_page(phys) (pfn_to_page(__phys_to_pfn(phys)))
|
||||
|
||||
/*
|
||||
* Minimum guaranted alignment in pgd_alloc(). The page table pointers passed
|
||||
* around in head.S and proc-*.S are shifted by this amount, in order to
|
||||
* leave spare high bits for systems with physical address extension. This
|
||||
* does not fully accomodate the 40-bit addressing capability of ARM LPAE, but
|
||||
* gives us about 38-bits or so.
|
||||
*/
|
||||
#ifdef CONFIG_ARM_LPAE
|
||||
#define ARCH_PGD_SHIFT L1_CACHE_SHIFT
|
||||
#else
|
||||
#define ARCH_PGD_SHIFT 0
|
||||
#endif
|
||||
#define ARCH_PGD_MASK ((1 << ARCH_PGD_SHIFT) - 1)
|
||||
|
||||
/*
|
||||
* PLAT_PHYS_OFFSET is the offset (from zero) of the start of physical
|
||||
* memory. This is used for XIP and NoMMU kernels, and on platforms that don't
|
||||
|
||||
@@ -16,11 +16,21 @@ enum {
|
||||
ARM_SEC_UNLIKELY,
|
||||
ARM_SEC_MAX,
|
||||
};
|
||||
#endif
|
||||
|
||||
struct mod_arch_specific {
|
||||
#ifdef CONFIG_ARM_UNWIND
|
||||
struct unwind_table *unwind[ARM_SEC_MAX];
|
||||
};
|
||||
#endif
|
||||
#ifdef CONFIG_ARM_MODULE_PLTS
|
||||
struct elf32_shdr *core_plt;
|
||||
struct elf32_shdr *init_plt;
|
||||
int core_plt_count;
|
||||
int init_plt_count;
|
||||
#endif
|
||||
};
|
||||
|
||||
u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val);
|
||||
|
||||
/*
|
||||
* Add the ARM architecture version to the version magic string
|
||||
|
||||
@@ -125,13 +125,6 @@ extern void cpu_resume(void);
|
||||
ttbr; \
|
||||
})
|
||||
|
||||
#define cpu_set_ttbr(nr, val) \
|
||||
do { \
|
||||
u64 ttbr = val; \
|
||||
__asm__("mcrr p15, " #nr ", %Q0, %R0, c2" \
|
||||
: : "r" (ttbr)); \
|
||||
} while (0)
|
||||
|
||||
#define cpu_get_pgd() \
|
||||
({ \
|
||||
u64 pg = cpu_get_ttbr(0); \
|
||||
|
||||
@@ -61,7 +61,7 @@ asmlinkage void secondary_start_kernel(void);
|
||||
struct secondary_data {
|
||||
union {
|
||||
unsigned long mpu_rgn_szr;
|
||||
unsigned long pgdir;
|
||||
u64 pgdir;
|
||||
};
|
||||
unsigned long swapper_pg_dir;
|
||||
void *stack;
|
||||
@@ -69,6 +69,7 @@ struct secondary_data {
|
||||
extern struct secondary_data secondary_data;
|
||||
extern volatile int pen_release;
|
||||
extern void secondary_startup(void);
|
||||
extern void secondary_startup_arm(void);
|
||||
|
||||
extern int __cpu_disable(void);
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
/* information about the system we're running on */
|
||||
extern unsigned int system_rev;
|
||||
extern const char *system_serial;
|
||||
extern unsigned int system_serial_low;
|
||||
extern unsigned int system_serial_high;
|
||||
extern unsigned int mem_fclk_21285;
|
||||
|
||||
@@ -34,6 +34,7 @@ obj-$(CONFIG_CPU_IDLE) += cpuidle.o
|
||||
obj-$(CONFIG_ISA_DMA_API) += dma.o
|
||||
obj-$(CONFIG_FIQ) += fiq.o fiqasm.o
|
||||
obj-$(CONFIG_MODULES) += armksyms.o module.o
|
||||
obj-$(CONFIG_ARM_MODULE_PLTS) += module-plts.o
|
||||
obj-$(CONFIG_ISA_DMA) += dma-isa.o
|
||||
obj-$(CONFIG_PCI) += bios32.o isa.o
|
||||
obj-$(CONFIG_ARM_CPU_SUSPEND) += sleep.o suspend.o
|
||||
|
||||
@@ -33,7 +33,9 @@ ret_fast_syscall:
|
||||
UNWIND(.fnstart )
|
||||
UNWIND(.cantunwind )
|
||||
disable_irq @ disable interrupts
|
||||
ldr r1, [tsk, #TI_FLAGS]
|
||||
ldr r1, [tsk, #TI_FLAGS] @ re-check for syscall tracing
|
||||
tst r1, #_TIF_SYSCALL_WORK
|
||||
bne __sys_trace_return
|
||||
tst r1, #_TIF_WORK_MASK
|
||||
bne fast_work_pending
|
||||
asm_trace_hardirqs_on
|
||||
|
||||
@@ -117,9 +117,14 @@ ENTRY(__switch_to)
|
||||
ENDPROC(__switch_to)
|
||||
|
||||
.data
|
||||
.align 8
|
||||
#if CONFIG_CPU_V7M_NUM_IRQ <= 112
|
||||
.align 9
|
||||
#else
|
||||
.align 10
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Vector table (64 words => 256 bytes natural alignment)
|
||||
* Vector table (Natural alignment need to be ensured)
|
||||
*/
|
||||
ENTRY(vector_table)
|
||||
.long 0 @ 0 - Reset stack pointer
|
||||
@@ -138,6 +143,6 @@ ENTRY(vector_table)
|
||||
.long __invalid_entry @ 13 - Reserved
|
||||
.long __pendsv_entry @ 14 - PendSV
|
||||
.long __invalid_entry @ 15 - SysTick
|
||||
.rept 64 - 16
|
||||
.long __irq_entry @ 16..64 - External Interrupts
|
||||
.rept CONFIG_CPU_V7M_NUM_IRQ
|
||||
.long __irq_entry @ External Interrupts
|
||||
.endr
|
||||
|
||||
@@ -123,7 +123,7 @@ ENTRY(secondary_startup)
|
||||
ENDPROC(secondary_startup)
|
||||
|
||||
ENTRY(__secondary_switched)
|
||||
ldr sp, [r7, #8] @ set up the stack pointer
|
||||
ldr sp, [r7, #12] @ set up the stack pointer
|
||||
mov fp, #0
|
||||
b secondary_start_kernel
|
||||
ENDPROC(__secondary_switched)
|
||||
|
||||
@@ -131,13 +131,30 @@ ENTRY(stext)
|
||||
* The following calls CPU specific code in a position independent
|
||||
* manner. See arch/arm/mm/proc-*.S for details. r10 = base of
|
||||
* xxx_proc_info structure selected by __lookup_processor_type
|
||||
* above. On return, the CPU will be ready for the MMU to be
|
||||
* turned on, and r0 will hold the CPU control register value.
|
||||
* above.
|
||||
*
|
||||
* The processor init function will be called with:
|
||||
* r1 - machine type
|
||||
* r2 - boot data (atags/dt) pointer
|
||||
* r4 - translation table base (low word)
|
||||
* r5 - translation table base (high word, if LPAE)
|
||||
* r8 - translation table base 1 (pfn if LPAE)
|
||||
* r9 - cpuid
|
||||
* r13 - virtual address for __enable_mmu -> __turn_mmu_on
|
||||
*
|
||||
* On return, the CPU will be ready for the MMU to be turned on,
|
||||
* r0 will hold the CPU control register value, r1, r2, r4, and
|
||||
* r9 will be preserved. r5 will also be preserved if LPAE.
|
||||
*/
|
||||
ldr r13, =__mmap_switched @ address to jump to after
|
||||
@ mmu has been enabled
|
||||
adr lr, BSYM(1f) @ return (PIC) address
|
||||
#ifdef CONFIG_ARM_LPAE
|
||||
mov r5, #0 @ high TTBR0
|
||||
mov r8, r4, lsr #12 @ TTBR1 is swapper_pg_dir pfn
|
||||
#else
|
||||
mov r8, r4 @ set TTBR1 to swapper_pg_dir
|
||||
#endif
|
||||
ldr r12, [r10, #PROCINFO_INITFUNC]
|
||||
add r12, r12, r10
|
||||
ret r12
|
||||
@@ -158,7 +175,7 @@ ENDPROC(stext)
|
||||
*
|
||||
* Returns:
|
||||
* r0, r3, r5-r7 corrupted
|
||||
* r4 = page table (see ARCH_PGD_SHIFT in asm/memory.h)
|
||||
* r4 = physical page table address
|
||||
*/
|
||||
__create_page_tables:
|
||||
pgtbl r4, r8 @ page table address
|
||||
@@ -333,7 +350,6 @@ __create_page_tables:
|
||||
#endif
|
||||
#ifdef CONFIG_ARM_LPAE
|
||||
sub r4, r4, #0x1000 @ point to the PGD table
|
||||
mov r4, r4, lsr #ARCH_PGD_SHIFT
|
||||
#endif
|
||||
ret lr
|
||||
ENDPROC(__create_page_tables)
|
||||
@@ -346,8 +362,8 @@ __turn_mmu_on_loc:
|
||||
|
||||
#if defined(CONFIG_SMP)
|
||||
.text
|
||||
ENTRY(secondary_startup_arm)
|
||||
.arm
|
||||
ENTRY(secondary_startup_arm)
|
||||
THUMB( adr r9, BSYM(1f) ) @ Kernel is entered in ARM.
|
||||
THUMB( bx r9 ) @ If this is a Thumb-2 kernel,
|
||||
THUMB( .thumb ) @ switch to Thumb now.
|
||||
@@ -381,9 +397,9 @@ ENTRY(secondary_startup)
|
||||
adr r4, __secondary_data
|
||||
ldmia r4, {r5, r7, r12} @ address to jump to after
|
||||
sub lr, r4, r5 @ mmu has been enabled
|
||||
ldr r4, [r7, lr] @ get secondary_data.pgdir
|
||||
add r7, r7, #4
|
||||
ldr r8, [r7, lr] @ get secondary_data.swapper_pg_dir
|
||||
add r3, r7, lr
|
||||
ldrd r4, [r3, #0] @ get secondary_data.pgdir
|
||||
ldr r8, [r3, #8] @ get secondary_data.swapper_pg_dir
|
||||
adr lr, BSYM(__enable_mmu) @ return address
|
||||
mov r13, r12 @ __secondary_switched address
|
||||
ldr r12, [r10, #PROCINFO_INITFUNC]
|
||||
@@ -397,7 +413,7 @@ ENDPROC(secondary_startup_arm)
|
||||
* r6 = &secondary_data
|
||||
*/
|
||||
ENTRY(__secondary_switched)
|
||||
ldr sp, [r7, #4] @ get secondary_data.stack
|
||||
ldr sp, [r7, #12] @ get secondary_data.stack
|
||||
mov fp, #0
|
||||
b secondary_start_kernel
|
||||
ENDPROC(__secondary_switched)
|
||||
@@ -416,12 +432,14 @@ __secondary_data:
|
||||
/*
|
||||
* Setup common bits before finally enabling the MMU. Essentially
|
||||
* this is just loading the page table pointer and domain access
|
||||
* registers.
|
||||
* registers. All these registers need to be preserved by the
|
||||
* processor setup function (or set in the case of r0)
|
||||
*
|
||||
* r0 = cp#15 control register
|
||||
* r1 = machine ID
|
||||
* r2 = atags or dtb pointer
|
||||
* r4 = page table (see ARCH_PGD_SHIFT in asm/memory.h)
|
||||
* r4 = TTBR pointer (low word)
|
||||
* r5 = TTBR pointer (high word if LPAE)
|
||||
* r9 = processor ID
|
||||
* r13 = *virtual* address to jump to upon completion
|
||||
*/
|
||||
@@ -440,7 +458,9 @@ __enable_mmu:
|
||||
#ifdef CONFIG_CPU_ICACHE_DISABLE
|
||||
bic r0, r0, #CR_I
|
||||
#endif
|
||||
#ifndef CONFIG_ARM_LPAE
|
||||
#ifdef CONFIG_ARM_LPAE
|
||||
mcrr p15, 0, r4, r5, c2 @ load TTBR0
|
||||
#else
|
||||
mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \
|
||||
domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
|
||||
domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \
|
||||
|
||||
183
arch/arm/kernel/module-plts.c
Normal file
183
arch/arm/kernel/module-plts.c
Normal file
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 <linux/elf.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <asm/cache.h>
|
||||
#include <asm/opcodes.h>
|
||||
|
||||
#define PLT_ENT_STRIDE L1_CACHE_BYTES
|
||||
#define PLT_ENT_COUNT (PLT_ENT_STRIDE / sizeof(u32))
|
||||
#define PLT_ENT_SIZE (sizeof(struct plt_entries) / PLT_ENT_COUNT)
|
||||
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
#define PLT_ENT_LDR __opcode_to_mem_thumb32(0xf8dff000 | \
|
||||
(PLT_ENT_STRIDE - 4))
|
||||
#else
|
||||
#define PLT_ENT_LDR __opcode_to_mem_arm(0xe59ff000 | \
|
||||
(PLT_ENT_STRIDE - 8))
|
||||
#endif
|
||||
|
||||
struct plt_entries {
|
||||
u32 ldr[PLT_ENT_COUNT];
|
||||
u32 lit[PLT_ENT_COUNT];
|
||||
};
|
||||
|
||||
static bool in_init(const struct module *mod, u32 addr)
|
||||
{
|
||||
return addr - (u32)mod->module_init < mod->init_size;
|
||||
}
|
||||
|
||||
u32 get_module_plt(struct module *mod, unsigned long loc, Elf32_Addr val)
|
||||
{
|
||||
struct plt_entries *plt, *plt_end;
|
||||
int c, *count;
|
||||
|
||||
if (in_init(mod, loc)) {
|
||||
plt = (void *)mod->arch.init_plt->sh_addr;
|
||||
plt_end = (void *)plt + mod->arch.init_plt->sh_size;
|
||||
count = &mod->arch.init_plt_count;
|
||||
} else {
|
||||
plt = (void *)mod->arch.core_plt->sh_addr;
|
||||
plt_end = (void *)plt + mod->arch.core_plt->sh_size;
|
||||
count = &mod->arch.core_plt_count;
|
||||
}
|
||||
|
||||
/* Look for an existing entry pointing to 'val' */
|
||||
for (c = *count; plt < plt_end; c -= PLT_ENT_COUNT, plt++) {
|
||||
int i;
|
||||
|
||||
if (!c) {
|
||||
/* Populate a new set of entries */
|
||||
*plt = (struct plt_entries){
|
||||
{ [0 ... PLT_ENT_COUNT - 1] = PLT_ENT_LDR, },
|
||||
{ val, }
|
||||
};
|
||||
++*count;
|
||||
return (u32)plt->ldr;
|
||||
}
|
||||
for (i = 0; i < PLT_ENT_COUNT; i++) {
|
||||
if (!plt->lit[i]) {
|
||||
plt->lit[i] = val;
|
||||
++*count;
|
||||
}
|
||||
if (plt->lit[i] == val)
|
||||
return (u32)&plt->ldr[i];
|
||||
}
|
||||
}
|
||||
BUG();
|
||||
}
|
||||
|
||||
static int duplicate_rel(Elf32_Addr base, const Elf32_Rel *rel, int num,
|
||||
u32 mask)
|
||||
{
|
||||
u32 *loc1, *loc2;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
if (rel[i].r_info != rel[num].r_info)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Identical relocation types against identical symbols can
|
||||
* still result in different PLT entries if the addend in the
|
||||
* place is different. So resolve the target of the relocation
|
||||
* to compare the values.
|
||||
*/
|
||||
loc1 = (u32 *)(base + rel[i].r_offset);
|
||||
loc2 = (u32 *)(base + rel[num].r_offset);
|
||||
if (((*loc1 ^ *loc2) & mask) == 0)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Count how many PLT entries we may need */
|
||||
static unsigned int count_plts(Elf32_Addr base, const Elf32_Rel *rel, int num)
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Sure, this is order(n^2), but it's usually short, and not
|
||||
* time critical
|
||||
*/
|
||||
for (i = 0; i < num; i++)
|
||||
switch (ELF32_R_TYPE(rel[i].r_info)) {
|
||||
case R_ARM_CALL:
|
||||
case R_ARM_PC24:
|
||||
case R_ARM_JUMP24:
|
||||
if (!duplicate_rel(base, rel, i,
|
||||
__opcode_to_mem_arm(0x00ffffff)))
|
||||
ret++;
|
||||
break;
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
case R_ARM_THM_CALL:
|
||||
case R_ARM_THM_JUMP24:
|
||||
if (!duplicate_rel(base, rel, i,
|
||||
__opcode_to_mem_thumb32(0x07ff2fff)))
|
||||
ret++;
|
||||
#endif
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
|
||||
char *secstrings, struct module *mod)
|
||||
{
|
||||
unsigned long core_plts = 0, init_plts = 0;
|
||||
Elf32_Shdr *s, *sechdrs_end = sechdrs + ehdr->e_shnum;
|
||||
|
||||
/*
|
||||
* To store the PLTs, we expand the .text section for core module code
|
||||
* and the .init.text section for initialization code.
|
||||
*/
|
||||
for (s = sechdrs; s < sechdrs_end; ++s)
|
||||
if (strcmp(".core.plt", secstrings + s->sh_name) == 0)
|
||||
mod->arch.core_plt = s;
|
||||
else if (strcmp(".init.plt", secstrings + s->sh_name) == 0)
|
||||
mod->arch.init_plt = s;
|
||||
|
||||
if (!mod->arch.core_plt || !mod->arch.init_plt) {
|
||||
pr_err("%s: sections missing\n", mod->name);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
for (s = sechdrs + 1; s < sechdrs_end; ++s) {
|
||||
const Elf32_Rel *rels = (void *)ehdr + s->sh_offset;
|
||||
int numrels = s->sh_size / sizeof(Elf32_Rel);
|
||||
Elf32_Shdr *dstsec = sechdrs + s->sh_info;
|
||||
|
||||
if (s->sh_type != SHT_REL)
|
||||
continue;
|
||||
|
||||
if (strstr(secstrings + s->sh_name, ".init"))
|
||||
init_plts += count_plts(dstsec->sh_addr, rels, numrels);
|
||||
else
|
||||
core_plts += count_plts(dstsec->sh_addr, rels, numrels);
|
||||
}
|
||||
|
||||
mod->arch.core_plt->sh_type = SHT_NOBITS;
|
||||
mod->arch.core_plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
|
||||
mod->arch.core_plt->sh_addralign = L1_CACHE_BYTES;
|
||||
mod->arch.core_plt->sh_size = round_up(core_plts * PLT_ENT_SIZE,
|
||||
sizeof(struct plt_entries));
|
||||
mod->arch.core_plt_count = 0;
|
||||
|
||||
mod->arch.init_plt->sh_type = SHT_NOBITS;
|
||||
mod->arch.init_plt->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
|
||||
mod->arch.init_plt->sh_addralign = L1_CACHE_BYTES;
|
||||
mod->arch.init_plt->sh_size = round_up(init_plts * PLT_ENT_SIZE,
|
||||
sizeof(struct plt_entries));
|
||||
mod->arch.init_plt_count = 0;
|
||||
pr_debug("%s: core.plt=%x, init.plt=%x\n", __func__,
|
||||
mod->arch.core_plt->sh_size, mod->arch.init_plt->sh_size);
|
||||
return 0;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user