Merge branch 'devel-stable' into for-next
Conflicts: arch/arm/include/asm/atomic.h arch/arm/include/asm/hardirq.h arch/arm/kernel/smp.c
This commit is contained in:
@@ -17,7 +17,8 @@ CFLAGS_REMOVE_return_address.o = -pg
|
||||
|
||||
obj-y := elf.o entry-common.o irq.o opcodes.o \
|
||||
process.o ptrace.o return_address.o \
|
||||
setup.o signal.o stacktrace.o sys_arm.o time.o traps.o
|
||||
setup.o signal.o sigreturn_codes.o \
|
||||
stacktrace.o sys_arm.o time.o traps.o
|
||||
|
||||
obj-$(CONFIG_ATAGS) += atags_parse.o
|
||||
obj-$(CONFIG_ATAGS_PROC) += atags_proc.o
|
||||
@@ -78,6 +79,7 @@ obj-$(CONFIG_CPU_XSC3) += xscale-cp0.o
|
||||
obj-$(CONFIG_CPU_MOHAWK) += xscale-cp0.o
|
||||
obj-$(CONFIG_CPU_PJ4) += pj4-cp0.o
|
||||
obj-$(CONFIG_IWMMXT) += iwmmxt.o
|
||||
obj-$(CONFIG_PERF_EVENTS) += perf_regs.o
|
||||
obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o perf_event_cpu.o
|
||||
AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt
|
||||
obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o
|
||||
|
@@ -155,4 +155,5 @@ EXPORT_SYMBOL(__gnu_mcount_nc);
|
||||
|
||||
#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
|
||||
EXPORT_SYMBOL(__pv_phys_offset);
|
||||
EXPORT_SYMBOL(__pv_offset);
|
||||
#endif
|
||||
|
@@ -416,9 +416,8 @@ __und_usr:
|
||||
bne __und_usr_thumb
|
||||
sub r4, r2, #4 @ ARM instr at LR - 4
|
||||
1: ldrt r0, [r4]
|
||||
#ifdef CONFIG_CPU_ENDIAN_BE8
|
||||
rev r0, r0 @ little endian instruction
|
||||
#endif
|
||||
ARM_BE8(rev r0, r0) @ little endian instruction
|
||||
|
||||
@ r0 = 32-bit ARM instruction which caused the exception
|
||||
@ r2 = PC value for the following instruction (:= regs->ARM_pc)
|
||||
@ r4 = PC value for the faulting instruction
|
||||
|
@@ -393,9 +393,7 @@ ENTRY(vector_swi)
|
||||
#else
|
||||
USER( ldr r10, [lr, #-4] ) @ get SWI instruction
|
||||
#endif
|
||||
#ifdef CONFIG_CPU_ENDIAN_BE8
|
||||
rev r10, r10 @ little endian instruction
|
||||
#endif
|
||||
ARM_BE8(rev r10, r10) @ little endian instruction
|
||||
|
||||
#elif defined(CONFIG_AEABI)
|
||||
|
||||
|
@@ -77,6 +77,7 @@
|
||||
|
||||
__HEAD
|
||||
ENTRY(stext)
|
||||
ARM_BE8(setend be ) @ ensure we are in BE8 mode
|
||||
|
||||
THUMB( adr r9, BSYM(1f) ) @ Kernel is always entered in ARM.
|
||||
THUMB( bx r9 ) @ If this is a Thumb-2 kernel,
|
||||
@@ -352,6 +353,9 @@ ENTRY(secondary_startup)
|
||||
* the processor type - there is no need to check the machine type
|
||||
* as it has already been validated by the primary processor.
|
||||
*/
|
||||
|
||||
ARM_BE8(setend be) @ ensure we are in BE8 mode
|
||||
|
||||
#ifdef CONFIG_ARM_VIRT_EXT
|
||||
bl __hyp_stub_install_secondary
|
||||
#endif
|
||||
@@ -555,6 +559,14 @@ ENTRY(fixup_smp)
|
||||
ldmfd sp!, {r4 - r6, pc}
|
||||
ENDPROC(fixup_smp)
|
||||
|
||||
#ifdef __ARMEB__
|
||||
#define LOW_OFFSET 0x4
|
||||
#define HIGH_OFFSET 0x0
|
||||
#else
|
||||
#define LOW_OFFSET 0x0
|
||||
#define HIGH_OFFSET 0x4
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
|
||||
|
||||
/* __fixup_pv_table - patch the stub instructions with the delta between
|
||||
@@ -565,17 +577,20 @@ ENDPROC(fixup_smp)
|
||||
__HEAD
|
||||
__fixup_pv_table:
|
||||
adr r0, 1f
|
||||
ldmia r0, {r3-r5, r7}
|
||||
sub r3, r0, r3 @ PHYS_OFFSET - PAGE_OFFSET
|
||||
ldmia r0, {r3-r7}
|
||||
mvn ip, #0
|
||||
subs r3, r0, r3 @ PHYS_OFFSET - PAGE_OFFSET
|
||||
add r4, r4, r3 @ adjust table start address
|
||||
add r5, r5, r3 @ adjust table end address
|
||||
add r7, r7, r3 @ adjust __pv_phys_offset address
|
||||
str r8, [r7] @ save computed PHYS_OFFSET to __pv_phys_offset
|
||||
add r6, r6, r3 @ adjust __pv_phys_offset address
|
||||
add r7, r7, r3 @ adjust __pv_offset address
|
||||
str r8, [r6, #LOW_OFFSET] @ save computed PHYS_OFFSET to __pv_phys_offset
|
||||
strcc ip, [r7, #HIGH_OFFSET] @ save to __pv_offset high bits
|
||||
mov r6, r3, lsr #24 @ constant for add/sub instructions
|
||||
teq r3, r6, lsl #24 @ must be 16MiB aligned
|
||||
THUMB( it ne @ cross section branch )
|
||||
bne __error
|
||||
str r6, [r7, #4] @ save to __pv_offset
|
||||
str r3, [r7, #LOW_OFFSET] @ save to __pv_offset low bits
|
||||
b __fixup_a_pv_table
|
||||
ENDPROC(__fixup_pv_table)
|
||||
|
||||
@@ -584,10 +599,19 @@ ENDPROC(__fixup_pv_table)
|
||||
.long __pv_table_begin
|
||||
.long __pv_table_end
|
||||
2: .long __pv_phys_offset
|
||||
.long __pv_offset
|
||||
|
||||
.text
|
||||
__fixup_a_pv_table:
|
||||
adr r0, 3f
|
||||
ldr r6, [r0]
|
||||
add r6, r6, r3
|
||||
ldr r0, [r6, #HIGH_OFFSET] @ pv_offset high word
|
||||
ldr r6, [r6, #LOW_OFFSET] @ pv_offset low word
|
||||
mov r6, r6, lsr #24
|
||||
cmn r0, #1
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
moveq r0, #0x200000 @ set bit 21, mov to mvn instruction
|
||||
lsls r6, #24
|
||||
beq 2f
|
||||
clz r7, r6
|
||||
@@ -601,18 +625,42 @@ __fixup_a_pv_table:
|
||||
b 2f
|
||||
1: add r7, r3
|
||||
ldrh ip, [r7, #2]
|
||||
and ip, 0x8f00
|
||||
orr ip, r6 @ mask in offset bits 31-24
|
||||
ARM_BE8(rev16 ip, ip)
|
||||
tst ip, #0x4000
|
||||
and ip, #0x8f00
|
||||
orrne ip, r6 @ mask in offset bits 31-24
|
||||
orreq ip, r0 @ mask in offset bits 7-0
|
||||
ARM_BE8(rev16 ip, ip)
|
||||
strh ip, [r7, #2]
|
||||
bne 2f
|
||||
ldrh ip, [r7]
|
||||
ARM_BE8(rev16 ip, ip)
|
||||
bic ip, #0x20
|
||||
orr ip, ip, r0, lsr #16
|
||||
ARM_BE8(rev16 ip, ip)
|
||||
strh ip, [r7]
|
||||
2: cmp r4, r5
|
||||
ldrcc r7, [r4], #4 @ use branch for delay slot
|
||||
bcc 1b
|
||||
bx lr
|
||||
#else
|
||||
moveq r0, #0x400000 @ set bit 22, mov to mvn instruction
|
||||
b 2f
|
||||
1: ldr ip, [r7, r3]
|
||||
#ifdef CONFIG_CPU_ENDIAN_BE8
|
||||
@ in BE8, we load data in BE, but instructions still in LE
|
||||
bic ip, ip, #0xff000000
|
||||
tst ip, #0x000f0000 @ check the rotation field
|
||||
orrne ip, ip, r6, lsl #24 @ mask in offset bits 31-24
|
||||
biceq ip, ip, #0x00004000 @ clear bit 22
|
||||
orreq ip, ip, r0, lsl #24 @ mask in offset bits 7-0
|
||||
#else
|
||||
bic ip, ip, #0x000000ff
|
||||
orr ip, ip, r6 @ mask in offset bits 31-24
|
||||
tst ip, #0xf00 @ check the rotation field
|
||||
orrne ip, ip, r6 @ mask in offset bits 31-24
|
||||
biceq ip, ip, #0x400000 @ clear bit 22
|
||||
orreq ip, ip, r0 @ mask in offset bits 7-0
|
||||
#endif
|
||||
str ip, [r7, r3]
|
||||
2: cmp r4, r5
|
||||
ldrcc r7, [r4], #4 @ use branch for delay slot
|
||||
@@ -621,28 +669,30 @@ __fixup_a_pv_table:
|
||||
#endif
|
||||
ENDPROC(__fixup_a_pv_table)
|
||||
|
||||
.align
|
||||
3: .long __pv_offset
|
||||
|
||||
ENTRY(fixup_pv_table)
|
||||
stmfd sp!, {r4 - r7, lr}
|
||||
ldr r2, 2f @ get address of __pv_phys_offset
|
||||
mov r3, #0 @ no offset
|
||||
mov r4, r0 @ r0 = table start
|
||||
add r5, r0, r1 @ r1 = table size
|
||||
ldr r6, [r2, #4] @ get __pv_offset
|
||||
bl __fixup_a_pv_table
|
||||
ldmfd sp!, {r4 - r7, pc}
|
||||
ENDPROC(fixup_pv_table)
|
||||
|
||||
.align
|
||||
2: .long __pv_phys_offset
|
||||
|
||||
.data
|
||||
.globl __pv_phys_offset
|
||||
.type __pv_phys_offset, %object
|
||||
__pv_phys_offset:
|
||||
.long 0
|
||||
.size __pv_phys_offset, . - __pv_phys_offset
|
||||
.quad 0
|
||||
.size __pv_phys_offset, . -__pv_phys_offset
|
||||
|
||||
.globl __pv_offset
|
||||
.type __pv_offset, %object
|
||||
__pv_offset:
|
||||
.long 0
|
||||
.quad 0
|
||||
.size __pv_offset, . -__pv_offset
|
||||
#endif
|
||||
|
||||
#include "head-common.S"
|
||||
|
@@ -24,6 +24,7 @@
|
||||
#include <asm/sections.h>
|
||||
#include <asm/smp_plat.h>
|
||||
#include <asm/unwind.h>
|
||||
#include <asm/opcodes.h>
|
||||
|
||||
#ifdef CONFIG_XIP_KERNEL
|
||||
/*
|
||||
@@ -60,6 +61,7 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
|
||||
Elf32_Sym *sym;
|
||||
const char *symname;
|
||||
s32 offset;
|
||||
u32 tmp;
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
u32 upper, lower, sign, j1, j2;
|
||||
#endif
|
||||
@@ -95,7 +97,8 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
|
||||
case R_ARM_PC24:
|
||||
case R_ARM_CALL:
|
||||
case R_ARM_JUMP24:
|
||||
offset = (*(u32 *)loc & 0x00ffffff) << 2;
|
||||
offset = __mem_to_opcode_arm(*(u32 *)loc);
|
||||
offset = (offset & 0x00ffffff) << 2;
|
||||
if (offset & 0x02000000)
|
||||
offset -= 0x04000000;
|
||||
|
||||
@@ -111,9 +114,10 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
|
||||
}
|
||||
|
||||
offset >>= 2;
|
||||
offset &= 0x00ffffff;
|
||||
|
||||
*(u32 *)loc &= 0xff000000;
|
||||
*(u32 *)loc |= offset & 0x00ffffff;
|
||||
*(u32 *)loc &= __opcode_to_mem_arm(0xff000000);
|
||||
*(u32 *)loc |= __opcode_to_mem_arm(offset);
|
||||
break;
|
||||
|
||||
case R_ARM_V4BX:
|
||||
@@ -121,8 +125,8 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
|
||||
* other bits to re-code instruction as
|
||||
* MOV PC,Rm.
|
||||
*/
|
||||
*(u32 *)loc &= 0xf000000f;
|
||||
*(u32 *)loc |= 0x01a0f000;
|
||||
*(u32 *)loc &= __opcode_to_mem_arm(0xf000000f);
|
||||
*(u32 *)loc |= __opcode_to_mem_arm(0x01a0f000);
|
||||
break;
|
||||
|
||||
case R_ARM_PREL31:
|
||||
@@ -132,7 +136,7 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
|
||||
|
||||
case R_ARM_MOVW_ABS_NC:
|
||||
case R_ARM_MOVT_ABS:
|
||||
offset = *(u32 *)loc;
|
||||
offset = tmp = __mem_to_opcode_arm(*(u32 *)loc);
|
||||
offset = ((offset & 0xf0000) >> 4) | (offset & 0xfff);
|
||||
offset = (offset ^ 0x8000) - 0x8000;
|
||||
|
||||
@@ -140,16 +144,18 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
|
||||
if (ELF32_R_TYPE(rel->r_info) == R_ARM_MOVT_ABS)
|
||||
offset >>= 16;
|
||||
|
||||
*(u32 *)loc &= 0xfff0f000;
|
||||
*(u32 *)loc |= ((offset & 0xf000) << 4) |
|
||||
(offset & 0x0fff);
|
||||
tmp &= 0xfff0f000;
|
||||
tmp |= ((offset & 0xf000) << 4) |
|
||||
(offset & 0x0fff);
|
||||
|
||||
*(u32 *)loc = __opcode_to_mem_arm(tmp);
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
case R_ARM_THM_CALL:
|
||||
case R_ARM_THM_JUMP24:
|
||||
upper = *(u16 *)loc;
|
||||
lower = *(u16 *)(loc + 2);
|
||||
upper = __mem_to_opcode_thumb16(*(u16 *)loc);
|
||||
lower = __mem_to_opcode_thumb16(*(u16 *)(loc + 2));
|
||||
|
||||
/*
|
||||
* 25 bit signed address range (Thumb-2 BL and B.W
|
||||
@@ -198,17 +204,20 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
|
||||
sign = (offset >> 24) & 1;
|
||||
j1 = sign ^ (~(offset >> 23) & 1);
|
||||
j2 = sign ^ (~(offset >> 22) & 1);
|
||||
*(u16 *)loc = (u16)((upper & 0xf800) | (sign << 10) |
|
||||
upper = (u16)((upper & 0xf800) | (sign << 10) |
|
||||
((offset >> 12) & 0x03ff));
|
||||
*(u16 *)(loc + 2) = (u16)((lower & 0xd000) |
|
||||
(j1 << 13) | (j2 << 11) |
|
||||
((offset >> 1) & 0x07ff));
|
||||
lower = (u16)((lower & 0xd000) |
|
||||
(j1 << 13) | (j2 << 11) |
|
||||
((offset >> 1) & 0x07ff));
|
||||
|
||||
*(u16 *)loc = __opcode_to_mem_thumb16(upper);
|
||||
*(u16 *)(loc + 2) = __opcode_to_mem_thumb16(lower);
|
||||
break;
|
||||
|
||||
case R_ARM_THM_MOVW_ABS_NC:
|
||||
case R_ARM_THM_MOVT_ABS:
|
||||
upper = *(u16 *)loc;
|
||||
lower = *(u16 *)(loc + 2);
|
||||
upper = __mem_to_opcode_thumb16(*(u16 *)loc);
|
||||
lower = __mem_to_opcode_thumb16(*(u16 *)(loc + 2));
|
||||
|
||||
/*
|
||||
* MOVT/MOVW instructions encoding in Thumb-2:
|
||||
@@ -229,12 +238,14 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
|
||||
if (ELF32_R_TYPE(rel->r_info) == R_ARM_THM_MOVT_ABS)
|
||||
offset >>= 16;
|
||||
|
||||
*(u16 *)loc = (u16)((upper & 0xfbf0) |
|
||||
((offset & 0xf000) >> 12) |
|
||||
((offset & 0x0800) >> 1));
|
||||
*(u16 *)(loc + 2) = (u16)((lower & 0x8f00) |
|
||||
((offset & 0x0700) << 4) |
|
||||
(offset & 0x00ff));
|
||||
upper = (u16)((upper & 0xfbf0) |
|
||||
((offset & 0xf000) >> 12) |
|
||||
((offset & 0x0800) >> 1));
|
||||
lower = (u16)((lower & 0x8f00) |
|
||||
((offset & 0x0700) << 4) |
|
||||
(offset & 0x00ff));
|
||||
*(u16 *)loc = __opcode_to_mem_thumb16(upper);
|
||||
*(u16 *)(loc + 2) = __opcode_to_mem_thumb16(lower);
|
||||
break;
|
||||
#endif
|
||||
|
||||
|
@@ -256,12 +256,11 @@ validate_event(struct pmu_hw_events *hw_events,
|
||||
struct perf_event *event)
|
||||
{
|
||||
struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
|
||||
struct pmu *leader_pmu = event->group_leader->pmu;
|
||||
|
||||
if (is_software_event(event))
|
||||
return 1;
|
||||
|
||||
if (event->pmu != leader_pmu || event->state < PERF_EVENT_STATE_OFF)
|
||||
if (event->state < PERF_EVENT_STATE_OFF)
|
||||
return 1;
|
||||
|
||||
if (event->state == PERF_EVENT_STATE_OFF && !event->attr.enable_on_exec)
|
||||
|
30
arch/arm/kernel/perf_regs.c
Normal file
30
arch/arm/kernel/perf_regs.c
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/bug.h>
|
||||
#include <asm/perf_regs.h>
|
||||
#include <asm/ptrace.h>
|
||||
|
||||
u64 perf_reg_value(struct pt_regs *regs, int idx)
|
||||
{
|
||||
if (WARN_ON_ONCE((u32)idx >= PERF_REG_ARM_MAX))
|
||||
return 0;
|
||||
|
||||
return regs->uregs[idx];
|
||||
}
|
||||
|
||||
#define REG_RESERVED (~((1ULL << PERF_REG_ARM_MAX) - 1))
|
||||
|
||||
int perf_reg_validate(u64 mask)
|
||||
{
|
||||
if (!mask || mask & REG_RESERVED)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 perf_reg_abi(struct task_struct *task)
|
||||
{
|
||||
return PERF_SAMPLE_REGS_ABI_32;
|
||||
}
|
@@ -73,6 +73,8 @@ __setup("fpe=", fpe_setup);
|
||||
#endif
|
||||
|
||||
extern void paging_init(const struct machine_desc *desc);
|
||||
extern void early_paging_init(const struct machine_desc *,
|
||||
struct proc_info_list *);
|
||||
extern void sanity_check_meminfo(void);
|
||||
extern enum reboot_mode reboot_mode;
|
||||
extern void setup_dma_zone(const struct machine_desc *desc);
|
||||
@@ -888,6 +890,8 @@ void __init setup_arch(char **cmdline_p)
|
||||
parse_early_param();
|
||||
|
||||
sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL);
|
||||
|
||||
early_paging_init(mdesc, lookup_processor_type(read_cpuid_id()));
|
||||
sanity_check_meminfo();
|
||||
arm_memblock_init(&meminfo, mdesc);
|
||||
|
||||
|
@@ -21,29 +21,7 @@
|
||||
#include <asm/unistd.h>
|
||||
#include <asm/vfp.h>
|
||||
|
||||
/*
|
||||
* For ARM syscalls, we encode the syscall number into the instruction.
|
||||
*/
|
||||
#define SWI_SYS_SIGRETURN (0xef000000|(__NR_sigreturn)|(__NR_OABI_SYSCALL_BASE))
|
||||
#define SWI_SYS_RT_SIGRETURN (0xef000000|(__NR_rt_sigreturn)|(__NR_OABI_SYSCALL_BASE))
|
||||
|
||||
/*
|
||||
* With EABI, the syscall number has to be loaded into r7.
|
||||
*/
|
||||
#define MOV_R7_NR_SIGRETURN (0xe3a07000 | (__NR_sigreturn - __NR_SYSCALL_BASE))
|
||||
#define MOV_R7_NR_RT_SIGRETURN (0xe3a07000 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE))
|
||||
|
||||
/*
|
||||
* For Thumb syscalls, we pass the syscall number via r7. We therefore
|
||||
* need two 16-bit instructions.
|
||||
*/
|
||||
#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_sigreturn - __NR_SYSCALL_BASE))
|
||||
#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE))
|
||||
|
||||
static const unsigned long sigreturn_codes[7] = {
|
||||
MOV_R7_NR_SIGRETURN, SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
|
||||
MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN,
|
||||
};
|
||||
extern const unsigned long sigreturn_codes[7];
|
||||
|
||||
static unsigned long signal_return_offset;
|
||||
|
||||
|
80
arch/arm/kernel/sigreturn_codes.S
Normal file
80
arch/arm/kernel/sigreturn_codes.S
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* sigreturn_codes.S - code sinpets for sigreturn syscalls
|
||||
*
|
||||
* Created by: Victor Kamensky, 2013-08-13
|
||||
* Copyright: (C) 2013 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 program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <asm/unistd.h>
|
||||
|
||||
/*
|
||||
* For ARM syscalls, we encode the syscall number into the instruction.
|
||||
* With EABI, the syscall number has to be loaded into r7. As result
|
||||
* ARM syscall sequence snippet will have move and svc in .arm encoding
|
||||
*
|
||||
* For Thumb syscalls, we pass the syscall number via r7. We therefore
|
||||
* need two 16-bit instructions in .thumb encoding
|
||||
*
|
||||
* Please note sigreturn_codes code are not executed in place. Instead
|
||||
* they just copied by kernel into appropriate places. Code inside of
|
||||
* arch/arm/kernel/signal.c is very sensitive to layout of these code
|
||||
* snippets.
|
||||
*/
|
||||
|
||||
#if __LINUX_ARM_ARCH__ <= 4
|
||||
/*
|
||||
* Note we manually set minimally required arch that supports
|
||||
* required thumb opcodes for early arch versions. It is OK
|
||||
* for this file to be used in combination with other
|
||||
* lower arch variants, since these code snippets are only
|
||||
* used as input data.
|
||||
*/
|
||||
.arch armv4t
|
||||
#endif
|
||||
|
||||
.section .rodata
|
||||
.global sigreturn_codes
|
||||
.type sigreturn_codes, #object
|
||||
|
||||
.arm
|
||||
|
||||
sigreturn_codes:
|
||||
|
||||
/* ARM sigreturn syscall code snippet */
|
||||
mov r7, #(__NR_sigreturn - __NR_SYSCALL_BASE)
|
||||
swi #(__NR_sigreturn)|(__NR_OABI_SYSCALL_BASE)
|
||||
|
||||
/* Thumb sigreturn syscall code snippet */
|
||||
.thumb
|
||||
movs r7, #(__NR_sigreturn - __NR_SYSCALL_BASE)
|
||||
swi #0
|
||||
|
||||
/* ARM sigreturn_rt syscall code snippet */
|
||||
.arm
|
||||
mov r7, #(__NR_rt_sigreturn - __NR_SYSCALL_BASE)
|
||||
swi #(__NR_rt_sigreturn)|(__NR_OABI_SYSCALL_BASE)
|
||||
|
||||
/* Thumb sigreturn_rt syscall code snippet */
|
||||
.thumb
|
||||
movs r7, #(__NR_rt_sigreturn - __NR_SYSCALL_BASE)
|
||||
swi #0
|
||||
|
||||
/*
|
||||
* Note on addtional space: setup_return in signal.c
|
||||
* algorithm uses two words copy regardless whether
|
||||
* it is thumb case or not, so we need additional
|
||||
* word after real last entry.
|
||||
*/
|
||||
.arm
|
||||
.space 4
|
||||
|
||||
.size sigreturn_codes, . - sigreturn_codes
|
@@ -55,6 +55,7 @@
|
||||
* specific registers and some other data for resume.
|
||||
* r0 = suspend function arg0
|
||||
* r1 = suspend function
|
||||
* r2 = MPIDR value the resuming CPU will use
|
||||
*/
|
||||
ENTRY(__cpu_suspend)
|
||||
stmfd sp!, {r4 - r11, lr}
|
||||
@@ -67,23 +68,18 @@ ENTRY(__cpu_suspend)
|
||||
mov r5, sp @ current virtual SP
|
||||
add r4, r4, #12 @ Space for pgd, virt sp, phys resume fn
|
||||
sub sp, sp, r4 @ allocate CPU state on stack
|
||||
stmfd sp!, {r0, r1} @ save suspend func arg and pointer
|
||||
add r0, sp, #8 @ save pointer to save block
|
||||
mov r1, r4 @ size of save block
|
||||
mov r2, r5 @ virtual SP
|
||||
ldr r3, =sleep_save_sp
|
||||
stmfd sp!, {r0, r1} @ save suspend func arg and pointer
|
||||
ldr r3, [r3, #SLEEP_SAVE_SP_VIRT]
|
||||
ALT_SMP(mrc p15, 0, r9, c0, c0, 5)
|
||||
ALT_UP_B(1f)
|
||||
ldr r8, =mpidr_hash
|
||||
/*
|
||||
* This ldmia relies on the memory layout of the mpidr_hash
|
||||
* struct mpidr_hash.
|
||||
*/
|
||||
ldmia r8, {r4-r7} @ r4 = mpidr mask (r5,r6,r7) = l[0,1,2] shifts
|
||||
compute_mpidr_hash lr, r5, r6, r7, r9, r4
|
||||
add r3, r3, lr, lsl #2
|
||||
1:
|
||||
ALT_SMP(ldr r0, =mpidr_hash)
|
||||
ALT_UP_B(1f)
|
||||
/* This ldmia relies on the memory layout of the mpidr_hash struct */
|
||||
ldmia r0, {r1, r6-r8} @ r1 = mpidr mask (r6,r7,r8) = l[0,1,2] shifts
|
||||
compute_mpidr_hash r0, r6, r7, r8, r2, r1
|
||||
add r3, r3, r0, lsl #2
|
||||
1: mov r2, r5 @ virtual SP
|
||||
mov r1, r4 @ size of save block
|
||||
add r0, sp, #8 @ pointer to save block
|
||||
bl __cpu_suspend_save
|
||||
adr lr, BSYM(cpu_suspend_abort)
|
||||
ldmfd sp!, {r0, pc} @ call suspend fn
|
||||
@@ -130,6 +126,7 @@ ENDPROC(cpu_resume_after_mmu)
|
||||
.data
|
||||
.align
|
||||
ENTRY(cpu_resume)
|
||||
ARM_BE8(setend be) @ ensure we are in BE mode
|
||||
mov r1, #0
|
||||
ALT_SMP(mrc p15, 0, r0, c0, c0, 5)
|
||||
ALT_UP_B(1f)
|
||||
|
@@ -68,6 +68,7 @@ enum ipi_msg_type {
|
||||
IPI_CALL_FUNC_SINGLE,
|
||||
IPI_CPU_STOP,
|
||||
IPI_IRQ_WORK,
|
||||
IPI_COMPLETION,
|
||||
};
|
||||
|
||||
static DECLARE_COMPLETION(cpu_running);
|
||||
@@ -82,7 +83,7 @@ void __init smp_set_ops(struct smp_operations *ops)
|
||||
|
||||
static unsigned long get_arch_pgd(pgd_t *pgd)
|
||||
{
|
||||
phys_addr_t pgdir = virt_to_phys(pgd);
|
||||
phys_addr_t pgdir = virt_to_idmap(pgd);
|
||||
BUG_ON(pgdir & ARCH_PGD_MASK);
|
||||
return pgdir >> ARCH_PGD_SHIFT;
|
||||
}
|
||||
@@ -467,6 +468,7 @@ static const char *ipi_types[NR_IPI] = {
|
||||
S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"),
|
||||
S(IPI_CPU_STOP, "CPU stop interrupts"),
|
||||
S(IPI_IRQ_WORK, "IRQ work interrupts"),
|
||||
S(IPI_COMPLETION, "completion interrupts"),
|
||||
};
|
||||
|
||||
void show_ipi_list(struct seq_file *p, int prec)
|
||||
@@ -526,6 +528,19 @@ static void ipi_cpu_stop(unsigned int cpu)
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
static DEFINE_PER_CPU(struct completion *, cpu_completion);
|
||||
|
||||
int register_ipi_completion(struct completion *completion, int cpu)
|
||||
{
|
||||
per_cpu(cpu_completion, cpu) = completion;
|
||||
return IPI_COMPLETION;
|
||||
}
|
||||
|
||||
static void ipi_complete(unsigned int cpu)
|
||||
{
|
||||
complete(per_cpu(cpu_completion, cpu));
|
||||
}
|
||||
|
||||
/*
|
||||
* Main handler for inter-processor interrupts
|
||||
*/
|
||||
@@ -584,6 +599,12 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
|
||||
break;
|
||||
#endif
|
||||
|
||||
case IPI_COMPLETION:
|
||||
irq_enter();
|
||||
ipi_complete(cpu);
|
||||
irq_exit();
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
|
||||
cpu, ipinr);
|
||||
|
@@ -28,7 +28,7 @@
|
||||
*/
|
||||
unsigned int __init scu_get_core_count(void __iomem *scu_base)
|
||||
{
|
||||
unsigned int ncores = __raw_readl(scu_base + SCU_CONFIG);
|
||||
unsigned int ncores = readl_relaxed(scu_base + SCU_CONFIG);
|
||||
return (ncores & 0x03) + 1;
|
||||
}
|
||||
|
||||
@@ -42,19 +42,19 @@ void scu_enable(void __iomem *scu_base)
|
||||
#ifdef CONFIG_ARM_ERRATA_764369
|
||||
/* Cortex-A9 only */
|
||||
if ((read_cpuid_id() & 0xff0ffff0) == 0x410fc090) {
|
||||
scu_ctrl = __raw_readl(scu_base + 0x30);
|
||||
scu_ctrl = readl_relaxed(scu_base + 0x30);
|
||||
if (!(scu_ctrl & 1))
|
||||
__raw_writel(scu_ctrl | 0x1, scu_base + 0x30);
|
||||
writel_relaxed(scu_ctrl | 0x1, scu_base + 0x30);
|
||||
}
|
||||
#endif
|
||||
|
||||
scu_ctrl = __raw_readl(scu_base + SCU_CTRL);
|
||||
scu_ctrl = readl_relaxed(scu_base + SCU_CTRL);
|
||||
/* already enabled? */
|
||||
if (scu_ctrl & 1)
|
||||
return;
|
||||
|
||||
scu_ctrl |= 1;
|
||||
__raw_writel(scu_ctrl, scu_base + SCU_CTRL);
|
||||
writel_relaxed(scu_ctrl, scu_base + SCU_CTRL);
|
||||
|
||||
/*
|
||||
* Ensure that the data accessed by CPU0 before the SCU was
|
||||
@@ -80,9 +80,9 @@ int scu_power_mode(void __iomem *scu_base, unsigned int mode)
|
||||
if (mode > 3 || mode == 1 || cpu > 3)
|
||||
return -EINVAL;
|
||||
|
||||
val = __raw_readb(scu_base + SCU_CPU_STATUS + cpu) & ~0x03;
|
||||
val = readb_relaxed(scu_base + SCU_CPU_STATUS + cpu) & ~0x03;
|
||||
val |= mode;
|
||||
__raw_writeb(val, scu_base + SCU_CPU_STATUS + cpu);
|
||||
writeb_relaxed(val, scu_base + SCU_CPU_STATUS + cpu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -45,7 +45,7 @@ static void twd_set_mode(enum clock_event_mode mode,
|
||||
case CLOCK_EVT_MODE_PERIODIC:
|
||||
ctrl = TWD_TIMER_CONTROL_ENABLE | TWD_TIMER_CONTROL_IT_ENABLE
|
||||
| TWD_TIMER_CONTROL_PERIODIC;
|
||||
__raw_writel(DIV_ROUND_CLOSEST(twd_timer_rate, HZ),
|
||||
writel_relaxed(DIV_ROUND_CLOSEST(twd_timer_rate, HZ),
|
||||
twd_base + TWD_TIMER_LOAD);
|
||||
break;
|
||||
case CLOCK_EVT_MODE_ONESHOT:
|
||||
@@ -58,18 +58,18 @@ static void twd_set_mode(enum clock_event_mode mode,
|
||||
ctrl = 0;
|
||||
}
|
||||
|
||||
__raw_writel(ctrl, twd_base + TWD_TIMER_CONTROL);
|
||||
writel_relaxed(ctrl, twd_base + TWD_TIMER_CONTROL);
|
||||
}
|
||||
|
||||
static int twd_set_next_event(unsigned long evt,
|
||||
struct clock_event_device *unused)
|
||||
{
|
||||
unsigned long ctrl = __raw_readl(twd_base + TWD_TIMER_CONTROL);
|
||||
unsigned long ctrl = readl_relaxed(twd_base + TWD_TIMER_CONTROL);
|
||||
|
||||
ctrl |= TWD_TIMER_CONTROL_ENABLE;
|
||||
|
||||
__raw_writel(evt, twd_base + TWD_TIMER_COUNTER);
|
||||
__raw_writel(ctrl, twd_base + TWD_TIMER_CONTROL);
|
||||
writel_relaxed(evt, twd_base + TWD_TIMER_COUNTER);
|
||||
writel_relaxed(ctrl, twd_base + TWD_TIMER_CONTROL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -82,8 +82,8 @@ static int twd_set_next_event(unsigned long evt,
|
||||
*/
|
||||
static int twd_timer_ack(void)
|
||||
{
|
||||
if (__raw_readl(twd_base + TWD_TIMER_INTSTAT)) {
|
||||
__raw_writel(1, twd_base + TWD_TIMER_INTSTAT);
|
||||
if (readl_relaxed(twd_base + TWD_TIMER_INTSTAT)) {
|
||||
writel_relaxed(1, twd_base + TWD_TIMER_INTSTAT);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -211,15 +211,15 @@ static void twd_calibrate_rate(void)
|
||||
waitjiffies += 5;
|
||||
|
||||
/* enable, no interrupt or reload */
|
||||
__raw_writel(0x1, twd_base + TWD_TIMER_CONTROL);
|
||||
writel_relaxed(0x1, twd_base + TWD_TIMER_CONTROL);
|
||||
|
||||
/* maximum value */
|
||||
__raw_writel(0xFFFFFFFFU, twd_base + TWD_TIMER_COUNTER);
|
||||
writel_relaxed(0xFFFFFFFFU, twd_base + TWD_TIMER_COUNTER);
|
||||
|
||||
while (get_jiffies_64() < waitjiffies)
|
||||
udelay(10);
|
||||
|
||||
count = __raw_readl(twd_base + TWD_TIMER_COUNTER);
|
||||
count = readl_relaxed(twd_base + TWD_TIMER_COUNTER);
|
||||
|
||||
twd_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5);
|
||||
|
||||
@@ -277,7 +277,7 @@ static void twd_timer_setup(void)
|
||||
* bother with the below.
|
||||
*/
|
||||
if (per_cpu(percpu_setup_called, cpu)) {
|
||||
__raw_writel(0, twd_base + TWD_TIMER_CONTROL);
|
||||
writel_relaxed(0, twd_base + TWD_TIMER_CONTROL);
|
||||
clockevents_register_device(clk);
|
||||
enable_percpu_irq(clk->irq, 0);
|
||||
return;
|
||||
@@ -290,7 +290,7 @@ static void twd_timer_setup(void)
|
||||
* The following is done once per CPU the first time .setup() is
|
||||
* called.
|
||||
*/
|
||||
__raw_writel(0, twd_base + TWD_TIMER_CONTROL);
|
||||
writel_relaxed(0, twd_base + TWD_TIMER_CONTROL);
|
||||
|
||||
clk->name = "local_timer";
|
||||
clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
|
||||
|
@@ -10,7 +10,7 @@
|
||||
#include <asm/suspend.h>
|
||||
#include <asm/tlbflush.h>
|
||||
|
||||
extern int __cpu_suspend(unsigned long, int (*)(unsigned long));
|
||||
extern int __cpu_suspend(unsigned long, int (*)(unsigned long), u32 cpuid);
|
||||
extern void cpu_resume_mmu(void);
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
@@ -21,6 +21,7 @@ extern void cpu_resume_mmu(void);
|
||||
int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
|
||||
{
|
||||
struct mm_struct *mm = current->active_mm;
|
||||
u32 __mpidr = cpu_logical_map(smp_processor_id());
|
||||
int ret;
|
||||
|
||||
if (!idmap_pgd)
|
||||
@@ -32,7 +33,7 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
|
||||
* resume (indicated by a zero return code), we need to switch
|
||||
* back to the correct page tables.
|
||||
*/
|
||||
ret = __cpu_suspend(arg, fn);
|
||||
ret = __cpu_suspend(arg, fn, __mpidr);
|
||||
if (ret == 0) {
|
||||
cpu_switch_mm(mm->pgd, mm);
|
||||
local_flush_bp_all();
|
||||
@@ -44,7 +45,8 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
|
||||
#else
|
||||
int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
|
||||
{
|
||||
return __cpu_suspend(arg, fn);
|
||||
u32 __mpidr = cpu_logical_map(smp_processor_id());
|
||||
return __cpu_suspend(arg, fn, __mpidr);
|
||||
}
|
||||
#define idmap_pgd NULL
|
||||
#endif
|
||||
|
@@ -34,6 +34,7 @@
|
||||
#include <asm/unwind.h>
|
||||
#include <asm/tls.h>
|
||||
#include <asm/system_misc.h>
|
||||
#include <asm/opcodes.h>
|
||||
|
||||
static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" };
|
||||
|
||||
@@ -341,15 +342,17 @@ void arm_notify_die(const char *str, struct pt_regs *regs,
|
||||
int is_valid_bugaddr(unsigned long pc)
|
||||
{
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
unsigned short bkpt;
|
||||
u16 bkpt;
|
||||
u16 insn = __opcode_to_mem_thumb16(BUG_INSTR_VALUE);
|
||||
#else
|
||||
unsigned long bkpt;
|
||||
u32 bkpt;
|
||||
u32 insn = __opcode_to_mem_arm(BUG_INSTR_VALUE);
|
||||
#endif
|
||||
|
||||
if (probe_kernel_address((unsigned *)pc, bkpt))
|
||||
return 0;
|
||||
|
||||
return bkpt == BUG_INSTR_VALUE;
|
||||
return bkpt == insn;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -402,25 +405,28 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
|
||||
if (processor_mode(regs) == SVC_MODE) {
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
if (thumb_mode(regs)) {
|
||||
instr = ((u16 *)pc)[0];
|
||||
instr = __mem_to_opcode_thumb16(((u16 *)pc)[0]);
|
||||
if (is_wide_instruction(instr)) {
|
||||
instr <<= 16;
|
||||
instr |= ((u16 *)pc)[1];
|
||||
u16 inst2;
|
||||
inst2 = __mem_to_opcode_thumb16(((u16 *)pc)[1]);
|
||||
instr = __opcode_thumb32_compose(instr, inst2);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
instr = *(u32 *) pc;
|
||||
instr = __mem_to_opcode_arm(*(u32 *) pc);
|
||||
} else if (thumb_mode(regs)) {
|
||||
if (get_user(instr, (u16 __user *)pc))
|
||||
goto die_sig;
|
||||
instr = __mem_to_opcode_thumb16(instr);
|
||||
if (is_wide_instruction(instr)) {
|
||||
unsigned int instr2;
|
||||
if (get_user(instr2, (u16 __user *)pc+1))
|
||||
goto die_sig;
|
||||
instr <<= 16;
|
||||
instr |= instr2;
|
||||
instr2 = __mem_to_opcode_thumb16(instr2);
|
||||
instr = __opcode_thumb32_compose(instr, instr2);
|
||||
}
|
||||
} else if (get_user(instr, (u32 __user *)pc)) {
|
||||
instr = __mem_to_opcode_arm(instr);
|
||||
goto die_sig;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user