Merge branch 'restart-cleanup' into restart
Conflicts: arch/arm/kernel/setup.c
This commit is contained in:
@@ -385,6 +385,8 @@
|
||||
CALL(sys_syncfs)
|
||||
CALL(sys_sendmmsg)
|
||||
/* 375 */ CALL(sys_setns)
|
||||
CALL(sys_process_vm_readv)
|
||||
CALL(sys_process_vm_writev)
|
||||
#ifndef syscalls_counted
|
||||
.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
|
||||
#define syscalls_counted
|
||||
|
@@ -497,7 +497,7 @@ ENDPROC(__und_usr)
|
||||
.popsection
|
||||
.pushsection __ex_table,"a"
|
||||
.long 1b, 4b
|
||||
#if __LINUX_ARM_ARCH__ >= 7
|
||||
#if CONFIG_ARM_THUMB && __LINUX_ARM_ARCH__ >= 6 && CONFIG_CPU_V7
|
||||
.long 2b, 4b
|
||||
.long 3b, 4b
|
||||
#endif
|
||||
|
@@ -360,7 +360,7 @@ __secondary_data:
|
||||
* r13 = *virtual* address to jump to upon completion
|
||||
*/
|
||||
__enable_mmu:
|
||||
#ifdef CONFIG_ALIGNMENT_TRAP
|
||||
#if defined(CONFIG_ALIGNMENT_TRAP) && __LINUX_ARM_ARCH__ < 6
|
||||
orr r0, r0, #CR_A
|
||||
#else
|
||||
bic r0, r0, #CR_A
|
||||
|
@@ -519,10 +519,12 @@ static const union decode_item arm_cccc_0000_____1001_table[] = {
|
||||
static const union decode_item arm_cccc_0001_____1001_table[] = {
|
||||
/* Synchronization primitives */
|
||||
|
||||
#if __LINUX_ARM_ARCH__ < 6
|
||||
/* Deprecated on ARMv6 and may be UNDEFINED on v7 */
|
||||
/* SMP/SWPB cccc 0001 0x00 xxxx xxxx xxxx 1001 xxxx */
|
||||
DECODE_EMULATEX (0x0fb000f0, 0x01000090, emulate_rd12rn16rm0_rwflags_nopc,
|
||||
REGS(NOPC, NOPC, 0, 0, NOPC)),
|
||||
|
||||
#endif
|
||||
/* LDREX/STREX{,D,B,H} cccc 0001 1xxx xxxx xxxx xxxx 1001 xxxx */
|
||||
/* And unallocated instructions... */
|
||||
DECODE_END
|
||||
|
@@ -427,18 +427,25 @@ void kprobe_arm_test_cases(void)
|
||||
|
||||
TEST_GROUP("Synchronization primitives")
|
||||
|
||||
/*
|
||||
* Use hard coded constants for SWP instructions to avoid warnings
|
||||
* about deprecated instructions.
|
||||
*/
|
||||
TEST_RP( ".word 0xe108e097 @ swp lr, r",7,VAL2,", [r",8,0,"]")
|
||||
TEST_R( ".word 0x610d0091 @ swpvs r0, r",1,VAL1,", [sp]")
|
||||
TEST_RP( ".word 0xe10cd09e @ swp sp, r",14,VAL2,", [r",12,13*4,"]")
|
||||
#if __LINUX_ARM_ARCH__ < 6
|
||||
TEST_RP("swp lr, r",7,VAL2,", [r",8,0,"]")
|
||||
TEST_R( "swpvs r0, r",1,VAL1,", [sp]")
|
||||
TEST_RP("swp sp, r",14,VAL2,", [r",12,13*4,"]")
|
||||
#else
|
||||
TEST_UNSUPPORTED(".word 0xe108e097 @ swp lr, r7, [r8]")
|
||||
TEST_UNSUPPORTED(".word 0x610d0091 @ swpvs r0, r1, [sp]")
|
||||
TEST_UNSUPPORTED(".word 0xe10cd09e @ swp sp, r14 [r12]")
|
||||
#endif
|
||||
TEST_UNSUPPORTED(".word 0xe102f091 @ swp pc, r1, [r2]")
|
||||
TEST_UNSUPPORTED(".word 0xe102009f @ swp r0, pc, [r2]")
|
||||
TEST_UNSUPPORTED(".word 0xe10f0091 @ swp r0, r1, [pc]")
|
||||
TEST_RP( ".word 0xe148e097 @ swpb lr, r",7,VAL2,", [r",8,0,"]")
|
||||
TEST_R( ".word 0x614d0091 @ swpvsb r0, r",1,VAL1,", [sp]")
|
||||
#if __LINUX_ARM_ARCH__ < 6
|
||||
TEST_RP("swpb lr, r",7,VAL2,", [r",8,0,"]")
|
||||
TEST_R( "swpvsb r0, r",1,VAL1,", [sp]")
|
||||
#else
|
||||
TEST_UNSUPPORTED(".word 0xe148e097 @ swpb lr, r7, [r8]")
|
||||
TEST_UNSUPPORTED(".word 0x614d0091 @ swpvsb r0, r1, [sp]")
|
||||
#endif
|
||||
TEST_UNSUPPORTED(".word 0xe142f091 @ swpb pc, r1, [r2]")
|
||||
|
||||
TEST_UNSUPPORTED(".word 0xe1100090") /* Unallocated space */
|
||||
@@ -550,7 +557,7 @@ void kprobe_arm_test_cases(void)
|
||||
TEST_RPR( "strccd r",8, VAL2,", [r",13,0, ", r",12,48,"]")
|
||||
TEST_RPR( "strd r",4, VAL1,", [r",2, 24,", r",3, 48,"]!")
|
||||
TEST_RPR( "strcsd r",12,VAL2,", [r",11,48,", -r",10,24,"]!")
|
||||
TEST_RPR( "strd r",2, VAL1,", [r",3, 24,"], r",4,48,"")
|
||||
TEST_RPR( "strd r",2, VAL1,", [r",5, 24,"], r",4,48,"")
|
||||
TEST_RPR( "strd r",10,VAL2,", [r",9, 48,"], -r",7,24,"")
|
||||
TEST_UNSUPPORTED(".word 0xe1afc0fa @ strd r12, [pc, r10]!")
|
||||
|
||||
|
@@ -222,8 +222,8 @@ void kprobe_thumb16_test_cases(void)
|
||||
DONT_TEST_IN_ITBLOCK(
|
||||
TEST_BF_R( "cbnz r",0,0, ", 2f")
|
||||
TEST_BF_R( "cbz r",2,-1,", 2f")
|
||||
TEST_BF_RX( "cbnz r",4,1, ", 2f",0x20)
|
||||
TEST_BF_RX( "cbz r",7,0, ", 2f",0x40)
|
||||
TEST_BF_RX( "cbnz r",4,1, ", 2f", SPACE_0x20)
|
||||
TEST_BF_RX( "cbz r",7,0, ", 2f", SPACE_0x40)
|
||||
)
|
||||
TEST_R("sxth r0, r",7, HH1,"")
|
||||
TEST_R("sxth r7, r",0, HH2,"")
|
||||
@@ -246,7 +246,7 @@ DONT_TEST_IN_ITBLOCK(
|
||||
TESTCASE_START(code) \
|
||||
TEST_ARG_PTR(13, offset) \
|
||||
TEST_ARG_END("") \
|
||||
TEST_BRANCH_F(code,0) \
|
||||
TEST_BRANCH_F(code) \
|
||||
TESTCASE_END
|
||||
|
||||
TEST("push {r0}")
|
||||
@@ -319,8 +319,8 @@ CONDITION_INSTRUCTIONS(8,
|
||||
|
||||
TEST_BF( "b 2f")
|
||||
TEST_BB( "b 2b")
|
||||
TEST_BF_X("b 2f", 0x400)
|
||||
TEST_BB_X("b 2b", 0x400)
|
||||
TEST_BF_X("b 2f", SPACE_0x400)
|
||||
TEST_BB_X("b 2b", SPACE_0x400)
|
||||
|
||||
TEST_GROUP("Testing instructions in IT blocks")
|
||||
|
||||
@@ -746,7 +746,7 @@ CONDITION_INSTRUCTIONS(22,
|
||||
TEST_BB("bne.w 2b")
|
||||
TEST_BF("bgt.w 2f")
|
||||
TEST_BB("blt.w 2b")
|
||||
TEST_BF_X("bpl.w 2f",0x1000)
|
||||
TEST_BF_X("bpl.w 2f", SPACE_0x1000)
|
||||
)
|
||||
|
||||
TEST_UNSUPPORTED("msr cpsr, r0")
|
||||
@@ -786,11 +786,11 @@ CONDITION_INSTRUCTIONS(22,
|
||||
|
||||
TEST_BF( "b.w 2f")
|
||||
TEST_BB( "b.w 2b")
|
||||
TEST_BF_X("b.w 2f", 0x1000)
|
||||
TEST_BF_X("b.w 2f", SPACE_0x1000)
|
||||
|
||||
TEST_BF( "bl.w 2f")
|
||||
TEST_BB( "bl.w 2b")
|
||||
TEST_BB_X("bl.w 2b", 0x1000)
|
||||
TEST_BB_X("bl.w 2b", SPACE_0x1000)
|
||||
|
||||
TEST_X( "blx __dummy_arm_subroutine",
|
||||
".arm \n\t"
|
||||
|
@@ -149,23 +149,31 @@ struct test_arg_end {
|
||||
"1: "instruction" \n\t" \
|
||||
" nop \n\t"
|
||||
|
||||
#define TEST_BRANCH_F(instruction, xtra_dist) \
|
||||
#define TEST_BRANCH_F(instruction) \
|
||||
TEST_INSTRUCTION(instruction) \
|
||||
".if "#xtra_dist" \n\t" \
|
||||
" b 99f \n\t" \
|
||||
".space "#xtra_dist" \n\t" \
|
||||
".endif \n\t" \
|
||||
" b 99f \n\t" \
|
||||
"2: nop \n\t"
|
||||
|
||||
#define TEST_BRANCH_B(instruction, xtra_dist) \
|
||||
#define TEST_BRANCH_B(instruction) \
|
||||
" b 50f \n\t" \
|
||||
" b 99f \n\t" \
|
||||
"2: nop \n\t" \
|
||||
" b 99f \n\t" \
|
||||
".if "#xtra_dist" \n\t" \
|
||||
".space "#xtra_dist" \n\t" \
|
||||
".endif \n\t" \
|
||||
TEST_INSTRUCTION(instruction)
|
||||
|
||||
#define TEST_BRANCH_FX(instruction, codex) \
|
||||
TEST_INSTRUCTION(instruction) \
|
||||
" b 99f \n\t" \
|
||||
codex" \n\t" \
|
||||
" b 99f \n\t" \
|
||||
"2: nop \n\t"
|
||||
|
||||
#define TEST_BRANCH_BX(instruction, codex) \
|
||||
" b 50f \n\t" \
|
||||
" b 99f \n\t" \
|
||||
"2: nop \n\t" \
|
||||
" b 99f \n\t" \
|
||||
codex" \n\t" \
|
||||
TEST_INSTRUCTION(instruction)
|
||||
|
||||
#define TESTCASE_END \
|
||||
@@ -301,47 +309,60 @@ struct test_arg_end {
|
||||
TESTCASE_START(code1 #reg1 code2) \
|
||||
TEST_ARG_PTR(reg1, val1) \
|
||||
TEST_ARG_END("") \
|
||||
TEST_BRANCH_F(code1 #reg1 code2, 0) \
|
||||
TEST_BRANCH_F(code1 #reg1 code2) \
|
||||
TESTCASE_END
|
||||
|
||||
#define TEST_BF_X(code, xtra_dist) \
|
||||
#define TEST_BF(code) \
|
||||
TESTCASE_START(code) \
|
||||
TEST_ARG_END("") \
|
||||
TEST_BRANCH_F(code, xtra_dist) \
|
||||
TEST_BRANCH_F(code) \
|
||||
TESTCASE_END
|
||||
|
||||
#define TEST_BB_X(code, xtra_dist) \
|
||||
#define TEST_BB(code) \
|
||||
TESTCASE_START(code) \
|
||||
TEST_ARG_END("") \
|
||||
TEST_BRANCH_B(code, xtra_dist) \
|
||||
TEST_BRANCH_B(code) \
|
||||
TESTCASE_END
|
||||
|
||||
#define TEST_BF_RX(code1, reg, val, code2, xtra_dist) \
|
||||
TESTCASE_START(code1 #reg code2) \
|
||||
TEST_ARG_REG(reg, val) \
|
||||
TEST_ARG_END("") \
|
||||
TEST_BRANCH_F(code1 #reg code2, xtra_dist) \
|
||||
#define TEST_BF_R(code1, reg, val, code2) \
|
||||
TESTCASE_START(code1 #reg code2) \
|
||||
TEST_ARG_REG(reg, val) \
|
||||
TEST_ARG_END("") \
|
||||
TEST_BRANCH_F(code1 #reg code2) \
|
||||
TESTCASE_END
|
||||
|
||||
#define TEST_BB_RX(code1, reg, val, code2, xtra_dist) \
|
||||
TESTCASE_START(code1 #reg code2) \
|
||||
TEST_ARG_REG(reg, val) \
|
||||
TEST_ARG_END("") \
|
||||
TEST_BRANCH_B(code1 #reg code2, xtra_dist) \
|
||||
#define TEST_BB_R(code1, reg, val, code2) \
|
||||
TESTCASE_START(code1 #reg code2) \
|
||||
TEST_ARG_REG(reg, val) \
|
||||
TEST_ARG_END("") \
|
||||
TEST_BRANCH_B(code1 #reg code2) \
|
||||
TESTCASE_END
|
||||
|
||||
#define TEST_BF(code) TEST_BF_X(code, 0)
|
||||
#define TEST_BB(code) TEST_BB_X(code, 0)
|
||||
|
||||
#define TEST_BF_R(code1, reg, val, code2) TEST_BF_RX(code1, reg, val, code2, 0)
|
||||
#define TEST_BB_R(code1, reg, val, code2) TEST_BB_RX(code1, reg, val, code2, 0)
|
||||
|
||||
#define TEST_BF_RR(code1, reg1, val1, code2, reg2, val2, code3) \
|
||||
TESTCASE_START(code1 #reg1 code2 #reg2 code3) \
|
||||
TEST_ARG_REG(reg1, val1) \
|
||||
TEST_ARG_REG(reg2, val2) \
|
||||
TEST_ARG_END("") \
|
||||
TEST_BRANCH_F(code1 #reg1 code2 #reg2 code3, 0) \
|
||||
TEST_BRANCH_F(code1 #reg1 code2 #reg2 code3) \
|
||||
TESTCASE_END
|
||||
|
||||
#define TEST_BF_X(code, codex) \
|
||||
TESTCASE_START(code) \
|
||||
TEST_ARG_END("") \
|
||||
TEST_BRANCH_FX(code, codex) \
|
||||
TESTCASE_END
|
||||
|
||||
#define TEST_BB_X(code, codex) \
|
||||
TESTCASE_START(code) \
|
||||
TEST_ARG_END("") \
|
||||
TEST_BRANCH_BX(code, codex) \
|
||||
TESTCASE_END
|
||||
|
||||
#define TEST_BF_RX(code1, reg, val, code2, codex) \
|
||||
TESTCASE_START(code1 #reg code2) \
|
||||
TEST_ARG_REG(reg, val) \
|
||||
TEST_ARG_END("") \
|
||||
TEST_BRANCH_FX(code1 #reg code2, codex) \
|
||||
TESTCASE_END
|
||||
|
||||
#define TEST_X(code, codex) \
|
||||
@@ -372,6 +393,25 @@ struct test_arg_end {
|
||||
TESTCASE_END
|
||||
|
||||
|
||||
/*
|
||||
* Macros for defining space directives spread over multiple lines.
|
||||
* These are required so the compiler guesses better the length of inline asm
|
||||
* code and will spill the literal pool early enough to avoid generating PC
|
||||
* relative loads with out of range offsets.
|
||||
*/
|
||||
#define TWICE(x) x x
|
||||
#define SPACE_0x8 TWICE(".space 4\n\t")
|
||||
#define SPACE_0x10 TWICE(SPACE_0x8)
|
||||
#define SPACE_0x20 TWICE(SPACE_0x10)
|
||||
#define SPACE_0x40 TWICE(SPACE_0x20)
|
||||
#define SPACE_0x80 TWICE(SPACE_0x40)
|
||||
#define SPACE_0x100 TWICE(SPACE_0x80)
|
||||
#define SPACE_0x200 TWICE(SPACE_0x100)
|
||||
#define SPACE_0x400 TWICE(SPACE_0x200)
|
||||
#define SPACE_0x800 TWICE(SPACE_0x400)
|
||||
#define SPACE_0x1000 TWICE(SPACE_0x800)
|
||||
|
||||
|
||||
/* Various values used in test cases... */
|
||||
#define N(val) (val ^ 0xffffffff)
|
||||
#define VAL1 0x12345678
|
||||
|
@@ -32,24 +32,6 @@ static atomic_t waiting_for_crash_ipi;
|
||||
|
||||
int machine_kexec_prepare(struct kimage *image)
|
||||
{
|
||||
unsigned long page_list;
|
||||
void *reboot_code_buffer;
|
||||
page_list = image->head & PAGE_MASK;
|
||||
|
||||
reboot_code_buffer = page_address(image->control_code_page);
|
||||
|
||||
/* Prepare parameters for reboot_code_buffer*/
|
||||
kexec_start_address = image->start;
|
||||
kexec_indirection_page = page_list;
|
||||
kexec_mach_type = machine_arch_type;
|
||||
kexec_boot_atags = image->start - KEXEC_ARM_ZIMAGE_OFFSET + KEXEC_ARM_ATAGS_OFFSET;
|
||||
|
||||
/* copy our kernel relocation code to the control code page */
|
||||
memcpy(reboot_code_buffer,
|
||||
relocate_new_kernel, relocate_new_kernel_size);
|
||||
|
||||
flush_icache_range((unsigned long) reboot_code_buffer,
|
||||
(unsigned long) reboot_code_buffer + KEXEC_CONTROL_PAGE_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -100,14 +82,31 @@ void (*kexec_reinit)(void);
|
||||
|
||||
void machine_kexec(struct kimage *image)
|
||||
{
|
||||
unsigned long page_list;
|
||||
unsigned long reboot_code_buffer_phys;
|
||||
void *reboot_code_buffer;
|
||||
|
||||
|
||||
page_list = image->head & PAGE_MASK;
|
||||
|
||||
/* we need both effective and real address here */
|
||||
reboot_code_buffer_phys =
|
||||
page_to_pfn(image->control_code_page) << PAGE_SHIFT;
|
||||
reboot_code_buffer = page_address(image->control_code_page);
|
||||
|
||||
/* Prepare parameters for reboot_code_buffer*/
|
||||
kexec_start_address = image->start;
|
||||
kexec_indirection_page = page_list;
|
||||
kexec_mach_type = machine_arch_type;
|
||||
kexec_boot_atags = image->start - KEXEC_ARM_ZIMAGE_OFFSET + KEXEC_ARM_ATAGS_OFFSET;
|
||||
|
||||
/* copy our kernel relocation code to the control code page */
|
||||
memcpy(reboot_code_buffer,
|
||||
relocate_new_kernel, relocate_new_kernel_size);
|
||||
|
||||
|
||||
flush_icache_range((unsigned long) reboot_code_buffer,
|
||||
(unsigned long) reboot_code_buffer + KEXEC_CONTROL_PAGE_SIZE);
|
||||
printk(KERN_INFO "Bye!\n");
|
||||
|
||||
if (kexec_reinit)
|
||||
|
@@ -343,19 +343,25 @@ validate_group(struct perf_event *event)
|
||||
{
|
||||
struct perf_event *sibling, *leader = event->group_leader;
|
||||
struct pmu_hw_events fake_pmu;
|
||||
DECLARE_BITMAP(fake_used_mask, ARMPMU_MAX_HWEVENTS);
|
||||
|
||||
memset(&fake_pmu, 0, sizeof(fake_pmu));
|
||||
/*
|
||||
* Initialise the fake PMU. We only need to populate the
|
||||
* used_mask for the purposes of validation.
|
||||
*/
|
||||
memset(fake_used_mask, 0, sizeof(fake_used_mask));
|
||||
fake_pmu.used_mask = fake_used_mask;
|
||||
|
||||
if (!validate_event(&fake_pmu, leader))
|
||||
return -ENOSPC;
|
||||
return -EINVAL;
|
||||
|
||||
list_for_each_entry(sibling, &leader->sibling_list, group_entry) {
|
||||
if (!validate_event(&fake_pmu, sibling))
|
||||
return -ENOSPC;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!validate_event(&fake_pmu, event))
|
||||
return -ENOSPC;
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -396,6 +402,9 @@ armpmu_reserve_hardware(struct arm_pmu *armpmu)
|
||||
int i, err, irq, irqs;
|
||||
struct platform_device *pmu_device = armpmu->plat_device;
|
||||
|
||||
if (!pmu_device)
|
||||
return -ENODEV;
|
||||
|
||||
err = reserve_pmu(armpmu->type);
|
||||
if (err) {
|
||||
pr_warning("unable to reserve pmu\n");
|
||||
@@ -631,6 +640,9 @@ static struct platform_device_id armpmu_plat_device_ids[] = {
|
||||
|
||||
static int __devinit armpmu_device_probe(struct platform_device *pdev)
|
||||
{
|
||||
if (!cpu_pmu)
|
||||
return -ENODEV;
|
||||
|
||||
cpu_pmu->plat_device = pdev;
|
||||
return 0;
|
||||
}
|
||||
|
@@ -33,3 +33,4 @@ release_pmu(enum arm_pmu_type type)
|
||||
{
|
||||
clear_bit_unlock(type, pmu_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(release_pmu);
|
||||
|
@@ -191,6 +191,9 @@ void cpu_idle(void)
|
||||
#endif
|
||||
|
||||
local_irq_disable();
|
||||
#ifdef CONFIG_PL310_ERRATA_769419
|
||||
wmb();
|
||||
#endif
|
||||
if (hlt_counter) {
|
||||
local_irq_enable();
|
||||
cpu_relax();
|
||||
|
@@ -461,8 +461,10 @@ static void __init setup_processor(void)
|
||||
cpu_name, read_cpuid_id(), read_cpuid_id() & 15,
|
||||
proc_arch[cpu_architecture()], cr_alignment);
|
||||
|
||||
sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS);
|
||||
sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
|
||||
snprintf(init_utsname()->machine, __NEW_UTS_LEN + 1, "%s%c",
|
||||
list->arch_name, ENDIANNESS);
|
||||
snprintf(elf_platform, ELF_PLATFORM_SIZE, "%s%c",
|
||||
list->elf_name, ENDIANNESS);
|
||||
elf_hwcap = list->elf_hwcap;
|
||||
#ifndef CONFIG_ARM_THUMB
|
||||
elf_hwcap &= ~HWCAP_THUMB;
|
||||
@@ -893,8 +895,6 @@ void __init setup_arch(char **cmdline_p)
|
||||
{
|
||||
struct machine_desc *mdesc;
|
||||
|
||||
unwind_init();
|
||||
|
||||
setup_processor();
|
||||
mdesc = setup_machine_fdt(__atags_pointer);
|
||||
if (!mdesc)
|
||||
@@ -902,6 +902,12 @@ void __init setup_arch(char **cmdline_p)
|
||||
machine_desc = mdesc;
|
||||
machine_name = mdesc->name;
|
||||
|
||||
#ifdef CONFIG_ZONE_DMA
|
||||
if (mdesc->dma_zone_size) {
|
||||
extern unsigned long arm_dma_zone_size;
|
||||
arm_dma_zone_size = mdesc->dma_zone_size;
|
||||
}
|
||||
#endif
|
||||
if (mdesc->restart_mode)
|
||||
reboot_setup(&mdesc->restart_mode);
|
||||
|
||||
@@ -935,12 +941,6 @@ void __init setup_arch(char **cmdline_p)
|
||||
|
||||
tcm_init();
|
||||
|
||||
#ifdef CONFIG_ZONE_DMA
|
||||
if (mdesc->dma_zone_size) {
|
||||
extern unsigned long arm_dma_zone_size;
|
||||
arm_dma_zone_size = mdesc->dma_zone_size;
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_MULTI_IRQ_HANDLER
|
||||
handle_arch_irq = mdesc->handle_irq;
|
||||
#endif
|
||||
|
@@ -43,7 +43,7 @@
|
||||
|
||||
struct cputopo_arm cpu_topology[NR_CPUS];
|
||||
|
||||
const struct cpumask *cpu_coregroup_mask(unsigned int cpu)
|
||||
const struct cpumask *cpu_coregroup_mask(int cpu)
|
||||
{
|
||||
return &cpu_topology[cpu].core_sibling;
|
||||
}
|
||||
|
@@ -67,7 +67,7 @@ EXPORT_SYMBOL(__aeabi_unwind_cpp_pr2);
|
||||
|
||||
struct unwind_ctrl_block {
|
||||
unsigned long vrs[16]; /* virtual register set */
|
||||
unsigned long *insn; /* pointer to the current instructions word */
|
||||
const unsigned long *insn; /* pointer to the current instructions word */
|
||||
int entries; /* number of entries left to interpret */
|
||||
int byte; /* current byte number in the instructions word */
|
||||
};
|
||||
@@ -83,8 +83,9 @@ enum regs {
|
||||
PC = 15
|
||||
};
|
||||
|
||||
extern struct unwind_idx __start_unwind_idx[];
|
||||
extern struct unwind_idx __stop_unwind_idx[];
|
||||
extern const struct unwind_idx __start_unwind_idx[];
|
||||
static const struct unwind_idx *__origin_unwind_idx;
|
||||
extern const struct unwind_idx __stop_unwind_idx[];
|
||||
|
||||
static DEFINE_SPINLOCK(unwind_lock);
|
||||
static LIST_HEAD(unwind_tables);
|
||||
@@ -98,45 +99,99 @@ static LIST_HEAD(unwind_tables);
|
||||
})
|
||||
|
||||
/*
|
||||
* Binary search in the unwind index. The entries entries are
|
||||
* Binary search in the unwind index. The entries are
|
||||
* guaranteed to be sorted in ascending order by the linker.
|
||||
*
|
||||
* start = first entry
|
||||
* origin = first entry with positive offset (or stop if there is no such entry)
|
||||
* stop - 1 = last entry
|
||||
*/
|
||||
static struct unwind_idx *search_index(unsigned long addr,
|
||||
struct unwind_idx *first,
|
||||
struct unwind_idx *last)
|
||||
static const struct unwind_idx *search_index(unsigned long addr,
|
||||
const struct unwind_idx *start,
|
||||
const struct unwind_idx *origin,
|
||||
const struct unwind_idx *stop)
|
||||
{
|
||||
pr_debug("%s(%08lx, %p, %p)\n", __func__, addr, first, last);
|
||||
unsigned long addr_prel31;
|
||||
|
||||
if (addr < first->addr) {
|
||||
pr_warning("unwind: Unknown symbol address %08lx\n", addr);
|
||||
return NULL;
|
||||
} else if (addr >= last->addr)
|
||||
return last;
|
||||
pr_debug("%s(%08lx, %p, %p, %p)\n",
|
||||
__func__, addr, start, origin, stop);
|
||||
|
||||
while (first < last - 1) {
|
||||
struct unwind_idx *mid = first + ((last - first + 1) >> 1);
|
||||
/*
|
||||
* only search in the section with the matching sign. This way the
|
||||
* prel31 numbers can be compared as unsigned longs.
|
||||
*/
|
||||
if (addr < (unsigned long)start)
|
||||
/* negative offsets: [start; origin) */
|
||||
stop = origin;
|
||||
else
|
||||
/* positive offsets: [origin; stop) */
|
||||
start = origin;
|
||||
|
||||
if (addr < mid->addr)
|
||||
last = mid;
|
||||
else
|
||||
first = mid;
|
||||
/* prel31 for address relavive to start */
|
||||
addr_prel31 = (addr - (unsigned long)start) & 0x7fffffff;
|
||||
|
||||
while (start < stop - 1) {
|
||||
const struct unwind_idx *mid = start + ((stop - start) >> 1);
|
||||
|
||||
/*
|
||||
* As addr_prel31 is relative to start an offset is needed to
|
||||
* make it relative to mid.
|
||||
*/
|
||||
if (addr_prel31 - ((unsigned long)mid - (unsigned long)start) <
|
||||
mid->addr_offset)
|
||||
stop = mid;
|
||||
else {
|
||||
/* keep addr_prel31 relative to start */
|
||||
addr_prel31 -= ((unsigned long)mid -
|
||||
(unsigned long)start);
|
||||
start = mid;
|
||||
}
|
||||
}
|
||||
|
||||
return first;
|
||||
if (likely(start->addr_offset <= addr_prel31))
|
||||
return start;
|
||||
else {
|
||||
pr_warning("unwind: Unknown symbol address %08lx\n", addr);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static struct unwind_idx *unwind_find_idx(unsigned long addr)
|
||||
static const struct unwind_idx *unwind_find_origin(
|
||||
const struct unwind_idx *start, const struct unwind_idx *stop)
|
||||
{
|
||||
struct unwind_idx *idx = NULL;
|
||||
pr_debug("%s(%p, %p)\n", __func__, start, stop);
|
||||
while (start < stop) {
|
||||
const struct unwind_idx *mid = start + ((stop - start) >> 1);
|
||||
|
||||
if (mid->addr_offset >= 0x40000000)
|
||||
/* negative offset */
|
||||
start = mid + 1;
|
||||
else
|
||||
/* positive offset */
|
||||
stop = mid;
|
||||
}
|
||||
pr_debug("%s -> %p\n", __func__, stop);
|
||||
return stop;
|
||||
}
|
||||
|
||||
static const struct unwind_idx *unwind_find_idx(unsigned long addr)
|
||||
{
|
||||
const struct unwind_idx *idx = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
pr_debug("%s(%08lx)\n", __func__, addr);
|
||||
|
||||
if (core_kernel_text(addr))
|
||||
if (core_kernel_text(addr)) {
|
||||
if (unlikely(!__origin_unwind_idx))
|
||||
__origin_unwind_idx =
|
||||
unwind_find_origin(__start_unwind_idx,
|
||||
__stop_unwind_idx);
|
||||
|
||||
/* main unwind table */
|
||||
idx = search_index(addr, __start_unwind_idx,
|
||||
__stop_unwind_idx - 1);
|
||||
else {
|
||||
__origin_unwind_idx,
|
||||
__stop_unwind_idx);
|
||||
} else {
|
||||
/* module unwind tables */
|
||||
struct unwind_table *table;
|
||||
|
||||
@@ -145,7 +200,8 @@ static struct unwind_idx *unwind_find_idx(unsigned long addr)
|
||||
if (addr >= table->begin_addr &&
|
||||
addr < table->end_addr) {
|
||||
idx = search_index(addr, table->start,
|
||||
table->stop - 1);
|
||||
table->origin,
|
||||
table->stop);
|
||||
/* Move-to-front to exploit common traces */
|
||||
list_move(&table->list, &unwind_tables);
|
||||
break;
|
||||
@@ -274,7 +330,7 @@ static int unwind_exec_insn(struct unwind_ctrl_block *ctrl)
|
||||
int unwind_frame(struct stackframe *frame)
|
||||
{
|
||||
unsigned long high, low;
|
||||
struct unwind_idx *idx;
|
||||
const struct unwind_idx *idx;
|
||||
struct unwind_ctrl_block ctrl;
|
||||
|
||||
/* only go to a higher address on the stack */
|
||||
@@ -399,7 +455,6 @@ struct unwind_table *unwind_table_add(unsigned long start, unsigned long size,
|
||||
unsigned long text_size)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct unwind_idx *idx;
|
||||
struct unwind_table *tab = kmalloc(sizeof(*tab), GFP_KERNEL);
|
||||
|
||||
pr_debug("%s(%08lx, %08lx, %08lx, %08lx)\n", __func__, start, size,
|
||||
@@ -408,15 +463,12 @@ struct unwind_table *unwind_table_add(unsigned long start, unsigned long size,
|
||||
if (!tab)
|
||||
return tab;
|
||||
|
||||
tab->start = (struct unwind_idx *)start;
|
||||
tab->stop = (struct unwind_idx *)(start + size);
|
||||
tab->start = (const struct unwind_idx *)start;
|
||||
tab->stop = (const struct unwind_idx *)(start + size);
|
||||
tab->origin = unwind_find_origin(tab->start, tab->stop);
|
||||
tab->begin_addr = text_addr;
|
||||
tab->end_addr = text_addr + text_size;
|
||||
|
||||
/* Convert the symbol addresses to absolute values */
|
||||
for (idx = tab->start; idx < tab->stop; idx++)
|
||||
idx->addr = prel31_to_addr(&idx->addr);
|
||||
|
||||
spin_lock_irqsave(&unwind_lock, flags);
|
||||
list_add_tail(&tab->list, &unwind_tables);
|
||||
spin_unlock_irqrestore(&unwind_lock, flags);
|
||||
@@ -437,16 +489,3 @@ void unwind_table_del(struct unwind_table *tab)
|
||||
|
||||
kfree(tab);
|
||||
}
|
||||
|
||||
int __init unwind_init(void)
|
||||
{
|
||||
struct unwind_idx *idx;
|
||||
|
||||
/* Convert the symbol addresses to absolute values */
|
||||
for (idx = __start_unwind_idx; idx < __stop_unwind_idx; idx++)
|
||||
idx->addr = prel31_to_addr(&idx->addr);
|
||||
|
||||
pr_debug("unwind: ARM stack unwinding initialised\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user