Merge branch 'devel-stable' into for-next
Conflicts: arch/arm/kernel/entry-armv.S
This commit is contained in:
commit
3ad55155b2
107 changed files with 5100 additions and 4016 deletions
267
Documentation/arm/kernel_user_helpers.txt
Normal file
267
Documentation/arm/kernel_user_helpers.txt
Normal file
|
@ -0,0 +1,267 @@
|
|||
Kernel-provided User Helpers
|
||||
============================
|
||||
|
||||
These are segment of kernel provided user code reachable from user space
|
||||
at a fixed address in kernel memory. This is used to provide user space
|
||||
with some operations which require kernel help because of unimplemented
|
||||
native feature and/or instructions in many ARM CPUs. The idea is for this
|
||||
code to be executed directly in user mode for best efficiency but which is
|
||||
too intimate with the kernel counter part to be left to user libraries.
|
||||
In fact this code might even differ from one CPU to another depending on
|
||||
the available instruction set, or whether it is a SMP systems. In other
|
||||
words, the kernel reserves the right to change this code as needed without
|
||||
warning. Only the entry points and their results as documented here are
|
||||
guaranteed to be stable.
|
||||
|
||||
This is different from (but doesn't preclude) a full blown VDSO
|
||||
implementation, however a VDSO would prevent some assembly tricks with
|
||||
constants that allows for efficient branching to those code segments. And
|
||||
since those code segments only use a few cycles before returning to user
|
||||
code, the overhead of a VDSO indirect far call would add a measurable
|
||||
overhead to such minimalistic operations.
|
||||
|
||||
User space is expected to bypass those helpers and implement those things
|
||||
inline (either in the code emitted directly by the compiler, or part of
|
||||
the implementation of a library call) when optimizing for a recent enough
|
||||
processor that has the necessary native support, but only if resulting
|
||||
binaries are already to be incompatible with earlier ARM processors due to
|
||||
useage of similar native instructions for other things. In other words
|
||||
don't make binaries unable to run on earlier processors just for the sake
|
||||
of not using these kernel helpers if your compiled code is not going to
|
||||
use new instructions for other purpose.
|
||||
|
||||
New helpers may be added over time, so an older kernel may be missing some
|
||||
helpers present in a newer kernel. For this reason, programs must check
|
||||
the value of __kuser_helper_version (see below) before assuming that it is
|
||||
safe to call any particular helper. This check should ideally be
|
||||
performed only once at process startup time, and execution aborted early
|
||||
if the required helpers are not provided by the kernel version that
|
||||
process is running on.
|
||||
|
||||
kuser_helper_version
|
||||
--------------------
|
||||
|
||||
Location: 0xffff0ffc
|
||||
|
||||
Reference declaration:
|
||||
|
||||
extern int32_t __kuser_helper_version;
|
||||
|
||||
Definition:
|
||||
|
||||
This field contains the number of helpers being implemented by the
|
||||
running kernel. User space may read this to determine the availability
|
||||
of a particular helper.
|
||||
|
||||
Usage example:
|
||||
|
||||
#define __kuser_helper_version (*(int32_t *)0xffff0ffc)
|
||||
|
||||
void check_kuser_version(void)
|
||||
{
|
||||
if (__kuser_helper_version < 2) {
|
||||
fprintf(stderr, "can't do atomic operations, kernel too old\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
Notes:
|
||||
|
||||
User space may assume that the value of this field never changes
|
||||
during the lifetime of any single process. This means that this
|
||||
field can be read once during the initialisation of a library or
|
||||
startup phase of a program.
|
||||
|
||||
kuser_get_tls
|
||||
-------------
|
||||
|
||||
Location: 0xffff0fe0
|
||||
|
||||
Reference prototype:
|
||||
|
||||
void * __kuser_get_tls(void);
|
||||
|
||||
Input:
|
||||
|
||||
lr = return address
|
||||
|
||||
Output:
|
||||
|
||||
r0 = TLS value
|
||||
|
||||
Clobbered registers:
|
||||
|
||||
none
|
||||
|
||||
Definition:
|
||||
|
||||
Get the TLS value as previously set via the __ARM_NR_set_tls syscall.
|
||||
|
||||
Usage example:
|
||||
|
||||
typedef void * (__kuser_get_tls_t)(void);
|
||||
#define __kuser_get_tls (*(__kuser_get_tls_t *)0xffff0fe0)
|
||||
|
||||
void foo()
|
||||
{
|
||||
void *tls = __kuser_get_tls();
|
||||
printf("TLS = %p\n", tls);
|
||||
}
|
||||
|
||||
Notes:
|
||||
|
||||
- Valid only if __kuser_helper_version >= 1 (from kernel version 2.6.12).
|
||||
|
||||
kuser_cmpxchg
|
||||
-------------
|
||||
|
||||
Location: 0xffff0fc0
|
||||
|
||||
Reference prototype:
|
||||
|
||||
int __kuser_cmpxchg(int32_t oldval, int32_t newval, volatile int32_t *ptr);
|
||||
|
||||
Input:
|
||||
|
||||
r0 = oldval
|
||||
r1 = newval
|
||||
r2 = ptr
|
||||
lr = return address
|
||||
|
||||
Output:
|
||||
|
||||
r0 = success code (zero or non-zero)
|
||||
C flag = set if r0 == 0, clear if r0 != 0
|
||||
|
||||
Clobbered registers:
|
||||
|
||||
r3, ip, flags
|
||||
|
||||
Definition:
|
||||
|
||||
Atomically store newval in *ptr only if *ptr is equal to oldval.
|
||||
Return zero if *ptr was changed or non-zero if no exchange happened.
|
||||
The C flag is also set if *ptr was changed to allow for assembly
|
||||
optimization in the calling code.
|
||||
|
||||
Usage example:
|
||||
|
||||
typedef int (__kuser_cmpxchg_t)(int oldval, int newval, volatile int *ptr);
|
||||
#define __kuser_cmpxchg (*(__kuser_cmpxchg_t *)0xffff0fc0)
|
||||
|
||||
int atomic_add(volatile int *ptr, int val)
|
||||
{
|
||||
int old, new;
|
||||
|
||||
do {
|
||||
old = *ptr;
|
||||
new = old + val;
|
||||
} while(__kuser_cmpxchg(old, new, ptr));
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
Notes:
|
||||
|
||||
- This routine already includes memory barriers as needed.
|
||||
|
||||
- Valid only if __kuser_helper_version >= 2 (from kernel version 2.6.12).
|
||||
|
||||
kuser_memory_barrier
|
||||
--------------------
|
||||
|
||||
Location: 0xffff0fa0
|
||||
|
||||
Reference prototype:
|
||||
|
||||
void __kuser_memory_barrier(void);
|
||||
|
||||
Input:
|
||||
|
||||
lr = return address
|
||||
|
||||
Output:
|
||||
|
||||
none
|
||||
|
||||
Clobbered registers:
|
||||
|
||||
none
|
||||
|
||||
Definition:
|
||||
|
||||
Apply any needed memory barrier to preserve consistency with data modified
|
||||
manually and __kuser_cmpxchg usage.
|
||||
|
||||
Usage example:
|
||||
|
||||
typedef void (__kuser_dmb_t)(void);
|
||||
#define __kuser_dmb (*(__kuser_dmb_t *)0xffff0fa0)
|
||||
|
||||
Notes:
|
||||
|
||||
- Valid only if __kuser_helper_version >= 3 (from kernel version 2.6.15).
|
||||
|
||||
kuser_cmpxchg64
|
||||
---------------
|
||||
|
||||
Location: 0xffff0f60
|
||||
|
||||
Reference prototype:
|
||||
|
||||
int __kuser_cmpxchg64(const int64_t *oldval,
|
||||
const int64_t *newval,
|
||||
volatile int64_t *ptr);
|
||||
|
||||
Input:
|
||||
|
||||
r0 = pointer to oldval
|
||||
r1 = pointer to newval
|
||||
r2 = pointer to target value
|
||||
lr = return address
|
||||
|
||||
Output:
|
||||
|
||||
r0 = success code (zero or non-zero)
|
||||
C flag = set if r0 == 0, clear if r0 != 0
|
||||
|
||||
Clobbered registers:
|
||||
|
||||
r3, lr, flags
|
||||
|
||||
Definition:
|
||||
|
||||
Atomically store the 64-bit value pointed by *newval in *ptr only if *ptr
|
||||
is equal to the 64-bit value pointed by *oldval. Return zero if *ptr was
|
||||
changed or non-zero if no exchange happened.
|
||||
|
||||
The C flag is also set if *ptr was changed to allow for assembly
|
||||
optimization in the calling code.
|
||||
|
||||
Usage example:
|
||||
|
||||
typedef int (__kuser_cmpxchg64_t)(const int64_t *oldval,
|
||||
const int64_t *newval,
|
||||
volatile int64_t *ptr);
|
||||
#define __kuser_cmpxchg64 (*(__kuser_cmpxchg64_t *)0xffff0f60)
|
||||
|
||||
int64_t atomic_add64(volatile int64_t *ptr, int64_t val)
|
||||
{
|
||||
int64_t old, new;
|
||||
|
||||
do {
|
||||
old = *ptr;
|
||||
new = old + val;
|
||||
} while(__kuser_cmpxchg64(&old, &new, ptr));
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
Notes:
|
||||
|
||||
- This routine already includes memory barriers as needed.
|
||||
|
||||
- Due to the length of this sequence, this spans 2 conventional kuser
|
||||
"slots", therefore 0xffff0f80 is not used as a valid entry point.
|
||||
|
||||
- Valid only if __kuser_helper_version >= 5 (from kernel version 3.1).
|
|
@ -10,7 +10,7 @@ config ARM
|
|||
select GENERIC_ATOMIC64 if (CPU_V6 || !CPU_32v6K || !AEABI)
|
||||
select HAVE_OPROFILE if (HAVE_PERF_EVENTS)
|
||||
select HAVE_ARCH_KGDB
|
||||
select HAVE_KPROBES if (!XIP_KERNEL && !THUMB2_KERNEL)
|
||||
select HAVE_KPROBES if !XIP_KERNEL
|
||||
select HAVE_KRETPROBES if (HAVE_KPROBES)
|
||||
select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
|
||||
select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL)
|
||||
|
|
|
@ -293,4 +293,13 @@
|
|||
.macro ldrusr, reg, ptr, inc, cond=al, rept=1, abort=9001f
|
||||
usracc ldr, \reg, \ptr, \inc, \cond, \rept, \abort
|
||||
.endm
|
||||
|
||||
/* Utility macro for declaring string literals */
|
||||
.macro string name:req, string
|
||||
.type \name , #object
|
||||
\name:
|
||||
.asciz "\string"
|
||||
.size \name , . - \name
|
||||
.endm
|
||||
|
||||
#endif /* __ASM_ASSEMBLER_H__ */
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
#ifndef __ASM_ARM_DMA_H
|
||||
#define __ASM_ARM_DMA_H
|
||||
|
||||
#include <asm/memory.h>
|
||||
|
||||
/*
|
||||
* This is the maximum virtual address which can be DMA'd from.
|
||||
*/
|
||||
#ifndef ARM_DMA_ZONE_SIZE
|
||||
#define MAX_DMA_ADDRESS 0xffffffff
|
||||
#ifndef CONFIG_ZONE_DMA
|
||||
#define MAX_DMA_ADDRESS 0xffffffffUL
|
||||
#else
|
||||
#define MAX_DMA_ADDRESS (PAGE_OFFSET + ARM_DMA_ZONE_SIZE)
|
||||
#define MAX_DMA_ADDRESS ({ \
|
||||
extern unsigned long arm_dma_zone_size; \
|
||||
arm_dma_zone_size ? \
|
||||
(PAGE_OFFSET + arm_dma_zone_size) : 0xffffffffUL; })
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ISA_DMA_API
|
||||
|
|
|
@ -4,22 +4,26 @@
|
|||
/*
|
||||
* HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP
|
||||
*/
|
||||
#define HWCAP_SWP 1
|
||||
#define HWCAP_HALF 2
|
||||
#define HWCAP_THUMB 4
|
||||
#define HWCAP_26BIT 8 /* Play it safe */
|
||||
#define HWCAP_FAST_MULT 16
|
||||
#define HWCAP_FPA 32
|
||||
#define HWCAP_VFP 64
|
||||
#define HWCAP_EDSP 128
|
||||
#define HWCAP_JAVA 256
|
||||
#define HWCAP_IWMMXT 512
|
||||
#define HWCAP_CRUNCH 1024
|
||||
#define HWCAP_THUMBEE 2048
|
||||
#define HWCAP_NEON 4096
|
||||
#define HWCAP_VFPv3 8192
|
||||
#define HWCAP_VFPv3D16 16384
|
||||
#define HWCAP_TLS 32768
|
||||
#define HWCAP_SWP (1 << 0)
|
||||
#define HWCAP_HALF (1 << 1)
|
||||
#define HWCAP_THUMB (1 << 2)
|
||||
#define HWCAP_26BIT (1 << 3) /* Play it safe */
|
||||
#define HWCAP_FAST_MULT (1 << 4)
|
||||
#define HWCAP_FPA (1 << 5)
|
||||
#define HWCAP_VFP (1 << 6)
|
||||
#define HWCAP_EDSP (1 << 7)
|
||||
#define HWCAP_JAVA (1 << 8)
|
||||
#define HWCAP_IWMMXT (1 << 9)
|
||||
#define HWCAP_CRUNCH (1 << 10)
|
||||
#define HWCAP_THUMBEE (1 << 11)
|
||||
#define HWCAP_NEON (1 << 12)
|
||||
#define HWCAP_VFPv3 (1 << 13)
|
||||
#define HWCAP_VFPv3D16 (1 << 14)
|
||||
#define HWCAP_TLS (1 << 15)
|
||||
#define HWCAP_VFPv4 (1 << 16)
|
||||
#define HWCAP_IDIVA (1 << 17)
|
||||
#define HWCAP_IDIVT (1 << 18)
|
||||
#define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT)
|
||||
|
||||
#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
|
||||
/*
|
||||
|
|
|
@ -24,12 +24,6 @@
|
|||
#define MAX_INSN_SIZE 2
|
||||
#define MAX_STACK_SIZE 64 /* 32 would probably be OK */
|
||||
|
||||
/*
|
||||
* This undefined instruction must be unique and
|
||||
* reserved solely for kprobes' use.
|
||||
*/
|
||||
#define KPROBE_BREAKPOINT_INSTRUCTION 0xe7f001f8
|
||||
|
||||
#define regs_return_value(regs) ((regs)->ARM_r0)
|
||||
#define flush_insn_slot(p) do { } while (0)
|
||||
#define kretprobe_blacklist_size 0
|
||||
|
@ -38,14 +32,17 @@ typedef u32 kprobe_opcode_t;
|
|||
|
||||
struct kprobe;
|
||||
typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *);
|
||||
|
||||
typedef unsigned long (kprobe_check_cc)(unsigned long);
|
||||
typedef void (kprobe_insn_singlestep_t)(struct kprobe *, struct pt_regs *);
|
||||
typedef void (kprobe_insn_fn_t)(void);
|
||||
|
||||
/* Architecture specific copy of original instruction. */
|
||||
struct arch_specific_insn {
|
||||
kprobe_opcode_t *insn;
|
||||
kprobe_insn_handler_t *insn_handler;
|
||||
kprobe_check_cc *insn_check_cc;
|
||||
kprobe_opcode_t *insn;
|
||||
kprobe_insn_handler_t *insn_handler;
|
||||
kprobe_check_cc *insn_check_cc;
|
||||
kprobe_insn_singlestep_t *insn_singlestep;
|
||||
kprobe_insn_fn_t *insn_fn;
|
||||
};
|
||||
|
||||
struct prev_kprobe {
|
||||
|
@ -62,20 +59,9 @@ struct kprobe_ctlblk {
|
|||
};
|
||||
|
||||
void arch_remove_kprobe(struct kprobe *);
|
||||
void kretprobe_trampoline(void);
|
||||
|
||||
int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr);
|
||||
int kprobe_exceptions_notify(struct notifier_block *self,
|
||||
unsigned long val, void *data);
|
||||
|
||||
enum kprobe_insn {
|
||||
INSN_REJECTED,
|
||||
INSN_GOOD,
|
||||
INSN_GOOD_NO_SLOT
|
||||
};
|
||||
|
||||
enum kprobe_insn arm_kprobe_decode_insn(kprobe_opcode_t,
|
||||
struct arch_specific_insn *);
|
||||
void __init arm_kprobe_decode_init(void);
|
||||
|
||||
#endif /* _ARM_KPROBES_H */
|
||||
|
|
|
@ -23,6 +23,10 @@ struct machine_desc {
|
|||
|
||||
unsigned int nr_irqs; /* number of IRQs */
|
||||
|
||||
#ifdef CONFIG_ZONE_DMA
|
||||
unsigned long dma_zone_size; /* size of DMA-able area */
|
||||
#endif
|
||||
|
||||
unsigned int video_start; /* start of video RAM */
|
||||
unsigned int video_end; /* end of video RAM */
|
||||
|
||||
|
|
|
@ -24,6 +24,8 @@ enum arm_perf_pmu_ids {
|
|||
ARM_PERF_PMU_ID_V6MP,
|
||||
ARM_PERF_PMU_ID_CA8,
|
||||
ARM_PERF_PMU_ID_CA9,
|
||||
ARM_PERF_PMU_ID_CA5,
|
||||
ARM_PERF_PMU_ID_CA15,
|
||||
ARM_NUM_PMU_IDS,
|
||||
};
|
||||
|
||||
|
|
|
@ -69,8 +69,9 @@
|
|||
#define PSR_c 0x000000ff /* Control */
|
||||
|
||||
/*
|
||||
* ARMv7 groups of APSR bits
|
||||
* ARMv7 groups of PSR bits
|
||||
*/
|
||||
#define APSR_MASK 0xf80f0000 /* N, Z, C, V, Q and GE flags */
|
||||
#define PSR_ISET_MASK 0x01000010 /* ISA state (J, T) mask */
|
||||
#define PSR_IT_MASK 0x0600fc00 /* If-Then execution state mask */
|
||||
#define PSR_ENDIAN_MASK 0x00000200 /* Endianness state mask */
|
||||
|
@ -199,6 +200,14 @@ extern unsigned long profile_pc(struct pt_regs *regs);
|
|||
#define predicate(x) ((x) & 0xf0000000)
|
||||
#define PREDICATE_ALWAYS 0xe0000000
|
||||
|
||||
/*
|
||||
* True if instr is a 32-bit thumb instruction. This works if instr
|
||||
* is the first or only half-word of a thumb instruction. It also works
|
||||
* when instr holds all 32-bits of a wide thumb instruction if stored
|
||||
* in the form (first_half<<16)|(second_half)
|
||||
*/
|
||||
#define is_wide_instruction(instr) ((unsigned)(instr) >= 0xe800)
|
||||
|
||||
/*
|
||||
* kprobe-based event tracer support
|
||||
*/
|
||||
|
|
|
@ -37,7 +37,12 @@ obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o
|
|||
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
|
||||
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
|
||||
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
|
||||
obj-$(CONFIG_KPROBES) += kprobes.o kprobes-decode.o
|
||||
obj-$(CONFIG_KPROBES) += kprobes.o kprobes-common.o
|
||||
ifdef CONFIG_THUMB2_KERNEL
|
||||
obj-$(CONFIG_KPROBES) += kprobes-thumb.o
|
||||
else
|
||||
obj-$(CONFIG_KPROBES) += kprobes-arm.o
|
||||
endif
|
||||
obj-$(CONFIG_ATAGS_PROC) += atags.o
|
||||
obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o
|
||||
obj-$(CONFIG_ARM_THUMBEE) += thumbee.o
|
||||
|
|
|
@ -377,7 +377,7 @@ ENDPROC(__pabt_svc)
|
|||
.endm
|
||||
|
||||
.macro kuser_cmpxchg_check
|
||||
#if __LINUX_ARM_ARCH__ < 6 && !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
|
||||
#if !defined(CONFIG_CPU_32v6K) && !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
|
||||
#ifndef CONFIG_MMU
|
||||
#warning "NPTL on non MMU needs fixing"
|
||||
#else
|
||||
|
@ -386,7 +386,7 @@ ENDPROC(__pabt_svc)
|
|||
@ perform a quick test inline since it should be false
|
||||
@ 99.9999% of the time. The rest is done out of line.
|
||||
cmp r4, #TASK_SIZE
|
||||
blhs kuser_cmpxchg_fixup
|
||||
blhs kuser_cmpxchg64_fixup
|
||||
#endif
|
||||
#endif
|
||||
.endm
|
||||
|
@ -701,31 +701,12 @@ ENDPROC(__switch_to)
|
|||
/*
|
||||
* User helpers.
|
||||
*
|
||||
* These are segment of kernel provided user code reachable from user space
|
||||
* at a fixed address in kernel memory. This is used to provide user space
|
||||
* with some operations which require kernel help because of unimplemented
|
||||
* native feature and/or instructions in many ARM CPUs. The idea is for
|
||||
* this code to be executed directly in user mode for best efficiency but
|
||||
* which is too intimate with the kernel counter part to be left to user
|
||||
* libraries. In fact this code might even differ from one CPU to another
|
||||
* depending on the available instruction set and restrictions like on
|
||||
* SMP systems. In other words, the kernel reserves the right to change
|
||||
* this code as needed without warning. Only the entry points and their
|
||||
* results are guaranteed to be stable.
|
||||
*
|
||||
* Each segment is 32-byte aligned and will be moved to the top of the high
|
||||
* vector page. New segments (if ever needed) must be added in front of
|
||||
* existing ones. This mechanism should be used only for things that are
|
||||
* really small and justified, and not be abused freely.
|
||||
*
|
||||
* User space is expected to implement those things inline when optimizing
|
||||
* for a processor that has the necessary native support, but only if such
|
||||
* resulting binaries are already to be incompatible with earlier ARM
|
||||
* processors due to the use of unsupported instructions other than what
|
||||
* is provided here. In other words don't make binaries unable to run on
|
||||
* earlier processors just for the sake of not using these kernel helpers
|
||||
* if your compiled code is not going to use the new instructions for other
|
||||
* purpose.
|
||||
* See Documentation/arm/kernel_user_helpers.txt for formal definitions.
|
||||
*/
|
||||
THUMB( .arm )
|
||||
|
||||
|
@ -742,97 +723,104 @@ ENDPROC(__switch_to)
|
|||
__kuser_helper_start:
|
||||
|
||||
/*
|
||||
* Reference prototype:
|
||||
*
|
||||
* void __kernel_memory_barrier(void)
|
||||
*
|
||||
* Input:
|
||||
*
|
||||
* lr = return address
|
||||
*
|
||||
* Output:
|
||||
*
|
||||
* none
|
||||
*
|
||||
* Clobbered:
|
||||
*
|
||||
* none
|
||||
*
|
||||
* Definition and user space usage example:
|
||||
*
|
||||
* typedef void (__kernel_dmb_t)(void);
|
||||
* #define __kernel_dmb (*(__kernel_dmb_t *)0xffff0fa0)
|
||||
*
|
||||
* Apply any needed memory barrier to preserve consistency with data modified
|
||||
* manually and __kuser_cmpxchg usage.
|
||||
*
|
||||
* This could be used as follows:
|
||||
*
|
||||
* #define __kernel_dmb() \
|
||||
* asm volatile ( "mov r0, #0xffff0fff; mov lr, pc; sub pc, r0, #95" \
|
||||
* : : : "r0", "lr","cc" )
|
||||
* Due to the length of some sequences, __kuser_cmpxchg64 spans 2 regular
|
||||
* kuser "slots", therefore 0xffff0f80 is not used as a valid entry point.
|
||||
*/
|
||||
|
||||
__kuser_cmpxchg64: @ 0xffff0f60
|
||||
|
||||
#if defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
|
||||
|
||||
/*
|
||||
* Poor you. No fast solution possible...
|
||||
* The kernel itself must perform the operation.
|
||||
* A special ghost syscall is used for that (see traps.c).
|
||||
*/
|
||||
stmfd sp!, {r7, lr}
|
||||
ldr r7, 1f @ it's 20 bits
|
||||
swi __ARM_NR_cmpxchg64
|
||||
ldmfd sp!, {r7, pc}
|
||||
1: .word __ARM_NR_cmpxchg64
|
||||
|
||||
#elif defined(CONFIG_CPU_32v6K)
|
||||
|
||||
stmfd sp!, {r4, r5, r6, r7}
|
||||
ldrd r4, r5, [r0] @ load old val
|
||||
ldrd r6, r7, [r1] @ load new val
|
||||
smp_dmb arm
|
||||
1: ldrexd r0, r1, [r2] @ load current val
|
||||
eors r3, r0, r4 @ compare with oldval (1)
|
||||
eoreqs r3, r1, r5 @ compare with oldval (2)
|
||||
strexdeq r3, r6, r7, [r2] @ store newval if eq
|
||||
teqeq r3, #1 @ success?
|
||||
beq 1b @ if no then retry
|
||||
smp_dmb arm
|
||||
rsbs r0, r3, #0 @ set returned val and C flag
|
||||
ldmfd sp!, {r4, r5, r6, r7}
|
||||
bx lr
|
||||
|
||||
#elif !defined(CONFIG_SMP)
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
|
||||
/*
|
||||
* The only thing that can break atomicity in this cmpxchg64
|
||||
* implementation is either an IRQ or a data abort exception
|
||||
* causing another process/thread to be scheduled in the middle of
|
||||
* the critical sequence. The same strategy as for cmpxchg is used.
|
||||
*/
|
||||
stmfd sp!, {r4, r5, r6, lr}
|
||||
ldmia r0, {r4, r5} @ load old val
|
||||
ldmia r1, {r6, lr} @ load new val
|
||||
1: ldmia r2, {r0, r1} @ load current val
|
||||
eors r3, r0, r4 @ compare with oldval (1)
|
||||
eoreqs r3, r1, r5 @ compare with oldval (2)
|
||||
2: stmeqia r2, {r6, lr} @ store newval if eq
|
||||
rsbs r0, r3, #0 @ set return val and C flag
|
||||
ldmfd sp!, {r4, r5, r6, pc}
|
||||
|
||||
.text
|
||||
kuser_cmpxchg64_fixup:
|
||||
@ Called from kuser_cmpxchg_fixup.
|
||||
@ r4 = address of interrupted insn (must be preserved).
|
||||
@ sp = saved regs. r7 and r8 are clobbered.
|
||||
@ 1b = first critical insn, 2b = last critical insn.
|
||||
@ If r4 >= 1b and r4 <= 2b then saved pc_usr is set to 1b.
|
||||
mov r7, #0xffff0fff
|
||||
sub r7, r7, #(0xffff0fff - (0xffff0f60 + (1b - __kuser_cmpxchg64)))
|
||||
subs r8, r4, r7
|
||||
rsbcss r8, r8, #(2b - 1b)
|
||||
strcs r7, [sp, #S_PC]
|
||||
#if __LINUX_ARM_ARCH__ < 6
|
||||
bcc kuser_cmpxchg32_fixup
|
||||
#endif
|
||||
mov pc, lr
|
||||
.previous
|
||||
|
||||
#else
|
||||
#warning "NPTL on non MMU needs fixing"
|
||||
mov r0, #-1
|
||||
adds r0, r0, #0
|
||||
usr_ret lr
|
||||
#endif
|
||||
|
||||
#else
|
||||
#error "incoherent kernel configuration"
|
||||
#endif
|
||||
|
||||
/* pad to next slot */
|
||||
.rept (16 - (. - __kuser_cmpxchg64)/4)
|
||||
.word 0
|
||||
.endr
|
||||
|
||||
.align 5
|
||||
|
||||
__kuser_memory_barrier: @ 0xffff0fa0
|
||||
smp_dmb arm
|
||||
usr_ret lr
|
||||
|
||||
.align 5
|
||||
|
||||
/*
|
||||
* Reference prototype:
|
||||
*
|
||||
* int __kernel_cmpxchg(int oldval, int newval, int *ptr)
|
||||
*
|
||||
* Input:
|
||||
*
|
||||
* r0 = oldval
|
||||
* r1 = newval
|
||||
* r2 = ptr
|
||||
* lr = return address
|
||||
*
|
||||
* Output:
|
||||
*
|
||||
* r0 = returned value (zero or non-zero)
|
||||
* C flag = set if r0 == 0, clear if r0 != 0
|
||||
*
|
||||
* Clobbered:
|
||||
*
|
||||
* r3, ip, flags
|
||||
*
|
||||
* Definition and user space usage example:
|
||||
*
|
||||
* typedef int (__kernel_cmpxchg_t)(int oldval, int newval, int *ptr);
|
||||
* #define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0)
|
||||
*
|
||||
* Atomically store newval in *ptr if *ptr is equal to oldval for user space.
|
||||
* Return zero if *ptr was changed or non-zero if no exchange happened.
|
||||
* The C flag is also set if *ptr was changed to allow for assembly
|
||||
* optimization in the calling code.
|
||||
*
|
||||
* Notes:
|
||||
*
|
||||
* - This routine already includes memory barriers as needed.
|
||||
*
|
||||
* For example, a user space atomic_add implementation could look like this:
|
||||
*
|
||||
* #define atomic_add(ptr, val) \
|
||||
* ({ register unsigned int *__ptr asm("r2") = (ptr); \
|
||||
* register unsigned int __result asm("r1"); \
|
||||
* asm volatile ( \
|
||||
* "1: @ atomic_add\n\t" \
|
||||
* "ldr r0, [r2]\n\t" \
|
||||
* "mov r3, #0xffff0fff\n\t" \
|
||||
* "add lr, pc, #4\n\t" \
|
||||
* "add r1, r0, %2\n\t" \
|
||||
* "add pc, r3, #(0xffff0fc0 - 0xffff0fff)\n\t" \
|
||||
* "bcc 1b" \
|
||||
* : "=&r" (__result) \
|
||||
* : "r" (__ptr), "rIL" (val) \
|
||||
* : "r0","r3","ip","lr","cc","memory" ); \
|
||||
* __result; })
|
||||
*/
|
||||
|
||||
__kuser_cmpxchg: @ 0xffff0fc0
|
||||
|
||||
#if defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
|
||||
|
@ -868,7 +856,7 @@ __kuser_cmpxchg: @ 0xffff0fc0
|
|||
usr_ret lr
|
||||
|
||||
.text
|
||||
kuser_cmpxchg_fixup:
|
||||
kuser_cmpxchg32_fixup:
|
||||
@ Called from kuser_cmpxchg_check macro.
|
||||
@ r4 = address of interrupted insn (must be preserved).
|
||||
@ sp = saved regs. r7 and r8 are clobbered.
|
||||
|
@ -906,39 +894,6 @@ kuser_cmpxchg_fixup:
|
|||
|
||||
.align 5
|
||||
|
||||
/*
|
||||
* Reference prototype:
|
||||
*
|
||||
* int __kernel_get_tls(void)
|
||||
*
|
||||
* Input:
|
||||
*
|
||||
* lr = return address
|
||||
*
|
||||
* Output:
|
||||
*
|
||||
* r0 = TLS value
|
||||
*
|
||||
* Clobbered:
|
||||
*
|
||||
* none
|
||||
*
|
||||
* Definition and user space usage example:
|
||||
*
|
||||
* typedef int (__kernel_get_tls_t)(void);
|
||||
* #define __kernel_get_tls (*(__kernel_get_tls_t *)0xffff0fe0)
|
||||
*
|
||||
* Get the TLS value as previously set via the __ARM_NR_set_tls syscall.
|
||||
*
|
||||
* This could be used as follows:
|
||||
*
|
||||
* #define __kernel_get_tls() \
|
||||
* ({ register unsigned int __val asm("r0"); \
|
||||
* asm( "mov r0, #0xffff0fff; mov lr, pc; sub pc, r0, #31" \
|
||||
* : "=r" (__val) : : "lr","cc" ); \
|
||||
* __val; })
|
||||
*/
|
||||
|
||||
__kuser_get_tls: @ 0xffff0fe0
|
||||
ldr r0, [pc, #(16 - 8)] @ read TLS, set in kuser_get_tls_init
|
||||
usr_ret lr
|
||||
|
@ -947,19 +902,6 @@ __kuser_get_tls: @ 0xffff0fe0
|
|||
.word 0 @ 0xffff0ff0 software TLS value, then
|
||||
.endr @ pad up to __kuser_helper_version
|
||||
|
||||
/*
|
||||
* Reference declaration:
|
||||
*
|
||||
* extern unsigned int __kernel_helper_version;
|
||||
*
|
||||
* Definition and user space usage example:
|
||||
*
|
||||
* #define __kernel_helper_version (*(unsigned int *)0xffff0ffc)
|
||||
*
|
||||
* User space may read this to determine the curent number of helpers
|
||||
* available.
|
||||
*/
|
||||
|
||||
__kuser_helper_version: @ 0xffff0ffc
|
||||
.word ((__kuser_helper_end - __kuser_helper_start) >> 5)
|
||||
|
||||
|
|
|
@ -121,15 +121,13 @@
|
|||
.endm
|
||||
#else /* CONFIG_THUMB2_KERNEL */
|
||||
.macro svc_exit, rpsr
|
||||
ldr lr, [sp, #S_SP] @ top of the stack
|
||||
ldrd r0, r1, [sp, #S_LR] @ calling lr and pc
|
||||
clrex @ clear the exclusive monitor
|
||||
ldr r0, [sp, #S_SP] @ top of the stack
|
||||
ldr r1, [sp, #S_PC] @ return address
|
||||
tst r0, #4 @ orig stack 8-byte aligned?
|
||||
stmdb r0, {r1, \rpsr} @ rfe context
|
||||
stmdb lr!, {r0, r1, \rpsr} @ calling lr and rfe context
|
||||
ldmia sp, {r0 - r12}
|
||||
ldr lr, [sp, #S_LR]
|
||||
addeq sp, sp, #S_FRAME_SIZE - 8 @ aligned
|
||||
addne sp, sp, #S_FRAME_SIZE - 4 @ not aligned
|
||||
mov sp, lr
|
||||
ldr lr, [sp], #4
|
||||
rfeia sp!
|
||||
.endm
|
||||
|
||||
|
|
999
arch/arm/kernel/kprobes-arm.c
Normal file
999
arch/arm/kernel/kprobes-arm.c
Normal file
|
@ -0,0 +1,999 @@
|
|||
/*
|
||||
* arch/arm/kernel/kprobes-decode.c
|
||||
*
|
||||
* Copyright (C) 2006, 2007 Motorola Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* We do not have hardware single-stepping on ARM, This
|
||||
* effort is further complicated by the ARM not having a
|
||||
* "next PC" register. Instructions that change the PC
|
||||
* can't be safely single-stepped in a MP environment, so
|
||||
* we have a lot of work to do:
|
||||
*
|
||||
* In the prepare phase:
|
||||
* *) If it is an instruction that does anything
|
||||
* with the CPU mode, we reject it for a kprobe.
|
||||
* (This is out of laziness rather than need. The
|
||||
* instructions could be simulated.)
|
||||
*
|
||||
* *) Otherwise, decode the instruction rewriting its
|
||||
* registers to take fixed, ordered registers and
|
||||
* setting a handler for it to run the instruction.
|
||||
*
|
||||
* In the execution phase by an instruction's handler:
|
||||
*
|
||||
* *) If the PC is written to by the instruction, the
|
||||
* instruction must be fully simulated in software.
|
||||
*
|
||||
* *) Otherwise, a modified form of the instruction is
|
||||
* directly executed. Its handler calls the
|
||||
* instruction in insn[0]. In insn[1] is a
|
||||
* "mov pc, lr" to return.
|
||||
*
|
||||
* Before calling, load up the reordered registers
|
||||
* from the original instruction's registers. If one
|
||||
* of the original input registers is the PC, compute
|
||||
* and adjust the appropriate input register.
|
||||
*
|
||||
* After call completes, copy the output registers to
|
||||
* the original instruction's original registers.
|
||||
*
|
||||
* We don't use a real breakpoint instruction since that
|
||||
* would have us in the kernel go from SVC mode to SVC
|
||||
* mode losing the link register. Instead we use an
|
||||
* undefined instruction. To simplify processing, the
|
||||
* undefined instruction used for kprobes must be reserved
|
||||
* exclusively for kprobes use.
|
||||
*
|
||||
* TODO: ifdef out some instruction decoding based on architecture.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kprobes.h>
|
||||
|
||||
#include "kprobes.h"
|
||||
|
||||
#define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit)))))
|
||||
|
||||
#define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25)
|
||||
|
||||
#if __LINUX_ARM_ARCH__ >= 6
|
||||
#define BLX(reg) "blx "reg" \n\t"
|
||||
#else
|
||||
#define BLX(reg) "mov lr, pc \n\t" \
|
||||
"mov pc, "reg" \n\t"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* To avoid the complications of mimicing single-stepping on a
|
||||
* processor without a Next-PC or a single-step mode, and to
|
||||
* avoid having to deal with the side-effects of boosting, we
|
||||
* simulate or emulate (almost) all ARM instructions.
|
||||
*
|
||||
* "Simulation" is where the instruction's behavior is duplicated in
|
||||
* C code. "Emulation" is where the original instruction is rewritten
|
||||
* and executed, often by altering its registers.
|
||||
*
|
||||
* By having all behavior of the kprobe'd instruction completed before
|
||||
* returning from the kprobe_handler(), all locks (scheduler and
|
||||
* interrupt) can safely be released. There is no need for secondary
|
||||
* breakpoints, no race with MP or preemptable kernels, nor having to
|
||||
* clean up resources counts at a later time impacting overall system
|
||||
* performance. By rewriting the instruction, only the minimum registers
|
||||
* need to be loaded and saved back optimizing performance.
|
||||
*
|
||||
* Calling the insnslot_*_rwflags version of a function doesn't hurt
|
||||
* anything even when the CPSR flags aren't updated by the
|
||||
* instruction. It's just a little slower in return for saving
|
||||
* a little space by not having a duplicate function that doesn't
|
||||
* update the flags. (The same optimization can be said for
|
||||
* instructions that do or don't perform register writeback)
|
||||
* Also, instructions can either read the flags, only write the
|
||||
* flags, or read and write the flags. To save combinations
|
||||
* rather than for sheer performance, flag functions just assume
|
||||
* read and write of flags.
|
||||
*/
|
||||
|
||||
static void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
kprobe_opcode_t insn = p->opcode;
|
||||
long iaddr = (long)p->addr;
|
||||
int disp = branch_displacement(insn);
|
||||
|
||||
if (insn & (1 << 24))
|
||||
regs->ARM_lr = iaddr + 4;
|
||||
|
||||
regs->ARM_pc = iaddr + 8 + disp;
|
||||
}
|
||||
|
||||
static void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
kprobe_opcode_t insn = p->opcode;
|
||||
long iaddr = (long)p->addr;
|
||||
int disp = branch_displacement(insn);
|
||||
|
||||
regs->ARM_lr = iaddr + 4;
|
||||
regs->ARM_pc = iaddr + 8 + disp + ((insn >> 23) & 0x2);
|
||||
regs->ARM_cpsr |= PSR_T_BIT;
|
||||
}
|
||||
|
||||
static void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
kprobe_opcode_t insn = p->opcode;
|
||||
int rm = insn & 0xf;
|
||||
long rmv = regs->uregs[rm];
|
||||
|
||||
if (insn & (1 << 5))
|
||||
regs->ARM_lr = (long)p->addr + 4;
|
||||
|
||||
regs->ARM_pc = rmv & ~0x1;
|
||||
regs->ARM_cpsr &= ~PSR_T_BIT;
|
||||
if (rmv & 0x1)
|
||||
regs->ARM_cpsr |= PSR_T_BIT;
|
||||
}
|
||||
|
||||
static void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
kprobe_opcode_t insn = p->opcode;
|
||||
int rd = (insn >> 12) & 0xf;
|
||||
unsigned long mask = 0xf8ff03df; /* Mask out execution state */
|
||||
regs->uregs[rd] = regs->ARM_cpsr & mask;
|
||||
}
|
||||
|
||||
static void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
regs->uregs[12] = regs->uregs[13];
|
||||
}
|
||||
|
||||
static void __kprobes
|
||||
emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
kprobe_opcode_t insn = p->opcode;
|
||||
unsigned long pc = (unsigned long)p->addr + 8;
|
||||
int rt = (insn >> 12) & 0xf;
|
||||
int rn = (insn >> 16) & 0xf;
|
||||
int rm = insn & 0xf;
|
||||
|
||||
register unsigned long rtv asm("r0") = regs->uregs[rt];
|
||||
register unsigned long rt2v asm("r1") = regs->uregs[rt+1];
|
||||
register unsigned long rnv asm("r2") = (rn == 15) ? pc
|
||||
: regs->uregs[rn];
|
||||
register unsigned long rmv asm("r3") = regs->uregs[rm];
|
||||
|
||||
__asm__ __volatile__ (
|
||||
BLX("%[fn]")
|
||||
: "=r" (rtv), "=r" (rt2v), "=r" (rnv)
|
||||
: "0" (rtv), "1" (rt2v), "2" (rnv), "r" (rmv),
|
||||
[fn] "r" (p->ainsn.insn_fn)
|
||||
: "lr", "memory", "cc"
|
||||
);
|
||||
|
||||
regs->uregs[rt] = rtv;
|
||||
regs->uregs[rt+1] = rt2v;
|
||||
if (is_writeback(insn))
|
||||
regs->uregs[rn] = rnv;
|
||||
}
|
||||
|
||||
static void __kprobes
|
||||
emulate_ldr(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
kprobe_opcode_t insn = p->opcode;
|
||||
unsigned long pc = (unsigned long)p->addr + 8;
|
||||
int rt = (insn >> 12) & 0xf;
|
||||
int rn = (insn >> 16) & 0xf;
|
||||
int rm = insn & 0xf;
|
||||
|
||||
register unsigned long rtv asm("r0");
|
||||
register unsigned long rnv asm("r2") = (rn == 15) ? pc
|
||||
: regs->uregs[rn];
|
||||
register unsigned long rmv asm("r3") = regs->uregs[rm];
|
||||
|
||||
__asm__ __volatile__ (
|
||||
BLX("%[fn]")
|
||||
: "=r" (rtv), "=r" (rnv)
|
||||
: "1" (rnv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn)
|
||||
: "lr", "memory", "cc"
|
||||
);
|
||||
|
||||
if (rt == 15)
|
||||
load_write_pc(rtv, regs);
|
||||
else
|
||||
regs->uregs[rt] = rtv;
|
||||
|
||||
if (is_writeback(insn))
|
||||
regs->uregs[rn] = rnv;
|
||||
}
|
||||
|
||||
static void __kprobes
|
||||
emulate_str(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
kprobe_opcode_t insn = p->opcode;
|
||||
unsigned long rtpc = (unsigned long)p->addr + str_pc_offset;
|
||||
unsigned long rnpc = (unsigned long)p->addr + 8;
|
||||
int rt = (insn >> 12) & 0xf;
|
||||
int rn = (insn >> 16) & 0xf;
|
||||
int rm = insn & 0xf;
|
||||
|
||||
register unsigned long rtv asm("r0") = (rt == 15) ? rtpc
|
||||
: regs->uregs[rt];
|
||||
register unsigned long rnv asm("r2") = (rn == 15) ? rnpc
|
||||
: regs->uregs[rn];
|
||||
register unsigned long rmv asm("r3") = regs->uregs[rm];
|
||||
|
||||
__asm__ __volatile__ (
|
||||
BLX("%[fn]")
|
||||
: "=r" (rnv)
|
||||
: "r" (rtv), "0" (rnv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn)
|
||||
: "lr", "memory", "cc"
|
||||
);
|
||||
|
||||
if (is_writeback(insn))
|
||||
regs->uregs[rn] = rnv;
|
||||
}
|
||||
|
||||
static void __kprobes
|
||||
emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
kprobe_opcode_t insn = p->opcode;
|
||||
unsigned long pc = (unsigned long)p->addr + 8;
|
||||
int rd = (insn >> 12) & 0xf;
|
||||
int rn = (insn >> 16) & 0xf;
|
||||
int rm = insn & 0xf;
|
||||
int rs = (insn >> 8) & 0xf;
|
||||
|
||||
register unsigned long rdv asm("r0") = regs->uregs[rd];
|
||||
register unsigned long rnv asm("r2") = (rn == 15) ? pc
|
||||
: regs->uregs[rn];
|
||||
register unsigned long rmv asm("r3") = (rm == 15) ? pc
|
||||
: regs->uregs[rm];
|
||||
register unsigned long rsv asm("r1") = regs->uregs[rs];
|
||||
unsigned long cpsr = regs->ARM_cpsr;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"msr cpsr_fs, %[cpsr] \n\t"
|
||||
BLX("%[fn]")
|
||||
"mrs %[cpsr], cpsr \n\t"
|
||||
: "=r" (rdv), [cpsr] "=r" (cpsr)
|
||||
: "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv),
|
||||
"1" (cpsr), [fn] "r" (p->ainsn.insn_fn)
|
||||
: "lr", "memory", "cc"
|
||||
);
|
||||
|
||||
if (rd == 15)
|
||||
alu_write_pc(rdv, regs);
|
||||
else
|
||||
regs->uregs[rd] = rdv;
|
||||
regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
|
||||
}
|
||||
|
||||
static void __kprobes
|
||||
emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
kprobe_opcode_t insn = p->opcode;
|
||||
int rd = (insn >> 12) & 0xf;
|
||||
int rn = (insn >> 16) & 0xf;
|
||||
int rm = insn & 0xf;
|
||||
|
||||
register unsigned long rdv asm("r0") = regs->uregs[rd];
|
||||
register unsigned long rnv asm("r2") = regs->uregs[rn];
|
||||
register unsigned long rmv asm("r3") = regs->uregs[rm];
|
||||
unsigned long cpsr = regs->ARM_cpsr;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"msr cpsr_fs, %[cpsr] \n\t"
|
||||
BLX("%[fn]")
|
||||
"mrs %[cpsr], cpsr \n\t"
|
||||
: "=r" (rdv), [cpsr] "=r" (cpsr)
|
||||
: "0" (rdv), "r" (rnv), "r" (rmv),
|
||||
"1" (cpsr), [fn] "r" (p->ainsn.insn_fn)
|
||||
: "lr", "memory", "cc"
|
||||
);
|
||||
|
||||
regs->uregs[rd] = rdv;
|
||||
regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
|
||||
}
|
||||
|
||||
static void __kprobes
|
||||
emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
kprobe_opcode_t insn = p->opcode;
|
||||
int rd = (insn >> 16) & 0xf;
|
||||
int rn = (insn >> 12) & 0xf;
|
||||
int rm = insn & 0xf;
|
||||
int rs = (insn >> 8) & 0xf;
|
||||
|
||||
register unsigned long rdv asm("r2") = regs->uregs[rd];
|
||||
register unsigned long rnv asm("r0") = regs->uregs[rn];
|
||||
register unsigned long rmv asm("r3") = regs->uregs[rm];
|
||||
register unsigned long rsv asm("r1") = regs->uregs[rs];
|
||||
unsigned long cpsr = regs->ARM_cpsr;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"msr cpsr_fs, %[cpsr] \n\t"
|
||||
BLX("%[fn]")
|
||||
"mrs %[cpsr], cpsr \n\t"
|
||||
: "=r" (rdv), [cpsr] "=r" (cpsr)
|
||||
: "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv),
|
||||
"1" (cpsr), [fn] "r" (p->ainsn.insn_fn)
|
||||
: "lr", "memory", "cc"
|
||||
);
|
||||
|
||||
regs->uregs[rd] = rdv;
|
||||
regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
|
||||
}
|
||||
|
||||
static void __kprobes
|
||||
emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
kprobe_opcode_t insn = p->opcode;
|
||||
int rd = (insn >> 12) & 0xf;
|
||||
int rm = insn & 0xf;
|
||||
|
||||
register unsigned long rdv asm("r0") = regs->uregs[rd];
|
||||
register unsigned long rmv asm("r3") = regs->uregs[rm];
|
||||
|
||||
__asm__ __volatile__ (
|
||||
BLX("%[fn]")
|
||||
: "=r" (rdv)
|
||||
: "0" (rdv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn)
|
||||
: "lr", "memory", "cc"
|
||||
);
|
||||
|
||||
regs->uregs[rd] = rdv;
|
||||
}
|
||||
|
||||
static void __kprobes
|
||||
emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
kprobe_opcode_t insn = p->opcode;
|
||||
int rdlo = (insn >> 12) & 0xf;
|
||||
int rdhi = (insn >> 16) & 0xf;
|
||||
int rn = insn & 0xf;
|
||||
int rm = (insn >> 8) & 0xf;
|
||||
|
||||
register unsigned long rdlov asm("r0") = regs->uregs[rdlo];
|
||||
register unsigned long rdhiv asm("r2") = regs->uregs[rdhi];
|
||||
register unsigned long rnv asm("r3") = regs->uregs[rn];
|
||||
register unsigned long rmv asm("r1") = regs->uregs[rm];
|
||||
unsigned long cpsr = regs->ARM_cpsr;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"msr cpsr_fs, %[cpsr] \n\t"
|
||||
BLX("%[fn]")
|
||||
"mrs %[cpsr], cpsr \n\t"
|
||||
: "=r" (rdlov), "=r" (rdhiv), [cpsr] "=r" (cpsr)
|
||||
: "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv),
|
||||
"2" (cpsr), [fn] "r" (p->ainsn.insn_fn)
|
||||
: "lr", "memory", "cc"
|
||||
);
|
||||
|
||||
regs->uregs[rdlo] = rdlov;
|
||||
regs->uregs[rdhi] = rdhiv;
|
||||
regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
|
||||
}
|
||||
|
||||
/*
|
||||
* For the instruction masking and comparisons in all the "space_*"
|
||||
* functions below, Do _not_ rearrange the order of tests unless
|
||||
* you're very, very sure of what you are doing. For the sake of
|
||||
* efficiency, the masks for some tests sometimes assume other test
|
||||
* have been done prior to them so the number of patterns to test
|
||||
* for an instruction set can be as broad as possible to reduce the
|
||||
* number of tests needed.
|
||||
*/
|
||||
|
||||
static const union decode_item arm_1111_table[] = {
|
||||
/* Unconditional instructions */
|
||||
|
||||
/* memory hint 1111 0100 x001 xxxx xxxx xxxx xxxx xxxx */
|
||||
/* PLDI (immediate) 1111 0100 x101 xxxx xxxx xxxx xxxx xxxx */
|
||||
/* PLDW (immediate) 1111 0101 x001 xxxx xxxx xxxx xxxx xxxx */
|
||||
/* PLD (immediate) 1111 0101 x101 xxxx xxxx xxxx xxxx xxxx */
|
||||
DECODE_SIMULATE (0xfe300000, 0xf4100000, kprobe_simulate_nop),
|
||||
|
||||
/* memory hint 1111 0110 x001 xxxx xxxx xxxx xxx0 xxxx */
|
||||
/* PLDI (register) 1111 0110 x101 xxxx xxxx xxxx xxx0 xxxx */
|
||||
/* PLDW (register) 1111 0111 x001 xxxx xxxx xxxx xxx0 xxxx */
|
||||
/* PLD (register) 1111 0111 x101 xxxx xxxx xxxx xxx0 xxxx */
|
||||
DECODE_SIMULATE (0xfe300010, 0xf6100000, kprobe_simulate_nop),
|
||||
|
||||
/* BLX (immediate) 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx */
|
||||
DECODE_SIMULATE (0xfe000000, 0xfa000000, simulate_blx1),
|
||||
|
||||
/* CPS 1111 0001 0000 xxx0 xxxx xxxx xx0x xxxx */
|
||||
/* SETEND 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */
|
||||
/* SRS 1111 100x x1x0 xxxx xxxx xxxx xxxx xxxx */
|
||||
/* RFE 1111 100x x0x1 xxxx xxxx xxxx xxxx xxxx */
|
||||
|
||||
/* Coprocessor instructions... */
|
||||
/* MCRR2 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx */
|
||||
/* MRRC2 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx */
|
||||
/* LDC2 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */
|
||||
/* STC2 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */
|
||||
/* CDP2 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */
|
||||
/* MCR2 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */
|
||||
/* MRC2 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */
|
||||
|
||||
/* Other unallocated instructions... */
|
||||
DECODE_END
|
||||
};
|
||||
|
||||
static const union decode_item arm_cccc_0001_0xx0____0xxx_table[] = {
|
||||
/* Miscellaneous instructions */
|
||||
|
||||
/* MRS cpsr cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */
|
||||
DECODE_SIMULATEX(0x0ff000f0, 0x01000000, simulate_mrs,
|
||||
REGS(0, NOPC, 0, 0, 0)),
|
||||
|
||||
/* BX cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */
|
||||
DECODE_SIMULATE (0x0ff000f0, 0x01200010, simulate_blx2bx),
|
||||
|
||||
/* BLX (register) cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */
|
||||
DECODE_SIMULATEX(0x0ff000f0, 0x01200030, simulate_blx2bx,
|
||||
REGS(0, 0, 0, 0, NOPC)),
|
||||
|
||||
/* CLZ cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */
|
||||
DECODE_EMULATEX (0x0ff000f0, 0x01600010, emulate_rd12rm0_noflags_nopc,
|
||||
REGS(0, NOPC, 0, 0, NOPC)),
|
||||
|
||||
/* QADD cccc 0001 0000 xxxx xxxx xxxx 0101 xxxx */
|
||||
/* QSUB cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx */
|
||||
/* QDADD cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx */
|
||||
/* QDSUB cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx */
|
||||
DECODE_EMULATEX (0x0f9000f0, 0x01000050, emulate_rd12rn16rm0_rwflags_nopc,
|
||||
REGS(NOPC, NOPC, 0, 0, NOPC)),
|
||||
|
||||
/* BXJ cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */
|
||||
/* MSR cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */
|
||||
/* MRS spsr cccc 0001 0100 xxxx xxxx xxxx 0000 xxxx */
|
||||
/* BKPT 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */
|
||||
/* SMC cccc 0001 0110 xxxx xxxx xxxx 0111 xxxx */
|
||||
/* And unallocated instructions... */
|
||||
DECODE_END
|
||||
};
|
||||
|
||||
static const union decode_item arm_cccc_0001_0xx0____1xx0_table[] = {
|
||||
/* Halfword multiply and multiply-accumulate */
|
||||
|
||||
/* SMLALxy cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */
|
||||
DECODE_EMULATEX (0x0ff00090, 0x01400080, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc,
|
||||
REGS(NOPC, NOPC, NOPC, 0, NOPC)),
|
||||
|
||||
/* SMULWy cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */
|
||||
DECODE_OR (0x0ff000b0, 0x012000a0),
|
||||
/* SMULxy cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */
|
||||
DECODE_EMULATEX (0x0ff00090, 0x01600080, emulate_rd16rn12rm0rs8_rwflags_nopc,
|
||||
REGS(NOPC, 0, NOPC, 0, NOPC)),
|
||||
|
||||
/* SMLAxy cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx */
|
||||
DECODE_OR (0x0ff00090, 0x01000080),
|
||||
/* SMLAWy cccc 0001 0010 xxxx xxxx xxxx 1x00 xxxx */
|
||||
DECODE_EMULATEX (0x0ff000b0, 0x01200080, emulate_rd16rn12rm0rs8_rwflags_nopc,
|
||||
REGS(NOPC, NOPC, NOPC, 0, NOPC)),
|
||||
|
||||
DECODE_END
|
||||
};
|
||||
|
||||
static const union decode_item arm_cccc_0000_____1001_table[] = {
|
||||
/* Multiply and multiply-accumulate */
|
||||
|
||||
/* MUL cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx */
|
||||
/* MULS cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx */
|
||||
DECODE_EMULATEX (0x0fe000f0, 0x00000090, emulate_rd16rn12rm0rs8_rwflags_nopc,
|
||||
REGS(NOPC, 0, NOPC, 0, NOPC)),
|
||||
|
||||
/* MLA cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx */
|
||||
/* MLAS cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx */
|
||||
DECODE_OR (0x0fe000f0, 0x00200090),
|
||||
/* MLS cccc 0000 0110 xxxx xxxx xxxx 1001 xxxx */
|
||||
DECODE_EMULATEX (0x0ff000f0, 0x00600090, emulate_rd16rn12rm0rs8_rwflags_nopc,
|
||||
REGS(NOPC, NOPC, NOPC, 0, NOPC)),
|
||||
|
||||
/* UMAAL cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx */
|
||||
DECODE_OR (0x0ff000f0, 0x00400090),
|
||||
/* UMULL cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx */
|
||||
/* UMULLS cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx */
|
||||
/* UMLAL cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx */
|
||||
/* UMLALS cccc 0000 1011 xxxx xxxx xxxx 1001 xxxx */
|
||||
/* SMULL cccc 0000 1100 xxxx xxxx xxxx 1001 xxxx */
|
||||
/* SMULLS cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx */
|
||||
/* SMLAL cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx */
|
||||
/* SMLALS cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx */
|
||||
DECODE_EMULATEX (0x0f8000f0, 0x00800090, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc,
|
||||
REGS(NOPC, NOPC, NOPC, 0, NOPC)),
|
||||
|
||||
DECODE_END
|
||||
};
|
||||
|
||||
static const union decode_item arm_cccc_0001_____1001_table[] = {
|
||||
/* Synchronization primitives */
|
||||
|
||||
/* SMP/SWPB cccc 0001 0x00 xxxx xxxx xxxx 1001 xxxx */
|
||||
DECODE_EMULATEX (0x0fb000f0, 0x01000090, emulate_rd12rn16rm0_rwflags_nopc,
|
||||
REGS(NOPC, NOPC, 0, 0, NOPC)),
|
||||
|
||||
/* LDREX/STREX{,D,B,H} cccc 0001 1xxx xxxx xxxx xxxx 1001 xxxx */
|
||||
/* And unallocated instructions... */
|
||||
DECODE_END
|
||||
};
|
||||
|
||||
static const union decode_item arm_cccc_000x_____1xx1_table[] = {
|
||||
/* Extra load/store instructions */
|
||||
|
||||
/* STRHT cccc 0000 xx10 xxxx xxxx xxxx 1011 xxxx */
|
||||
/* ??? cccc 0000 xx10 xxxx xxxx xxxx 11x1 xxxx */
|
||||
/* LDRHT cccc 0000 xx11 xxxx xxxx xxxx 1011 xxxx */
|
||||
/* LDRSBT cccc 0000 xx11 xxxx xxxx xxxx 1101 xxxx */
|
||||
/* LDRSHT cccc 0000 xx11 xxxx xxxx xxxx 1111 xxxx */
|
||||
DECODE_REJECT (0x0f200090, 0x00200090),
|
||||
|
||||
/* LDRD/STRD lr,pc,{... cccc 000x x0x0 xxxx 111x xxxx 1101 xxxx */
|
||||
DECODE_REJECT (0x0e10e0d0, 0x0000e0d0),
|
||||
|
||||
/* LDRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1101 xxxx */
|
||||
/* STRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx */
|
||||
DECODE_EMULATEX (0x0e5000d0, 0x000000d0, emulate_ldrdstrd,
|
||||
REGS(NOPCWB, NOPCX, 0, 0, NOPC)),
|
||||
|
||||
/* LDRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1101 xxxx */
|
||||
/* STRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1111 xxxx */
|
||||
DECODE_EMULATEX (0x0e5000d0, 0x004000d0, emulate_ldrdstrd,
|
||||
REGS(NOPCWB, NOPCX, 0, 0, 0)),
|
||||
|
||||
/* STRH (register) cccc 000x x0x0 xxxx xxxx xxxx 1011 xxxx */
|
||||
DECODE_EMULATEX (0x0e5000f0, 0x000000b0, emulate_str,
|
||||
REGS(NOPCWB, NOPC, 0, 0, NOPC)),
|
||||
|
||||
/* LDRH (register) cccc 000x x0x1 xxxx xxxx xxxx 1011 xxxx */
|
||||
/* LDRSB (register) cccc 000x x0x1 xxxx xxxx xxxx 1101 xxxx */
|
||||
/* LDRSH (register) cccc 000x x0x1 xxxx xxxx xxxx 1111 xxxx */
|
||||
DECODE_EMULATEX (0x0e500090, 0x00100090, emulate_ldr,
|
||||
REGS(NOPCWB, NOPC, 0, 0, NOPC)),
|
||||
|
||||
/* STRH (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1011 xxxx */
|
||||
DECODE_EMULATEX (0x0e5000f0, 0x004000b0, emulate_str,
|
||||
REGS(NOPCWB, NOPC, 0, 0, 0)),
|
||||
|
||||
/* LDRH (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1011 xxxx */
|
||||
/* LDRSB (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1101 xxxx */
|
||||
/* LDRSH (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1111 xxxx */
|
||||
DECODE_EMULATEX (0x0e500090, 0x00500090, emulate_ldr,
|
||||
REGS(NOPCWB, NOPC, 0, 0, 0)),
|
||||
|
||||
DECODE_END
|
||||
};
|
||||
|
||||
static const union decode_item arm_cccc_000x_table[] = {
|
||||
/* Data-processing (register) */
|
||||
|
||||
/* <op>S PC, ... cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx */
|
||||
DECODE_REJECT (0x0e10f000, 0x0010f000),
|
||||
|
||||
/* MOV IP, SP 1110 0001 1010 0000 1100 0000 0000 1101 */
|
||||
DECODE_SIMULATE (0xffffffff, 0xe1a0c00d, simulate_mov_ipsp),
|
||||
|
||||
/* TST (register) cccc 0001 0001 xxxx xxxx xxxx xxx0 xxxx */
|
||||
/* TEQ (register) cccc 0001 0011 xxxx xxxx xxxx xxx0 xxxx */
|
||||
/* CMP (register) cccc 0001 0101 xxxx xxxx xxxx xxx0 xxxx */
|
||||
/* CMN (register) cccc 0001 0111 xxxx xxxx xxxx xxx0 xxxx */
|
||||
DECODE_EMULATEX (0x0f900010, 0x01100000, emulate_rd12rn16rm0rs8_rwflags,
|
||||
REGS(ANY, 0, 0, 0, ANY)),
|
||||
|
||||
/* MOV (register) cccc 0001 101x xxxx xxxx xxxx xxx0 xxxx */
|
||||
/* MVN (register) cccc 0001 111x xxxx xxxx xxxx xxx0 xxxx */
|
||||
DECODE_EMULATEX (0x0fa00010, 0x01a00000, emulate_rd12rn16rm0rs8_rwflags,
|
||||
REGS(0, ANY, 0, 0, ANY)),
|
||||
|
||||
/* AND (register) cccc 0000 000x xxxx xxxx xxxx xxx0 xxxx */
|
||||
/* EOR (register) cccc 0000 001x xxxx xxxx xxxx xxx0 xxxx */
|
||||
/* SUB (register) cccc 0000 010x xxxx xxxx xxxx xxx0 xxxx */
|
||||
/* RSB (register) cccc 0000 011x xxxx xxxx xxxx xxx0 xxxx */
|
||||
/* ADD (register) cccc 0000 100x xxxx xxxx xxxx xxx0 xxxx */
|
||||
/* ADC (register) cccc 0000 101x xxxx xxxx xxxx xxx0 xxxx */
|
||||
/* SBC (register) cccc 0000 110x xxxx xxxx xxxx xxx0 xxxx */
|
||||
/* RSC (register) cccc 0000 111x xxxx xxxx xxxx xxx0 xxxx */
|
||||
/* ORR (register) cccc 0001 100x xxxx xxxx xxxx xxx0 xxxx */
|
||||
/* BIC (register) cccc 0001 110x xxxx xxxx xxxx xxx0 xxxx */
|
||||
DECODE_EMULATEX (0x0e000010, 0x00000000, emulate_rd12rn16rm0rs8_rwflags,
|
||||
REGS(ANY, ANY, 0, 0, ANY)),
|
||||
|
||||
/* TST (reg-shift reg) cccc 0001 0001 xxxx xxxx xxxx 0xx1 xxxx */
|
||||
/* TEQ (reg-shift reg) cccc 0001 0011 xxxx xxxx xxxx 0xx1 xxxx */
|
||||
/* CMP (reg-shift reg) cccc 0001 0101 xxxx xxxx xxxx 0xx1 xxxx */
|
||||
/* CMN (reg-shift reg) cccc 0001 0111 xxxx xxxx xxxx 0xx1 xxxx */
|
||||
DECODE_EMULATEX (0x0f900090, 0x01100010, emulate_rd12rn16rm0rs8_rwflags,
|
||||
REGS(ANY, 0, NOPC, 0, ANY)),
|
||||
|
||||
/* MOV (reg-shift reg) cccc 0001 101x xxxx xxxx xxxx 0xx1 xxxx */
|
||||
/* MVN (reg-shift reg) cccc 0001 111x xxxx xxxx xxxx 0xx1 xxxx */
|
||||
DECODE_EMULATEX (0x0fa00090, 0x01a00010, emulate_rd12rn16rm0rs8_rwflags,
|
||||
REGS(0, ANY, NOPC, 0, ANY)),
|
||||
|
||||
/* AND (reg-shift reg) cccc 0000 000x xxxx xxxx xxxx 0xx1 xxxx */
|
||||
/* EOR (reg-shift reg) cccc 0000 001x xxxx xxxx xxxx 0xx1 xxxx */
|
||||
/* SUB (reg-shift reg) cccc 0000 010x xxxx xxxx xxxx 0xx1 xxxx */
|
||||
/* RSB (reg-shift reg) cccc 0000 011x xxxx xxxx xxxx 0xx1 xxxx */
|
||||
/* ADD (reg-shift reg) cccc 0000 100x xxxx xxxx xxxx 0xx1 xxxx */
|
||||
/* ADC (reg-shift reg) cccc 0000 101x xxxx xxxx xxxx 0xx1 xxxx */
|
||||
/* SBC (reg-shift reg) cccc 0000 110x xxxx xxxx xxxx 0xx1 xxxx */
|
||||
/* RSC (reg-shift reg) cccc 0000 111x xxxx xxxx xxxx 0xx1 xxxx */
|
||||
/* ORR (reg-shift reg) cccc 0001 100x xxxx xxxx xxxx 0xx1 xxxx */
|
||||
/* BIC (reg-shift reg) cccc 0001 110x xxxx xxxx xxxx 0xx1 xxxx */
|
||||
DECODE_EMULATEX (0x0e000090, 0x00000010, emulate_rd12rn16rm0rs8_rwflags,
|
||||
REGS(ANY, ANY, NOPC, 0, ANY)),
|
||||
|
||||
DECODE_END
|
||||
};
|
||||
|
||||
static const union decode_item arm_cccc_001x_table[] = {
|
||||
/* Data-processing (immediate) */
|
||||
|
||||
/* MOVW cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */
|
||||
/* MOVT cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */
|
||||
DECODE_EMULATEX (0x0fb00000, 0x03000000, emulate_rd12rm0_noflags_nopc,
|
||||
REGS(0, NOPC, 0, 0, 0)),
|
||||
|
||||
/* YIELD cccc 0011 0010 0000 xxxx xxxx 0000 0001 */
|
||||
DECODE_OR (0x0fff00ff, 0x03200001),
|
||||
/* SEV cccc 0011 0010 0000 xxxx xxxx 0000 0100 */
|
||||
DECODE_EMULATE (0x0fff00ff, 0x03200004, kprobe_emulate_none),
|
||||
/* NOP cccc 0011 0010 0000 xxxx xxxx 0000 0000 */
|
||||
/* WFE cccc 0011 0010 0000 xxxx xxxx 0000 0010 */
|
||||
/* WFI cccc 0011 0010 0000 xxxx xxxx 0000 0011 */
|
||||
DECODE_SIMULATE (0x0fff00fc, 0x03200000, kprobe_simulate_nop),
|
||||
/* DBG cccc 0011 0010 0000 xxxx xxxx ffff xxxx */
|
||||
/* unallocated hints cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */
|
||||
/* MSR (immediate) cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx */
|
||||
DECODE_REJECT (0x0fb00000, 0x03200000),
|
||||
|
||||
/* <op>S PC, ... cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx */
|
||||
DECODE_REJECT (0x0e10f000, 0x0210f000),
|
||||
|
||||
/* TST (immediate) cccc 0011 0001 xxxx xxxx xxxx xxxx xxxx */
|
||||
/* TEQ (immediate) cccc 0011 0011 xxxx xxxx xxxx xxxx xxxx */
|
||||
/* CMP (immediate) cccc 0011 0101 xxxx xxxx xxxx xxxx xxxx */
|
||||
/* CMN (immediate) cccc 0011 0111 xxxx xxxx xxxx xxxx xxxx */
|
||||
DECODE_EMULATEX (0x0f900000, 0x03100000, emulate_rd12rn16rm0rs8_rwflags,
|
||||
REGS(ANY, 0, 0, 0, 0)),
|
||||
|
||||
/* MOV (immediate) cccc 0011 101x xxxx xxxx xxxx xxxx xxxx */
|
||||
/* MVN (immediate) cccc 0011 111x xxxx xxxx xxxx xxxx xxxx */
|
||||
DECODE_EMULATEX (0x0fa00000, 0x03a00000, emulate_rd12rn16rm0rs8_rwflags,
|
||||
REGS(0, ANY, 0, 0, 0)),
|
||||
|
||||
/* AND (immediate) cccc 0010 000x xxxx xxxx xxxx xxxx xxxx */
|
||||
/* EOR (immediate) cccc 0010 001x xxxx xxxx xxxx xxxx xxxx */
|
||||
/* SUB (immediate) cccc 0010 010x xxxx xxxx xxxx xxxx xxxx */
|
||||
/* RSB (immediate) cccc 0010 011x xxxx xxxx xxxx xxxx xxxx */
|
||||
/* ADD (immediate) cccc 0010 100x xxxx xxxx xxxx xxxx xxxx */
|
||||
/* ADC (immediate) cccc 0010 101x xxxx xxxx xxxx xxxx xxxx */
|
||||
/* SBC (immediate) cccc 0010 110x xxxx xxxx xxxx xxxx xxxx */
|
||||
/* RSC (immediate) cccc 0010 111x xxxx xxxx xxxx xxxx xxxx */
|
||||
/* ORR (immediate) cccc 0011 100x xxxx xxxx xxxx xxxx xxxx */
|
||||
/* BIC (immediate) cccc 0011 110x xxxx xxxx xxxx xxxx xxxx */
|
||||
DECODE_EMULATEX (0x0e000000, 0x02000000, emulate_rd12rn16rm0rs8_rwflags,
|
||||
REGS(ANY, ANY, 0, 0, 0)),
|
||||
|
||||
DECODE_END
|
||||
};
|
||||
|
||||
static const union decode_item arm_cccc_0110_____xxx1_table[] = {
|
||||
/* Media instructions */
|
||||
|
||||
/* SEL cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx */
|
||||
DECODE_EMULATEX (0x0ff000f0, 0x068000b0, emulate_rd12rn16rm0_rwflags_nopc,
|
||||
REGS(NOPC, NOPC, 0, 0, NOPC)),
|
||||
|
||||
/* SSAT cccc 0110 101x xxxx xxxx xxxx xx01 xxxx */
|
||||
/* USAT cccc 0110 111x xxxx xxxx xxxx xx01 xxxx */
|
||||
DECODE_OR(0x0fa00030, 0x06a00010),
|
||||
/* SSAT16 cccc 0110 1010 xxxx xxxx xxxx 0011 xxxx */
|
||||
/* USAT16 cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx */
|
||||
DECODE_EMULATEX (0x0fb000f0, 0x06a00030, emulate_rd12rn16rm0_rwflags_nopc,
|
||||
REGS(0, NOPC, 0, 0, NOPC)),
|
||||
|
||||
/* REV cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */
|
||||
/* REV16 cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */
|
||||
/* RBIT cccc 0110 1111 xxxx xxxx xxxx 0011 xxxx */
|
||||
/* REVSH cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */
|
||||
DECODE_EMULATEX (0x0fb00070, 0x06b00030, emulate_rd12rm0_noflags_nopc,
|
||||
REGS(0, NOPC, 0, 0, NOPC)),
|
||||
|
||||
/* ??? cccc 0110 0x00 xxxx xxxx xxxx xxx1 xxxx */
|
||||
DECODE_REJECT (0x0fb00010, 0x06000010),
|
||||
/* ??? cccc 0110 0xxx xxxx xxxx xxxx 1011 xxxx */
|
||||
DECODE_REJECT (0x0f8000f0, 0x060000b0),
|
||||
/* ??? cccc 0110 0xxx xxxx xxxx xxxx 1101 xxxx */
|
||||
DECODE_REJECT (0x0f8000f0, 0x060000d0),
|
||||
/* SADD16 cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx */
|
||||
/* SADDSUBX cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx */
|
||||
/* SSUBADDX cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx */
|
||||
/* SSUB16 cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx */
|
||||
/* SADD8 cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx */
|
||||
/* SSUB8 cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx */
|
||||
/* QADD16 cccc 0110 0010 xxxx xxxx xxxx 0001 xxxx */
|
||||
/* QADDSUBX cccc 0110 0010 xxxx xxxx xxxx 0011 xxxx */
|
||||
/* QSUBADDX cccc 0110 0010 xxxx xxxx xxxx 0101 xxxx */
|
||||
/* QSUB16 cccc 0110 0010 xxxx xxxx xxxx 0111 xxxx */
|
||||
/* QADD8 cccc 0110 0010 xxxx xxxx xxxx 1001 xxxx */
|
||||
/* QSUB8 cccc 0110 0010 xxxx xxxx xxxx 1111 xxxx */
|
||||
/* SHADD16 cccc 0110 0011 xxxx xxxx xxxx 0001 xxxx */
|
||||
/* SHADDSUBX cccc 0110 0011 xxxx xxxx xxxx 0011 xxxx */
|
||||
/* SHSUBADDX cccc 0110 0011 xxxx xxxx xxxx 0101 xxxx */
|
||||
/* SHSUB16 cccc 0110 0011 xxxx xxxx xxxx 0111 xxxx */
|
||||
/* SHADD8 cccc 0110 0011 xxxx xxxx xxxx 1001 xxxx */
|
||||
/* SHSUB8 cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx */
|
||||
/* UADD16 cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx */
|
||||
/* UADDSUBX cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx */
|
||||
/* USUBADDX cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx */
|
||||
/* USUB16 cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx */
|
||||
/* UADD8 cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx */
|
||||
/* USUB8 cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx */
|
||||
/* UQADD16 cccc 0110 0110 xxxx xxxx xxxx 0001 xxxx */
|
||||
/* UQADDSUBX cccc 0110 0110 xxxx xxxx xxxx 0011 xxxx */
|
||||
/* UQSUBADDX cccc 0110 0110 xxxx xxxx xxxx 0101 xxxx */
|
||||
/* UQSUB16 cccc 0110 0110 xxxx xxxx xxxx 0111 xxxx */
|
||||
/* UQADD8 cccc 0110 0110 xxxx xxxx xxxx 1001 xxxx */
|
||||
/* UQSUB8 cccc 0110 0110 xxxx xxxx xxxx 1111 xxxx */
|
||||
/* UHADD16 cccc 0110 0111 xxxx xxxx xxxx 0001 xxxx */
|
||||
/* UHADDSUBX cccc 0110 0111 xxxx xxxx xxxx 0011 xxxx */
|
||||
/* UHSUBADDX cccc 0110 0111 xxxx xxxx xxxx 0101 xxxx */
|
||||
/* UHSUB16 cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx */
|
||||
/* UHADD8 cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx */
|
||||
/* UHSUB8 cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx */
|
||||
DECODE_EMULATEX (0x0f800010, 0x06000010, emulate_rd12rn16rm0_rwflags_nopc,
|
||||
REGS(NOPC, NOPC, 0, 0, NOPC)),
|
||||
|
||||
/* PKHBT cccc 0110 1000 xxxx xxxx xxxx x001 xxxx */
|
||||
/* PKHTB cccc 0110 1000 xxxx xxxx xxxx x101 xxxx */
|
||||
DECODE_EMULATEX (0x0ff00030, 0x06800010, emulate_rd12rn16rm0_rwflags_nopc,
|
||||
REGS(NOPC, NOPC, 0, 0, NOPC)),
|
||||
|
||||
/* ??? cccc 0110 1001 xxxx xxxx xxxx 0111 xxxx */
|
||||
/* ??? cccc 0110 1101 xxxx xxxx xxxx 0111 xxxx */
|
||||
DECODE_REJECT (0x0fb000f0, 0x06900070),
|
||||
|
||||
/* SXTB16 cccc 0110 1000 1111 xxxx xxxx 0111 xxxx */
|
||||
/* SXTB cccc 0110 1010 1111 xxxx xxxx 0111 xxxx */
|
||||
/* SXTH cccc 0110 1011 1111 xxxx xxxx 0111 xxxx */
|
||||
/* UXTB16 cccc 0110 1100 1111 xxxx xxxx 0111 xxxx */
|
||||
/* UXTB cccc 0110 1110 1111 xxxx xxxx 0111 xxxx */
|
||||
/* UXTH cccc 0110 1111 1111 xxxx xxxx 0111 xxxx */
|
||||
DECODE_EMULATEX (0x0f8f00f0, 0x068f0070, emulate_rd12rm0_noflags_nopc,
|
||||
REGS(0, NOPC, 0, 0, NOPC)),
|
||||
|
||||
/* SXTAB16 cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx */
|
||||
/* SXTAB cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx */
|
||||
/* SXTAH cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx */
|
||||
/* UXTAB16 cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx */
|
||||
/* UXTAB cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx */
|
||||
/* UXTAH cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx */
|
||||
DECODE_EMULATEX (0x0f8000f0, 0x06800070, emulate_rd12rn16rm0_rwflags_nopc,
|
||||
REGS(NOPCX, NOPC, 0, 0, NOPC)),
|
||||
|
||||
DECODE_END
|
||||
};
|
||||
|
||||
static const union decode_item arm_cccc_0111_____xxx1_table[] = {
|
||||
/* Media instructions */
|
||||
|
||||
/* UNDEFINED cccc 0111 1111 xxxx xxxx xxxx 1111 xxxx */
|
||||
DECODE_REJECT (0x0ff000f0, 0x07f000f0),
|
||||
|
||||
/* SMLALD cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */
|
||||
/* SMLSLD cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */
|
||||
DECODE_EMULATEX (0x0ff00090, 0x07400010, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc,
|
||||
REGS(NOPC, NOPC, NOPC, 0, NOPC)),
|
||||
|
||||
/* SMUAD cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx */
|
||||
/* SMUSD cccc 0111 0000 xxxx 1111 xxxx 01x1 xxxx */
|
||||
DECODE_OR (0x0ff0f090, 0x0700f010),
|
||||
/* SMMUL cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx */
|
||||
DECODE_OR (0x0ff0f0d0, 0x0750f010),
|
||||
/* USAD8 cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx */
|
||||
DECODE_EMULATEX (0x0ff0f0f0, 0x0780f010, emulate_rd16rn12rm0rs8_rwflags_nopc,
|
||||
REGS(NOPC, 0, NOPC, 0, NOPC)),
|
||||
|
||||
/* SMLAD cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx */
|
||||
/* SMLSD cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx */
|
||||
DECODE_OR (0x0ff00090, 0x07000010),
|
||||
/* SMMLA cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx */
|
||||
DECODE_OR (0x0ff000d0, 0x07500010),
|
||||
/* USADA8 cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx */
|
||||
DECODE_EMULATEX (0x0ff000f0, 0x07800010, emulate_rd16rn12rm0rs8_rwflags_nopc,
|
||||
REGS(NOPC, NOPCX, NOPC, 0, NOPC)),
|
||||
|
||||
/* SMMLS cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx */
|
||||
DECODE_EMULATEX (0x0ff000d0, 0x075000d0, emulate_rd16rn12rm0rs8_rwflags_nopc,
|
||||
REGS(NOPC, NOPC, NOPC, 0, NOPC)),
|
||||
|
||||
/* SBFX cccc 0111 101x xxxx xxxx xxxx x101 xxxx */
|
||||
/* UBFX cccc 0111 111x xxxx xxxx xxxx x101 xxxx */
|
||||
DECODE_EMULATEX (0x0fa00070, 0x07a00050, emulate_rd12rm0_noflags_nopc,
|
||||
REGS(0, NOPC, 0, 0, NOPC)),
|
||||
|
||||
/* BFC cccc 0111 110x xxxx xxxx xxxx x001 1111 */
|
||||
DECODE_EMULATEX (0x0fe0007f, 0x07c0001f, emulate_rd12rm0_noflags_nopc,
|
||||
REGS(0, NOPC, 0, 0, 0)),
|
||||
|
||||
/* BFI cccc 0111 110x xxxx xxxx xxxx x001 xxxx */
|
||||
DECODE_EMULATEX (0x0fe00070, 0x07c00010, emulate_rd12rm0_noflags_nopc,
|
||||
REGS(0, NOPC, 0, 0, NOPCX)),
|
||||
|
||||
DECODE_END
|
||||
};
|
||||
|
||||
static const union decode_item arm_cccc_01xx_table[] = {
|
||||
/* Load/store word and unsigned byte */
|
||||
|
||||
/* LDRB/STRB pc,[...] cccc 01xx x0xx xxxx xxxx xxxx xxxx xxxx */
|
||||
DECODE_REJECT (0x0c40f000, 0x0440f000),
|
||||
|
||||
/* STRT cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */
|
||||
/* LDRT cccc 01x0 x011 xxxx xxxx xxxx xxxx xxxx */
|
||||
/* STRBT cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */
|
||||
/* LDRBT cccc 01x0 x111 xxxx xxxx xxxx xxxx xxxx */
|
||||
DECODE_REJECT (0x0d200000, 0x04200000),
|
||||
|
||||
/* STR (immediate) cccc 010x x0x0 xxxx xxxx xxxx xxxx xxxx */
|
||||
/* STRB (immediate) cccc 010x x1x0 xxxx xxxx xxxx xxxx xxxx */
|
||||
DECODE_EMULATEX (0x0e100000, 0x04000000, emulate_str,
|
||||
REGS(NOPCWB, ANY, 0, 0, 0)),
|
||||
|
||||
/* LDR (immediate) cccc 010x x0x1 xxxx xxxx xxxx xxxx xxxx */
|
||||
/* LDRB (immediate) cccc 010x x1x1 xxxx xxxx xxxx xxxx xxxx */
|
||||
DECODE_EMULATEX (0x0e100000, 0x04100000, emulate_ldr,
|
||||
REGS(NOPCWB, ANY, 0, 0, 0)),
|
||||
|
||||
/* STR (register) cccc 011x x0x0 xxxx xxxx xxxx xxxx xxxx */
|
||||
/* STRB (register) cccc 011x x1x0 xxxx xxxx xxxx xxxx xxxx */
|
||||
DECODE_EMULATEX (0x0e100000, 0x06000000, emulate_str,
|
||||
REGS(NOPCWB, ANY, 0, 0, NOPC)),
|
||||
|
||||
/* LDR (register) cccc 011x x0x1 xxxx xxxx xxxx xxxx xxxx */
|
||||
/* LDRB (register) cccc 011x x1x1 xxxx xxxx xxxx xxxx xxxx */
|
||||
DECODE_EMULATEX (0x0e100000, 0x06100000, emulate_ldr,
|
||||
REGS(NOPCWB, ANY, 0, 0, NOPC)),
|
||||
|
||||
DECODE_END
|
||||
};
|
||||
|
||||
static const union decode_item arm_cccc_100x_table[] = {
|
||||
/* Block data transfer instructions */
|
||||
|
||||
/* LDM cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */
|
||||
/* STM cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */
|
||||
DECODE_CUSTOM (0x0e400000, 0x08000000, kprobe_decode_ldmstm),
|
||||
|
||||
/* STM (user registers) cccc 100x x1x0 xxxx xxxx xxxx xxxx xxxx */
|
||||
/* LDM (user registers) cccc 100x x1x1 xxxx 0xxx xxxx xxxx xxxx */
|
||||
/* LDM (exception ret) cccc 100x x1x1 xxxx 1xxx xxxx xxxx xxxx */
|
||||
DECODE_END
|
||||
};
|
||||
|
||||
const union decode_item kprobe_decode_arm_table[] = {
|
||||
/*
|
||||
* Unconditional instructions
|
||||
* 1111 xxxx xxxx xxxx xxxx xxxx xxxx xxxx
|
||||
*/
|
||||
DECODE_TABLE (0xf0000000, 0xf0000000, arm_1111_table),
|
||||
|
||||
/*
|
||||
* Miscellaneous instructions
|
||||
* cccc 0001 0xx0 xxxx xxxx xxxx 0xxx xxxx
|
||||
*/
|
||||
DECODE_TABLE (0x0f900080, 0x01000000, arm_cccc_0001_0xx0____0xxx_table),
|
||||
|
||||
/*
|
||||
* Halfword multiply and multiply-accumulate
|
||||
* cccc 0001 0xx0 xxxx xxxx xxxx 1xx0 xxxx
|
||||
*/
|
||||
DECODE_TABLE (0x0f900090, 0x01000080, arm_cccc_0001_0xx0____1xx0_table),
|
||||
|
||||
/*
|
||||
* Multiply and multiply-accumulate
|
||||
* cccc 0000 xxxx xxxx xxxx xxxx 1001 xxxx
|
||||
*/
|
||||
DECODE_TABLE (0x0f0000f0, 0x00000090, arm_cccc_0000_____1001_table),
|
||||
|
||||
/*
|
||||
* Synchronization primitives
|
||||
* cccc 0001 xxxx xxxx xxxx xxxx 1001 xxxx
|
||||
*/
|
||||
DECODE_TABLE (0x0f0000f0, 0x01000090, arm_cccc_0001_____1001_table),
|
||||
|
||||
/*
|
||||
* Extra load/store instructions
|
||||
* cccc 000x xxxx xxxx xxxx xxxx 1xx1 xxxx
|
||||
*/
|
||||
DECODE_TABLE (0x0e000090, 0x00000090, arm_cccc_000x_____1xx1_table),
|
||||
|
||||
/*
|
||||
* Data-processing (register)
|
||||
* cccc 000x xxxx xxxx xxxx xxxx xxx0 xxxx
|
||||
* Data-processing (register-shifted register)
|
||||
* cccc 000x xxxx xxxx xxxx xxxx 0xx1 xxxx
|
||||
*/
|
||||
DECODE_TABLE (0x0e000000, 0x00000000, arm_cccc_000x_table),
|
||||
|
||||
/*
|
||||
* Data-processing (immediate)
|
||||
* cccc 001x xxxx xxxx xxxx xxxx xxxx xxxx
|
||||
*/
|
||||
DECODE_TABLE (0x0e000000, 0x02000000, arm_cccc_001x_table),
|
||||
|
||||
/*
|
||||
* Media instructions
|
||||
* cccc 011x xxxx xxxx xxxx xxxx xxx1 xxxx
|
||||
*/
|
||||
DECODE_TABLE (0x0f000010, 0x06000010, arm_cccc_0110_____xxx1_table),
|
||||
DECODE_TABLE (0x0f000010, 0x07000010, arm_cccc_0111_____xxx1_table),
|
||||
|
||||
/*
|
||||
* Load/store word and unsigned byte
|
||||
* cccc 01xx xxxx xxxx xxxx xxxx xxxx xxxx
|
||||
*/
|
||||
DECODE_TABLE (0x0c000000, 0x04000000, arm_cccc_01xx_table),
|
||||
|
||||
/*
|
||||
* Block data transfer instructions
|
||||
* cccc 100x xxxx xxxx xxxx xxxx xxxx xxxx
|
||||
*/
|
||||
DECODE_TABLE (0x0e000000, 0x08000000, arm_cccc_100x_table),
|
||||
|
||||
/* B cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */
|
||||
/* BL cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */
|
||||
DECODE_SIMULATE (0x0e000000, 0x0a000000, simulate_bbl),
|
||||
|
||||
/*
|
||||
* Supervisor Call, and coprocessor instructions
|
||||
*/
|
||||
|
||||
/* MCRR cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx */
|
||||
/* MRRC cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx */
|
||||
/* LDC cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */
|
||||
/* STC cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */
|
||||
/* CDP cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */
|
||||
/* MCR cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */
|
||||
/* MRC cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */
|
||||
/* SVC cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */
|
||||
DECODE_REJECT (0x0c000000, 0x0c000000),
|
||||
|
||||
DECODE_END
|
||||
};
|
||||
|
||||
static void __kprobes arm_singlestep(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
regs->ARM_pc += 4;
|
||||
p->ainsn.insn_handler(p, regs);
|
||||
}
|
||||
|
||||
/* Return:
|
||||
* INSN_REJECTED If instruction is one not allowed to kprobe,
|
||||
* INSN_GOOD If instruction is supported and uses instruction slot,
|
||||
* INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot.
|
||||
*
|
||||
* For instructions we don't want to kprobe (INSN_REJECTED return result):
|
||||
* These are generally ones that modify the processor state making
|
||||
* them "hard" to simulate such as switches processor modes or
|
||||
* make accesses in alternate modes. Any of these could be simulated
|
||||
* if the work was put into it, but low return considering they
|
||||
* should also be very rare.
|
||||
*/
|
||||
enum kprobe_insn __kprobes
|
||||
arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi)
|
||||
{
|
||||
asi->insn_singlestep = arm_singlestep;
|
||||
asi->insn_check_cc = kprobe_condition_checks[insn>>28];
|
||||
return kprobe_decode_insn(insn, asi, kprobe_decode_arm_table, false);
|
||||
}
|
577
arch/arm/kernel/kprobes-common.c
Normal file
577
arch/arm/kernel/kprobes-common.c
Normal file
|
@ -0,0 +1,577 @@
|
|||
/*
|
||||
* arch/arm/kernel/kprobes-common.c
|
||||
*
|
||||
* Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
|
||||
*
|
||||
* Some contents moved here from arch/arm/include/asm/kprobes-arm.c which is
|
||||
* Copyright (C) 2006, 2007 Motorola Inc.
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/kprobes.h>
|
||||
|
||||
#include "kprobes.h"
|
||||
|
||||
|
||||
#ifndef find_str_pc_offset
|
||||
|
||||
/*
|
||||
* For STR and STM instructions, an ARM core may choose to use either
|
||||
* a +8 or a +12 displacement from the current instruction's address.
|
||||
* Whichever value is chosen for a given core, it must be the same for
|
||||
* both instructions and may not change. This function measures it.
|
||||
*/
|
||||
|
||||
int str_pc_offset;
|
||||
|
||||
void __init find_str_pc_offset(void)
|
||||
{
|
||||
int addr, scratch, ret;
|
||||
|
||||
__asm__ (
|
||||
"sub %[ret], pc, #4 \n\t"
|
||||
"str pc, %[addr] \n\t"
|
||||
"ldr %[scr], %[addr] \n\t"
|
||||
"sub %[ret], %[scr], %[ret] \n\t"
|
||||
: [ret] "=r" (ret), [scr] "=r" (scratch), [addr] "+m" (addr));
|
||||
|
||||
str_pc_offset = ret;
|
||||
}
|
||||
|
||||
#endif /* !find_str_pc_offset */
|
||||
|
||||
|
||||
#ifndef test_load_write_pc_interworking
|
||||
|
||||
bool load_write_pc_interworks;
|
||||
|
||||
void __init test_load_write_pc_interworking(void)
|
||||
{
|
||||
int arch = cpu_architecture();
|
||||
BUG_ON(arch == CPU_ARCH_UNKNOWN);
|
||||
load_write_pc_interworks = arch >= CPU_ARCH_ARMv5T;
|
||||
}
|
||||
|
||||
#endif /* !test_load_write_pc_interworking */
|
||||
|
||||
|
||||
#ifndef test_alu_write_pc_interworking
|
||||
|
||||
bool alu_write_pc_interworks;
|
||||
|
||||
void __init test_alu_write_pc_interworking(void)
|
||||
{
|
||||
int arch = cpu_architecture();
|
||||
BUG_ON(arch == CPU_ARCH_UNKNOWN);
|
||||
alu_write_pc_interworks = arch >= CPU_ARCH_ARMv7;
|
||||
}
|
||||
|
||||
#endif /* !test_alu_write_pc_interworking */
|
||||
|
||||
|
||||
void __init arm_kprobe_decode_init(void)
|
||||
{
|
||||
find_str_pc_offset();
|
||||
test_load_write_pc_interworking();
|
||||
test_alu_write_pc_interworking();
|
||||
}
|
||||
|
||||
|
||||
static unsigned long __kprobes __check_eq(unsigned long cpsr)
|
||||
{
|
||||
return cpsr & PSR_Z_BIT;
|
||||
}
|
||||
|
||||
static unsigned long __kprobes __check_ne(unsigned long cpsr)
|
||||
{
|
||||
return (~cpsr) & PSR_Z_BIT;
|
||||
}
|
||||
|
||||
static unsigned long __kprobes __check_cs(unsigned long cpsr)
|
||||
{
|
||||
return cpsr & PSR_C_BIT;
|
||||
}
|
||||
|
||||
static unsigned long __kprobes __check_cc(unsigned long cpsr)
|
||||
{
|
||||
return (~cpsr) & PSR_C_BIT;
|
||||
}
|
||||
|
||||
static unsigned long __kprobes __check_mi(unsigned long cpsr)
|
||||
{
|
||||
return cpsr & PSR_N_BIT;
|
||||
}
|
||||
|
||||
static unsigned long __kprobes __check_pl(unsigned long cpsr)
|
||||
{
|
||||
return (~cpsr) & PSR_N_BIT;
|
||||
}
|
||||
|
||||
static unsigned long __kprobes __check_vs(unsigned long cpsr)
|
||||
{
|
||||
return cpsr & PSR_V_BIT;
|
||||
}
|
||||
|
||||
static unsigned long __kprobes __check_vc(unsigned long cpsr)
|
||||
{
|
||||
return (~cpsr) & PSR_V_BIT;
|
||||
}
|
||||
|
||||
static unsigned long __kprobes __check_hi(unsigned long cpsr)
|
||||
{
|
||||
cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */
|
||||
return cpsr & PSR_C_BIT;
|
||||
}
|
||||
|
||||
static unsigned long __kprobes __check_ls(unsigned long cpsr)
|
||||
{
|
||||
cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */
|
||||
return (~cpsr) & PSR_C_BIT;
|
||||
}
|
||||
|
||||
static unsigned long __kprobes __check_ge(unsigned long cpsr)
|
||||
{
|
||||
cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
|
||||
return (~cpsr) & PSR_N_BIT;
|
||||
}
|
||||
|
||||
static unsigned long __kprobes __check_lt(unsigned long cpsr)
|
||||
{
|
||||
cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
|
||||
return cpsr & PSR_N_BIT;
|
||||
}
|
||||
|
||||
static unsigned long __kprobes __check_gt(unsigned long cpsr)
|
||||
{
|
||||
unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
|
||||
temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */
|
||||
return (~temp) & PSR_N_BIT;
|
||||
}
|
||||
|
||||
static unsigned long __kprobes __check_le(unsigned long cpsr)
|
||||
{
|
||||
unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
|
||||
temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */
|
||||
return temp & PSR_N_BIT;
|
||||
}
|
||||
|
||||
static unsigned long __kprobes __check_al(unsigned long cpsr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
kprobe_check_cc * const kprobe_condition_checks[16] = {
|
||||
&__check_eq, &__check_ne, &__check_cs, &__check_cc,
|
||||
&__check_mi, &__check_pl, &__check_vs, &__check_vc,
|
||||
&__check_hi, &__check_ls, &__check_ge, &__check_lt,
|
||||
&__check_gt, &__check_le, &__check_al, &__check_al
|
||||
};
|
||||
|
||||
|
||||
void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
}
|
||||
|
||||
void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
p->ainsn.insn_fn();
|
||||
}
|
||||
|
||||
static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
kprobe_opcode_t insn = p->opcode;
|
||||
int rn = (insn >> 16) & 0xf;
|
||||
int lbit = insn & (1 << 20);
|
||||
int wbit = insn & (1 << 21);
|
||||
int ubit = insn & (1 << 23);
|
||||
int pbit = insn & (1 << 24);
|
||||
long *addr = (long *)regs->uregs[rn];
|
||||
int reg_bit_vector;
|
||||
int reg_count;
|
||||
|
||||
reg_count = 0;
|
||||
reg_bit_vector = insn & 0xffff;
|
||||
while (reg_bit_vector) {
|
||||
reg_bit_vector &= (reg_bit_vector - 1);
|
||||
++reg_count;
|
||||
}
|
||||
|
||||
if (!ubit)
|
||||
addr -= reg_count;
|
||||
addr += (!pbit == !ubit);
|
||||
|
||||
reg_bit_vector = insn & 0xffff;
|
||||
while (reg_bit_vector) {
|
||||
int reg = __ffs(reg_bit_vector);
|
||||
reg_bit_vector &= (reg_bit_vector - 1);
|
||||
if (lbit)
|
||||
regs->uregs[reg] = *addr++;
|
||||
else
|
||||
*addr++ = regs->uregs[reg];
|
||||
}
|
||||
|
||||
if (wbit) {
|
||||
if (!ubit)
|
||||
addr -= reg_count;
|
||||
addr -= (!pbit == !ubit);
|
||||
regs->uregs[rn] = (long)addr;
|
||||
}
|
||||
}
|
||||
|
||||
static void __kprobes simulate_stm1_pc(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
regs->ARM_pc = (long)p->addr + str_pc_offset;
|
||||
simulate_ldm1stm1(p, regs);
|
||||
regs->ARM_pc = (long)p->addr + 4;
|
||||
}
|
||||
|
||||
static void __kprobes simulate_ldm1_pc(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
simulate_ldm1stm1(p, regs);
|
||||
load_write_pc(regs->ARM_pc, regs);
|
||||
}
|
||||
|
||||
static void __kprobes
|
||||
emulate_generic_r0_12_noflags(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
register void *rregs asm("r1") = regs;
|
||||
register void *rfn asm("lr") = p->ainsn.insn_fn;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"stmdb sp!, {%[regs], r11} \n\t"
|
||||
"ldmia %[regs], {r0-r12} \n\t"
|
||||
#if __LINUX_ARM_ARCH__ >= 6
|
||||
"blx %[fn] \n\t"
|
||||
#else
|
||||
"str %[fn], [sp, #-4]! \n\t"
|
||||
"adr lr, 1f \n\t"
|
||||
"ldr pc, [sp], #4 \n\t"
|
||||
"1: \n\t"
|
||||
#endif
|
||||
"ldr lr, [sp], #4 \n\t" /* lr = regs */
|
||||
"stmia lr, {r0-r12} \n\t"
|
||||
"ldr r11, [sp], #4 \n\t"
|
||||
: [regs] "=r" (rregs), [fn] "=r" (rfn)
|
||||
: "0" (rregs), "1" (rfn)
|
||||
: "r0", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r12", "memory", "cc"
|
||||
);
|
||||
}
|
||||
|
||||
static void __kprobes
|
||||
emulate_generic_r2_14_noflags(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
emulate_generic_r0_12_noflags(p, (struct pt_regs *)(regs->uregs+2));
|
||||
}
|
||||
|
||||
static void __kprobes
|
||||
emulate_ldm_r3_15(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
emulate_generic_r0_12_noflags(p, (struct pt_regs *)(regs->uregs+3));
|
||||
load_write_pc(regs->ARM_pc, regs);
|
||||
}
|
||||
|
||||
enum kprobe_insn __kprobes
|
||||
kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi)
|
||||
{
|
||||
kprobe_insn_handler_t *handler = 0;
|
||||
unsigned reglist = insn & 0xffff;
|
||||
int is_ldm = insn & 0x100000;
|
||||
int rn = (insn >> 16) & 0xf;
|
||||
|
||||
if (rn <= 12 && (reglist & 0xe000) == 0) {
|
||||
/* Instruction only uses registers in the range R0..R12 */
|
||||
handler = emulate_generic_r0_12_noflags;
|
||||
|
||||
} else if (rn >= 2 && (reglist & 0x8003) == 0) {
|
||||
/* Instruction only uses registers in the range R2..R14 */
|
||||
rn -= 2;
|
||||
reglist >>= 2;
|
||||
handler = emulate_generic_r2_14_noflags;
|
||||
|
||||
} else if (rn >= 3 && (reglist & 0x0007) == 0) {
|
||||
/* Instruction only uses registers in the range R3..R15 */
|
||||
if (is_ldm && (reglist & 0x8000)) {
|
||||
rn -= 3;
|
||||
reglist >>= 3;
|
||||
handler = emulate_ldm_r3_15;
|
||||
}
|
||||
}
|
||||
|
||||
if (handler) {
|
||||
/* We can emulate the instruction in (possibly) modified form */
|
||||
asi->insn[0] = (insn & 0xfff00000) | (rn << 16) | reglist;
|
||||
asi->insn_handler = handler;
|
||||
return INSN_GOOD;
|
||||
}
|
||||
|
||||
/* Fallback to slower simulation... */
|
||||
if (reglist & 0x8000)
|
||||
handler = is_ldm ? simulate_ldm1_pc : simulate_stm1_pc;
|
||||
else
|
||||
handler = simulate_ldm1stm1;
|
||||
asi->insn_handler = handler;
|
||||
return INSN_GOOD_NO_SLOT;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Prepare an instruction slot to receive an instruction for emulating.
|
||||
* This is done by placing a subroutine return after the location where the
|
||||
* instruction will be placed. We also modify ARM instructions to be
|
||||
* unconditional as the condition code will already be checked before any
|
||||
* emulation handler is called.
|
||||
*/
|
||||
static kprobe_opcode_t __kprobes
|
||||
prepare_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi,
|
||||
bool thumb)
|
||||
{
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
if (thumb) {
|
||||
u16 *thumb_insn = (u16 *)asi->insn;
|
||||
thumb_insn[1] = 0x4770; /* Thumb bx lr */
|
||||
thumb_insn[2] = 0x4770; /* Thumb bx lr */
|
||||
return insn;
|
||||
}
|
||||
asi->insn[1] = 0xe12fff1e; /* ARM bx lr */
|
||||
#else
|
||||
asi->insn[1] = 0xe1a0f00e; /* mov pc, lr */
|
||||
#endif
|
||||
/* Make an ARM instruction unconditional */
|
||||
if (insn < 0xe0000000)
|
||||
insn = (insn | 0xe0000000) & ~0x10000000;
|
||||
return insn;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a (probably modified) instruction into the slot previously prepared by
|
||||
* prepare_emulated_insn
|
||||
*/
|
||||
static void __kprobes
|
||||
set_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi,
|
||||
bool thumb)
|
||||
{
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
if (thumb) {
|
||||
u16 *ip = (u16 *)asi->insn;
|
||||
if (is_wide_instruction(insn))
|
||||
*ip++ = insn >> 16;
|
||||
*ip++ = insn;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
asi->insn[0] = insn;
|
||||
}
|
||||
|
||||
/*
|
||||
* When we modify the register numbers encoded in an instruction to be emulated,
|
||||
* the new values come from this define. For ARM and 32-bit Thumb instructions
|
||||
* this gives...
|
||||
*
|
||||
* bit position 16 12 8 4 0
|
||||
* ---------------+---+---+---+---+---+
|
||||
* register r2 r0 r1 -- r3
|
||||
*/
|
||||
#define INSN_NEW_BITS 0x00020103
|
||||
|
||||
/* Each nibble has same value as that at INSN_NEW_BITS bit 16 */
|
||||
#define INSN_SAMEAS16_BITS 0x22222222
|
||||
|
||||
/*
|
||||
* Validate and modify each of the registers encoded in an instruction.
|
||||
*
|
||||
* Each nibble in regs contains a value from enum decode_reg_type. For each
|
||||
* non-zero value, the corresponding nibble in pinsn is validated and modified
|
||||
* according to the type.
|
||||
*/
|
||||
static bool __kprobes decode_regs(kprobe_opcode_t* pinsn, u32 regs)
|
||||
{
|
||||
kprobe_opcode_t insn = *pinsn;
|
||||
kprobe_opcode_t mask = 0xf; /* Start at least significant nibble */
|
||||
|
||||
for (; regs != 0; regs >>= 4, mask <<= 4) {
|
||||
|
||||
kprobe_opcode_t new_bits = INSN_NEW_BITS;
|
||||
|
||||
switch (regs & 0xf) {
|
||||
|
||||
case REG_TYPE_NONE:
|
||||
/* Nibble not a register, skip to next */
|
||||
continue;
|
||||
|
||||
case REG_TYPE_ANY:
|
||||
/* Any register is allowed */
|
||||
break;
|
||||
|
||||
case REG_TYPE_SAMEAS16:
|
||||
/* Replace register with same as at bit position 16 */
|
||||
new_bits = INSN_SAMEAS16_BITS;
|
||||
break;
|
||||
|
||||
case REG_TYPE_SP:
|
||||
/* Only allow SP (R13) */
|
||||
if ((insn ^ 0xdddddddd) & mask)
|
||||
goto reject;
|
||||
break;
|
||||
|
||||
case REG_TYPE_PC:
|
||||
/* Only allow PC (R15) */
|
||||
if ((insn ^ 0xffffffff) & mask)
|
||||
goto reject;
|
||||
break;
|
||||
|
||||
case REG_TYPE_NOSP:
|
||||
/* Reject SP (R13) */
|
||||
if (((insn ^ 0xdddddddd) & mask) == 0)
|
||||
goto reject;
|
||||
break;
|
||||
|
||||
case REG_TYPE_NOSPPC:
|
||||
case REG_TYPE_NOSPPCX:
|
||||
/* Reject SP and PC (R13 and R15) */
|
||||
if (((insn ^ 0xdddddddd) & 0xdddddddd & mask) == 0)
|
||||
goto reject;
|
||||
break;
|
||||
|
||||
case REG_TYPE_NOPCWB:
|
||||
if (!is_writeback(insn))
|
||||
break; /* No writeback, so any register is OK */
|
||||
/* fall through... */
|
||||
case REG_TYPE_NOPC:
|
||||
case REG_TYPE_NOPCX:
|
||||
/* Reject PC (R15) */
|
||||
if (((insn ^ 0xffffffff) & mask) == 0)
|
||||
goto reject;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Replace value of nibble with new register number... */
|
||||
insn &= ~mask;
|
||||
insn |= new_bits & mask;
|
||||
}
|
||||
|
||||
*pinsn = insn;
|
||||
return true;
|
||||
|
||||
reject:
|
||||
return false;
|
||||
}
|
||||
|
||||
static const int decode_struct_sizes[NUM_DECODE_TYPES] = {
|
||||
[DECODE_TYPE_TABLE] = sizeof(struct decode_table),
|
||||
[DECODE_TYPE_CUSTOM] = sizeof(struct decode_custom),
|
||||
[DECODE_TYPE_SIMULATE] = sizeof(struct decode_simulate),
|
||||
[DECODE_TYPE_EMULATE] = sizeof(struct decode_emulate),
|
||||
[DECODE_TYPE_OR] = sizeof(struct decode_or),
|
||||
[DECODE_TYPE_REJECT] = sizeof(struct decode_reject)
|
||||
};
|
||||
|
||||
/*
|
||||
* kprobe_decode_insn operates on data tables in order to decode an ARM
|
||||
* architecture instruction onto which a kprobe has been placed.
|
||||
*
|
||||
* These instruction decoding tables are a concatenation of entries each
|
||||
* of which consist of one of the following structs:
|
||||
*
|
||||
* decode_table
|
||||
* decode_custom
|
||||
* decode_simulate
|
||||
* decode_emulate
|
||||
* decode_or
|
||||
* decode_reject
|
||||
*
|
||||
* Each of these starts with a struct decode_header which has the following
|
||||
* fields:
|
||||
*
|
||||
* type_regs
|
||||
* mask
|
||||
* value
|
||||
*
|
||||
* The least significant DECODE_TYPE_BITS of type_regs contains a value
|
||||
* from enum decode_type, this indicates which of the decode_* structs
|
||||
* the entry contains. The value DECODE_TYPE_END indicates the end of the
|
||||
* table.
|
||||
*
|
||||
* When the table is parsed, each entry is checked in turn to see if it
|
||||
* matches the instruction to be decoded using the test:
|
||||
*
|
||||
* (insn & mask) == value
|
||||
*
|
||||
* If no match is found before the end of the table is reached then decoding
|
||||
* fails with INSN_REJECTED.
|
||||
*
|
||||
* When a match is found, decode_regs() is called to validate and modify each
|
||||
* of the registers encoded in the instruction; the data it uses to do this
|
||||
* is (type_regs >> DECODE_TYPE_BITS). A validation failure will cause decoding
|
||||
* to fail with INSN_REJECTED.
|
||||
*
|
||||
* Once the instruction has passed the above tests, further processing
|
||||
* depends on the type of the table entry's decode struct.
|
||||
*
|
||||
*/
|
||||
int __kprobes
|
||||
kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi,
|
||||
const union decode_item *table, bool thumb)
|
||||
{
|
||||
const struct decode_header *h = (struct decode_header *)table;
|
||||
const struct decode_header *next;
|
||||
bool matched = false;
|
||||
|
||||
insn = prepare_emulated_insn(insn, asi, thumb);
|
||||
|
||||
for (;; h = next) {
|
||||
enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK;
|
||||
u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS;
|
||||
|
||||
if (type == DECODE_TYPE_END)
|
||||
return INSN_REJECTED;
|
||||
|
||||
next = (struct decode_header *)
|
||||
((uintptr_t)h + decode_struct_sizes[type]);
|
||||
|
||||
if (!matched && (insn & h->mask.bits) != h->value.bits)
|
||||
continue;
|
||||
|
||||
if (!decode_regs(&insn, regs))
|
||||
return INSN_REJECTED;
|
||||
|
||||
switch (type) {
|
||||
|
||||
case DECODE_TYPE_TABLE: {
|
||||
struct decode_table *d = (struct decode_table *)h;
|
||||
next = (struct decode_header *)d->table.table;
|
||||
break;
|
||||
}
|
||||
|
||||
case DECODE_TYPE_CUSTOM: {
|
||||
struct decode_custom *d = (struct decode_custom *)h;
|
||||
return (*d->decoder.decoder)(insn, asi);
|
||||
}
|
||||
|
||||
case DECODE_TYPE_SIMULATE: {
|
||||
struct decode_simulate *d = (struct decode_simulate *)h;
|
||||
asi->insn_handler = d->handler.handler;
|
||||
return INSN_GOOD_NO_SLOT;
|
||||
}
|
||||
|
||||
case DECODE_TYPE_EMULATE: {
|
||||
struct decode_emulate *d = (struct decode_emulate *)h;
|
||||
asi->insn_handler = d->handler.handler;
|
||||
set_emulated_insn(insn, asi, thumb);
|
||||
return INSN_GOOD;
|
||||
}
|
||||
|
||||
case DECODE_TYPE_OR:
|
||||
matched = true;
|
||||
break;
|
||||
|
||||
case DECODE_TYPE_REJECT:
|
||||
default:
|
||||
return INSN_REJECTED;
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
1462
arch/arm/kernel/kprobes-thumb.c
Normal file
1462
arch/arm/kernel/kprobes-thumb.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -28,14 +28,16 @@
|
|||
#include <asm/traps.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
#include "kprobes.h"
|
||||
|
||||
#define MIN_STACK_SIZE(addr) \
|
||||
min((unsigned long)MAX_STACK_SIZE, \
|
||||
(unsigned long)current_thread_info() + THREAD_START_SP - (addr))
|
||||
|
||||
#define flush_insns(addr, cnt) \
|
||||
#define flush_insns(addr, size) \
|
||||
flush_icache_range((unsigned long)(addr), \
|
||||
(unsigned long)(addr) + \
|
||||
sizeof(kprobe_opcode_t) * (cnt))
|
||||
(size))
|
||||
|
||||
/* Used as a marker in ARM_pc to note when we're in a jprobe. */
|
||||
#define JPROBE_MAGIC_ADDR 0xffffffff
|
||||
|
@ -49,16 +51,35 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
|
|||
kprobe_opcode_t insn;
|
||||
kprobe_opcode_t tmp_insn[MAX_INSN_SIZE];
|
||||
unsigned long addr = (unsigned long)p->addr;
|
||||
bool thumb;
|
||||
kprobe_decode_insn_t *decode_insn;
|
||||
int is;
|
||||
|
||||
if (addr & 0x3 || in_exception_text(addr))
|
||||
if (in_exception_text(addr))
|
||||
return -EINVAL;
|
||||
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
thumb = true;
|
||||
addr &= ~1; /* Bit 0 would normally be set to indicate Thumb code */
|
||||
insn = ((u16 *)addr)[0];
|
||||
if (is_wide_instruction(insn)) {
|
||||
insn <<= 16;
|
||||
insn |= ((u16 *)addr)[1];
|
||||
decode_insn = thumb32_kprobe_decode_insn;
|
||||
} else
|
||||
decode_insn = thumb16_kprobe_decode_insn;
|
||||
#else /* !CONFIG_THUMB2_KERNEL */
|
||||
thumb = false;
|
||||
if (addr & 0x3)
|
||||
return -EINVAL;
|
||||
insn = *p->addr;
|
||||
decode_insn = arm_kprobe_decode_insn;
|
||||
#endif
|
||||
|
||||
p->opcode = insn;
|
||||
p->ainsn.insn = tmp_insn;
|
||||
|
||||
switch (arm_kprobe_decode_insn(insn, &p->ainsn)) {
|
||||
switch ((*decode_insn)(insn, &p->ainsn)) {
|
||||
case INSN_REJECTED: /* not supported */
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -68,7 +89,10 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
|
|||
return -ENOMEM;
|
||||
for (is = 0; is < MAX_INSN_SIZE; ++is)
|
||||
p->ainsn.insn[is] = tmp_insn[is];
|
||||
flush_insns(p->ainsn.insn, MAX_INSN_SIZE);
|
||||
flush_insns(p->ainsn.insn,
|
||||
sizeof(p->ainsn.insn[0]) * MAX_INSN_SIZE);
|
||||
p->ainsn.insn_fn = (kprobe_insn_fn_t *)
|
||||
((uintptr_t)p->ainsn.insn | thumb);
|
||||
break;
|
||||
|
||||
case INSN_GOOD_NO_SLOT: /* instruction doesn't need insn slot */
|
||||
|
@ -79,24 +103,88 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
|
||||
/*
|
||||
* For a 32-bit Thumb breakpoint spanning two memory words we need to take
|
||||
* special precautions to insert the breakpoint atomically, especially on SMP
|
||||
* systems. This is achieved by calling this arming function using stop_machine.
|
||||
*/
|
||||
static int __kprobes set_t32_breakpoint(void *addr)
|
||||
{
|
||||
((u16 *)addr)[0] = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION >> 16;
|
||||
((u16 *)addr)[1] = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION & 0xffff;
|
||||
flush_insns(addr, 2*sizeof(u16));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __kprobes arch_arm_kprobe(struct kprobe *p)
|
||||
{
|
||||
*p->addr = KPROBE_BREAKPOINT_INSTRUCTION;
|
||||
flush_insns(p->addr, 1);
|
||||
uintptr_t addr = (uintptr_t)p->addr & ~1; /* Remove any Thumb flag */
|
||||
|
||||
if (!is_wide_instruction(p->opcode)) {
|
||||
*(u16 *)addr = KPROBE_THUMB16_BREAKPOINT_INSTRUCTION;
|
||||
flush_insns(addr, sizeof(u16));
|
||||
} else if (addr & 2) {
|
||||
/* A 32-bit instruction spanning two words needs special care */
|
||||
stop_machine(set_t32_breakpoint, (void *)addr, &cpu_online_map);
|
||||
} else {
|
||||
/* Word aligned 32-bit instruction can be written atomically */
|
||||
u32 bkp = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION;
|
||||
#ifndef __ARMEB__ /* Swap halfwords for little-endian */
|
||||
bkp = (bkp >> 16) | (bkp << 16);
|
||||
#endif
|
||||
*(u32 *)addr = bkp;
|
||||
flush_insns(addr, sizeof(u32));
|
||||
}
|
||||
}
|
||||
|
||||
#else /* !CONFIG_THUMB2_KERNEL */
|
||||
|
||||
void __kprobes arch_arm_kprobe(struct kprobe *p)
|
||||
{
|
||||
kprobe_opcode_t insn = p->opcode;
|
||||
kprobe_opcode_t brkp = KPROBE_ARM_BREAKPOINT_INSTRUCTION;
|
||||
if (insn >= 0xe0000000)
|
||||
brkp |= 0xe0000000; /* Unconditional instruction */
|
||||
else
|
||||
brkp |= insn & 0xf0000000; /* Copy condition from insn */
|
||||
*p->addr = brkp;
|
||||
flush_insns(p->addr, sizeof(p->addr[0]));
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_THUMB2_KERNEL */
|
||||
|
||||
/*
|
||||
* The actual disarming is done here on each CPU and synchronized using
|
||||
* stop_machine. This synchronization is necessary on SMP to avoid removing
|
||||
* a probe between the moment the 'Undefined Instruction' exception is raised
|
||||
* and the moment the exception handler reads the faulting instruction from
|
||||
* memory.
|
||||
* memory. It is also needed to atomically set the two half-words of a 32-bit
|
||||
* Thumb breakpoint.
|
||||
*/
|
||||
int __kprobes __arch_disarm_kprobe(void *p)
|
||||
{
|
||||
struct kprobe *kp = p;
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
u16 *addr = (u16 *)((uintptr_t)kp->addr & ~1);
|
||||
kprobe_opcode_t insn = kp->opcode;
|
||||
unsigned int len;
|
||||
|
||||
if (is_wide_instruction(insn)) {
|
||||
((u16 *)addr)[0] = insn>>16;
|
||||
((u16 *)addr)[1] = insn;
|
||||
len = 2*sizeof(u16);
|
||||
} else {
|
||||
((u16 *)addr)[0] = insn;
|
||||
len = sizeof(u16);
|
||||
}
|
||||
flush_insns(addr, len);
|
||||
|
||||
#else /* !CONFIG_THUMB2_KERNEL */
|
||||
*kp->addr = kp->opcode;
|
||||
flush_insns(kp->addr, 1);
|
||||
flush_insns(kp->addr, sizeof(kp->addr[0]));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -130,12 +218,24 @@ static void __kprobes set_current_kprobe(struct kprobe *p)
|
|||
__get_cpu_var(current_kprobe) = p;
|
||||
}
|
||||
|
||||
static void __kprobes singlestep(struct kprobe *p, struct pt_regs *regs,
|
||||
struct kprobe_ctlblk *kcb)
|
||||
static void __kprobes
|
||||
singlestep_skip(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
regs->ARM_cpsr = it_advance(regs->ARM_cpsr);
|
||||
if (is_wide_instruction(p->opcode))
|
||||
regs->ARM_pc += 4;
|
||||
else
|
||||
regs->ARM_pc += 2;
|
||||
#else
|
||||
regs->ARM_pc += 4;
|
||||
if (p->ainsn.insn_check_cc(regs->ARM_cpsr))
|
||||
p->ainsn.insn_handler(p, regs);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void __kprobes
|
||||
singlestep(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb)
|
||||
{
|
||||
p->ainsn.insn_singlestep(p, regs);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -149,11 +249,23 @@ void __kprobes kprobe_handler(struct pt_regs *regs)
|
|||
{
|
||||
struct kprobe *p, *cur;
|
||||
struct kprobe_ctlblk *kcb;
|
||||
kprobe_opcode_t *addr = (kprobe_opcode_t *)regs->ARM_pc;
|
||||
|
||||
kcb = get_kprobe_ctlblk();
|
||||
cur = kprobe_running();
|
||||
p = get_kprobe(addr);
|
||||
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
/*
|
||||
* First look for a probe which was registered using an address with
|
||||
* bit 0 set, this is the usual situation for pointers to Thumb code.
|
||||
* If not found, fallback to looking for one with bit 0 clear.
|
||||
*/
|
||||
p = get_kprobe((kprobe_opcode_t *)(regs->ARM_pc | 1));
|
||||
if (!p)
|
||||
p = get_kprobe((kprobe_opcode_t *)regs->ARM_pc);
|
||||
|
||||
#else /* ! CONFIG_THUMB2_KERNEL */
|
||||
p = get_kprobe((kprobe_opcode_t *)regs->ARM_pc);
|
||||
#endif
|
||||
|
||||
if (p) {
|
||||
if (cur) {
|
||||
|
@ -173,7 +285,8 @@ void __kprobes kprobe_handler(struct pt_regs *regs)
|
|||
/* impossible cases */
|
||||
BUG();
|
||||
}
|
||||
} else {
|
||||
} else if (p->ainsn.insn_check_cc(regs->ARM_cpsr)) {
|
||||
/* Probe hit and conditional execution check ok. */
|
||||
set_current_kprobe(p);
|
||||
kcb->kprobe_status = KPROBE_HIT_ACTIVE;
|
||||
|
||||
|
@ -193,6 +306,13 @@ void __kprobes kprobe_handler(struct pt_regs *regs)
|
|||
}
|
||||
reset_current_kprobe();
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Probe hit but conditional execution check failed,
|
||||
* so just skip the instruction and continue as if
|
||||
* nothing had happened.
|
||||
*/
|
||||
singlestep_skip(p, regs);
|
||||
}
|
||||
} else if (cur) {
|
||||
/* We probably hit a jprobe. Call its break handler. */
|
||||
|
@ -300,7 +420,11 @@ void __naked __kprobes kretprobe_trampoline(void)
|
|||
"bl trampoline_handler \n\t"
|
||||
"mov lr, r0 \n\t"
|
||||
"ldmia sp!, {r0 - r11} \n\t"
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
"bx lr \n\t"
|
||||
#else
|
||||
"mov pc, lr \n\t"
|
||||
#endif
|
||||
: : : "memory");
|
||||
}
|
||||
|
||||
|
@ -378,11 +502,22 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
|
|||
struct jprobe *jp = container_of(p, struct jprobe, kp);
|
||||
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
||||
long sp_addr = regs->ARM_sp;
|
||||
long cpsr;
|
||||
|
||||
kcb->jprobe_saved_regs = *regs;
|
||||
memcpy(kcb->jprobes_stack, (void *)sp_addr, MIN_STACK_SIZE(sp_addr));
|
||||
regs->ARM_pc = (long)jp->entry;
|
||||
regs->ARM_cpsr |= PSR_I_BIT;
|
||||
|
||||
cpsr = regs->ARM_cpsr | PSR_I_BIT;
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
/* Set correct Thumb state in cpsr */
|
||||
if (regs->ARM_pc & 1)
|
||||
cpsr |= PSR_T_BIT;
|
||||
else
|
||||
cpsr &= ~PSR_T_BIT;
|
||||
#endif
|
||||
regs->ARM_cpsr = cpsr;
|
||||
|
||||
preempt_disable();
|
||||
return 1;
|
||||
}
|
||||
|
@ -404,7 +539,12 @@ void __kprobes jprobe_return(void)
|
|||
* This is to prevent any simulated instruction from writing
|
||||
* over the regs when they are accessing the stack.
|
||||
*/
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
"sub r0, %0, %1 \n\t"
|
||||
"mov sp, r0 \n\t"
|
||||
#else
|
||||
"sub sp, %0, %1 \n\t"
|
||||
#endif
|
||||
"ldr r0, ="__stringify(JPROBE_MAGIC_ADDR)"\n\t"
|
||||
"str %0, [sp, %2] \n\t"
|
||||
"str r0, [sp, %3] \n\t"
|
||||
|
@ -415,15 +555,28 @@ void __kprobes jprobe_return(void)
|
|||
* Return to the context saved by setjmp_pre_handler
|
||||
* and restored by longjmp_break_handler.
|
||||
*/
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
"ldr lr, [sp, %2] \n\t" /* lr = saved sp */
|
||||
"ldrd r0, r1, [sp, %5] \n\t" /* r0,r1 = saved lr,pc */
|
||||
"ldr r2, [sp, %4] \n\t" /* r2 = saved psr */
|
||||
"stmdb lr!, {r0, r1, r2} \n\t" /* push saved lr and */
|
||||
/* rfe context */
|
||||
"ldmia sp, {r0 - r12} \n\t"
|
||||
"mov sp, lr \n\t"
|
||||
"ldr lr, [sp], #4 \n\t"
|
||||
"rfeia sp! \n\t"
|
||||
#else
|
||||
"ldr r0, [sp, %4] \n\t"
|
||||
"msr cpsr_cxsf, r0 \n\t"
|
||||
"ldmia sp, {r0 - pc} \n\t"
|
||||
#endif
|
||||
:
|
||||
: "r" (kcb->jprobe_saved_regs.ARM_sp),
|
||||
"I" (sizeof(struct pt_regs) * 2),
|
||||
"J" (offsetof(struct pt_regs, ARM_sp)),
|
||||
"J" (offsetof(struct pt_regs, ARM_pc)),
|
||||
"J" (offsetof(struct pt_regs, ARM_cpsr))
|
||||
"J" (offsetof(struct pt_regs, ARM_cpsr)),
|
||||
"J" (offsetof(struct pt_regs, ARM_lr))
|
||||
: "memory", "cc");
|
||||
}
|
||||
|
||||
|
@ -460,17 +613,44 @@ int __kprobes arch_trampoline_kprobe(struct kprobe *p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct undef_hook kprobes_break_hook = {
|
||||
.instr_mask = 0xffffffff,
|
||||
.instr_val = KPROBE_BREAKPOINT_INSTRUCTION,
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
|
||||
static struct undef_hook kprobes_thumb16_break_hook = {
|
||||
.instr_mask = 0xffff,
|
||||
.instr_val = KPROBE_THUMB16_BREAKPOINT_INSTRUCTION,
|
||||
.cpsr_mask = MODE_MASK,
|
||||
.cpsr_val = SVC_MODE,
|
||||
.fn = kprobe_trap_handler,
|
||||
};
|
||||
|
||||
static struct undef_hook kprobes_thumb32_break_hook = {
|
||||
.instr_mask = 0xffffffff,
|
||||
.instr_val = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION,
|
||||
.cpsr_mask = MODE_MASK,
|
||||
.cpsr_val = SVC_MODE,
|
||||
.fn = kprobe_trap_handler,
|
||||
};
|
||||
|
||||
#else /* !CONFIG_THUMB2_KERNEL */
|
||||
|
||||
static struct undef_hook kprobes_arm_break_hook = {
|
||||
.instr_mask = 0x0fffffff,
|
||||
.instr_val = KPROBE_ARM_BREAKPOINT_INSTRUCTION,
|
||||
.cpsr_mask = MODE_MASK,
|
||||
.cpsr_val = SVC_MODE,
|
||||
.fn = kprobe_trap_handler,
|
||||
};
|
||||
|
||||
#endif /* !CONFIG_THUMB2_KERNEL */
|
||||
|
||||
int __init arch_init_kprobes()
|
||||
{
|
||||
arm_kprobe_decode_init();
|
||||
register_undef_hook(&kprobes_break_hook);
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
register_undef_hook(&kprobes_thumb16_break_hook);
|
||||
register_undef_hook(&kprobes_thumb32_break_hook);
|
||||
#else
|
||||
register_undef_hook(&kprobes_arm_break_hook);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
|
420
arch/arm/kernel/kprobes.h
Normal file
420
arch/arm/kernel/kprobes.h
Normal file
|
@ -0,0 +1,420 @@
|
|||
/*
|
||||
* arch/arm/kernel/kprobes.h
|
||||
*
|
||||
* Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
|
||||
*
|
||||
* Some contents moved here from arch/arm/include/asm/kprobes.h which is
|
||||
* Copyright (C) 2006, 2007 Motorola Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _ARM_KERNEL_KPROBES_H
|
||||
#define _ARM_KERNEL_KPROBES_H
|
||||
|
||||
/*
|
||||
* These undefined instructions must be unique and
|
||||
* reserved solely for kprobes' use.
|
||||
*/
|
||||
#define KPROBE_ARM_BREAKPOINT_INSTRUCTION 0x07f001f8
|
||||
#define KPROBE_THUMB16_BREAKPOINT_INSTRUCTION 0xde18
|
||||
#define KPROBE_THUMB32_BREAKPOINT_INSTRUCTION 0xf7f0a018
|
||||
|
||||
|
||||
enum kprobe_insn {
|
||||
INSN_REJECTED,
|
||||
INSN_GOOD,
|
||||
INSN_GOOD_NO_SLOT
|
||||
};
|
||||
|
||||
typedef enum kprobe_insn (kprobe_decode_insn_t)(kprobe_opcode_t,
|
||||
struct arch_specific_insn *);
|
||||
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
|
||||
enum kprobe_insn thumb16_kprobe_decode_insn(kprobe_opcode_t,
|
||||
struct arch_specific_insn *);
|
||||
enum kprobe_insn thumb32_kprobe_decode_insn(kprobe_opcode_t,
|
||||
struct arch_specific_insn *);
|
||||
|
||||
#else /* !CONFIG_THUMB2_KERNEL */
|
||||
|
||||
enum kprobe_insn arm_kprobe_decode_insn(kprobe_opcode_t,
|
||||
struct arch_specific_insn *);
|
||||
#endif
|
||||
|
||||
void __init arm_kprobe_decode_init(void);
|
||||
|
||||
extern kprobe_check_cc * const kprobe_condition_checks[16];
|
||||
|
||||
|
||||
#if __LINUX_ARM_ARCH__ >= 7
|
||||
|
||||
/* str_pc_offset is architecturally defined from ARMv7 onwards */
|
||||
#define str_pc_offset 8
|
||||
#define find_str_pc_offset()
|
||||
|
||||
#else /* __LINUX_ARM_ARCH__ < 7 */
|
||||
|
||||
/* We need a run-time check to determine str_pc_offset */
|
||||
extern int str_pc_offset;
|
||||
void __init find_str_pc_offset(void);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Update ITSTATE after normal execution of an IT block instruction.
|
||||
*
|
||||
* The 8 IT state bits are split into two parts in CPSR:
|
||||
* ITSTATE<1:0> are in CPSR<26:25>
|
||||
* ITSTATE<7:2> are in CPSR<15:10>
|
||||
*/
|
||||
static inline unsigned long it_advance(unsigned long cpsr)
|
||||
{
|
||||
if ((cpsr & 0x06000400) == 0) {
|
||||
/* ITSTATE<2:0> == 0 means end of IT block, so clear IT state */
|
||||
cpsr &= ~PSR_IT_MASK;
|
||||
} else {
|
||||
/* We need to shift left ITSTATE<4:0> */
|
||||
const unsigned long mask = 0x06001c00; /* Mask ITSTATE<4:0> */
|
||||
unsigned long it = cpsr & mask;
|
||||
it <<= 1;
|
||||
it |= it >> (27 - 10); /* Carry ITSTATE<2> to correct place */
|
||||
it &= mask;
|
||||
cpsr &= ~mask;
|
||||
cpsr |= it;
|
||||
}
|
||||
return cpsr;
|
||||
}
|
||||
|
||||
static inline void __kprobes bx_write_pc(long pcv, struct pt_regs *regs)
|
||||
{
|
||||
long cpsr = regs->ARM_cpsr;
|
||||
if (pcv & 0x1) {
|
||||
cpsr |= PSR_T_BIT;
|
||||
pcv &= ~0x1;
|
||||
} else {
|
||||
cpsr &= ~PSR_T_BIT;
|
||||
pcv &= ~0x2; /* Avoid UNPREDICTABLE address allignment */
|
||||
}
|
||||
regs->ARM_cpsr = cpsr;
|
||||
regs->ARM_pc = pcv;
|
||||
}
|
||||
|
||||
|
||||
#if __LINUX_ARM_ARCH__ >= 6
|
||||
|
||||
/* Kernels built for >= ARMv6 should never run on <= ARMv5 hardware, so... */
|
||||
#define load_write_pc_interworks true
|
||||
#define test_load_write_pc_interworking()
|
||||
|
||||
#else /* __LINUX_ARM_ARCH__ < 6 */
|
||||
|
||||
/* We need run-time testing to determine if load_write_pc() should interwork. */
|
||||
extern bool load_write_pc_interworks;
|
||||
void __init test_load_write_pc_interworking(void);
|
||||
|
||||
#endif
|
||||
|
||||
static inline void __kprobes load_write_pc(long pcv, struct pt_regs *regs)
|
||||
{
|
||||
if (load_write_pc_interworks)
|
||||
bx_write_pc(pcv, regs);
|
||||
else
|
||||
regs->ARM_pc = pcv;
|
||||
}
|
||||
|
||||
|
||||
#if __LINUX_ARM_ARCH__ >= 7
|
||||
|
||||
#define alu_write_pc_interworks true
|
||||
#define test_alu_write_pc_interworking()
|
||||
|
||||
#elif __LINUX_ARM_ARCH__ <= 5
|
||||
|
||||
/* Kernels built for <= ARMv5 should never run on >= ARMv6 hardware, so... */
|
||||
#define alu_write_pc_interworks false
|
||||
#define test_alu_write_pc_interworking()
|
||||
|
||||
#else /* __LINUX_ARM_ARCH__ == 6 */
|
||||
|
||||
/* We could be an ARMv6 binary on ARMv7 hardware so we need a run-time check. */
|
||||
extern bool alu_write_pc_interworks;
|
||||
void __init test_alu_write_pc_interworking(void);
|
||||
|
||||
#endif /* __LINUX_ARM_ARCH__ == 6 */
|
||||
|
||||
static inline void __kprobes alu_write_pc(long pcv, struct pt_regs *regs)
|
||||
{
|
||||
if (alu_write_pc_interworks)
|
||||
bx_write_pc(pcv, regs);
|
||||
else
|
||||
regs->ARM_pc = pcv;
|
||||
}
|
||||
|
||||
|
||||
void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs);
|
||||
void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs);
|
||||
|
||||
enum kprobe_insn __kprobes
|
||||
kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi);
|
||||
|
||||
/*
|
||||
* Test if load/store instructions writeback the address register.
|
||||
* if P (bit 24) == 0 or W (bit 21) == 1
|
||||
*/
|
||||
#define is_writeback(insn) ((insn ^ 0x01000000) & 0x01200000)
|
||||
|
||||
/*
|
||||
* The following definitions and macros are used to build instruction
|
||||
* decoding tables for use by kprobe_decode_insn.
|
||||
*
|
||||
* These tables are a concatenation of entries each of which consist of one of
|
||||
* the decode_* structs. All of the fields in every type of decode structure
|
||||
* are of the union type decode_item, therefore the entire decode table can be
|
||||
* viewed as an array of these and declared like:
|
||||
*
|
||||
* static const union decode_item table_name[] = {};
|
||||
*
|
||||
* In order to construct each entry in the table, macros are used to
|
||||
* initialise a number of sequential decode_item values in a layout which
|
||||
* matches the relevant struct. E.g. DECODE_SIMULATE initialise a struct
|
||||
* decode_simulate by initialising four decode_item objects like this...
|
||||
*
|
||||
* {.bits = _type},
|
||||
* {.bits = _mask},
|
||||
* {.bits = _value},
|
||||
* {.handler = _handler},
|
||||
*
|
||||
* Initialising a specified member of the union means that the compiler
|
||||
* will produce a warning if the argument is of an incorrect type.
|
||||
*
|
||||
* Below is a list of each of the macros used to initialise entries and a
|
||||
* description of the action performed when that entry is matched to an
|
||||
* instruction. A match is found when (instruction & mask) == value.
|
||||
*
|
||||
* DECODE_TABLE(mask, value, table)
|
||||
* Instruction decoding jumps to parsing the new sub-table 'table'.
|
||||
*
|
||||
* DECODE_CUSTOM(mask, value, decoder)
|
||||
* The custom function 'decoder' is called to the complete decoding
|
||||
* of an instruction.
|
||||
*
|
||||
* DECODE_SIMULATE(mask, value, handler)
|
||||
* Set the probes instruction handler to 'handler', this will be used
|
||||
* to simulate the instruction when the probe is hit. Decoding returns
|
||||
* with INSN_GOOD_NO_SLOT.
|
||||
*
|
||||
* DECODE_EMULATE(mask, value, handler)
|
||||
* Set the probes instruction handler to 'handler', this will be used
|
||||
* to emulate the instruction when the probe is hit. The modified
|
||||
* instruction (see below) is placed in the probes instruction slot so it
|
||||
* may be called by the emulation code. Decoding returns with INSN_GOOD.
|
||||
*
|
||||
* DECODE_REJECT(mask, value)
|
||||
* Instruction decoding fails with INSN_REJECTED
|
||||
*
|
||||
* DECODE_OR(mask, value)
|
||||
* This allows the mask/value test of multiple table entries to be
|
||||
* logically ORed. Once an 'or' entry is matched the decoding action to
|
||||
* be performed is that of the next entry which isn't an 'or'. E.g.
|
||||
*
|
||||
* DECODE_OR (mask1, value1)
|
||||
* DECODE_OR (mask2, value2)
|
||||
* DECODE_SIMULATE (mask3, value3, simulation_handler)
|
||||
*
|
||||
* This means that if any of the three mask/value pairs match the
|
||||
* instruction being decoded, then 'simulation_handler' will be used
|
||||
* for it.
|
||||
*
|
||||
* Both the SIMULATE and EMULATE macros have a second form which take an
|
||||
* additional 'regs' argument.
|
||||
*
|
||||
* DECODE_SIMULATEX(mask, value, handler, regs)
|
||||
* DECODE_EMULATEX (mask, value, handler, regs)
|
||||
*
|
||||
* These are used to specify what kind of CPU register is encoded in each of the
|
||||
* least significant 5 nibbles of the instruction being decoded. The regs value
|
||||
* is specified using the REGS macro, this takes any of the REG_TYPE_* values
|
||||
* from enum decode_reg_type as arguments; only the '*' part of the name is
|
||||
* given. E.g.
|
||||
*
|
||||
* REGS(0, ANY, NOPC, 0, ANY)
|
||||
*
|
||||
* This indicates an instruction is encoded like:
|
||||
*
|
||||
* bits 19..16 ignore
|
||||
* bits 15..12 any register allowed here
|
||||
* bits 11.. 8 any register except PC allowed here
|
||||
* bits 7.. 4 ignore
|
||||
* bits 3.. 0 any register allowed here
|
||||
*
|
||||
* This register specification is checked after a decode table entry is found to
|
||||
* match an instruction (through the mask/value test). Any invalid register then
|
||||
* found in the instruction will cause decoding to fail with INSN_REJECTED. In
|
||||
* the above example this would happen if bits 11..8 of the instruction were
|
||||
* 1111, indicating R15 or PC.
|
||||
*
|
||||
* As well as checking for legal combinations of registers, this data is also
|
||||
* used to modify the registers encoded in the instructions so that an
|
||||
* emulation routines can use it. (See decode_regs() and INSN_NEW_BITS.)
|
||||
*
|
||||
* Here is a real example which matches ARM instructions of the form
|
||||
* "AND <Rd>,<Rn>,<Rm>,<shift> <Rs>"
|
||||
*
|
||||
* DECODE_EMULATEX (0x0e000090, 0x00000010, emulate_rd12rn16rm0rs8_rwflags,
|
||||
* REGS(ANY, ANY, NOPC, 0, ANY)),
|
||||
* ^ ^ ^ ^
|
||||
* Rn Rd Rs Rm
|
||||
*
|
||||
* Decoding the instruction "AND R4, R5, R6, ASL R15" will be rejected because
|
||||
* Rs == R15
|
||||
*
|
||||
* Decoding the instruction "AND R4, R5, R6, ASL R7" will be accepted and the
|
||||
* instruction will be modified to "AND R0, R2, R3, ASL R1" and then placed into
|
||||
* the kprobes instruction slot. This can then be called later by the handler
|
||||
* function emulate_rd12rn16rm0rs8_rwflags in order to simulate the instruction.
|
||||
*/
|
||||
|
||||
enum decode_type {
|
||||
DECODE_TYPE_END,
|
||||
DECODE_TYPE_TABLE,
|
||||
DECODE_TYPE_CUSTOM,
|
||||
DECODE_TYPE_SIMULATE,
|
||||
DECODE_TYPE_EMULATE,
|
||||
DECODE_TYPE_OR,
|
||||
DECODE_TYPE_REJECT,
|
||||
NUM_DECODE_TYPES /* Must be last enum */
|
||||
};
|
||||
|
||||
#define DECODE_TYPE_BITS 4
|
||||
#define DECODE_TYPE_MASK ((1 << DECODE_TYPE_BITS) - 1)
|
||||
|
||||
enum decode_reg_type {
|
||||
REG_TYPE_NONE = 0, /* Not a register, ignore */
|
||||
REG_TYPE_ANY, /* Any register allowed */
|
||||
REG_TYPE_SAMEAS16, /* Register should be same as that at bits 19..16 */
|
||||
REG_TYPE_SP, /* Register must be SP */
|
||||
REG_TYPE_PC, /* Register must be PC */
|
||||
REG_TYPE_NOSP, /* Register must not be SP */
|
||||
REG_TYPE_NOSPPC, /* Register must not be SP or PC */
|
||||
REG_TYPE_NOPC, /* Register must not be PC */
|
||||
REG_TYPE_NOPCWB, /* No PC if load/store write-back flag also set */
|
||||
|
||||
/* The following types are used when the encoding for PC indicates
|
||||
* another instruction form. This distiction only matters for test
|
||||
* case coverage checks.
|
||||
*/
|
||||
REG_TYPE_NOPCX, /* Register must not be PC */
|
||||
REG_TYPE_NOSPPCX, /* Register must not be SP or PC */
|
||||
|
||||
/* Alias to allow '0' arg to be used in REGS macro. */
|
||||
REG_TYPE_0 = REG_TYPE_NONE
|
||||
};
|
||||
|
||||
#define REGS(r16, r12, r8, r4, r0) \
|
||||
((REG_TYPE_##r16) << 16) + \
|
||||
((REG_TYPE_##r12) << 12) + \
|
||||
((REG_TYPE_##r8) << 8) + \
|
||||
((REG_TYPE_##r4) << 4) + \
|
||||
(REG_TYPE_##r0)
|
||||
|
||||
union decode_item {
|
||||
u32 bits;
|
||||
const union decode_item *table;
|
||||
kprobe_insn_handler_t *handler;
|
||||
kprobe_decode_insn_t *decoder;
|
||||
};
|
||||
|
||||
|
||||
#define DECODE_END \
|
||||
{.bits = DECODE_TYPE_END}
|
||||
|
||||
|
||||
struct decode_header {
|
||||
union decode_item type_regs;
|
||||
union decode_item mask;
|
||||
union decode_item value;
|
||||
};
|
||||
|
||||
#define DECODE_HEADER(_type, _mask, _value, _regs) \
|
||||
{.bits = (_type) | ((_regs) << DECODE_TYPE_BITS)}, \
|
||||
{.bits = (_mask)}, \
|
||||
{.bits = (_value)}
|
||||
|
||||
|
||||
struct decode_table {
|
||||
struct decode_header header;
|
||||
union decode_item table;
|
||||
};
|
||||
|
||||
#define DECODE_TABLE(_mask, _value, _table) \
|
||||
DECODE_HEADER(DECODE_TYPE_TABLE, _mask, _value, 0), \
|
||||
{.table = (_table)}
|
||||
|
||||
|
||||
struct decode_custom {
|
||||
struct decode_header header;
|
||||
union decode_item decoder;
|
||||
};
|
||||
|
||||
#define DECODE_CUSTOM(_mask, _value, _decoder) \
|
||||
DECODE_HEADER(DECODE_TYPE_CUSTOM, _mask, _value, 0), \
|
||||
{.decoder = (_decoder)}
|
||||
|
||||
|
||||
struct decode_simulate {
|
||||
struct decode_header header;
|
||||
union decode_item handler;
|
||||
};
|
||||
|
||||
#define DECODE_SIMULATEX(_mask, _value, _handler, _regs) \
|
||||
DECODE_HEADER(DECODE_TYPE_SIMULATE, _mask, _value, _regs), \
|
||||
{.handler = (_handler)}
|
||||
|
||||
#define DECODE_SIMULATE(_mask, _value, _handler) \
|
||||
DECODE_SIMULATEX(_mask, _value, _handler, 0)
|
||||
|
||||
|
||||
struct decode_emulate {
|
||||
struct decode_header header;
|
||||
union decode_item handler;
|
||||
};
|
||||
|
||||
#define DECODE_EMULATEX(_mask, _value, _handler, _regs) \
|
||||
DECODE_HEADER(DECODE_TYPE_EMULATE, _mask, _value, _regs), \
|
||||
{.handler = (_handler)}
|
||||
|
||||
#define DECODE_EMULATE(_mask, _value, _handler) \
|
||||
DECODE_EMULATEX(_mask, _value, _handler, 0)
|
||||
|
||||
|
||||
struct decode_or {
|
||||
struct decode_header header;
|
||||
};
|
||||
|
||||
#define DECODE_OR(_mask, _value) \
|
||||
DECODE_HEADER(DECODE_TYPE_OR, _mask, _value, 0)
|
||||
|
||||
|
||||
struct decode_reject {
|
||||
struct decode_header header;
|
||||
};
|
||||
|
||||
#define DECODE_REJECT(_mask, _value) \
|
||||
DECODE_HEADER(DECODE_TYPE_REJECT, _mask, _value, 0)
|
||||
|
||||
|
||||
int kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi,
|
||||
const union decode_item *table, bool thumb16);
|
||||
|
||||
|
||||
#endif /* _ARM_KERNEL_KPROBES_H */
|
|
@ -662,6 +662,12 @@ init_hw_perf_events(void)
|
|||
case 0xC090: /* Cortex-A9 */
|
||||
armpmu = armv7_a9_pmu_init();
|
||||
break;
|
||||
case 0xC050: /* Cortex-A5 */
|
||||
armpmu = armv7_a5_pmu_init();
|
||||
break;
|
||||
case 0xC0F0: /* Cortex-A15 */
|
||||
armpmu = armv7_a15_pmu_init();
|
||||
break;
|
||||
}
|
||||
/* Intel CPUs [xscale]. */
|
||||
} else if (0x69 == implementor) {
|
||||
|
|
|
@ -17,17 +17,23 @@
|
|||
*/
|
||||
|
||||
#ifdef CONFIG_CPU_V7
|
||||
/* Common ARMv7 event types */
|
||||
/*
|
||||
* Common ARMv7 event types
|
||||
*
|
||||
* Note: An implementation may not be able to count all of these events
|
||||
* but the encodings are considered to be `reserved' in the case that
|
||||
* they are not available.
|
||||
*/
|
||||
enum armv7_perf_types {
|
||||
ARMV7_PERFCTR_PMNC_SW_INCR = 0x00,
|
||||
ARMV7_PERFCTR_IFETCH_MISS = 0x01,
|
||||
ARMV7_PERFCTR_ITLB_MISS = 0x02,
|
||||
ARMV7_PERFCTR_DCACHE_REFILL = 0x03,
|
||||
ARMV7_PERFCTR_DCACHE_ACCESS = 0x04,
|
||||
ARMV7_PERFCTR_DCACHE_REFILL = 0x03, /* L1 */
|
||||
ARMV7_PERFCTR_DCACHE_ACCESS = 0x04, /* L1 */
|
||||
ARMV7_PERFCTR_DTLB_REFILL = 0x05,
|
||||
ARMV7_PERFCTR_DREAD = 0x06,
|
||||
ARMV7_PERFCTR_DWRITE = 0x07,
|
||||
|
||||
ARMV7_PERFCTR_INSTR_EXECUTED = 0x08,
|
||||
ARMV7_PERFCTR_EXC_TAKEN = 0x09,
|
||||
ARMV7_PERFCTR_EXC_EXECUTED = 0x0A,
|
||||
ARMV7_PERFCTR_CID_WRITE = 0x0B,
|
||||
|
@ -39,21 +45,30 @@ enum armv7_perf_types {
|
|||
*/
|
||||
ARMV7_PERFCTR_PC_WRITE = 0x0C,
|
||||
ARMV7_PERFCTR_PC_IMM_BRANCH = 0x0D,
|
||||
ARMV7_PERFCTR_PC_PROC_RETURN = 0x0E,
|
||||
ARMV7_PERFCTR_UNALIGNED_ACCESS = 0x0F,
|
||||
|
||||
/* These events are defined by the PMUv2 supplement (ARM DDI 0457A). */
|
||||
ARMV7_PERFCTR_PC_BRANCH_MIS_PRED = 0x10,
|
||||
ARMV7_PERFCTR_CLOCK_CYCLES = 0x11,
|
||||
|
||||
ARMV7_PERFCTR_PC_BRANCH_MIS_USED = 0x12,
|
||||
ARMV7_PERFCTR_PC_BRANCH_PRED = 0x12,
|
||||
ARMV7_PERFCTR_MEM_ACCESS = 0x13,
|
||||
ARMV7_PERFCTR_L1_ICACHE_ACCESS = 0x14,
|
||||
ARMV7_PERFCTR_L1_DCACHE_WB = 0x15,
|
||||
ARMV7_PERFCTR_L2_DCACHE_ACCESS = 0x16,
|
||||
ARMV7_PERFCTR_L2_DCACHE_REFILL = 0x17,
|
||||
ARMV7_PERFCTR_L2_DCACHE_WB = 0x18,
|
||||
ARMV7_PERFCTR_BUS_ACCESS = 0x19,
|
||||
ARMV7_PERFCTR_MEMORY_ERROR = 0x1A,
|
||||
ARMV7_PERFCTR_INSTR_SPEC = 0x1B,
|
||||
ARMV7_PERFCTR_TTBR_WRITE = 0x1C,
|
||||
ARMV7_PERFCTR_BUS_CYCLES = 0x1D,
|
||||
|
||||
ARMV7_PERFCTR_CPU_CYCLES = 0xFF
|
||||
};
|
||||
|
||||
/* ARMv7 Cortex-A8 specific event types */
|
||||
enum armv7_a8_perf_types {
|
||||
ARMV7_PERFCTR_INSTR_EXECUTED = 0x08,
|
||||
|
||||
ARMV7_PERFCTR_PC_PROC_RETURN = 0x0E,
|
||||
|
||||
ARMV7_PERFCTR_WRITE_BUFFER_FULL = 0x40,
|
||||
ARMV7_PERFCTR_L2_STORE_MERGED = 0x41,
|
||||
ARMV7_PERFCTR_L2_STORE_BUFF = 0x42,
|
||||
|
@ -138,6 +153,39 @@ enum armv7_a9_perf_types {
|
|||
ARMV7_PERFCTR_PLE_RQST_PROG = 0xA5
|
||||
};
|
||||
|
||||
/* ARMv7 Cortex-A5 specific event types */
|
||||
enum armv7_a5_perf_types {
|
||||
ARMV7_PERFCTR_IRQ_TAKEN = 0x86,
|
||||
ARMV7_PERFCTR_FIQ_TAKEN = 0x87,
|
||||
|
||||
ARMV7_PERFCTR_EXT_MEM_RQST = 0xc0,
|
||||
ARMV7_PERFCTR_NC_EXT_MEM_RQST = 0xc1,
|
||||
ARMV7_PERFCTR_PREFETCH_LINEFILL = 0xc2,
|
||||
ARMV7_PERFCTR_PREFETCH_LINEFILL_DROP = 0xc3,
|
||||
ARMV7_PERFCTR_ENTER_READ_ALLOC = 0xc4,
|
||||
ARMV7_PERFCTR_READ_ALLOC = 0xc5,
|
||||
|
||||
ARMV7_PERFCTR_STALL_SB_FULL = 0xc9,
|
||||
};
|
||||
|
||||
/* ARMv7 Cortex-A15 specific event types */
|
||||
enum armv7_a15_perf_types {
|
||||
ARMV7_PERFCTR_L1_DCACHE_READ_ACCESS = 0x40,
|
||||
ARMV7_PERFCTR_L1_DCACHE_WRITE_ACCESS = 0x41,
|
||||
ARMV7_PERFCTR_L1_DCACHE_READ_REFILL = 0x42,
|
||||
ARMV7_PERFCTR_L1_DCACHE_WRITE_REFILL = 0x43,
|
||||
|
||||
ARMV7_PERFCTR_L1_DTLB_READ_REFILL = 0x4C,
|
||||
ARMV7_PERFCTR_L1_DTLB_WRITE_REFILL = 0x4D,
|
||||
|
||||
ARMV7_PERFCTR_L2_DCACHE_READ_ACCESS = 0x50,
|
||||
ARMV7_PERFCTR_L2_DCACHE_WRITE_ACCESS = 0x51,
|
||||
ARMV7_PERFCTR_L2_DCACHE_READ_REFILL = 0x52,
|
||||
ARMV7_PERFCTR_L2_DCACHE_WRITE_REFILL = 0x53,
|
||||
|
||||
ARMV7_PERFCTR_SPEC_PC_WRITE = 0x76,
|
||||
};
|
||||
|
||||
/*
|
||||
* Cortex-A8 HW events mapping
|
||||
*
|
||||
|
@ -207,11 +255,6 @@ static const unsigned armv7_a8_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
|
|||
},
|
||||
},
|
||||
[C(DTLB)] = {
|
||||
/*
|
||||
* Only ITLB misses and DTLB refills are supported.
|
||||
* If users want the DTLB refills misses a raw counter
|
||||
* must be used.
|
||||
*/
|
||||
[C(OP_READ)] = {
|
||||
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
|
||||
[C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL,
|
||||
|
@ -323,11 +366,6 @@ static const unsigned armv7_a9_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
|
|||
},
|
||||
},
|
||||
[C(DTLB)] = {
|
||||
/*
|
||||
* Only ITLB misses and DTLB refills are supported.
|
||||
* If users want the DTLB refills misses a raw counter
|
||||
* must be used.
|
||||
*/
|
||||
[C(OP_READ)] = {
|
||||
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
|
||||
[C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL,
|
||||
|
@ -373,6 +411,242 @@ static const unsigned armv7_a9_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
|
|||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Cortex-A5 HW events mapping
|
||||
*/
|
||||
static const unsigned armv7_a5_perf_map[PERF_COUNT_HW_MAX] = {
|
||||
[PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES,
|
||||
[PERF_COUNT_HW_INSTRUCTIONS] = ARMV7_PERFCTR_INSTR_EXECUTED,
|
||||
[PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED,
|
||||
[PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED,
|
||||
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_PC_WRITE,
|
||||
[PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
|
||||
[PERF_COUNT_HW_BUS_CYCLES] = HW_OP_UNSUPPORTED,
|
||||
};
|
||||
|
||||
static const unsigned armv7_a5_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
|
||||
[PERF_COUNT_HW_CACHE_OP_MAX]
|
||||
[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
|
||||
[C(L1D)] = {
|
||||
[C(OP_READ)] = {
|
||||
[C(RESULT_ACCESS)]
|
||||
= ARMV7_PERFCTR_DCACHE_ACCESS,
|
||||
[C(RESULT_MISS)]
|
||||
= ARMV7_PERFCTR_DCACHE_REFILL,
|
||||
},
|
||||
[C(OP_WRITE)] = {
|
||||
[C(RESULT_ACCESS)]
|
||||
= ARMV7_PERFCTR_DCACHE_ACCESS,
|
||||
[C(RESULT_MISS)]
|
||||
= ARMV7_PERFCTR_DCACHE_REFILL,
|
||||
},
|
||||
[C(OP_PREFETCH)] = {
|
||||
[C(RESULT_ACCESS)]
|
||||
= ARMV7_PERFCTR_PREFETCH_LINEFILL,
|
||||
[C(RESULT_MISS)]
|
||||
= ARMV7_PERFCTR_PREFETCH_LINEFILL_DROP,
|
||||
},
|
||||
},
|
||||
[C(L1I)] = {
|
||||
[C(OP_READ)] = {
|
||||
[C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS,
|
||||
[C(RESULT_MISS)] = ARMV7_PERFCTR_IFETCH_MISS,
|
||||
},
|
||||
[C(OP_WRITE)] = {
|
||||
[C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS,
|
||||
[C(RESULT_MISS)] = ARMV7_PERFCTR_IFETCH_MISS,
|
||||
},
|
||||
/*
|
||||
* The prefetch counters don't differentiate between the I
|
||||
* side and the D side.
|
||||
*/
|
||||
[C(OP_PREFETCH)] = {
|
||||
[C(RESULT_ACCESS)]
|
||||
= ARMV7_PERFCTR_PREFETCH_LINEFILL,
|
||||
[C(RESULT_MISS)]
|
||||
= ARMV7_PERFCTR_PREFETCH_LINEFILL_DROP,
|
||||
},
|
||||
},
|
||||
[C(LL)] = {
|
||||
[C(OP_READ)] = {
|
||||
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
|
||||
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
|
||||
},
|
||||
[C(OP_WRITE)] = {
|
||||
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
|
||||
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
|
||||
},
|
||||
[C(OP_PREFETCH)] = {
|
||||
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
|
||||
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
|
||||
},
|
||||
},
|
||||
[C(DTLB)] = {
|
||||
[C(OP_READ)] = {
|
||||
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
|
||||
[C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL,
|
||||
},
|
||||
[C(OP_WRITE)] = {
|
||||
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
|
||||
[C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL,
|
||||
},
|
||||
[C(OP_PREFETCH)] = {
|
||||
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
|
||||
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
|
||||
},
|
||||
},
|
||||
[C(ITLB)] = {
|
||||
[C(OP_READ)] = {
|
||||
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
|
||||
[C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS,
|
||||
},
|
||||
[C(OP_WRITE)] = {
|
||||
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
|
||||
[C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS,
|
||||
},
|
||||
[C(OP_PREFETCH)] = {
|
||||
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
|
||||
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
|
||||
},
|
||||
},
|
||||
[C(BPU)] = {
|
||||
[C(OP_READ)] = {
|
||||
[C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED,
|
||||
[C(RESULT_MISS)]
|
||||
= ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
|
||||
},
|
||||
[C(OP_WRITE)] = {
|
||||
[C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED,
|
||||
[C(RESULT_MISS)]
|
||||
= ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
|
||||
},
|
||||
[C(OP_PREFETCH)] = {
|
||||
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
|
||||
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Cortex-A15 HW events mapping
|
||||
*/
|
||||
static const unsigned armv7_a15_perf_map[PERF_COUNT_HW_MAX] = {
|
||||
[PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES,
|
||||
[PERF_COUNT_HW_INSTRUCTIONS] = ARMV7_PERFCTR_INSTR_EXECUTED,
|
||||
[PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED,
|
||||
[PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED,
|
||||
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_SPEC_PC_WRITE,
|
||||
[PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
|
||||
[PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_BUS_CYCLES,
|
||||
};
|
||||
|
||||
static const unsigned armv7_a15_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
|
||||
[PERF_COUNT_HW_CACHE_OP_MAX]
|
||||
[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
|
||||
[C(L1D)] = {
|
||||
[C(OP_READ)] = {
|
||||
[C(RESULT_ACCESS)]
|
||||
= ARMV7_PERFCTR_L1_DCACHE_READ_ACCESS,
|
||||
[C(RESULT_MISS)]
|
||||
= ARMV7_PERFCTR_L1_DCACHE_READ_REFILL,
|
||||
},
|
||||
[C(OP_WRITE)] = {
|
||||
[C(RESULT_ACCESS)]
|
||||
= ARMV7_PERFCTR_L1_DCACHE_WRITE_ACCESS,
|
||||
[C(RESULT_MISS)]
|
||||
= ARMV7_PERFCTR_L1_DCACHE_WRITE_REFILL,
|
||||
},
|
||||
[C(OP_PREFETCH)] = {
|
||||
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
|
||||
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
|
||||
},
|
||||
},
|
||||
[C(L1I)] = {
|
||||
/*
|
||||
* Not all performance counters differentiate between read
|
||||
* and write accesses/misses so we're not always strictly
|
||||
* correct, but it's the best we can do. Writes and reads get
|
||||
* combined in these cases.
|
||||
*/
|
||||
[C(OP_READ)] = {
|
||||
[C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS,
|
||||
[C(RESULT_MISS)] = ARMV7_PERFCTR_IFETCH_MISS,
|
||||
},
|
||||
[C(OP_WRITE)] = {
|
||||
[C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS,
|
||||
[C(RESULT_MISS)] = ARMV7_PERFCTR_IFETCH_MISS,
|
||||
},
|
||||
[C(OP_PREFETCH)] = {
|
||||
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
|
||||
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
|
||||
},
|
||||
},
|
||||
[C(LL)] = {
|
||||
[C(OP_READ)] = {
|
||||
[C(RESULT_ACCESS)]
|
||||
= ARMV7_PERFCTR_L2_DCACHE_READ_ACCESS,
|
||||
[C(RESULT_MISS)]
|
||||
= ARMV7_PERFCTR_L2_DCACHE_READ_REFILL,
|
||||
},
|
||||
[C(OP_WRITE)] = {
|
||||
[C(RESULT_ACCESS)]
|
||||
= ARMV7_PERFCTR_L2_DCACHE_WRITE_ACCESS,
|
||||
[C(RESULT_MISS)]
|
||||
= ARMV7_PERFCTR_L2_DCACHE_WRITE_REFILL,
|
||||
},
|
||||
[C(OP_PREFETCH)] = {
|
||||
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
|
||||
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
|
||||
},
|
||||
},
|
||||
[C(DTLB)] = {
|
||||
[C(OP_READ)] = {
|
||||
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
|
||||
[C(RESULT_MISS)]
|
||||
= ARMV7_PERFCTR_L1_DTLB_READ_REFILL,
|
||||
},
|
||||
[C(OP_WRITE)] = {
|
||||
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
|
||||
[C(RESULT_MISS)]
|
||||
= ARMV7_PERFCTR_L1_DTLB_WRITE_REFILL,
|
||||
},
|
||||
[C(OP_PREFETCH)] = {
|
||||
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
|
||||
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
|
||||
},
|
||||
},
|
||||
[C(ITLB)] = {
|
||||
[C(OP_READ)] = {
|
||||
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
|
||||
[C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS,
|
||||
},
|
||||
[C(OP_WRITE)] = {
|
||||
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
|
||||
[C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_MISS,
|
||||
},
|
||||
[C(OP_PREFETCH)] = {
|
||||
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
|
||||
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
|
||||
},
|
||||
},
|
||||
[C(BPU)] = {
|
||||
[C(OP_READ)] = {
|
||||
[C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED,
|
||||
[C(RESULT_MISS)]
|
||||
= ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
|
||||
},
|
||||
[C(OP_WRITE)] = {
|
||||
[C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED,
|
||||
[C(RESULT_MISS)]
|
||||
= ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
|
||||
},
|
||||
[C(OP_PREFETCH)] = {
|
||||
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
|
||||
[C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Perf Events counters
|
||||
*/
|
||||
|
@ -905,6 +1179,26 @@ static const struct arm_pmu *__init armv7_a9_pmu_init(void)
|
|||
armv7pmu.num_events = armv7_read_num_pmnc_events();
|
||||
return &armv7pmu;
|
||||
}
|
||||
|
||||
static const struct arm_pmu *__init armv7_a5_pmu_init(void)
|
||||
{
|
||||
armv7pmu.id = ARM_PERF_PMU_ID_CA5;
|
||||
armv7pmu.name = "ARMv7 Cortex-A5";
|
||||
armv7pmu.cache_map = &armv7_a5_perf_cache_map;
|
||||
armv7pmu.event_map = &armv7_a5_perf_map;
|
||||
armv7pmu.num_events = armv7_read_num_pmnc_events();
|
||||
return &armv7pmu;
|
||||
}
|
||||
|
||||
static const struct arm_pmu *__init armv7_a15_pmu_init(void)
|
||||
{
|
||||
armv7pmu.id = ARM_PERF_PMU_ID_CA15;
|
||||
armv7pmu.name = "ARMv7 Cortex-A15";
|
||||
armv7pmu.cache_map = &armv7_a15_perf_cache_map;
|
||||
armv7pmu.event_map = &armv7_a15_perf_map;
|
||||
armv7pmu.num_events = armv7_read_num_pmnc_events();
|
||||
return &armv7pmu;
|
||||
}
|
||||
#else
|
||||
static const struct arm_pmu *__init armv7_a8_pmu_init(void)
|
||||
{
|
||||
|
@ -915,4 +1209,14 @@ static const struct arm_pmu *__init armv7_a9_pmu_init(void)
|
|||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const struct arm_pmu *__init armv7_a5_pmu_init(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const struct arm_pmu *__init armv7_a15_pmu_init(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_CPU_V7 */
|
||||
|
|
|
@ -228,34 +228,12 @@ static struct undef_hook thumb_break_hook = {
|
|||
.fn = break_trap,
|
||||
};
|
||||
|
||||
static int thumb2_break_trap(struct pt_regs *regs, unsigned int instr)
|
||||
{
|
||||
unsigned int instr2;
|
||||
void __user *pc;
|
||||
|
||||
/* Check the second half of the instruction. */
|
||||
pc = (void __user *)(instruction_pointer(regs) + 2);
|
||||
|
||||
if (processor_mode(regs) == SVC_MODE) {
|
||||
instr2 = *(u16 *) pc;
|
||||
} else {
|
||||
get_user(instr2, (u16 __user *)pc);
|
||||
}
|
||||
|
||||
if (instr2 == 0xa000) {
|
||||
ptrace_break(current, regs);
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static struct undef_hook thumb2_break_hook = {
|
||||
.instr_mask = 0xffff,
|
||||
.instr_val = 0xf7f0,
|
||||
.instr_mask = 0xffffffff,
|
||||
.instr_val = 0xf7f0a000,
|
||||
.cpsr_mask = PSR_T_BIT,
|
||||
.cpsr_val = PSR_T_BIT,
|
||||
.fn = thumb2_break_trap,
|
||||
.fn = break_trap,
|
||||
};
|
||||
|
||||
static int __init ptrace_break_init(void)
|
||||
|
|
|
@ -919,6 +919,12 @@ 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
|
||||
|
@ -980,6 +986,10 @@ static const char *hwcap_str[] = {
|
|||
"neon",
|
||||
"vfpv3",
|
||||
"vfpv3d16",
|
||||
"tls",
|
||||
"vfpv4",
|
||||
"idiva",
|
||||
"idivt",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
|
@ -355,9 +355,24 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
|
|||
pc = (void __user *)instruction_pointer(regs);
|
||||
|
||||
if (processor_mode(regs) == SVC_MODE) {
|
||||
instr = *(u32 *) pc;
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
if (thumb_mode(regs)) {
|
||||
instr = ((u16 *)pc)[0];
|
||||
if (is_wide_instruction(instr)) {
|
||||
instr <<= 16;
|
||||
instr |= ((u16 *)pc)[1];
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
instr = *(u32 *) pc;
|
||||
} else if (thumb_mode(regs)) {
|
||||
get_user(instr, (u16 __user *)pc);
|
||||
if (is_wide_instruction(instr)) {
|
||||
unsigned int instr2;
|
||||
get_user(instr2, (u16 __user *)pc+1);
|
||||
instr <<= 16;
|
||||
instr |= instr2;
|
||||
}
|
||||
} else {
|
||||
get_user(instr, (u32 __user *)pc);
|
||||
}
|
||||
|
|
|
@ -681,4 +681,5 @@ MACHINE_START(DAVINCI_DA830_EVM, "DaVinci DA830/OMAP-L137/AM17x EVM")
|
|||
.init_irq = cp_intc_init,
|
||||
.timer = &davinci_timer,
|
||||
.init_machine = da830_evm_init,
|
||||
.dma_zone_size = SZ_128M,
|
||||
MACHINE_END
|
||||
|
|
|
@ -1261,4 +1261,5 @@ MACHINE_START(DAVINCI_DA850_EVM, "DaVinci DA850/OMAP-L138/AM18x EVM")
|
|||
.init_irq = cp_intc_init,
|
||||
.timer = &davinci_timer,
|
||||
.init_machine = da850_evm_init,
|
||||
.dma_zone_size = SZ_128M,
|
||||
MACHINE_END
|
||||
|
|
|
@ -356,4 +356,5 @@ MACHINE_START(DAVINCI_DM355_EVM, "DaVinci DM355 EVM")
|
|||
.init_irq = davinci_irq_init,
|
||||
.timer = &davinci_timer,
|
||||
.init_machine = dm355_evm_init,
|
||||
.dma_zone_size = SZ_128M,
|
||||
MACHINE_END
|
||||
|
|
|
@ -275,4 +275,5 @@ MACHINE_START(DM355_LEOPARD, "DaVinci DM355 leopard")
|
|||
.init_irq = davinci_irq_init,
|
||||
.timer = &davinci_timer,
|
||||
.init_machine = dm355_leopard_init,
|
||||
.dma_zone_size = SZ_128M,
|
||||
MACHINE_END
|
||||
|
|
|
@ -617,5 +617,6 @@ MACHINE_START(DAVINCI_DM365_EVM, "DaVinci DM365 EVM")
|
|||
.init_irq = davinci_irq_init,
|
||||
.timer = &davinci_timer,
|
||||
.init_machine = dm365_evm_init,
|
||||
.dma_zone_size = SZ_128M,
|
||||
MACHINE_END
|
||||
|
||||
|
|
|
@ -717,4 +717,5 @@ MACHINE_START(DAVINCI_EVM, "DaVinci DM644x EVM")
|
|||
.init_irq = davinci_irq_init,
|
||||
.timer = &davinci_timer,
|
||||
.init_machine = davinci_evm_init,
|
||||
.dma_zone_size = SZ_128M,
|
||||
MACHINE_END
|
||||
|
|
|
@ -802,6 +802,7 @@ MACHINE_START(DAVINCI_DM6467_EVM, "DaVinci DM646x EVM")
|
|||
.init_irq = davinci_irq_init,
|
||||
.timer = &davinci_timer,
|
||||
.init_machine = evm_init,
|
||||
.dma_zone_size = SZ_128M,
|
||||
MACHINE_END
|
||||
|
||||
MACHINE_START(DAVINCI_DM6467TEVM, "DaVinci DM6467T EVM")
|
||||
|
@ -810,5 +811,6 @@ MACHINE_START(DAVINCI_DM6467TEVM, "DaVinci DM6467T EVM")
|
|||
.init_irq = davinci_irq_init,
|
||||
.timer = &davinci_timer,
|
||||
.init_machine = evm_init,
|
||||
.dma_zone_size = SZ_128M,
|
||||
MACHINE_END
|
||||
|
||||
|
|
|
@ -570,4 +570,5 @@ MACHINE_START(MITYOMAPL138, "MityDSP-L138/MityARM-1808")
|
|||
.init_irq = cp_intc_init,
|
||||
.timer = &davinci_timer,
|
||||
.init_machine = mityomapl138_init,
|
||||
.dma_zone_size = SZ_128M,
|
||||
MACHINE_END
|
||||
|
|
|
@ -277,4 +277,5 @@ MACHINE_START(NEUROS_OSD2, "Neuros OSD2")
|
|||
.init_irq = davinci_irq_init,
|
||||
.timer = &davinci_timer,
|
||||
.init_machine = davinci_ntosd2_init,
|
||||
.dma_zone_size = SZ_128M,
|
||||
MACHINE_END
|
||||
|
|
|
@ -343,4 +343,5 @@ MACHINE_START(OMAPL138_HAWKBOARD, "AM18x/OMAP-L138 Hawkboard")
|
|||
.init_irq = cp_intc_init,
|
||||
.timer = &davinci_timer,
|
||||
.init_machine = omapl138_hawk_init,
|
||||
.dma_zone_size = SZ_128M,
|
||||
MACHINE_END
|
||||
|
|
|
@ -156,4 +156,5 @@ MACHINE_START(SFFSDR, "Lyrtech SFFSDR")
|
|||
.init_irq = davinci_irq_init,
|
||||
.timer = &davinci_timer,
|
||||
.init_machine = davinci_sffsdr_init,
|
||||
.dma_zone_size = SZ_128M,
|
||||
MACHINE_END
|
||||
|
|
|
@ -282,4 +282,5 @@ MACHINE_START(TNETV107X, "TNETV107X EVM")
|
|||
.init_irq = cp_intc_init,
|
||||
.timer = &davinci_timer,
|
||||
.init_machine = tnetv107x_evm_board_init,
|
||||
.dma_zone_size = SZ_128M,
|
||||
MACHINE_END
|
||||
|
|
|
@ -41,11 +41,4 @@
|
|||
*/
|
||||
#define CONSISTENT_DMA_SIZE (14<<20)
|
||||
|
||||
/*
|
||||
* Restrict DMA-able region to workaround silicon bug. The bug
|
||||
* restricts buffers available for DMA to video hardware to be
|
||||
* below 128M
|
||||
*/
|
||||
#define ARM_DMA_ZONE_SIZE SZ_128M
|
||||
|
||||
#endif /* __ASM_ARCH_MEMORY_H */
|
||||
|
|
|
@ -33,4 +33,5 @@ MACHINE_START(H7201, "Hynix GMS30C7201")
|
|||
.map_io = h720x_map_io,
|
||||
.init_irq = h720x_init_irq,
|
||||
.timer = &h7201_timer,
|
||||
.dma_zone_size = SZ_256M,
|
||||
MACHINE_END
|
||||
|
|
|
@ -76,4 +76,5 @@ MACHINE_START(H7202, "Hynix HMS30C7202")
|
|||
.init_irq = h7202_init_irq,
|
||||
.timer = &h7202_timer,
|
||||
.init_machine = init_eval_h7202,
|
||||
.dma_zone_size = SZ_256M,
|
||||
MACHINE_END
|
||||
|
|
|
@ -8,11 +8,4 @@
|
|||
#define __ASM_ARCH_MEMORY_H
|
||||
|
||||
#define PLAT_PHYS_OFFSET UL(0x40000000)
|
||||
/*
|
||||
* This is the maximum DMA address that can be DMAd to.
|
||||
* There should not be more than (0xd0000000 - 0xc0000000)
|
||||
* bytes of RAM.
|
||||
*/
|
||||
#define ARM_DMA_ZONE_SIZE SZ_256M
|
||||
|
||||
#endif
|
||||
|
|
|
@ -169,6 +169,9 @@ MACHINE_START(AVILA, "Gateworks Avila Network Platform")
|
|||
.timer = &ixp4xx_timer,
|
||||
.boot_params = 0x0100,
|
||||
.init_machine = avila_init,
|
||||
#if defined(CONFIG_PCI)
|
||||
.dma_zone_size = SZ_64M,
|
||||
#endif
|
||||
MACHINE_END
|
||||
|
||||
/*
|
||||
|
@ -184,6 +187,9 @@ MACHINE_START(LOFT, "Giant Shoulder Inc Loft board")
|
|||
.timer = &ixp4xx_timer,
|
||||
.boot_params = 0x0100,
|
||||
.init_machine = avila_init,
|
||||
#if defined(CONFIG_PCI)
|
||||
.dma_zone_size = SZ_64M,
|
||||
#endif
|
||||
MACHINE_END
|
||||
#endif
|
||||
|
||||
|
|
|
@ -114,6 +114,9 @@ MACHINE_START(ADI_COYOTE, "ADI Engineering Coyote")
|
|||
.timer = &ixp4xx_timer,
|
||||
.boot_params = 0x0100,
|
||||
.init_machine = coyote_init,
|
||||
#if defined(CONFIG_PCI)
|
||||
.dma_zone_size = SZ_64M,
|
||||
#endif
|
||||
MACHINE_END
|
||||
#endif
|
||||
|
||||
|
|
|
@ -284,4 +284,7 @@ MACHINE_START(DSMG600, "D-Link DSM-G600 RevA")
|
|||
.init_irq = ixp4xx_init_irq,
|
||||
.timer = &dsmg600_timer,
|
||||
.init_machine = dsmg600_init,
|
||||
#if defined(CONFIG_PCI)
|
||||
.dma_zone_size = SZ_64M,
|
||||
#endif
|
||||
MACHINE_END
|
||||
|
|
|
@ -275,5 +275,8 @@ MACHINE_START(FSG, "Freecom FSG-3")
|
|||
.timer = &ixp4xx_timer,
|
||||
.boot_params = 0x0100,
|
||||
.init_machine = fsg_init,
|
||||
#if defined(CONFIG_PCI)
|
||||
.dma_zone_size = SZ_64M,
|
||||
#endif
|
||||
MACHINE_END
|
||||
|
||||
|
|
|
@ -101,5 +101,8 @@ MACHINE_START(GATEWAY7001, "Gateway 7001 AP")
|
|||
.timer = &ixp4xx_timer,
|
||||
.boot_params = 0x0100,
|
||||
.init_machine = gateway7001_init,
|
||||
#if defined(CONFIG_PCI)
|
||||
.dma_zone_size = SZ_64M,
|
||||
#endif
|
||||
MACHINE_END
|
||||
#endif
|
||||
|
|
|
@ -501,4 +501,7 @@ MACHINE_START(GORAMO_MLR, "MultiLink")
|
|||
.timer = &ixp4xx_timer,
|
||||
.boot_params = 0x0100,
|
||||
.init_machine = gmlr_init,
|
||||
#if defined(CONFIG_PCI)
|
||||
.dma_zone_size = SZ_64M,
|
||||
#endif
|
||||
MACHINE_END
|
||||
|
|
|
@ -169,6 +169,9 @@ MACHINE_START(GTWX5715, "Gemtek GTWX5715 (Linksys WRV54G)")
|
|||
.timer = &ixp4xx_timer,
|
||||
.boot_params = 0x0100,
|
||||
.init_machine = gtwx5715_init,
|
||||
#if defined(CONFIG_PCI)
|
||||
.dma_zone_size = SZ_64M,
|
||||
#endif
|
||||
MACHINE_END
|
||||
|
||||
|
||||
|
|
|
@ -14,8 +14,4 @@
|
|||
*/
|
||||
#define PLAT_PHYS_OFFSET UL(0x00000000)
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
#define ARM_DMA_ZONE_SIZE SZ_64M
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -258,6 +258,9 @@ MACHINE_START(IXDP425, "Intel IXDP425 Development Platform")
|
|||
.timer = &ixp4xx_timer,
|
||||
.boot_params = 0x0100,
|
||||
.init_machine = ixdp425_init,
|
||||
#if defined(CONFIG_PCI)
|
||||
.dma_zone_size = SZ_64M,
|
||||
#endif
|
||||
MACHINE_END
|
||||
#endif
|
||||
|
||||
|
@ -269,6 +272,9 @@ MACHINE_START(IXDP465, "Intel IXDP465 Development Platform")
|
|||
.timer = &ixp4xx_timer,
|
||||
.boot_params = 0x0100,
|
||||
.init_machine = ixdp425_init,
|
||||
#if defined(CONFIG_PCI)
|
||||
.dma_zone_size = SZ_64M,
|
||||
#endif
|
||||
MACHINE_END
|
||||
#endif
|
||||
|
||||
|
@ -280,6 +286,9 @@ MACHINE_START(IXCDP1100, "Intel IXCDP1100 Development Platform")
|
|||
.timer = &ixp4xx_timer,
|
||||
.boot_params = 0x0100,
|
||||
.init_machine = ixdp425_init,
|
||||
#if defined(CONFIG_PCI)
|
||||
.dma_zone_size = SZ_64M,
|
||||
#endif
|
||||
MACHINE_END
|
||||
#endif
|
||||
|
||||
|
@ -291,5 +300,8 @@ MACHINE_START(KIXRP435, "Intel KIXRP435 Reference Platform")
|
|||
.timer = &ixp4xx_timer,
|
||||
.boot_params = 0x0100,
|
||||
.init_machine = ixdp425_init,
|
||||
#if defined(CONFIG_PCI)
|
||||
.dma_zone_size = SZ_64M,
|
||||
#endif
|
||||
MACHINE_END
|
||||
#endif
|
||||
|
|
|
@ -319,4 +319,7 @@ MACHINE_START(NAS100D, "Iomega NAS 100d")
|
|||
.init_irq = ixp4xx_init_irq,
|
||||
.timer = &ixp4xx_timer,
|
||||
.init_machine = nas100d_init,
|
||||
#if defined(CONFIG_PCI)
|
||||
.dma_zone_size = SZ_64M,
|
||||
#endif
|
||||
MACHINE_END
|
||||
|
|
|
@ -305,4 +305,7 @@ MACHINE_START(NSLU2, "Linksys NSLU2")
|
|||
.init_irq = ixp4xx_init_irq,
|
||||
.timer = &nslu2_timer,
|
||||
.init_machine = nslu2_init,
|
||||
#if defined(CONFIG_PCI)
|
||||
.dma_zone_size = SZ_64M,
|
||||
#endif
|
||||
MACHINE_END
|
||||
|
|
|
@ -241,4 +241,7 @@ MACHINE_START(ARCOM_VULCAN, "Arcom/Eurotech Vulcan")
|
|||
.timer = &ixp4xx_timer,
|
||||
.boot_params = 0x0100,
|
||||
.init_machine = vulcan_init,
|
||||
#if defined(CONFIG_PCI)
|
||||
.dma_zone_size = SZ_64M,
|
||||
#endif
|
||||
MACHINE_END
|
||||
|
|
|
@ -102,5 +102,8 @@ MACHINE_START(WG302V2, "Netgear WG302 v2 / WAG302 v2")
|
|||
.timer = &ixp4xx_timer,
|
||||
.boot_params = 0x0100,
|
||||
.init_machine = wg302v2_init,
|
||||
#if defined(CONFIG_PCI)
|
||||
.dma_zone_size = SZ_64M,
|
||||
#endif
|
||||
MACHINE_END
|
||||
#endif
|
||||
|
|
|
@ -518,4 +518,7 @@ MACHINE_START(ARMCORE, "Compulab CM-X2XX")
|
|||
.init_irq = cmx2xx_init_irq,
|
||||
.timer = &pxa_timer,
|
||||
.init_machine = cmx2xx_init,
|
||||
#ifdef CONFIG_PCI
|
||||
.dma_zone_size = SZ_64M,
|
||||
#endif
|
||||
MACHINE_END
|
||||
|
|
|
@ -17,8 +17,4 @@
|
|||
*/
|
||||
#define PLAT_PHYS_OFFSET UL(0xa0000000)
|
||||
|
||||
#if defined(CONFIG_MACH_ARMCORE) && defined(CONFIG_PCI)
|
||||
#define ARM_DMA_ZONE_SIZE SZ_64M
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -29,10 +29,6 @@
|
|||
#define PLAT_PHYS_OFFSET UL(0x00000000)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ZONE_DMA
|
||||
#define ARM_DMA_ZONE_SIZE SZ_256M
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SPARSEMEM
|
||||
|
||||
/*
|
||||
|
|
|
@ -470,4 +470,7 @@ MACHINE_START(REALVIEW_EB, "ARM-RealView EB")
|
|||
.init_irq = gic_init_irq,
|
||||
.timer = &realview_eb_timer,
|
||||
.init_machine = realview_eb_init,
|
||||
#ifdef CONFIG_ZONE_DMA
|
||||
.dma_zone_size = SZ_256M,
|
||||
#endif
|
||||
MACHINE_END
|
||||
|
|
|
@ -365,4 +365,7 @@ MACHINE_START(REALVIEW_PB1176, "ARM-RealView PB1176")
|
|||
.init_irq = gic_init_irq,
|
||||
.timer = &realview_pb1176_timer,
|
||||
.init_machine = realview_pb1176_init,
|
||||
#ifdef CONFIG_ZONE_DMA
|
||||
.dma_zone_size = SZ_256M,
|
||||
#endif
|
||||
MACHINE_END
|
||||
|
|
|
@ -367,4 +367,7 @@ MACHINE_START(REALVIEW_PB11MP, "ARM-RealView PB11MPCore")
|
|||
.init_irq = gic_init_irq,
|
||||
.timer = &realview_pb11mp_timer,
|
||||
.init_machine = realview_pb11mp_init,
|
||||
#ifdef CONFIG_ZONE_DMA
|
||||
.dma_zone_size = SZ_256M,
|
||||
#endif
|
||||
MACHINE_END
|
||||
|
|
|
@ -317,4 +317,7 @@ MACHINE_START(REALVIEW_PBA8, "ARM-RealView PB-A8")
|
|||
.init_irq = gic_init_irq,
|
||||
.timer = &realview_pba8_timer,
|
||||
.init_machine = realview_pba8_init,
|
||||
#ifdef CONFIG_ZONE_DMA
|
||||
.dma_zone_size = SZ_256M,
|
||||
#endif
|
||||
MACHINE_END
|
||||
|
|
|
@ -400,4 +400,7 @@ MACHINE_START(REALVIEW_PBX, "ARM-RealView PBX")
|
|||
.init_irq = gic_init_irq,
|
||||
.timer = &realview_pbx_timer,
|
||||
.init_machine = realview_pbx_init,
|
||||
#ifdef CONFIG_ZONE_DMA
|
||||
.dma_zone_size = SZ_256M,
|
||||
#endif
|
||||
MACHINE_END
|
||||
|
|
|
@ -453,4 +453,7 @@ MACHINE_START(ASSABET, "Intel-Assabet")
|
|||
.init_irq = sa1100_init_irq,
|
||||
.timer = &sa1100_timer,
|
||||
.init_machine = assabet_init,
|
||||
#ifdef CONFIG_SA1111
|
||||
.dma_zone_size = SZ_1M,
|
||||
#endif
|
||||
MACHINE_END
|
||||
|
|
|
@ -306,4 +306,7 @@ MACHINE_START(BADGE4, "Hewlett-Packard Laboratories BadgePAD 4")
|
|||
.map_io = badge4_map_io,
|
||||
.init_irq = sa1100_init_irq,
|
||||
.timer = &sa1100_timer,
|
||||
#ifdef CONFIG_SA1111
|
||||
.dma_zone_size = SZ_1M,
|
||||
#endif
|
||||
MACHINE_END
|
||||
|
|
|
@ -14,10 +14,6 @@
|
|||
*/
|
||||
#define PLAT_PHYS_OFFSET UL(0xc0000000)
|
||||
|
||||
#ifdef CONFIG_SA1111
|
||||
#define ARM_DMA_ZONE_SIZE SZ_1M
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Because of the wide memory address space between physical RAM banks on the
|
||||
* SA1100, it's much convenient to use Linux's SparseMEM support to implement
|
||||
|
|
|
@ -369,4 +369,7 @@ MACHINE_START(JORNADA720, "HP Jornada 720")
|
|||
.init_irq = sa1100_init_irq,
|
||||
.timer = &sa1100_timer,
|
||||
.init_machine = jornada720_mach_init,
|
||||
#ifdef CONFIG_SA1111
|
||||
.dma_zone_size = SZ_1M,
|
||||
#endif
|
||||
MACHINE_END
|
||||
|
|
|
@ -156,4 +156,5 @@ MACHINE_START(SHARK, "Shark")
|
|||
.map_io = shark_map_io,
|
||||
.init_irq = shark_init_irq,
|
||||
.timer = &shark_timer,
|
||||
.dma_zone_size = SZ_4M,
|
||||
MACHINE_END
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
*/
|
||||
#define PLAT_PHYS_OFFSET UL(0x08000000)
|
||||
|
||||
#define ARM_DMA_ZONE_SIZE SZ_4M
|
||||
|
||||
/*
|
||||
* Cache flushing area
|
||||
*/
|
||||
|
|
|
@ -242,16 +242,5 @@ ENDPROC(fa_dma_unmap_area)
|
|||
|
||||
__INITDATA
|
||||
|
||||
.type fa_cache_fns, #object
|
||||
ENTRY(fa_cache_fns)
|
||||
.long fa_flush_icache_all
|
||||
.long fa_flush_kern_cache_all
|
||||
.long fa_flush_user_cache_all
|
||||
.long fa_flush_user_cache_range
|
||||
.long fa_coherent_kern_range
|
||||
.long fa_coherent_user_range
|
||||
.long fa_flush_kern_dcache_area
|
||||
.long fa_dma_map_area
|
||||
.long fa_dma_unmap_area
|
||||
.long fa_dma_flush_range
|
||||
.size fa_cache_fns, . - fa_cache_fns
|
||||
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
|
||||
define_cache_functions fa
|
||||
|
|
|
@ -129,16 +129,5 @@ ENDPROC(v3_dma_map_area)
|
|||
|
||||
__INITDATA
|
||||
|
||||
.type v3_cache_fns, #object
|
||||
ENTRY(v3_cache_fns)
|
||||
.long v3_flush_icache_all
|
||||
.long v3_flush_kern_cache_all
|
||||
.long v3_flush_user_cache_all
|
||||
.long v3_flush_user_cache_range
|
||||
.long v3_coherent_kern_range
|
||||
.long v3_coherent_user_range
|
||||
.long v3_flush_kern_dcache_area
|
||||
.long v3_dma_map_area
|
||||
.long v3_dma_unmap_area
|
||||
.long v3_dma_flush_range
|
||||
.size v3_cache_fns, . - v3_cache_fns
|
||||
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
|
||||
define_cache_functions v3
|
||||
|
|
|
@ -141,16 +141,5 @@ ENDPROC(v4_dma_map_area)
|
|||
|
||||
__INITDATA
|
||||
|
||||
.type v4_cache_fns, #object
|
||||
ENTRY(v4_cache_fns)
|
||||
.long v4_flush_icache_all
|
||||
.long v4_flush_kern_cache_all
|
||||
.long v4_flush_user_cache_all
|
||||
.long v4_flush_user_cache_range
|
||||
.long v4_coherent_kern_range
|
||||
.long v4_coherent_user_range
|
||||
.long v4_flush_kern_dcache_area
|
||||
.long v4_dma_map_area
|
||||
.long v4_dma_unmap_area
|
||||
.long v4_dma_flush_range
|
||||
.size v4_cache_fns, . - v4_cache_fns
|
||||
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
|
||||
define_cache_functions v4
|
||||
|
|
|
@ -253,16 +253,5 @@ ENDPROC(v4wb_dma_unmap_area)
|
|||
|
||||
__INITDATA
|
||||
|
||||
.type v4wb_cache_fns, #object
|
||||
ENTRY(v4wb_cache_fns)
|
||||
.long v4wb_flush_icache_all
|
||||
.long v4wb_flush_kern_cache_all
|
||||
.long v4wb_flush_user_cache_all
|
||||
.long v4wb_flush_user_cache_range
|
||||
.long v4wb_coherent_kern_range
|
||||
.long v4wb_coherent_user_range
|
||||
.long v4wb_flush_kern_dcache_area
|
||||
.long v4wb_dma_map_area
|
||||
.long v4wb_dma_unmap_area
|
||||
.long v4wb_dma_flush_range
|
||||
.size v4wb_cache_fns, . - v4wb_cache_fns
|
||||
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
|
||||
define_cache_functions v4wb
|
||||
|
|
|
@ -197,16 +197,5 @@ ENDPROC(v4wt_dma_map_area)
|
|||
|
||||
__INITDATA
|
||||
|
||||
.type v4wt_cache_fns, #object
|
||||
ENTRY(v4wt_cache_fns)
|
||||
.long v4wt_flush_icache_all
|
||||
.long v4wt_flush_kern_cache_all
|
||||
.long v4wt_flush_user_cache_all
|
||||
.long v4wt_flush_user_cache_range
|
||||
.long v4wt_coherent_kern_range
|
||||
.long v4wt_coherent_user_range
|
||||
.long v4wt_flush_kern_dcache_area
|
||||
.long v4wt_dma_map_area
|
||||
.long v4wt_dma_unmap_area
|
||||
.long v4wt_dma_flush_range
|
||||
.size v4wt_cache_fns, . - v4wt_cache_fns
|
||||
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
|
||||
define_cache_functions v4wt
|
||||
|
|
|
@ -330,16 +330,5 @@ ENDPROC(v6_dma_unmap_area)
|
|||
|
||||
__INITDATA
|
||||
|
||||
.type v6_cache_fns, #object
|
||||
ENTRY(v6_cache_fns)
|
||||
.long v6_flush_icache_all
|
||||
.long v6_flush_kern_cache_all
|
||||
.long v6_flush_user_cache_all
|
||||
.long v6_flush_user_cache_range
|
||||
.long v6_coherent_kern_range
|
||||
.long v6_coherent_user_range
|
||||
.long v6_flush_kern_dcache_area
|
||||
.long v6_dma_map_area
|
||||
.long v6_dma_unmap_area
|
||||
.long v6_dma_flush_range
|
||||
.size v6_cache_fns, . - v6_cache_fns
|
||||
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
|
||||
define_cache_functions v6
|
||||
|
|
|
@ -325,16 +325,5 @@ ENDPROC(v7_dma_unmap_area)
|
|||
|
||||
__INITDATA
|
||||
|
||||
.type v7_cache_fns, #object
|
||||
ENTRY(v7_cache_fns)
|
||||
.long v7_flush_icache_all
|
||||
.long v7_flush_kern_cache_all
|
||||
.long v7_flush_user_cache_all
|
||||
.long v7_flush_user_cache_range
|
||||
.long v7_coherent_kern_range
|
||||
.long v7_coherent_user_range
|
||||
.long v7_flush_kern_dcache_area
|
||||
.long v7_dma_map_area
|
||||
.long v7_dma_unmap_area
|
||||
.long v7_dma_flush_range
|
||||
.size v7_cache_fns, . - v7_cache_fns
|
||||
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
|
||||
define_cache_functions v7
|
||||
|
|
|
@ -212,6 +212,10 @@ static void __init arm_bootmem_init(unsigned long start_pfn,
|
|||
}
|
||||
|
||||
#ifdef CONFIG_ZONE_DMA
|
||||
|
||||
unsigned long arm_dma_zone_size __read_mostly;
|
||||
EXPORT_SYMBOL(arm_dma_zone_size);
|
||||
|
||||
/*
|
||||
* The DMA mask corresponding to the maximum bus address allocatable
|
||||
* using GFP_DMA. The default here places no restriction on DMA
|
||||
|
@ -275,19 +279,17 @@ static void __init arm_bootmem_free(unsigned long min, unsigned long max_low,
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef ARM_DMA_ZONE_SIZE
|
||||
#ifndef CONFIG_ZONE_DMA
|
||||
#error ARM_DMA_ZONE_SIZE set but no DMA zone to limit allocations
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ZONE_DMA
|
||||
/*
|
||||
* Adjust the sizes according to any special requirements for
|
||||
* this machine type.
|
||||
*/
|
||||
arm_adjust_dma_zone(zone_size, zhole_size,
|
||||
ARM_DMA_ZONE_SIZE >> PAGE_SHIFT);
|
||||
|
||||
arm_dma_limit = PHYS_OFFSET + ARM_DMA_ZONE_SIZE - 1;
|
||||
if (arm_dma_zone_size) {
|
||||
arm_adjust_dma_zone(zone_size, zhole_size,
|
||||
arm_dma_zone_size >> PAGE_SHIFT);
|
||||
arm_dma_limit = PHYS_OFFSET + arm_dma_zone_size - 1;
|
||||
} else
|
||||
arm_dma_limit = 0xffffffff;
|
||||
#endif
|
||||
|
||||
free_area_init_node(0, zone_size, min, zhole_size);
|
||||
|
|
|
@ -364,17 +364,8 @@ ENTRY(arm1020_dma_unmap_area)
|
|||
mov pc, lr
|
||||
ENDPROC(arm1020_dma_unmap_area)
|
||||
|
||||
ENTRY(arm1020_cache_fns)
|
||||
.long arm1020_flush_icache_all
|
||||
.long arm1020_flush_kern_cache_all
|
||||
.long arm1020_flush_user_cache_all
|
||||
.long arm1020_flush_user_cache_range
|
||||
.long arm1020_coherent_kern_range
|
||||
.long arm1020_coherent_user_range
|
||||
.long arm1020_flush_kern_dcache_area
|
||||
.long arm1020_dma_map_area
|
||||
.long arm1020_dma_unmap_area
|
||||
.long arm1020_dma_flush_range
|
||||
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
|
||||
define_cache_functions arm1020
|
||||
|
||||
.align 5
|
||||
ENTRY(cpu_arm1020_dcache_clean_area)
|
||||
|
@ -477,38 +468,14 @@ arm1020_crval:
|
|||
crval clear=0x0000593f, mmuset=0x00003935, ucset=0x00001930
|
||||
|
||||
__INITDATA
|
||||
@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
|
||||
define_processor_functions arm1020, dabort=v4t_early_abort, pabort=legacy_pabort
|
||||
|
||||
/*
|
||||
* Purpose : Function pointers used to access above functions - all calls
|
||||
* come through these
|
||||
*/
|
||||
.type arm1020_processor_functions, #object
|
||||
arm1020_processor_functions:
|
||||
.word v4t_early_abort
|
||||
.word legacy_pabort
|
||||
.word cpu_arm1020_proc_init
|
||||
.word cpu_arm1020_proc_fin
|
||||
.word cpu_arm1020_reset
|
||||
.word cpu_arm1020_do_idle
|
||||
.word cpu_arm1020_dcache_clean_area
|
||||
.word cpu_arm1020_switch_mm
|
||||
.word cpu_arm1020_set_pte_ext
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.size arm1020_processor_functions, . - arm1020_processor_functions
|
||||
|
||||
.section ".rodata"
|
||||
|
||||
.type cpu_arch_name, #object
|
||||
cpu_arch_name:
|
||||
.asciz "armv5t"
|
||||
.size cpu_arch_name, . - cpu_arch_name
|
||||
|
||||
.type cpu_elf_name, #object
|
||||
cpu_elf_name:
|
||||
.asciz "v5"
|
||||
.size cpu_elf_name, . - cpu_elf_name
|
||||
string cpu_arch_name, "armv5t"
|
||||
string cpu_elf_name, "v5"
|
||||
|
||||
.type cpu_arm1020_name, #object
|
||||
cpu_arm1020_name:
|
||||
|
|
|
@ -350,17 +350,8 @@ ENTRY(arm1020e_dma_unmap_area)
|
|||
mov pc, lr
|
||||
ENDPROC(arm1020e_dma_unmap_area)
|
||||
|
||||
ENTRY(arm1020e_cache_fns)
|
||||
.long arm1020e_flush_icache_all
|
||||
.long arm1020e_flush_kern_cache_all
|
||||
.long arm1020e_flush_user_cache_all
|
||||
.long arm1020e_flush_user_cache_range
|
||||
.long arm1020e_coherent_kern_range
|
||||
.long arm1020e_coherent_user_range
|
||||
.long arm1020e_flush_kern_dcache_area
|
||||
.long arm1020e_dma_map_area
|
||||
.long arm1020e_dma_unmap_area
|
||||
.long arm1020e_dma_flush_range
|
||||
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
|
||||
define_cache_functions arm1020e
|
||||
|
||||
.align 5
|
||||
ENTRY(cpu_arm1020e_dcache_clean_area)
|
||||
|
@ -458,43 +449,14 @@ arm1020e_crval:
|
|||
crval clear=0x00007f3f, mmuset=0x00003935, ucset=0x00001930
|
||||
|
||||
__INITDATA
|
||||
|
||||
/*
|
||||
* Purpose : Function pointers used to access above functions - all calls
|
||||
* come through these
|
||||
*/
|
||||
.type arm1020e_processor_functions, #object
|
||||
arm1020e_processor_functions:
|
||||
.word v4t_early_abort
|
||||
.word legacy_pabort
|
||||
.word cpu_arm1020e_proc_init
|
||||
.word cpu_arm1020e_proc_fin
|
||||
.word cpu_arm1020e_reset
|
||||
.word cpu_arm1020e_do_idle
|
||||
.word cpu_arm1020e_dcache_clean_area
|
||||
.word cpu_arm1020e_switch_mm
|
||||
.word cpu_arm1020e_set_pte_ext
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.size arm1020e_processor_functions, . - arm1020e_processor_functions
|
||||
@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
|
||||
define_processor_functions arm1020e, dabort=v4t_early_abort, pabort=legacy_pabort
|
||||
|
||||
.section ".rodata"
|
||||
|
||||
.type cpu_arch_name, #object
|
||||
cpu_arch_name:
|
||||
.asciz "armv5te"
|
||||
.size cpu_arch_name, . - cpu_arch_name
|
||||
|
||||
.type cpu_elf_name, #object
|
||||
cpu_elf_name:
|
||||
.asciz "v5"
|
||||
.size cpu_elf_name, . - cpu_elf_name
|
||||
|
||||
.type cpu_arm1020e_name, #object
|
||||
cpu_arm1020e_name:
|
||||
.asciz "ARM1020E"
|
||||
.size cpu_arm1020e_name, . - cpu_arm1020e_name
|
||||
string cpu_arch_name, "armv5te"
|
||||
string cpu_elf_name, "v5"
|
||||
string cpu_arm1020e_name, "ARM1020E"
|
||||
|
||||
.align
|
||||
|
||||
|
|
|
@ -339,17 +339,8 @@ ENTRY(arm1022_dma_unmap_area)
|
|||
mov pc, lr
|
||||
ENDPROC(arm1022_dma_unmap_area)
|
||||
|
||||
ENTRY(arm1022_cache_fns)
|
||||
.long arm1022_flush_icache_all
|
||||
.long arm1022_flush_kern_cache_all
|
||||
.long arm1022_flush_user_cache_all
|
||||
.long arm1022_flush_user_cache_range
|
||||
.long arm1022_coherent_kern_range
|
||||
.long arm1022_coherent_user_range
|
||||
.long arm1022_flush_kern_dcache_area
|
||||
.long arm1022_dma_map_area
|
||||
.long arm1022_dma_unmap_area
|
||||
.long arm1022_dma_flush_range
|
||||
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
|
||||
define_cache_functions arm1022
|
||||
|
||||
.align 5
|
||||
ENTRY(cpu_arm1022_dcache_clean_area)
|
||||
|
@ -441,43 +432,14 @@ arm1022_crval:
|
|||
crval clear=0x00007f3f, mmuset=0x00003935, ucset=0x00001930
|
||||
|
||||
__INITDATA
|
||||
|
||||
/*
|
||||
* Purpose : Function pointers used to access above functions - all calls
|
||||
* come through these
|
||||
*/
|
||||
.type arm1022_processor_functions, #object
|
||||
arm1022_processor_functions:
|
||||
.word v4t_early_abort
|
||||
.word legacy_pabort
|
||||
.word cpu_arm1022_proc_init
|
||||
.word cpu_arm1022_proc_fin
|
||||
.word cpu_arm1022_reset
|
||||
.word cpu_arm1022_do_idle
|
||||
.word cpu_arm1022_dcache_clean_area
|
||||
.word cpu_arm1022_switch_mm
|
||||
.word cpu_arm1022_set_pte_ext
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.size arm1022_processor_functions, . - arm1022_processor_functions
|
||||
@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
|
||||
define_processor_functions arm1022, dabort=v4t_early_abort, pabort=legacy_pabort
|
||||
|
||||
.section ".rodata"
|
||||
|
||||
.type cpu_arch_name, #object
|
||||
cpu_arch_name:
|
||||
.asciz "armv5te"
|
||||
.size cpu_arch_name, . - cpu_arch_name
|
||||
|
||||
.type cpu_elf_name, #object
|
||||
cpu_elf_name:
|
||||
.asciz "v5"
|
||||
.size cpu_elf_name, . - cpu_elf_name
|
||||
|
||||
.type cpu_arm1022_name, #object
|
||||
cpu_arm1022_name:
|
||||
.asciz "ARM1022"
|
||||
.size cpu_arm1022_name, . - cpu_arm1022_name
|
||||
string cpu_arch_name, "armv5te"
|
||||
string cpu_elf_name, "v5"
|
||||
string cpu_arm1022_name, "ARM1022"
|
||||
|
||||
.align
|
||||
|
||||
|
|
|
@ -333,17 +333,8 @@ ENTRY(arm1026_dma_unmap_area)
|
|||
mov pc, lr
|
||||
ENDPROC(arm1026_dma_unmap_area)
|
||||
|
||||
ENTRY(arm1026_cache_fns)
|
||||
.long arm1026_flush_icache_all
|
||||
.long arm1026_flush_kern_cache_all
|
||||
.long arm1026_flush_user_cache_all
|
||||
.long arm1026_flush_user_cache_range
|
||||
.long arm1026_coherent_kern_range
|
||||
.long arm1026_coherent_user_range
|
||||
.long arm1026_flush_kern_dcache_area
|
||||
.long arm1026_dma_map_area
|
||||
.long arm1026_dma_unmap_area
|
||||
.long arm1026_dma_flush_range
|
||||
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
|
||||
define_cache_functions arm1026
|
||||
|
||||
.align 5
|
||||
ENTRY(cpu_arm1026_dcache_clean_area)
|
||||
|
@ -436,45 +427,15 @@ arm1026_crval:
|
|||
crval clear=0x00007f3f, mmuset=0x00003935, ucset=0x00001934
|
||||
|
||||
__INITDATA
|
||||
|
||||
/*
|
||||
* Purpose : Function pointers used to access above functions - all calls
|
||||
* come through these
|
||||
*/
|
||||
.type arm1026_processor_functions, #object
|
||||
arm1026_processor_functions:
|
||||
.word v5t_early_abort
|
||||
.word legacy_pabort
|
||||
.word cpu_arm1026_proc_init
|
||||
.word cpu_arm1026_proc_fin
|
||||
.word cpu_arm1026_reset
|
||||
.word cpu_arm1026_do_idle
|
||||
.word cpu_arm1026_dcache_clean_area
|
||||
.word cpu_arm1026_switch_mm
|
||||
.word cpu_arm1026_set_pte_ext
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.size arm1026_processor_functions, . - arm1026_processor_functions
|
||||
@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
|
||||
define_processor_functions arm1026, dabort=v5t_early_abort, pabort=legacy_pabort
|
||||
|
||||
.section .rodata
|
||||
|
||||
.type cpu_arch_name, #object
|
||||
cpu_arch_name:
|
||||
.asciz "armv5tej"
|
||||
.size cpu_arch_name, . - cpu_arch_name
|
||||
|
||||
.type cpu_elf_name, #object
|
||||
cpu_elf_name:
|
||||
.asciz "v5"
|
||||
.size cpu_elf_name, . - cpu_elf_name
|
||||
string cpu_arch_name, "armv5tej"
|
||||
string cpu_elf_name, "v5"
|
||||
.align
|
||||
|
||||
.type cpu_arm1026_name, #object
|
||||
cpu_arm1026_name:
|
||||
.asciz "ARM1026EJ-S"
|
||||
.size cpu_arm1026_name, . - cpu_arm1026_name
|
||||
|
||||
string cpu_arm1026_name, "ARM1026EJ-S"
|
||||
.align
|
||||
|
||||
.section ".proc.info.init", #alloc, #execinstr
|
||||
|
|
|
@ -267,159 +267,57 @@ __arm7_setup: mov r0, #0
|
|||
|
||||
__INITDATA
|
||||
|
||||
/*
|
||||
* Purpose : Function pointers used to access above functions - all calls
|
||||
* come through these
|
||||
*/
|
||||
.type arm6_processor_functions, #object
|
||||
ENTRY(arm6_processor_functions)
|
||||
.word cpu_arm6_data_abort
|
||||
.word legacy_pabort
|
||||
.word cpu_arm6_proc_init
|
||||
.word cpu_arm6_proc_fin
|
||||
.word cpu_arm6_reset
|
||||
.word cpu_arm6_do_idle
|
||||
.word cpu_arm6_dcache_clean_area
|
||||
.word cpu_arm6_switch_mm
|
||||
.word cpu_arm6_set_pte_ext
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.size arm6_processor_functions, . - arm6_processor_functions
|
||||
|
||||
/*
|
||||
* Purpose : Function pointers used to access above functions - all calls
|
||||
* come through these
|
||||
*/
|
||||
.type arm7_processor_functions, #object
|
||||
ENTRY(arm7_processor_functions)
|
||||
.word cpu_arm7_data_abort
|
||||
.word legacy_pabort
|
||||
.word cpu_arm7_proc_init
|
||||
.word cpu_arm7_proc_fin
|
||||
.word cpu_arm7_reset
|
||||
.word cpu_arm7_do_idle
|
||||
.word cpu_arm7_dcache_clean_area
|
||||
.word cpu_arm7_switch_mm
|
||||
.word cpu_arm7_set_pte_ext
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.size arm7_processor_functions, . - arm7_processor_functions
|
||||
@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
|
||||
define_processor_functions arm6, dabort=cpu_arm6_data_abort, pabort=legacy_pabort
|
||||
define_processor_functions arm7, dabort=cpu_arm7_data_abort, pabort=legacy_pabort
|
||||
|
||||
.section ".rodata"
|
||||
|
||||
.type cpu_arch_name, #object
|
||||
cpu_arch_name: .asciz "armv3"
|
||||
.size cpu_arch_name, . - cpu_arch_name
|
||||
|
||||
.type cpu_elf_name, #object
|
||||
cpu_elf_name: .asciz "v3"
|
||||
.size cpu_elf_name, . - cpu_elf_name
|
||||
|
||||
.type cpu_arm6_name, #object
|
||||
cpu_arm6_name: .asciz "ARM6"
|
||||
.size cpu_arm6_name, . - cpu_arm6_name
|
||||
|
||||
.type cpu_arm610_name, #object
|
||||
cpu_arm610_name:
|
||||
.asciz "ARM610"
|
||||
.size cpu_arm610_name, . - cpu_arm610_name
|
||||
|
||||
.type cpu_arm7_name, #object
|
||||
cpu_arm7_name: .asciz "ARM7"
|
||||
.size cpu_arm7_name, . - cpu_arm7_name
|
||||
|
||||
.type cpu_arm710_name, #object
|
||||
cpu_arm710_name:
|
||||
.asciz "ARM710"
|
||||
.size cpu_arm710_name, . - cpu_arm710_name
|
||||
string cpu_arch_name, "armv3"
|
||||
string cpu_elf_name, "v3"
|
||||
string cpu_arm6_name, "ARM6"
|
||||
string cpu_arm610_name, "ARM610"
|
||||
string cpu_arm7_name, "ARM7"
|
||||
string cpu_arm710_name, "ARM710"
|
||||
|
||||
.align
|
||||
|
||||
.section ".proc.info.init", #alloc, #execinstr
|
||||
|
||||
.type __arm6_proc_info, #object
|
||||
__arm6_proc_info:
|
||||
.long 0x41560600
|
||||
.long 0xfffffff0
|
||||
.long 0x00000c1e
|
||||
.macro arm67_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, \
|
||||
cpu_mm_mmu_flags:req, cpu_flush:req, cpu_proc_funcs:req
|
||||
.type __\name\()_proc_info, #object
|
||||
__\name\()_proc_info:
|
||||
.long \cpu_val
|
||||
.long \cpu_mask
|
||||
.long \cpu_mm_mmu_flags
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_BIT4 | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
b __arm6_setup
|
||||
b \cpu_flush
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP | HWCAP_26BIT
|
||||
.long cpu_arm6_name
|
||||
.long arm6_processor_functions
|
||||
.long \cpu_name
|
||||
.long \cpu_proc_funcs
|
||||
.long v3_tlb_fns
|
||||
.long v3_user_fns
|
||||
.long v3_cache_fns
|
||||
.size __arm6_proc_info, . - __arm6_proc_info
|
||||
.size __\name\()_proc_info, . - __\name\()_proc_info
|
||||
.endm
|
||||
|
||||
.type __arm610_proc_info, #object
|
||||
__arm610_proc_info:
|
||||
.long 0x41560610
|
||||
.long 0xfffffff0
|
||||
.long 0x00000c1e
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_BIT4 | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
b __arm6_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP | HWCAP_26BIT
|
||||
.long cpu_arm610_name
|
||||
.long arm6_processor_functions
|
||||
.long v3_tlb_fns
|
||||
.long v3_user_fns
|
||||
.long v3_cache_fns
|
||||
.size __arm610_proc_info, . - __arm610_proc_info
|
||||
|
||||
.type __arm7_proc_info, #object
|
||||
__arm7_proc_info:
|
||||
.long 0x41007000
|
||||
.long 0xffffff00
|
||||
.long 0x00000c1e
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_BIT4 | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
b __arm7_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP | HWCAP_26BIT
|
||||
.long cpu_arm7_name
|
||||
.long arm7_processor_functions
|
||||
.long v3_tlb_fns
|
||||
.long v3_user_fns
|
||||
.long v3_cache_fns
|
||||
.size __arm7_proc_info, . - __arm7_proc_info
|
||||
|
||||
.type __arm710_proc_info, #object
|
||||
__arm710_proc_info:
|
||||
.long 0x41007100
|
||||
.long 0xfff8ff00
|
||||
.long PMD_TYPE_SECT | \
|
||||
arm67_proc_info arm6, 0x41560600, 0xfffffff0, cpu_arm6_name, \
|
||||
0x00000c1e, __arm6_setup, arm6_processor_functions
|
||||
arm67_proc_info arm610, 0x41560610, 0xfffffff0, cpu_arm610_name, \
|
||||
0x00000c1e, __arm6_setup, arm6_processor_functions
|
||||
arm67_proc_info arm7, 0x41007000, 0xffffff00, cpu_arm7_name, \
|
||||
0x00000c1e, __arm7_setup, arm7_processor_functions
|
||||
arm67_proc_info arm710, 0x41007100, 0xfff8ff00, cpu_arm710_name, \
|
||||
PMD_TYPE_SECT | \
|
||||
PMD_SECT_BUFFERABLE | \
|
||||
PMD_SECT_CACHEABLE | \
|
||||
PMD_BIT4 | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_BIT4 | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
b __arm7_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP | HWCAP_26BIT
|
||||
.long cpu_arm710_name
|
||||
.long arm7_processor_functions
|
||||
.long v3_tlb_fns
|
||||
.long v3_user_fns
|
||||
.long v3_cache_fns
|
||||
.size __arm710_proc_info, . - __arm710_proc_info
|
||||
PMD_SECT_AP_READ, \
|
||||
__arm7_setup, arm7_processor_functions
|
||||
|
|
|
@ -169,46 +169,15 @@ arm720_crval:
|
|||
crval clear=0x00002f3f, mmuset=0x0000213d, ucset=0x00000130
|
||||
|
||||
__INITDATA
|
||||
|
||||
/*
|
||||
* Purpose : Function pointers used to access above functions - all calls
|
||||
* come through these
|
||||
*/
|
||||
.type arm720_processor_functions, #object
|
||||
ENTRY(arm720_processor_functions)
|
||||
.word v4t_late_abort
|
||||
.word legacy_pabort
|
||||
.word cpu_arm720_proc_init
|
||||
.word cpu_arm720_proc_fin
|
||||
.word cpu_arm720_reset
|
||||
.word cpu_arm720_do_idle
|
||||
.word cpu_arm720_dcache_clean_area
|
||||
.word cpu_arm720_switch_mm
|
||||
.word cpu_arm720_set_pte_ext
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.size arm720_processor_functions, . - arm720_processor_functions
|
||||
@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
|
||||
define_processor_functions arm720, dabort=v4t_late_abort, pabort=legacy_pabort
|
||||
|
||||
.section ".rodata"
|
||||
|
||||
.type cpu_arch_name, #object
|
||||
cpu_arch_name: .asciz "armv4t"
|
||||
.size cpu_arch_name, . - cpu_arch_name
|
||||
|
||||
.type cpu_elf_name, #object
|
||||
cpu_elf_name: .asciz "v4"
|
||||
.size cpu_elf_name, . - cpu_elf_name
|
||||
|
||||
.type cpu_arm710_name, #object
|
||||
cpu_arm710_name:
|
||||
.asciz "ARM710T"
|
||||
.size cpu_arm710_name, . - cpu_arm710_name
|
||||
|
||||
.type cpu_arm720_name, #object
|
||||
cpu_arm720_name:
|
||||
.asciz "ARM720T"
|
||||
.size cpu_arm720_name, . - cpu_arm720_name
|
||||
string cpu_arch_name, "armv4t"
|
||||
string cpu_elf_name, "v4"
|
||||
string cpu_arm710_name, "ARM710T"
|
||||
string cpu_arm720_name, "ARM720T"
|
||||
|
||||
.align
|
||||
|
||||
|
@ -218,10 +187,11 @@ cpu_arm720_name:
|
|||
|
||||
.section ".proc.info.init", #alloc, #execinstr
|
||||
|
||||
.type __arm710_proc_info, #object
|
||||
__arm710_proc_info:
|
||||
.long 0x41807100 @ cpu_val
|
||||
.long 0xffffff00 @ cpu_mask
|
||||
.macro arm720_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, cpu_flush:req
|
||||
.type __\name\()_proc_info,#object
|
||||
__\name\()_proc_info:
|
||||
.long \cpu_val
|
||||
.long \cpu_mask
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_BUFFERABLE | \
|
||||
PMD_SECT_CACHEABLE | \
|
||||
|
@ -232,38 +202,17 @@ __arm710_proc_info:
|
|||
PMD_BIT4 | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
b __arm710_setup @ cpu_flush
|
||||
b \cpu_flush @ cpu_flush
|
||||
.long cpu_arch_name @ arch_name
|
||||
.long cpu_elf_name @ elf_name
|
||||
.long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB @ elf_hwcap
|
||||
.long cpu_arm710_name @ name
|
||||
.long \cpu_name
|
||||
.long arm720_processor_functions
|
||||
.long v4_tlb_fns
|
||||
.long v4wt_user_fns
|
||||
.long v4_cache_fns
|
||||
.size __arm710_proc_info, . - __arm710_proc_info
|
||||
.size __\name\()_proc_info, . - __\name\()_proc_info
|
||||
.endm
|
||||
|
||||
.type __arm720_proc_info, #object
|
||||
__arm720_proc_info:
|
||||
.long 0x41807200 @ cpu_val
|
||||
.long 0xffffff00 @ cpu_mask
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_BUFFERABLE | \
|
||||
PMD_SECT_CACHEABLE | \
|
||||
PMD_BIT4 | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_BIT4 | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
b __arm720_setup @ cpu_flush
|
||||
.long cpu_arch_name @ arch_name
|
||||
.long cpu_elf_name @ elf_name
|
||||
.long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB @ elf_hwcap
|
||||
.long cpu_arm720_name @ name
|
||||
.long arm720_processor_functions
|
||||
.long v4_tlb_fns
|
||||
.long v4wt_user_fns
|
||||
.long v4_cache_fns
|
||||
.size __arm720_proc_info, . - __arm720_proc_info
|
||||
arm720_proc_info arm710, 0x41807100, 0xffffff00, cpu_arm710_name, __arm710_setup
|
||||
arm720_proc_info arm720, 0x41807200, 0xffffff00, cpu_arm720_name, __arm720_setup
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include <asm/pgtable.h>
|
||||
#include <asm/ptrace.h>
|
||||
|
||||
#include "proc-macros.S"
|
||||
|
||||
.text
|
||||
/*
|
||||
* cpu_arm740_proc_init()
|
||||
|
@ -115,42 +117,14 @@ __arm740_setup:
|
|||
|
||||
__INITDATA
|
||||
|
||||
/*
|
||||
* Purpose : Function pointers used to access above functions - all calls
|
||||
* come through these
|
||||
*/
|
||||
.type arm740_processor_functions, #object
|
||||
ENTRY(arm740_processor_functions)
|
||||
.word v4t_late_abort
|
||||
.word legacy_pabort
|
||||
.word cpu_arm740_proc_init
|
||||
.word cpu_arm740_proc_fin
|
||||
.word cpu_arm740_reset
|
||||
.word cpu_arm740_do_idle
|
||||
.word cpu_arm740_dcache_clean_area
|
||||
.word cpu_arm740_switch_mm
|
||||
.word 0 @ cpu_*_set_pte
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.size arm740_processor_functions, . - arm740_processor_functions
|
||||
@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
|
||||
define_processor_functions arm740, dabort=v4t_late_abort, pabort=legacy_pabort, nommu=1
|
||||
|
||||
.section ".rodata"
|
||||
|
||||
.type cpu_arch_name, #object
|
||||
cpu_arch_name:
|
||||
.asciz "armv4"
|
||||
.size cpu_arch_name, . - cpu_arch_name
|
||||
|
||||
.type cpu_elf_name, #object
|
||||
cpu_elf_name:
|
||||
.asciz "v4"
|
||||
.size cpu_elf_name, . - cpu_elf_name
|
||||
|
||||
.type cpu_arm740_name, #object
|
||||
cpu_arm740_name:
|
||||
.ascii "ARM740T"
|
||||
.size cpu_arm740_name, . - cpu_arm740_name
|
||||
string cpu_arch_name, "armv4"
|
||||
string cpu_elf_name, "v4"
|
||||
string cpu_arm740_name, "ARM740T"
|
||||
|
||||
.align
|
||||
|
||||
|
@ -170,5 +144,3 @@ __arm740_proc_info:
|
|||
.long 0
|
||||
.long v3_cache_fns @ cache model
|
||||
.size __arm740_proc_info, . - __arm740_proc_info
|
||||
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include <asm/pgtable.h>
|
||||
#include <asm/ptrace.h>
|
||||
|
||||
#include "proc-macros.S"
|
||||
|
||||
.text
|
||||
/*
|
||||
* cpu_arm7tdmi_proc_init()
|
||||
|
@ -55,197 +57,57 @@ __arm7tdmi_setup:
|
|||
|
||||
__INITDATA
|
||||
|
||||
/*
|
||||
* Purpose : Function pointers used to access above functions - all calls
|
||||
* come through these
|
||||
*/
|
||||
.type arm7tdmi_processor_functions, #object
|
||||
ENTRY(arm7tdmi_processor_functions)
|
||||
.word v4t_late_abort
|
||||
.word legacy_pabort
|
||||
.word cpu_arm7tdmi_proc_init
|
||||
.word cpu_arm7tdmi_proc_fin
|
||||
.word cpu_arm7tdmi_reset
|
||||
.word cpu_arm7tdmi_do_idle
|
||||
.word cpu_arm7tdmi_dcache_clean_area
|
||||
.word cpu_arm7tdmi_switch_mm
|
||||
.word 0 @ cpu_*_set_pte
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.size arm7tdmi_processor_functions, . - arm7tdmi_processor_functions
|
||||
@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
|
||||
define_processor_functions arm7tdmi, dabort=v4t_late_abort, pabort=legacy_pabort, nommu=1
|
||||
|
||||
.section ".rodata"
|
||||
|
||||
.type cpu_arch_name, #object
|
||||
cpu_arch_name:
|
||||
.asciz "armv4t"
|
||||
.size cpu_arch_name, . - cpu_arch_name
|
||||
|
||||
.type cpu_elf_name, #object
|
||||
cpu_elf_name:
|
||||
.asciz "v4"
|
||||
.size cpu_elf_name, . - cpu_elf_name
|
||||
|
||||
.type cpu_arm7tdmi_name, #object
|
||||
cpu_arm7tdmi_name:
|
||||
.asciz "ARM7TDMI"
|
||||
.size cpu_arm7tdmi_name, . - cpu_arm7tdmi_name
|
||||
|
||||
.type cpu_triscenda7_name, #object
|
||||
cpu_triscenda7_name:
|
||||
.asciz "Triscend-A7x"
|
||||
.size cpu_triscenda7_name, . - cpu_triscenda7_name
|
||||
|
||||
.type cpu_at91_name, #object
|
||||
cpu_at91_name:
|
||||
.asciz "Atmel-AT91M40xxx"
|
||||
.size cpu_at91_name, . - cpu_at91_name
|
||||
|
||||
.type cpu_s3c3410_name, #object
|
||||
cpu_s3c3410_name:
|
||||
.asciz "Samsung-S3C3410"
|
||||
.size cpu_s3c3410_name, . - cpu_s3c3410_name
|
||||
|
||||
.type cpu_s3c44b0x_name, #object
|
||||
cpu_s3c44b0x_name:
|
||||
.asciz "Samsung-S3C44B0x"
|
||||
.size cpu_s3c44b0x_name, . - cpu_s3c44b0x_name
|
||||
|
||||
.type cpu_s3c4510b, #object
|
||||
cpu_s3c4510b_name:
|
||||
.asciz "Samsung-S3C4510B"
|
||||
.size cpu_s3c4510b_name, . - cpu_s3c4510b_name
|
||||
|
||||
.type cpu_s3c4530_name, #object
|
||||
cpu_s3c4530_name:
|
||||
.asciz "Samsung-S3C4530"
|
||||
.size cpu_s3c4530_name, . - cpu_s3c4530_name
|
||||
|
||||
.type cpu_netarm_name, #object
|
||||
cpu_netarm_name:
|
||||
.asciz "NETARM"
|
||||
.size cpu_netarm_name, . - cpu_netarm_name
|
||||
string cpu_arch_name, "armv4t"
|
||||
string cpu_elf_name, "v4"
|
||||
string cpu_arm7tdmi_name, "ARM7TDMI"
|
||||
string cpu_triscenda7_name, "Triscend-A7x"
|
||||
string cpu_at91_name, "Atmel-AT91M40xxx"
|
||||
string cpu_s3c3410_name, "Samsung-S3C3410"
|
||||
string cpu_s3c44b0x_name, "Samsung-S3C44B0x"
|
||||
string cpu_s3c4510b_name, "Samsung-S3C4510B"
|
||||
string cpu_s3c4530_name, "Samsung-S3C4530"
|
||||
string cpu_netarm_name, "NETARM"
|
||||
|
||||
.align
|
||||
|
||||
.section ".proc.info.init", #alloc, #execinstr
|
||||
|
||||
.type __arm7tdmi_proc_info, #object
|
||||
__arm7tdmi_proc_info:
|
||||
.long 0x41007700
|
||||
.long 0xfff8ff00
|
||||
.macro arm7tdmi_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, \
|
||||
extra_hwcaps=0
|
||||
.type __\name\()_proc_info, #object
|
||||
__\name\()_proc_info:
|
||||
.long \cpu_val
|
||||
.long \cpu_mask
|
||||
.long 0
|
||||
.long 0
|
||||
b __arm7tdmi_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP | HWCAP_26BIT
|
||||
.long cpu_arm7tdmi_name
|
||||
.long HWCAP_SWP | HWCAP_26BIT | ( \extra_hwcaps )
|
||||
.long \cpu_name
|
||||
.long arm7tdmi_processor_functions
|
||||
.long 0
|
||||
.long 0
|
||||
.long v4_cache_fns
|
||||
.size __arm7tdmi_proc_info, . - __arm7tdmi_proc_info
|
||||
.size __\name\()_proc_info, . - __\name\()_proc_info
|
||||
.endm
|
||||
|
||||
.type __triscenda7_proc_info, #object
|
||||
__triscenda7_proc_info:
|
||||
.long 0x0001d2ff
|
||||
.long 0x0001ffff
|
||||
.long 0
|
||||
.long 0
|
||||
b __arm7tdmi_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT
|
||||
.long cpu_triscenda7_name
|
||||
.long arm7tdmi_processor_functions
|
||||
.long 0
|
||||
.long 0
|
||||
.long v4_cache_fns
|
||||
.size __triscenda7_proc_info, . - __triscenda7_proc_info
|
||||
|
||||
.type __at91_proc_info, #object
|
||||
__at91_proc_info:
|
||||
.long 0x14000040
|
||||
.long 0xfff000e0
|
||||
.long 0
|
||||
.long 0
|
||||
b __arm7tdmi_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT
|
||||
.long cpu_at91_name
|
||||
.long arm7tdmi_processor_functions
|
||||
.long 0
|
||||
.long 0
|
||||
.long v4_cache_fns
|
||||
.size __at91_proc_info, . - __at91_proc_info
|
||||
|
||||
.type __s3c4510b_proc_info, #object
|
||||
__s3c4510b_proc_info:
|
||||
.long 0x36365000
|
||||
.long 0xfffff000
|
||||
.long 0
|
||||
.long 0
|
||||
b __arm7tdmi_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT
|
||||
.long cpu_s3c4510b_name
|
||||
.long arm7tdmi_processor_functions
|
||||
.long 0
|
||||
.long 0
|
||||
.long v4_cache_fns
|
||||
.size __s3c4510b_proc_info, . - __s3c4510b_proc_info
|
||||
|
||||
.type __s3c4530_proc_info, #object
|
||||
__s3c4530_proc_info:
|
||||
.long 0x4c000000
|
||||
.long 0xfff000e0
|
||||
.long 0
|
||||
.long 0
|
||||
b __arm7tdmi_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT
|
||||
.long cpu_s3c4530_name
|
||||
.long arm7tdmi_processor_functions
|
||||
.long 0
|
||||
.long 0
|
||||
.long v4_cache_fns
|
||||
.size __s3c4530_proc_info, . - __s3c4530_proc_info
|
||||
|
||||
.type __s3c3410_proc_info, #object
|
||||
__s3c3410_proc_info:
|
||||
.long 0x34100000
|
||||
.long 0xffff0000
|
||||
.long 0
|
||||
.long 0
|
||||
b __arm7tdmi_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT
|
||||
.long cpu_s3c3410_name
|
||||
.long arm7tdmi_processor_functions
|
||||
.long 0
|
||||
.long 0
|
||||
.long v4_cache_fns
|
||||
.size __s3c3410_proc_info, . - __s3c3410_proc_info
|
||||
|
||||
.type __s3c44b0x_proc_info, #object
|
||||
__s3c44b0x_proc_info:
|
||||
.long 0x44b00000
|
||||
.long 0xffff0000
|
||||
.long 0
|
||||
.long 0
|
||||
b __arm7tdmi_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT
|
||||
.long cpu_s3c44b0x_name
|
||||
.long arm7tdmi_processor_functions
|
||||
.long 0
|
||||
.long 0
|
||||
.long v4_cache_fns
|
||||
.size __s3c44b0x_proc_info, . - __s3c44b0x_proc_info
|
||||
arm7tdmi_proc_info arm7tdmi, 0x41007700, 0xfff8ff00, \
|
||||
cpu_arm7tdmi_name
|
||||
arm7tdmi_proc_info triscenda7, 0x0001d2ff, 0x0001ffff, \
|
||||
cpu_triscenda7_name, extra_hwcaps=HWCAP_THUMB
|
||||
arm7tdmi_proc_info at91, 0x14000040, 0xfff000e0, \
|
||||
cpu_at91_name, extra_hwcaps=HWCAP_THUMB
|
||||
arm7tdmi_proc_info s3c4510b, 0x36365000, 0xfffff000, \
|
||||
cpu_s3c4510b_name, extra_hwcaps=HWCAP_THUMB
|
||||
arm7tdmi_proc_info s3c4530, 0x4c000000, 0xfff000e0, \
|
||||
cpu_s3c4530_name, extra_hwcaps=HWCAP_THUMB
|
||||
arm7tdmi_proc_info s3c3410, 0x34100000, 0xffff0000, \
|
||||
cpu_s3c3410_name, extra_hwcaps=HWCAP_THUMB
|
||||
arm7tdmi_proc_info s3c44b0x, 0x44b00000, 0xffff0000, \
|
||||
cpu_s3c44b0x_name, extra_hwcaps=HWCAP_THUMB
|
||||
|
|
|
@ -315,18 +315,8 @@ ENTRY(arm920_dma_unmap_area)
|
|||
mov pc, lr
|
||||
ENDPROC(arm920_dma_unmap_area)
|
||||
|
||||
ENTRY(arm920_cache_fns)
|
||||
.long arm920_flush_icache_all
|
||||
.long arm920_flush_kern_cache_all
|
||||
.long arm920_flush_user_cache_all
|
||||
.long arm920_flush_user_cache_range
|
||||
.long arm920_coherent_kern_range
|
||||
.long arm920_coherent_user_range
|
||||
.long arm920_flush_kern_dcache_area
|
||||
.long arm920_dma_map_area
|
||||
.long arm920_dma_unmap_area
|
||||
.long arm920_dma_flush_range
|
||||
|
||||
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
|
||||
define_cache_functions arm920
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -416,9 +406,6 @@ ENTRY(cpu_arm920_do_resume)
|
|||
PMD_SECT_CACHEABLE | PMD_BIT4 | PMD_SECT_AP_WRITE
|
||||
b cpu_resume_mmu
|
||||
ENDPROC(cpu_arm920_do_resume)
|
||||
#else
|
||||
#define cpu_arm920_do_suspend 0
|
||||
#define cpu_arm920_do_resume 0
|
||||
#endif
|
||||
|
||||
__CPUINIT
|
||||
|
@ -450,43 +437,14 @@ arm920_crval:
|
|||
crval clear=0x00003f3f, mmuset=0x00003135, ucset=0x00001130
|
||||
|
||||
__INITDATA
|
||||
|
||||
/*
|
||||
* Purpose : Function pointers used to access above functions - all calls
|
||||
* come through these
|
||||
*/
|
||||
.type arm920_processor_functions, #object
|
||||
arm920_processor_functions:
|
||||
.word v4t_early_abort
|
||||
.word legacy_pabort
|
||||
.word cpu_arm920_proc_init
|
||||
.word cpu_arm920_proc_fin
|
||||
.word cpu_arm920_reset
|
||||
.word cpu_arm920_do_idle
|
||||
.word cpu_arm920_dcache_clean_area
|
||||
.word cpu_arm920_switch_mm
|
||||
.word cpu_arm920_set_pte_ext
|
||||
.word cpu_arm920_suspend_size
|
||||
.word cpu_arm920_do_suspend
|
||||
.word cpu_arm920_do_resume
|
||||
.size arm920_processor_functions, . - arm920_processor_functions
|
||||
@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
|
||||
define_processor_functions arm920, dabort=v4t_early_abort, pabort=legacy_pabort, suspend=1
|
||||
|
||||
.section ".rodata"
|
||||
|
||||
.type cpu_arch_name, #object
|
||||
cpu_arch_name:
|
||||
.asciz "armv4t"
|
||||
.size cpu_arch_name, . - cpu_arch_name
|
||||
|
||||
.type cpu_elf_name, #object
|
||||
cpu_elf_name:
|
||||
.asciz "v4"
|
||||
.size cpu_elf_name, . - cpu_elf_name
|
||||
|
||||
.type cpu_arm920_name, #object
|
||||
cpu_arm920_name:
|
||||
.asciz "ARM920T"
|
||||
.size cpu_arm920_name, . - cpu_arm920_name
|
||||
string cpu_arch_name, "armv4t"
|
||||
string cpu_elf_name, "v4"
|
||||
string cpu_arm920_name, "ARM920T"
|
||||
|
||||
.align
|
||||
|
||||
|
|
|
@ -317,18 +317,8 @@ ENTRY(arm922_dma_unmap_area)
|
|||
mov pc, lr
|
||||
ENDPROC(arm922_dma_unmap_area)
|
||||
|
||||
ENTRY(arm922_cache_fns)
|
||||
.long arm922_flush_icache_all
|
||||
.long arm922_flush_kern_cache_all
|
||||
.long arm922_flush_user_cache_all
|
||||
.long arm922_flush_user_cache_range
|
||||
.long arm922_coherent_kern_range
|
||||
.long arm922_coherent_user_range
|
||||
.long arm922_flush_kern_dcache_area
|
||||
.long arm922_dma_map_area
|
||||
.long arm922_dma_unmap_area
|
||||
.long arm922_dma_flush_range
|
||||
|
||||
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
|
||||
define_cache_functions arm922
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -420,43 +410,14 @@ arm922_crval:
|
|||
crval clear=0x00003f3f, mmuset=0x00003135, ucset=0x00001130
|
||||
|
||||
__INITDATA
|
||||
|
||||
/*
|
||||
* Purpose : Function pointers used to access above functions - all calls
|
||||
* come through these
|
||||
*/
|
||||
.type arm922_processor_functions, #object
|
||||
arm922_processor_functions:
|
||||
.word v4t_early_abort
|
||||
.word legacy_pabort
|
||||
.word cpu_arm922_proc_init
|
||||
.word cpu_arm922_proc_fin
|
||||
.word cpu_arm922_reset
|
||||
.word cpu_arm922_do_idle
|
||||
.word cpu_arm922_dcache_clean_area
|
||||
.word cpu_arm922_switch_mm
|
||||
.word cpu_arm922_set_pte_ext
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.size arm922_processor_functions, . - arm922_processor_functions
|
||||
@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
|
||||
define_processor_functions arm922, dabort=v4t_early_abort, pabort=legacy_pabort
|
||||
|
||||
.section ".rodata"
|
||||
|
||||
.type cpu_arch_name, #object
|
||||
cpu_arch_name:
|
||||
.asciz "armv4t"
|
||||
.size cpu_arch_name, . - cpu_arch_name
|
||||
|
||||
.type cpu_elf_name, #object
|
||||
cpu_elf_name:
|
||||
.asciz "v4"
|
||||
.size cpu_elf_name, . - cpu_elf_name
|
||||
|
||||
.type cpu_arm922_name, #object
|
||||
cpu_arm922_name:
|
||||
.asciz "ARM922T"
|
||||
.size cpu_arm922_name, . - cpu_arm922_name
|
||||
string cpu_arch_name, "armv4t"
|
||||
string cpu_elf_name, "v4"
|
||||
string cpu_arm922_name, "ARM922T"
|
||||
|
||||
.align
|
||||
|
||||
|
|
|
@ -372,17 +372,8 @@ ENTRY(arm925_dma_unmap_area)
|
|||
mov pc, lr
|
||||
ENDPROC(arm925_dma_unmap_area)
|
||||
|
||||
ENTRY(arm925_cache_fns)
|
||||
.long arm925_flush_icache_all
|
||||
.long arm925_flush_kern_cache_all
|
||||
.long arm925_flush_user_cache_all
|
||||
.long arm925_flush_user_cache_range
|
||||
.long arm925_coherent_kern_range
|
||||
.long arm925_coherent_user_range
|
||||
.long arm925_flush_kern_dcache_area
|
||||
.long arm925_dma_map_area
|
||||
.long arm925_dma_unmap_area
|
||||
.long arm925_dma_flush_range
|
||||
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
|
||||
define_cache_functions arm925
|
||||
|
||||
ENTRY(cpu_arm925_dcache_clean_area)
|
||||
#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
|
||||
|
@ -487,52 +478,24 @@ arm925_crval:
|
|||
crval clear=0x00007f3f, mmuset=0x0000313d, ucset=0x00001130
|
||||
|
||||
__INITDATA
|
||||
|
||||
/*
|
||||
* Purpose : Function pointers used to access above functions - all calls
|
||||
* come through these
|
||||
*/
|
||||
.type arm925_processor_functions, #object
|
||||
arm925_processor_functions:
|
||||
.word v4t_early_abort
|
||||
.word legacy_pabort
|
||||
.word cpu_arm925_proc_init
|
||||
.word cpu_arm925_proc_fin
|
||||
.word cpu_arm925_reset
|
||||
.word cpu_arm925_do_idle
|
||||
.word cpu_arm925_dcache_clean_area
|
||||
.word cpu_arm925_switch_mm
|
||||
.word cpu_arm925_set_pte_ext
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.size arm925_processor_functions, . - arm925_processor_functions
|
||||
@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
|
||||
define_processor_functions arm925, dabort=v4t_early_abort, pabort=legacy_pabort
|
||||
|
||||
.section ".rodata"
|
||||
|
||||
.type cpu_arch_name, #object
|
||||
cpu_arch_name:
|
||||
.asciz "armv4t"
|
||||
.size cpu_arch_name, . - cpu_arch_name
|
||||
|
||||
.type cpu_elf_name, #object
|
||||
cpu_elf_name:
|
||||
.asciz "v4"
|
||||
.size cpu_elf_name, . - cpu_elf_name
|
||||
|
||||
.type cpu_arm925_name, #object
|
||||
cpu_arm925_name:
|
||||
.asciz "ARM925T"
|
||||
.size cpu_arm925_name, . - cpu_arm925_name
|
||||
string cpu_arch_name, "armv4t"
|
||||
string cpu_elf_name, "v4"
|
||||
string cpu_arm925_name, "ARM925T"
|
||||
|
||||
.align
|
||||
|
||||
.section ".proc.info.init", #alloc, #execinstr
|
||||
|
||||
.type __arm925_proc_info,#object
|
||||
__arm925_proc_info:
|
||||
.long 0x54029250
|
||||
.long 0xfffffff0
|
||||
.macro arm925_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, cache
|
||||
.type __\name\()_proc_info,#object
|
||||
__\name\()_proc_info:
|
||||
.long \cpu_val
|
||||
.long \cpu_mask
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_BIT4 | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
|
@ -550,27 +513,8 @@ __arm925_proc_info:
|
|||
.long v4wbi_tlb_fns
|
||||
.long v4wb_user_fns
|
||||
.long arm925_cache_fns
|
||||
.size __arm925_proc_info, . - __arm925_proc_info
|
||||
.size __\name\()_proc_info, . - __\name\()_proc_info
|
||||
.endm
|
||||
|
||||
.type __arm915_proc_info,#object
|
||||
__arm915_proc_info:
|
||||
.long 0x54029150
|
||||
.long 0xfffffff0
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_BIT4 | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_BIT4 | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
b __arm925_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
|
||||
.long cpu_arm925_name
|
||||
.long arm925_processor_functions
|
||||
.long v4wbi_tlb_fns
|
||||
.long v4wb_user_fns
|
||||
.long arm925_cache_fns
|
||||
.size __arm925_proc_info, . - __arm925_proc_info
|
||||
arm925_proc_info arm925, 0x54029250, 0xfffffff0, cpu_arm925_name
|
||||
arm925_proc_info arm915, 0x54029150, 0xfffffff0, cpu_arm925_name
|
||||
|
|
|
@ -335,17 +335,8 @@ ENTRY(arm926_dma_unmap_area)
|
|||
mov pc, lr
|
||||
ENDPROC(arm926_dma_unmap_area)
|
||||
|
||||
ENTRY(arm926_cache_fns)
|
||||
.long arm926_flush_icache_all
|
||||
.long arm926_flush_kern_cache_all
|
||||
.long arm926_flush_user_cache_all
|
||||
.long arm926_flush_user_cache_range
|
||||
.long arm926_coherent_kern_range
|
||||
.long arm926_coherent_user_range
|
||||
.long arm926_flush_kern_dcache_area
|
||||
.long arm926_dma_map_area
|
||||
.long arm926_dma_unmap_area
|
||||
.long arm926_dma_flush_range
|
||||
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
|
||||
define_cache_functions arm926
|
||||
|
||||
ENTRY(cpu_arm926_dcache_clean_area)
|
||||
#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
|
||||
|
@ -430,9 +421,6 @@ ENTRY(cpu_arm926_do_resume)
|
|||
PMD_SECT_CACHEABLE | PMD_BIT4 | PMD_SECT_AP_WRITE
|
||||
b cpu_resume_mmu
|
||||
ENDPROC(cpu_arm926_do_resume)
|
||||
#else
|
||||
#define cpu_arm926_do_suspend 0
|
||||
#define cpu_arm926_do_resume 0
|
||||
#endif
|
||||
|
||||
__CPUINIT
|
||||
|
@ -475,42 +463,14 @@ arm926_crval:
|
|||
|
||||
__INITDATA
|
||||
|
||||
/*
|
||||
* Purpose : Function pointers used to access above functions - all calls
|
||||
* come through these
|
||||
*/
|
||||
.type arm926_processor_functions, #object
|
||||
arm926_processor_functions:
|
||||
.word v5tj_early_abort
|
||||
.word legacy_pabort
|
||||
.word cpu_arm926_proc_init
|
||||
.word cpu_arm926_proc_fin
|
||||
.word cpu_arm926_reset
|
||||
.word cpu_arm926_do_idle
|
||||
.word cpu_arm926_dcache_clean_area
|
||||
.word cpu_arm926_switch_mm
|
||||
.word cpu_arm926_set_pte_ext
|
||||
.word cpu_arm926_suspend_size
|
||||
.word cpu_arm926_do_suspend
|
||||
.word cpu_arm926_do_resume
|
||||
.size arm926_processor_functions, . - arm926_processor_functions
|
||||
@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
|
||||
define_processor_functions arm926, dabort=v5tj_early_abort, pabort=legacy_pabort, suspend=1
|
||||
|
||||
.section ".rodata"
|
||||
|
||||
.type cpu_arch_name, #object
|
||||
cpu_arch_name:
|
||||
.asciz "armv5tej"
|
||||
.size cpu_arch_name, . - cpu_arch_name
|
||||
|
||||
.type cpu_elf_name, #object
|
||||
cpu_elf_name:
|
||||
.asciz "v5"
|
||||
.size cpu_elf_name, . - cpu_elf_name
|
||||
|
||||
.type cpu_arm926_name, #object
|
||||
cpu_arm926_name:
|
||||
.asciz "ARM926EJ-S"
|
||||
.size cpu_arm926_name, . - cpu_arm926_name
|
||||
string cpu_arch_name, "armv5tej"
|
||||
string cpu_elf_name, "v5"
|
||||
string cpu_arm926_name, "ARM926EJ-S"
|
||||
|
||||
.align
|
||||
|
||||
|
|
|
@ -264,17 +264,8 @@ ENTRY(arm940_dma_unmap_area)
|
|||
mov pc, lr
|
||||
ENDPROC(arm940_dma_unmap_area)
|
||||
|
||||
ENTRY(arm940_cache_fns)
|
||||
.long arm940_flush_icache_all
|
||||
.long arm940_flush_kern_cache_all
|
||||
.long arm940_flush_user_cache_all
|
||||
.long arm940_flush_user_cache_range
|
||||
.long arm940_coherent_kern_range
|
||||
.long arm940_coherent_user_range
|
||||
.long arm940_flush_kern_dcache_area
|
||||
.long arm940_dma_map_area
|
||||
.long arm940_dma_unmap_area
|
||||
.long arm940_dma_flush_range
|
||||
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
|
||||
define_cache_functions arm940
|
||||
|
||||
__CPUINIT
|
||||
|
||||
|
@ -348,42 +339,14 @@ __arm940_setup:
|
|||
|
||||
__INITDATA
|
||||
|
||||
/*
|
||||
* Purpose : Function pointers used to access above functions - all calls
|
||||
* come through these
|
||||
*/
|
||||
.type arm940_processor_functions, #object
|
||||
ENTRY(arm940_processor_functions)
|
||||
.word nommu_early_abort
|
||||
.word legacy_pabort
|
||||
.word cpu_arm940_proc_init
|
||||
.word cpu_arm940_proc_fin
|
||||
.word cpu_arm940_reset
|
||||
.word cpu_arm940_do_idle
|
||||
.word cpu_arm940_dcache_clean_area
|
||||
.word cpu_arm940_switch_mm
|
||||
.word 0 @ cpu_*_set_pte
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.size arm940_processor_functions, . - arm940_processor_functions
|
||||
@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
|
||||
define_processor_functions arm940, dabort=nommu_early_abort, pabort=legacy_pabort, nommu=1
|
||||
|
||||
.section ".rodata"
|
||||
|
||||
.type cpu_arch_name, #object
|
||||
cpu_arch_name:
|
||||
.asciz "armv4t"
|
||||
.size cpu_arch_name, . - cpu_arch_name
|
||||
|
||||
.type cpu_elf_name, #object
|
||||
cpu_elf_name:
|
||||
.asciz "v4"
|
||||
.size cpu_elf_name, . - cpu_elf_name
|
||||
|
||||
.type cpu_arm940_name, #object
|
||||
cpu_arm940_name:
|
||||
.ascii "ARM940T"
|
||||
.size cpu_arm940_name, . - cpu_arm940_name
|
||||
string cpu_arch_name, "armv4t"
|
||||
string cpu_elf_name, "v4"
|
||||
string cpu_arm940_name, "ARM940T"
|
||||
|
||||
.align
|
||||
|
||||
|
|
|
@ -306,18 +306,8 @@ ENTRY(arm946_dma_unmap_area)
|
|||
mov pc, lr
|
||||
ENDPROC(arm946_dma_unmap_area)
|
||||
|
||||
ENTRY(arm946_cache_fns)
|
||||
.long arm946_flush_icache_all
|
||||
.long arm946_flush_kern_cache_all
|
||||
.long arm946_flush_user_cache_all
|
||||
.long arm946_flush_user_cache_range
|
||||
.long arm946_coherent_kern_range
|
||||
.long arm946_coherent_user_range
|
||||
.long arm946_flush_kern_dcache_area
|
||||
.long arm946_dma_map_area
|
||||
.long arm946_dma_unmap_area
|
||||
.long arm946_dma_flush_range
|
||||
|
||||
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
|
||||
define_cache_functions arm946
|
||||
|
||||
ENTRY(cpu_arm946_dcache_clean_area)
|
||||
#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
|
||||
|
@ -403,43 +393,14 @@ __arm946_setup:
|
|||
|
||||
__INITDATA
|
||||
|
||||
/*
|
||||
* Purpose : Function pointers used to access above functions - all calls
|
||||
* come through these
|
||||
*/
|
||||
.type arm946_processor_functions, #object
|
||||
ENTRY(arm946_processor_functions)
|
||||
.word nommu_early_abort
|
||||
.word legacy_pabort
|
||||
.word cpu_arm946_proc_init
|
||||
.word cpu_arm946_proc_fin
|
||||
.word cpu_arm946_reset
|
||||
.word cpu_arm946_do_idle
|
||||
|
||||
.word cpu_arm946_dcache_clean_area
|
||||
.word cpu_arm946_switch_mm
|
||||
.word 0 @ cpu_*_set_pte
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.size arm946_processor_functions, . - arm946_processor_functions
|
||||
@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
|
||||
define_processor_functions arm946, dabort=nommu_early_abort, pabort=legacy_pabort, nommu=1
|
||||
|
||||
.section ".rodata"
|
||||
|
||||
.type cpu_arch_name, #object
|
||||
cpu_arch_name:
|
||||
.asciz "armv5te"
|
||||
.size cpu_arch_name, . - cpu_arch_name
|
||||
|
||||
.type cpu_elf_name, #object
|
||||
cpu_elf_name:
|
||||
.asciz "v5t"
|
||||
.size cpu_elf_name, . - cpu_elf_name
|
||||
|
||||
.type cpu_arm946_name, #object
|
||||
cpu_arm946_name:
|
||||
.ascii "ARM946E-S"
|
||||
.size cpu_arm946_name, . - cpu_arm946_name
|
||||
string cpu_arch_name, "armv5te"
|
||||
string cpu_elf_name, "v5t"
|
||||
string cpu_arm946_name, "ARM946E-S"
|
||||
|
||||
.align
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include <asm/pgtable.h>
|
||||
#include <asm/ptrace.h>
|
||||
|
||||
#include "proc-macros.S"
|
||||
|
||||
.text
|
||||
/*
|
||||
* cpu_arm9tdmi_proc_init()
|
||||
|
@ -55,82 +57,38 @@ __arm9tdmi_setup:
|
|||
|
||||
__INITDATA
|
||||
|
||||
/*
|
||||
* Purpose : Function pointers used to access above functions - all calls
|
||||
* come through these
|
||||
*/
|
||||
.type arm9tdmi_processor_functions, #object
|
||||
ENTRY(arm9tdmi_processor_functions)
|
||||
.word nommu_early_abort
|
||||
.word legacy_pabort
|
||||
.word cpu_arm9tdmi_proc_init
|
||||
.word cpu_arm9tdmi_proc_fin
|
||||
.word cpu_arm9tdmi_reset
|
||||
.word cpu_arm9tdmi_do_idle
|
||||
.word cpu_arm9tdmi_dcache_clean_area
|
||||
.word cpu_arm9tdmi_switch_mm
|
||||
.word 0 @ cpu_*_set_pte
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.size arm9tdmi_processor_functions, . - arm9tdmi_processor_functions
|
||||
@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
|
||||
define_processor_functions arm9tdmi, dabort=nommu_early_abort, pabort=legacy_pabort, nommu=1
|
||||
|
||||
.section ".rodata"
|
||||
|
||||
.type cpu_arch_name, #object
|
||||
cpu_arch_name:
|
||||
.asciz "armv4t"
|
||||
.size cpu_arch_name, . - cpu_arch_name
|
||||
|
||||
.type cpu_elf_name, #object
|
||||
cpu_elf_name:
|
||||
.asciz "v4"
|
||||
.size cpu_elf_name, . - cpu_elf_name
|
||||
|
||||
.type cpu_arm9tdmi_name, #object
|
||||
cpu_arm9tdmi_name:
|
||||
.asciz "ARM9TDMI"
|
||||
.size cpu_arm9tdmi_name, . - cpu_arm9tdmi_name
|
||||
|
||||
.type cpu_p2001_name, #object
|
||||
cpu_p2001_name:
|
||||
.asciz "P2001"
|
||||
.size cpu_p2001_name, . - cpu_p2001_name
|
||||
string cpu_arch_name, "armv4t"
|
||||
string cpu_elf_name, "v4"
|
||||
string cpu_arm9tdmi_name, "ARM9TDMI"
|
||||
string cpu_p2001_name, "P2001"
|
||||
|
||||
.align
|
||||
|
||||
.section ".proc.info.init", #alloc, #execinstr
|
||||
|
||||
.type __arm9tdmi_proc_info, #object
|
||||
__arm9tdmi_proc_info:
|
||||
.long 0x41009900
|
||||
.long 0xfff8ff00
|
||||
.macro arm9tdmi_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req
|
||||
.type __\name\()_proc_info, #object
|
||||
__\name\()_proc_info:
|
||||
.long \cpu_val
|
||||
.long \cpu_mask
|
||||
.long 0
|
||||
.long 0
|
||||
b __arm9tdmi_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT
|
||||
.long cpu_arm9tdmi_name
|
||||
.long \cpu_name
|
||||
.long arm9tdmi_processor_functions
|
||||
.long 0
|
||||
.long 0
|
||||
.long v4_cache_fns
|
||||
.size __arm9tdmi_proc_info, . - __arm9tdmi_proc_info
|
||||
.size __\name\()_proc_info, . - __\name\()_proc_info
|
||||
.endm
|
||||
|
||||
.type __p2001_proc_info, #object
|
||||
__p2001_proc_info:
|
||||
.long 0x41029000
|
||||
.long 0xffffffff
|
||||
.long 0
|
||||
.long 0
|
||||
b __arm9tdmi_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT
|
||||
.long cpu_p2001_name
|
||||
.long arm9tdmi_processor_functions
|
||||
.long 0
|
||||
.long 0
|
||||
.long v4_cache_fns
|
||||
.size __p2001_proc_info, . - __p2001_proc_info
|
||||
arm9tdmi_proc_info arm9tdmi, 0x41009900, 0xfff8ff00, cpu_arm9tdmi_name
|
||||
arm9tdmi_proc_info p2001, 0x41029000, 0xffffffff, cpu_p2001_name
|
||||
|
|
|
@ -180,42 +180,14 @@ fa526_cr1_set:
|
|||
|
||||
__INITDATA
|
||||
|
||||
/*
|
||||
* Purpose : Function pointers used to access above functions - all calls
|
||||
* come through these
|
||||
*/
|
||||
.type fa526_processor_functions, #object
|
||||
fa526_processor_functions:
|
||||
.word v4_early_abort
|
||||
.word legacy_pabort
|
||||
.word cpu_fa526_proc_init
|
||||
.word cpu_fa526_proc_fin
|
||||
.word cpu_fa526_reset
|
||||
.word cpu_fa526_do_idle
|
||||
.word cpu_fa526_dcache_clean_area
|
||||
.word cpu_fa526_switch_mm
|
||||
.word cpu_fa526_set_pte_ext
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.size fa526_processor_functions, . - fa526_processor_functions
|
||||
@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
|
||||
define_processor_functions fa526, dabort=v4_early_abort, pabort=legacy_pabort
|
||||
|
||||
.section ".rodata"
|
||||
|
||||
.type cpu_arch_name, #object
|
||||
cpu_arch_name:
|
||||
.asciz "armv4"
|
||||
.size cpu_arch_name, . - cpu_arch_name
|
||||
|
||||
.type cpu_elf_name, #object
|
||||
cpu_elf_name:
|
||||
.asciz "v4"
|
||||
.size cpu_elf_name, . - cpu_elf_name
|
||||
|
||||
.type cpu_fa526_name, #object
|
||||
cpu_fa526_name:
|
||||
.asciz "FA526"
|
||||
.size cpu_fa526_name, . - cpu_fa526_name
|
||||
string cpu_arch_name, "armv4"
|
||||
string cpu_elf_name, "v4"
|
||||
string cpu_fa526_name, "FA526"
|
||||
|
||||
.align
|
||||
|
||||
|
|
|
@ -411,29 +411,28 @@ ENTRY(feroceon_dma_unmap_area)
|
|||
mov pc, lr
|
||||
ENDPROC(feroceon_dma_unmap_area)
|
||||
|
||||
ENTRY(feroceon_cache_fns)
|
||||
.long feroceon_flush_icache_all
|
||||
.long feroceon_flush_kern_cache_all
|
||||
.long feroceon_flush_user_cache_all
|
||||
.long feroceon_flush_user_cache_range
|
||||
.long feroceon_coherent_kern_range
|
||||
.long feroceon_coherent_user_range
|
||||
.long feroceon_flush_kern_dcache_area
|
||||
.long feroceon_dma_map_area
|
||||
.long feroceon_dma_unmap_area
|
||||
.long feroceon_dma_flush_range
|
||||
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
|
||||
define_cache_functions feroceon
|
||||
|
||||
ENTRY(feroceon_range_cache_fns)
|
||||
.long feroceon_flush_icache_all
|
||||
.long feroceon_flush_kern_cache_all
|
||||
.long feroceon_flush_user_cache_all
|
||||
.long feroceon_flush_user_cache_range
|
||||
.long feroceon_coherent_kern_range
|
||||
.long feroceon_coherent_user_range
|
||||
.long feroceon_range_flush_kern_dcache_area
|
||||
.long feroceon_range_dma_map_area
|
||||
.long feroceon_dma_unmap_area
|
||||
.long feroceon_range_dma_flush_range
|
||||
.macro range_alias basename
|
||||
.globl feroceon_range_\basename
|
||||
.type feroceon_range_\basename , %function
|
||||
.equ feroceon_range_\basename , feroceon_\basename
|
||||
.endm
|
||||
|
||||
/*
|
||||
* Most of the cache functions are unchanged for this case.
|
||||
* Export suitable alias symbols for the unchanged functions:
|
||||
*/
|
||||
range_alias flush_icache_all
|
||||
range_alias flush_user_cache_all
|
||||
range_alias flush_kern_cache_all
|
||||
range_alias flush_user_cache_range
|
||||
range_alias coherent_kern_range
|
||||
range_alias coherent_user_range
|
||||
range_alias dma_unmap_area
|
||||
|
||||
define_cache_functions feroceon_range
|
||||
|
||||
.align 5
|
||||
ENTRY(cpu_feroceon_dcache_clean_area)
|
||||
|
@ -539,67 +538,27 @@ feroceon_crval:
|
|||
|
||||
__INITDATA
|
||||
|
||||
/*
|
||||
* Purpose : Function pointers used to access above functions - all calls
|
||||
* come through these
|
||||
*/
|
||||
.type feroceon_processor_functions, #object
|
||||
feroceon_processor_functions:
|
||||
.word v5t_early_abort
|
||||
.word legacy_pabort
|
||||
.word cpu_feroceon_proc_init
|
||||
.word cpu_feroceon_proc_fin
|
||||
.word cpu_feroceon_reset
|
||||
.word cpu_feroceon_do_idle
|
||||
.word cpu_feroceon_dcache_clean_area
|
||||
.word cpu_feroceon_switch_mm
|
||||
.word cpu_feroceon_set_pte_ext
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.size feroceon_processor_functions, . - feroceon_processor_functions
|
||||
@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
|
||||
define_processor_functions feroceon, dabort=v5t_early_abort, pabort=legacy_pabort
|
||||
|
||||
.section ".rodata"
|
||||
|
||||
.type cpu_arch_name, #object
|
||||
cpu_arch_name:
|
||||
.asciz "armv5te"
|
||||
.size cpu_arch_name, . - cpu_arch_name
|
||||
|
||||
.type cpu_elf_name, #object
|
||||
cpu_elf_name:
|
||||
.asciz "v5"
|
||||
.size cpu_elf_name, . - cpu_elf_name
|
||||
|
||||
.type cpu_feroceon_name, #object
|
||||
cpu_feroceon_name:
|
||||
.asciz "Feroceon"
|
||||
.size cpu_feroceon_name, . - cpu_feroceon_name
|
||||
|
||||
.type cpu_88fr531_name, #object
|
||||
cpu_88fr531_name:
|
||||
.asciz "Feroceon 88FR531-vd"
|
||||
.size cpu_88fr531_name, . - cpu_88fr531_name
|
||||
|
||||
.type cpu_88fr571_name, #object
|
||||
cpu_88fr571_name:
|
||||
.asciz "Feroceon 88FR571-vd"
|
||||
.size cpu_88fr571_name, . - cpu_88fr571_name
|
||||
|
||||
.type cpu_88fr131_name, #object
|
||||
cpu_88fr131_name:
|
||||
.asciz "Feroceon 88FR131"
|
||||
.size cpu_88fr131_name, . - cpu_88fr131_name
|
||||
string cpu_arch_name, "armv5te"
|
||||
string cpu_elf_name, "v5"
|
||||
string cpu_feroceon_name, "Feroceon"
|
||||
string cpu_88fr531_name, "Feroceon 88FR531-vd"
|
||||
string cpu_88fr571_name, "Feroceon 88FR571-vd"
|
||||
string cpu_88fr131_name, "Feroceon 88FR131"
|
||||
|
||||
.align
|
||||
|
||||
.section ".proc.info.init", #alloc, #execinstr
|
||||
|
||||
#ifdef CONFIG_CPU_FEROCEON_OLD_ID
|
||||
.type __feroceon_old_id_proc_info,#object
|
||||
__feroceon_old_id_proc_info:
|
||||
.long 0x41009260
|
||||
.long 0xff00fff0
|
||||
.macro feroceon_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, cache:req
|
||||
.type __\name\()_proc_info,#object
|
||||
__\name\()_proc_info:
|
||||
.long \cpu_val
|
||||
.long \cpu_mask
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_BUFFERABLE | \
|
||||
PMD_SECT_CACHEABLE | \
|
||||
|
@ -614,85 +573,22 @@ __feroceon_old_id_proc_info:
|
|||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
|
||||
.long cpu_feroceon_name
|
||||
.long \cpu_name
|
||||
.long feroceon_processor_functions
|
||||
.long v4wbi_tlb_fns
|
||||
.long feroceon_user_fns
|
||||
.long feroceon_cache_fns
|
||||
.size __feroceon_old_id_proc_info, . - __feroceon_old_id_proc_info
|
||||
.long \cache
|
||||
.size __\name\()_proc_info, . - __\name\()_proc_info
|
||||
.endm
|
||||
|
||||
#ifdef CONFIG_CPU_FEROCEON_OLD_ID
|
||||
feroceon_proc_info feroceon_old_id, 0x41009260, 0xff00fff0, \
|
||||
cpu_name=cpu_feroceon_name, cache=feroceon_cache_fns
|
||||
#endif
|
||||
|
||||
.type __88fr531_proc_info,#object
|
||||
__88fr531_proc_info:
|
||||
.long 0x56055310
|
||||
.long 0xfffffff0
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_BUFFERABLE | \
|
||||
PMD_SECT_CACHEABLE | \
|
||||
PMD_BIT4 | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_BIT4 | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
b __feroceon_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
|
||||
.long cpu_88fr531_name
|
||||
.long feroceon_processor_functions
|
||||
.long v4wbi_tlb_fns
|
||||
.long feroceon_user_fns
|
||||
.long feroceon_cache_fns
|
||||
.size __88fr531_proc_info, . - __88fr531_proc_info
|
||||
|
||||
.type __88fr571_proc_info,#object
|
||||
__88fr571_proc_info:
|
||||
.long 0x56155710
|
||||
.long 0xfffffff0
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_BUFFERABLE | \
|
||||
PMD_SECT_CACHEABLE | \
|
||||
PMD_BIT4 | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_BIT4 | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
b __feroceon_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
|
||||
.long cpu_88fr571_name
|
||||
.long feroceon_processor_functions
|
||||
.long v4wbi_tlb_fns
|
||||
.long feroceon_user_fns
|
||||
.long feroceon_range_cache_fns
|
||||
.size __88fr571_proc_info, . - __88fr571_proc_info
|
||||
|
||||
.type __88fr131_proc_info,#object
|
||||
__88fr131_proc_info:
|
||||
.long 0x56251310
|
||||
.long 0xfffffff0
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_BUFFERABLE | \
|
||||
PMD_SECT_CACHEABLE | \
|
||||
PMD_BIT4 | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_BIT4 | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
b __feroceon_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
|
||||
.long cpu_88fr131_name
|
||||
.long feroceon_processor_functions
|
||||
.long v4wbi_tlb_fns
|
||||
.long feroceon_user_fns
|
||||
.long feroceon_range_cache_fns
|
||||
.size __88fr131_proc_info, . - __88fr131_proc_info
|
||||
feroceon_proc_info 88fr531, 0x56055310, 0xfffffff0, cpu_88fr531_name, \
|
||||
cache=feroceon_cache_fns
|
||||
feroceon_proc_info 88fr571, 0x56155710, 0xfffffff0, cpu_88fr571_name, \
|
||||
cache=feroceon_range_cache_fns
|
||||
feroceon_proc_info 88fr131, 0x56251310, 0xfffffff0, cpu_88fr131_name, \
|
||||
cache=feroceon_range_cache_fns
|
||||
|
|
|
@ -254,3 +254,71 @@
|
|||
mcr p15, 0, r0, c7, c10, 1 @ clean L1 D line
|
||||
mcr p15, 0, ip, c7, c10, 4 @ data write barrier
|
||||
.endm
|
||||
|
||||
.macro define_processor_functions name:req, dabort:req, pabort:req, nommu=0, suspend=0
|
||||
.type \name\()_processor_functions, #object
|
||||
.align 2
|
||||
ENTRY(\name\()_processor_functions)
|
||||
.word \dabort
|
||||
.word \pabort
|
||||
.word cpu_\name\()_proc_init
|
||||
.word cpu_\name\()_proc_fin
|
||||
.word cpu_\name\()_reset
|
||||
.word cpu_\name\()_do_idle
|
||||
.word cpu_\name\()_dcache_clean_area
|
||||
.word cpu_\name\()_switch_mm
|
||||
|
||||
.if \nommu
|
||||
.word 0
|
||||
.else
|
||||
.word cpu_\name\()_set_pte_ext
|
||||
.endif
|
||||
|
||||
.if \suspend
|
||||
.word cpu_\name\()_suspend_size
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.word cpu_\name\()_do_suspend
|
||||
.word cpu_\name\()_do_resume
|
||||
#else
|
||||
.word 0
|
||||
.word 0
|
||||
#endif
|
||||
.else
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.endif
|
||||
|
||||
.size \name\()_processor_functions, . - \name\()_processor_functions
|
||||
.endm
|
||||
|
||||
.macro define_cache_functions name:req
|
||||
.align 2
|
||||
.type \name\()_cache_fns, #object
|
||||
ENTRY(\name\()_cache_fns)
|
||||
.long \name\()_flush_icache_all
|
||||
.long \name\()_flush_kern_cache_all
|
||||
.long \name\()_flush_user_cache_all
|
||||
.long \name\()_flush_user_cache_range
|
||||
.long \name\()_coherent_kern_range
|
||||
.long \name\()_coherent_user_range
|
||||
.long \name\()_flush_kern_dcache_area
|
||||
.long \name\()_dma_map_area
|
||||
.long \name\()_dma_unmap_area
|
||||
.long \name\()_dma_flush_range
|
||||
.size \name\()_cache_fns, . - \name\()_cache_fns
|
||||
.endm
|
||||
|
||||
.macro define_tlb_functions name:req, flags_up:req, flags_smp
|
||||
.type \name\()_tlb_fns, #object
|
||||
ENTRY(\name\()_tlb_fns)
|
||||
.long \name\()_flush_user_tlb_range
|
||||
.long \name\()_flush_kern_tlb_range
|
||||
.ifnb \flags_smp
|
||||
ALT_SMP(.long \flags_smp )
|
||||
ALT_UP(.long \flags_up )
|
||||
.else
|
||||
.long \flags_up
|
||||
.endif
|
||||
.size \name\()_tlb_fns, . - \name\()_tlb_fns
|
||||
.endm
|
||||
|
|
|
@ -92,6 +92,17 @@ ENTRY(cpu_mohawk_do_idle)
|
|||
mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt
|
||||
mov pc, lr
|
||||
|
||||
/*
|
||||
* flush_icache_all()
|
||||
*
|
||||
* Unconditionally clean and invalidate the entire icache.
|
||||
*/
|
||||
ENTRY(mohawk_flush_icache_all)
|
||||
mov r0, #0
|
||||
mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
|
||||
mov pc, lr
|
||||
ENDPROC(mohawk_flush_icache_all)
|
||||
|
||||
/*
|
||||
* flush_user_cache_all()
|
||||
*
|
||||
|
@ -288,16 +299,8 @@ ENTRY(mohawk_dma_unmap_area)
|
|||
mov pc, lr
|
||||
ENDPROC(mohawk_dma_unmap_area)
|
||||
|
||||
ENTRY(mohawk_cache_fns)
|
||||
.long mohawk_flush_kern_cache_all
|
||||
.long mohawk_flush_user_cache_all
|
||||
.long mohawk_flush_user_cache_range
|
||||
.long mohawk_coherent_kern_range
|
||||
.long mohawk_coherent_user_range
|
||||
.long mohawk_flush_kern_dcache_area
|
||||
.long mohawk_dma_map_area
|
||||
.long mohawk_dma_unmap_area
|
||||
.long mohawk_dma_flush_range
|
||||
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
|
||||
define_cache_functions mohawk
|
||||
|
||||
ENTRY(cpu_mohawk_dcache_clean_area)
|
||||
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
|
||||
|
@ -373,42 +376,14 @@ mohawk_crval:
|
|||
|
||||
__INITDATA
|
||||
|
||||
/*
|
||||
* Purpose : Function pointers used to access above functions - all calls
|
||||
* come through these
|
||||
*/
|
||||
.type mohawk_processor_functions, #object
|
||||
mohawk_processor_functions:
|
||||
.word v5t_early_abort
|
||||
.word legacy_pabort
|
||||
.word cpu_mohawk_proc_init
|
||||
.word cpu_mohawk_proc_fin
|
||||
.word cpu_mohawk_reset
|
||||
.word cpu_mohawk_do_idle
|
||||
.word cpu_mohawk_dcache_clean_area
|
||||
.word cpu_mohawk_switch_mm
|
||||
.word cpu_mohawk_set_pte_ext
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.size mohawk_processor_functions, . - mohawk_processor_functions
|
||||
@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
|
||||
define_processor_functions mohawk, dabort=v5t_early_abort, pabort=legacy_pabort
|
||||
|
||||
.section ".rodata"
|
||||
|
||||
.type cpu_arch_name, #object
|
||||
cpu_arch_name:
|
||||
.asciz "armv5te"
|
||||
.size cpu_arch_name, . - cpu_arch_name
|
||||
|
||||
.type cpu_elf_name, #object
|
||||
cpu_elf_name:
|
||||
.asciz "v5"
|
||||
.size cpu_elf_name, . - cpu_elf_name
|
||||
|
||||
.type cpu_mohawk_name, #object
|
||||
cpu_mohawk_name:
|
||||
.asciz "Marvell 88SV331x"
|
||||
.size cpu_mohawk_name, . - cpu_mohawk_name
|
||||
string cpu_arch_name, "armv5te"
|
||||
string cpu_elf_name, "v5"
|
||||
string cpu_mohawk_name, "Marvell 88SV331x"
|
||||
|
||||
.align
|
||||
|
||||
|
|
|
@ -187,43 +187,14 @@ sa110_crval:
|
|||
|
||||
__INITDATA
|
||||
|
||||
/*
|
||||
* Purpose : Function pointers used to access above functions - all calls
|
||||
* come through these
|
||||
*/
|
||||
|
||||
.type sa110_processor_functions, #object
|
||||
ENTRY(sa110_processor_functions)
|
||||
.word v4_early_abort
|
||||
.word legacy_pabort
|
||||
.word cpu_sa110_proc_init
|
||||
.word cpu_sa110_proc_fin
|
||||
.word cpu_sa110_reset
|
||||
.word cpu_sa110_do_idle
|
||||
.word cpu_sa110_dcache_clean_area
|
||||
.word cpu_sa110_switch_mm
|
||||
.word cpu_sa110_set_pte_ext
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.size sa110_processor_functions, . - sa110_processor_functions
|
||||
@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
|
||||
define_processor_functions sa110, dabort=v4_early_abort, pabort=legacy_pabort
|
||||
|
||||
.section ".rodata"
|
||||
|
||||
.type cpu_arch_name, #object
|
||||
cpu_arch_name:
|
||||
.asciz "armv4"
|
||||
.size cpu_arch_name, . - cpu_arch_name
|
||||
|
||||
.type cpu_elf_name, #object
|
||||
cpu_elf_name:
|
||||
.asciz "v4"
|
||||
.size cpu_elf_name, . - cpu_elf_name
|
||||
|
||||
.type cpu_sa110_name, #object
|
||||
cpu_sa110_name:
|
||||
.asciz "StrongARM-110"
|
||||
.size cpu_sa110_name, . - cpu_sa110_name
|
||||
string cpu_arch_name, "armv4"
|
||||
string cpu_elf_name, "v4"
|
||||
string cpu_sa110_name, "StrongARM-110"
|
||||
|
||||
.align
|
||||
|
||||
|
|
|
@ -198,9 +198,6 @@ ENTRY(cpu_sa1100_do_resume)
|
|||
PMD_SECT_CACHEABLE | PMD_SECT_AP_WRITE
|
||||
b cpu_resume_mmu
|
||||
ENDPROC(cpu_sa1100_do_resume)
|
||||
#else
|
||||
#define cpu_sa1100_do_suspend 0
|
||||
#define cpu_sa1100_do_resume 0
|
||||
#endif
|
||||
|
||||
__CPUINIT
|
||||
|
@ -233,60 +230,29 @@ sa1100_crval:
|
|||
|
||||
__INITDATA
|
||||
|
||||
/*
|
||||
* Purpose : Function pointers used to access above functions - all calls
|
||||
* come through these
|
||||
*/
|
||||
|
||||
/*
|
||||
* SA1100 and SA1110 share the same function calls
|
||||
*/
|
||||
.type sa1100_processor_functions, #object
|
||||
ENTRY(sa1100_processor_functions)
|
||||
.word v4_early_abort
|
||||
.word legacy_pabort
|
||||
.word cpu_sa1100_proc_init
|
||||
.word cpu_sa1100_proc_fin
|
||||
.word cpu_sa1100_reset
|
||||
.word cpu_sa1100_do_idle
|
||||
.word cpu_sa1100_dcache_clean_area
|
||||
.word cpu_sa1100_switch_mm
|
||||
.word cpu_sa1100_set_pte_ext
|
||||
.word cpu_sa1100_suspend_size
|
||||
.word cpu_sa1100_do_suspend
|
||||
.word cpu_sa1100_do_resume
|
||||
.size sa1100_processor_functions, . - sa1100_processor_functions
|
||||
|
||||
@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
|
||||
define_processor_functions sa1100, dabort=v4_early_abort, pabort=legacy_pabort, suspend=1
|
||||
|
||||
.section ".rodata"
|
||||
|
||||
.type cpu_arch_name, #object
|
||||
cpu_arch_name:
|
||||
.asciz "armv4"
|
||||
.size cpu_arch_name, . - cpu_arch_name
|
||||
|
||||
.type cpu_elf_name, #object
|
||||
cpu_elf_name:
|
||||
.asciz "v4"
|
||||
.size cpu_elf_name, . - cpu_elf_name
|
||||
|
||||
.type cpu_sa1100_name, #object
|
||||
cpu_sa1100_name:
|
||||
.asciz "StrongARM-1100"
|
||||
.size cpu_sa1100_name, . - cpu_sa1100_name
|
||||
|
||||
.type cpu_sa1110_name, #object
|
||||
cpu_sa1110_name:
|
||||
.asciz "StrongARM-1110"
|
||||
.size cpu_sa1110_name, . - cpu_sa1110_name
|
||||
string cpu_arch_name, "armv4"
|
||||
string cpu_elf_name, "v4"
|
||||
string cpu_sa1100_name, "StrongARM-1100"
|
||||
string cpu_sa1110_name, "StrongARM-1110"
|
||||
|
||||
.align
|
||||
|
||||
.section ".proc.info.init", #alloc, #execinstr
|
||||
|
||||
.type __sa1100_proc_info,#object
|
||||
__sa1100_proc_info:
|
||||
.long 0x4401a110
|
||||
.long 0xfffffff0
|
||||
.macro sa1100_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req
|
||||
.type __\name\()_proc_info,#object
|
||||
__\name\()_proc_info:
|
||||
.long \cpu_val
|
||||
.long \cpu_mask
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_BUFFERABLE | \
|
||||
PMD_SECT_CACHEABLE | \
|
||||
|
@ -299,32 +265,13 @@ __sa1100_proc_info:
|
|||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT
|
||||
.long cpu_sa1100_name
|
||||
.long \cpu_name
|
||||
.long sa1100_processor_functions
|
||||
.long v4wb_tlb_fns
|
||||
.long v4_mc_user_fns
|
||||
.long v4wb_cache_fns
|
||||
.size __sa1100_proc_info, . - __sa1100_proc_info
|
||||
.size __\name\()_proc_info, . - __\name\()_proc_info
|
||||
.endm
|
||||
|
||||
.type __sa1110_proc_info,#object
|
||||
__sa1110_proc_info:
|
||||
.long 0x6901b110
|
||||
.long 0xfffffff0
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_BUFFERABLE | \
|
||||
PMD_SECT_CACHEABLE | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
b __sa1100_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT
|
||||
.long cpu_sa1110_name
|
||||
.long sa1100_processor_functions
|
||||
.long v4wb_tlb_fns
|
||||
.long v4_mc_user_fns
|
||||
.long v4wb_cache_fns
|
||||
.size __sa1110_proc_info, . - __sa1110_proc_info
|
||||
sa1100_proc_info sa1100, 0x4401a110, 0xfffffff0, cpu_sa1100_name
|
||||
sa1100_proc_info sa1110, 0x6901b110, 0xfffffff0, cpu_sa1110_name
|
||||
|
|
|
@ -56,6 +56,11 @@ ENTRY(cpu_v6_proc_fin)
|
|||
*/
|
||||
.align 5
|
||||
ENTRY(cpu_v6_reset)
|
||||
mrc p15, 0, r1, c1, c0, 0 @ ctrl register
|
||||
bic r1, r1, #0x1 @ ...............m
|
||||
mcr p15, 0, r1, c1, c0, 0 @ disable MMU
|
||||
mov r1, #0
|
||||
mcr p15, 0, r1, c7, c5, 4 @ ISB
|
||||
mov pc, r0
|
||||
|
||||
/*
|
||||
|
@ -164,16 +169,9 @@ ENDPROC(cpu_v6_do_resume)
|
|||
cpu_resume_l1_flags:
|
||||
ALT_SMP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_SMP)
|
||||
ALT_UP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_UP)
|
||||
#else
|
||||
#define cpu_v6_do_suspend 0
|
||||
#define cpu_v6_do_resume 0
|
||||
#endif
|
||||
|
||||
|
||||
.type cpu_v6_name, #object
|
||||
cpu_v6_name:
|
||||
.asciz "ARMv6-compatible processor"
|
||||
.size cpu_v6_name, . - cpu_v6_name
|
||||
string cpu_v6_name, "ARMv6-compatible processor"
|
||||
|
||||
.align
|
||||
|
||||
|
@ -239,33 +237,13 @@ v6_crval:
|
|||
|
||||
__INITDATA
|
||||
|
||||
.type v6_processor_functions, #object
|
||||
ENTRY(v6_processor_functions)
|
||||
.word v6_early_abort
|
||||
.word v6_pabort
|
||||
.word cpu_v6_proc_init
|
||||
.word cpu_v6_proc_fin
|
||||
.word cpu_v6_reset
|
||||
.word cpu_v6_do_idle
|
||||
.word cpu_v6_dcache_clean_area
|
||||
.word cpu_v6_switch_mm
|
||||
.word cpu_v6_set_pte_ext
|
||||
.word cpu_v6_suspend_size
|
||||
.word cpu_v6_do_suspend
|
||||
.word cpu_v6_do_resume
|
||||
.size v6_processor_functions, . - v6_processor_functions
|
||||
@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
|
||||
define_processor_functions v6, dabort=v6_early_abort, pabort=v6_pabort, suspend=1
|
||||
|
||||
.section ".rodata"
|
||||
|
||||
.type cpu_arch_name, #object
|
||||
cpu_arch_name:
|
||||
.asciz "armv6"
|
||||
.size cpu_arch_name, . - cpu_arch_name
|
||||
|
||||
.type cpu_elf_name, #object
|
||||
cpu_elf_name:
|
||||
.asciz "v6"
|
||||
.size cpu_elf_name, . - cpu_elf_name
|
||||
string cpu_arch_name, "armv6"
|
||||
string cpu_elf_name, "v6"
|
||||
.align
|
||||
|
||||
.section ".proc.info.init", #alloc, #execinstr
|
||||
|
|
|
@ -58,9 +58,16 @@ ENDPROC(cpu_v7_proc_fin)
|
|||
* to what would be the reset vector.
|
||||
*
|
||||
* - loc - location to jump to for soft reset
|
||||
*
|
||||
* This code must be executed using a flat identity mapping with
|
||||
* caches disabled.
|
||||
*/
|
||||
.align 5
|
||||
ENTRY(cpu_v7_reset)
|
||||
mrc p15, 0, r1, c1, c0, 0 @ ctrl register
|
||||
bic r1, r1, #0x1 @ ...............m
|
||||
mcr p15, 0, r1, c1, c0, 0 @ disable MMU
|
||||
isb
|
||||
mov pc, r0
|
||||
ENDPROC(cpu_v7_reset)
|
||||
|
||||
|
@ -173,8 +180,7 @@ ENTRY(cpu_v7_set_pte_ext)
|
|||
mov pc, lr
|
||||
ENDPROC(cpu_v7_set_pte_ext)
|
||||
|
||||
cpu_v7_name:
|
||||
.ascii "ARMv7 Processor"
|
||||
string cpu_v7_name, "ARMv7 Processor"
|
||||
.align
|
||||
|
||||
/*
|
||||
|
@ -257,9 +263,6 @@ ENDPROC(cpu_v7_do_resume)
|
|||
cpu_resume_l1_flags:
|
||||
ALT_SMP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_SMP)
|
||||
ALT_UP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_UP)
|
||||
#else
|
||||
#define cpu_v7_do_suspend 0
|
||||
#define cpu_v7_do_resume 0
|
||||
#endif
|
||||
|
||||
__CPUINIT
|
||||
|
@ -279,13 +282,20 @@ cpu_resume_l1_flags:
|
|||
* It is assumed that:
|
||||
* - cache type register is implemented
|
||||
*/
|
||||
__v7_ca5mp_setup:
|
||||
__v7_ca9mp_setup:
|
||||
mov r10, #(1 << 0) @ TLB ops broadcasting
|
||||
b 1f
|
||||
__v7_ca15mp_setup:
|
||||
mov r10, #0
|
||||
1:
|
||||
#ifdef CONFIG_SMP
|
||||
ALT_SMP(mrc p15, 0, r0, c1, c0, 1)
|
||||
ALT_UP(mov r0, #(1 << 6)) @ fake it for UP
|
||||
tst r0, #(1 << 6) @ SMP/nAMP mode enabled?
|
||||
orreq r0, r0, #(1 << 6) | (1 << 0) @ Enable SMP/nAMP mode and
|
||||
mcreq p15, 0, r0, c1, c0, 1 @ TLB ops broadcasting
|
||||
orreq r0, r0, #(1 << 6) @ Enable SMP/nAMP mode
|
||||
orreq r0, r0, r10 @ Enable CPU-specific SMP bits
|
||||
mcreq p15, 0, r0, c1, c0, 1
|
||||
#endif
|
||||
__v7_setup:
|
||||
adr r12, __v7_setup_stack @ the local stack
|
||||
|
@ -411,66 +421,69 @@ __v7_setup_stack:
|
|||
|
||||
__INITDATA
|
||||
|
||||
.type v7_processor_functions, #object
|
||||
ENTRY(v7_processor_functions)
|
||||
.word v7_early_abort
|
||||
.word v7_pabort
|
||||
.word cpu_v7_proc_init
|
||||
.word cpu_v7_proc_fin
|
||||
.word cpu_v7_reset
|
||||
.word cpu_v7_do_idle
|
||||
.word cpu_v7_dcache_clean_area
|
||||
.word cpu_v7_switch_mm
|
||||
.word cpu_v7_set_pte_ext
|
||||
.word cpu_v7_suspend_size
|
||||
.word cpu_v7_do_suspend
|
||||
.word cpu_v7_do_resume
|
||||
.size v7_processor_functions, . - v7_processor_functions
|
||||
@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
|
||||
define_processor_functions v7, dabort=v7_early_abort, pabort=v7_pabort, suspend=1
|
||||
|
||||
.section ".rodata"
|
||||
|
||||
.type cpu_arch_name, #object
|
||||
cpu_arch_name:
|
||||
.asciz "armv7"
|
||||
.size cpu_arch_name, . - cpu_arch_name
|
||||
|
||||
.type cpu_elf_name, #object
|
||||
cpu_elf_name:
|
||||
.asciz "v7"
|
||||
.size cpu_elf_name, . - cpu_elf_name
|
||||
string cpu_arch_name, "armv7"
|
||||
string cpu_elf_name, "v7"
|
||||
.align
|
||||
|
||||
.section ".proc.info.init", #alloc, #execinstr
|
||||
|
||||
.type __v7_ca9mp_proc_info, #object
|
||||
__v7_ca9mp_proc_info:
|
||||
.long 0x410fc090 @ Required ID value
|
||||
.long 0xff0ffff0 @ Mask for ID
|
||||
ALT_SMP(.long \
|
||||
PMD_TYPE_SECT | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ | \
|
||||
PMD_FLAGS_SMP)
|
||||
ALT_UP(.long \
|
||||
PMD_TYPE_SECT | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ | \
|
||||
PMD_FLAGS_UP)
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_XN | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
W(b) __v7_ca9mp_setup
|
||||
/*
|
||||
* Standard v7 proc info content
|
||||
*/
|
||||
.macro __v7_proc initfunc, mm_mmuflags = 0, io_mmuflags = 0, hwcaps = 0
|
||||
ALT_SMP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | \
|
||||
PMD_FLAGS_SMP | \mm_mmuflags)
|
||||
ALT_UP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | \
|
||||
PMD_FLAGS_UP | \mm_mmuflags)
|
||||
.long PMD_TYPE_SECT | PMD_SECT_XN | PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ | \io_mmuflags
|
||||
W(b) \initfunc
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_TLS
|
||||
.long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_FAST_MULT | \
|
||||
HWCAP_EDSP | HWCAP_TLS | \hwcaps
|
||||
.long cpu_v7_name
|
||||
.long v7_processor_functions
|
||||
.long v7wbi_tlb_fns
|
||||
.long v6_user_fns
|
||||
.long v7_cache_fns
|
||||
.endm
|
||||
|
||||
/*
|
||||
* ARM Ltd. Cortex A5 processor.
|
||||
*/
|
||||
.type __v7_ca5mp_proc_info, #object
|
||||
__v7_ca5mp_proc_info:
|
||||
.long 0x410fc050
|
||||
.long 0xff0ffff0
|
||||
__v7_proc __v7_ca5mp_setup
|
||||
.size __v7_ca5mp_proc_info, . - __v7_ca5mp_proc_info
|
||||
|
||||
/*
|
||||
* ARM Ltd. Cortex A9 processor.
|
||||
*/
|
||||
.type __v7_ca9mp_proc_info, #object
|
||||
__v7_ca9mp_proc_info:
|
||||
.long 0x410fc090
|
||||
.long 0xff0ffff0
|
||||
__v7_proc __v7_ca9mp_setup
|
||||
.size __v7_ca9mp_proc_info, . - __v7_ca9mp_proc_info
|
||||
|
||||
/*
|
||||
* ARM Ltd. Cortex A15 processor.
|
||||
*/
|
||||
.type __v7_ca15mp_proc_info, #object
|
||||
__v7_ca15mp_proc_info:
|
||||
.long 0x410fc0f0
|
||||
.long 0xff0ffff0
|
||||
__v7_proc __v7_ca15mp_setup, hwcaps = HWCAP_IDIV
|
||||
.size __v7_ca15mp_proc_info, . - __v7_ca15mp_proc_info
|
||||
|
||||
/*
|
||||
* Match any ARMv7 processor core.
|
||||
*/
|
||||
|
@ -478,27 +491,5 @@ __v7_ca9mp_proc_info:
|
|||
__v7_proc_info:
|
||||
.long 0x000f0000 @ Required ID value
|
||||
.long 0x000f0000 @ Mask for ID
|
||||
ALT_SMP(.long \
|
||||
PMD_TYPE_SECT | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ | \
|
||||
PMD_FLAGS_SMP)
|
||||
ALT_UP(.long \
|
||||
PMD_TYPE_SECT | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ | \
|
||||
PMD_FLAGS_UP)
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_XN | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
W(b) __v7_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_TLS
|
||||
.long cpu_v7_name
|
||||
.long v7_processor_functions
|
||||
.long v7wbi_tlb_fns
|
||||
.long v6_user_fns
|
||||
.long v7_cache_fns
|
||||
__v7_proc __v7_setup
|
||||
.size __v7_proc_info, . - __v7_proc_info
|
||||
|
|
|
@ -335,17 +335,8 @@ ENTRY(xsc3_dma_unmap_area)
|
|||
mov pc, lr
|
||||
ENDPROC(xsc3_dma_unmap_area)
|
||||
|
||||
ENTRY(xsc3_cache_fns)
|
||||
.long xsc3_flush_icache_all
|
||||
.long xsc3_flush_kern_cache_all
|
||||
.long xsc3_flush_user_cache_all
|
||||
.long xsc3_flush_user_cache_range
|
||||
.long xsc3_coherent_kern_range
|
||||
.long xsc3_coherent_user_range
|
||||
.long xsc3_flush_kern_dcache_area
|
||||
.long xsc3_dma_map_area
|
||||
.long xsc3_dma_unmap_area
|
||||
.long xsc3_dma_flush_range
|
||||
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
|
||||
define_cache_functions xsc3
|
||||
|
||||
ENTRY(cpu_xsc3_dcache_clean_area)
|
||||
1: mcr p15, 0, r0, c7, c10, 1 @ clean L1 D line
|
||||
|
@ -454,9 +445,6 @@ ENTRY(cpu_xsc3_do_resume)
|
|||
ldr r3, =0x542e @ section flags
|
||||
b cpu_resume_mmu
|
||||
ENDPROC(cpu_xsc3_do_resume)
|
||||
#else
|
||||
#define cpu_xsc3_do_suspend 0
|
||||
#define cpu_xsc3_do_resume 0
|
||||
#endif
|
||||
|
||||
__CPUINIT
|
||||
|
@ -503,52 +491,24 @@ xsc3_crval:
|
|||
|
||||
__INITDATA
|
||||
|
||||
/*
|
||||
* Purpose : Function pointers used to access above functions - all calls
|
||||
* come through these
|
||||
*/
|
||||
|
||||
.type xsc3_processor_functions, #object
|
||||
ENTRY(xsc3_processor_functions)
|
||||
.word v5t_early_abort
|
||||
.word legacy_pabort
|
||||
.word cpu_xsc3_proc_init
|
||||
.word cpu_xsc3_proc_fin
|
||||
.word cpu_xsc3_reset
|
||||
.word cpu_xsc3_do_idle
|
||||
.word cpu_xsc3_dcache_clean_area
|
||||
.word cpu_xsc3_switch_mm
|
||||
.word cpu_xsc3_set_pte_ext
|
||||
.word cpu_xsc3_suspend_size
|
||||
.word cpu_xsc3_do_suspend
|
||||
.word cpu_xsc3_do_resume
|
||||
.size xsc3_processor_functions, . - xsc3_processor_functions
|
||||
@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
|
||||
define_processor_functions xsc3, dabort=v5t_early_abort, pabort=legacy_pabort, suspend=1
|
||||
|
||||
.section ".rodata"
|
||||
|
||||
.type cpu_arch_name, #object
|
||||
cpu_arch_name:
|
||||
.asciz "armv5te"
|
||||
.size cpu_arch_name, . - cpu_arch_name
|
||||
|
||||
.type cpu_elf_name, #object
|
||||
cpu_elf_name:
|
||||
.asciz "v5"
|
||||
.size cpu_elf_name, . - cpu_elf_name
|
||||
|
||||
.type cpu_xsc3_name, #object
|
||||
cpu_xsc3_name:
|
||||
.asciz "XScale-V3 based processor"
|
||||
.size cpu_xsc3_name, . - cpu_xsc3_name
|
||||
string cpu_arch_name, "armv5te"
|
||||
string cpu_elf_name, "v5"
|
||||
string cpu_xsc3_name, "XScale-V3 based processor"
|
||||
|
||||
.align
|
||||
|
||||
.section ".proc.info.init", #alloc, #execinstr
|
||||
|
||||
.type __xsc3_proc_info,#object
|
||||
__xsc3_proc_info:
|
||||
.long 0x69056000
|
||||
.long 0xffffe000
|
||||
.macro xsc3_proc_info name:req, cpu_val:req, cpu_mask:req
|
||||
.type __\name\()_proc_info,#object
|
||||
__\name\()_proc_info:
|
||||
.long \cpu_val
|
||||
.long \cpu_mask
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_BUFFERABLE | \
|
||||
PMD_SECT_CACHEABLE | \
|
||||
|
@ -566,29 +526,10 @@ __xsc3_proc_info:
|
|||
.long v4wbi_tlb_fns
|
||||
.long xsc3_mc_user_fns
|
||||
.long xsc3_cache_fns
|
||||
.size __xsc3_proc_info, . - __xsc3_proc_info
|
||||
.size __\name\()_proc_info, . - __\name\()_proc_info
|
||||
.endm
|
||||
|
||||
xsc3_proc_info xsc3, 0x69056000, 0xffffe000
|
||||
|
||||
/* Note: PXA935 changed its implementor ID from Intel to Marvell */
|
||||
|
||||
.type __xsc3_pxa935_proc_info,#object
|
||||
__xsc3_pxa935_proc_info:
|
||||
.long 0x56056000
|
||||
.long 0xffffe000
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_BUFFERABLE | \
|
||||
PMD_SECT_CACHEABLE | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
b __xsc3_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
|
||||
.long cpu_xsc3_name
|
||||
.long xsc3_processor_functions
|
||||
.long v4wbi_tlb_fns
|
||||
.long xsc3_mc_user_fns
|
||||
.long xsc3_cache_fns
|
||||
.size __xsc3_pxa935_proc_info, . - __xsc3_pxa935_proc_info
|
||||
xsc3_proc_info xsc3_pxa935, 0x56056000, 0xffffe000
|
||||
|
|
|
@ -390,12 +390,12 @@ ENDPROC(xscale_dma_map_area)
|
|||
* - size - size of region
|
||||
* - dir - DMA direction
|
||||
*/
|
||||
ENTRY(xscale_dma_a0_map_area)
|
||||
ENTRY(xscale_80200_A0_A1_dma_map_area)
|
||||
add r1, r1, r0
|
||||
teq r2, #DMA_TO_DEVICE
|
||||
beq xscale_dma_clean_range
|
||||
b xscale_dma_flush_range
|
||||
ENDPROC(xscale_dma_a0_map_area)
|
||||
ENDPROC(xscale_80200_A0_A1_dma_map_area)
|
||||
|
||||
/*
|
||||
* dma_unmap_area(start, size, dir)
|
||||
|
@ -407,17 +407,8 @@ ENTRY(xscale_dma_unmap_area)
|
|||
mov pc, lr
|
||||
ENDPROC(xscale_dma_unmap_area)
|
||||
|
||||
ENTRY(xscale_cache_fns)
|
||||
.long xscale_flush_icache_all
|
||||
.long xscale_flush_kern_cache_all
|
||||
.long xscale_flush_user_cache_all
|
||||
.long xscale_flush_user_cache_range
|
||||
.long xscale_coherent_kern_range
|
||||
.long xscale_coherent_user_range
|
||||
.long xscale_flush_kern_dcache_area
|
||||
.long xscale_dma_map_area
|
||||
.long xscale_dma_unmap_area
|
||||
.long xscale_dma_flush_range
|
||||
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
|
||||
define_cache_functions xscale
|
||||
|
||||
/*
|
||||
* On stepping A0/A1 of the 80200, invalidating D-cache by line doesn't
|
||||
|
@ -432,16 +423,28 @@ ENTRY(xscale_cache_fns)
|
|||
* revision January 22, 2003, available at:
|
||||
* http://www.intel.com/design/iio/specupdt/273415.htm
|
||||
*/
|
||||
ENTRY(xscale_80200_A0_A1_cache_fns)
|
||||
.long xscale_flush_kern_cache_all
|
||||
.long xscale_flush_user_cache_all
|
||||
.long xscale_flush_user_cache_range
|
||||
.long xscale_coherent_kern_range
|
||||
.long xscale_coherent_user_range
|
||||
.long xscale_flush_kern_dcache_area
|
||||
.long xscale_dma_a0_map_area
|
||||
.long xscale_dma_unmap_area
|
||||
.long xscale_dma_flush_range
|
||||
.macro a0_alias basename
|
||||
.globl xscale_80200_A0_A1_\basename
|
||||
.type xscale_80200_A0_A1_\basename , %function
|
||||
.equ xscale_80200_A0_A1_\basename , xscale_\basename
|
||||
.endm
|
||||
|
||||
/*
|
||||
* Most of the cache functions are unchanged for these processor revisions.
|
||||
* Export suitable alias symbols for the unchanged functions:
|
||||
*/
|
||||
a0_alias flush_icache_all
|
||||
a0_alias flush_user_cache_all
|
||||
a0_alias flush_kern_cache_all
|
||||
a0_alias flush_user_cache_range
|
||||
a0_alias coherent_kern_range
|
||||
a0_alias coherent_user_range
|
||||
a0_alias flush_kern_dcache_area
|
||||
a0_alias dma_flush_range
|
||||
a0_alias dma_unmap_area
|
||||
|
||||
@ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
|
||||
define_cache_functions xscale_80200_A0_A1
|
||||
|
||||
ENTRY(cpu_xscale_dcache_clean_area)
|
||||
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
|
||||
|
@ -551,9 +554,6 @@ ENTRY(cpu_xscale_do_resume)
|
|||
PMD_SECT_CACHEABLE | PMD_SECT_AP_WRITE
|
||||
b cpu_resume_mmu
|
||||
ENDPROC(cpu_xscale_do_resume)
|
||||
#else
|
||||
#define cpu_xscale_do_suspend 0
|
||||
#define cpu_xscale_do_resume 0
|
||||
#endif
|
||||
|
||||
__CPUINIT
|
||||
|
@ -587,432 +587,74 @@ xscale_crval:
|
|||
|
||||
__INITDATA
|
||||
|
||||
/*
|
||||
* Purpose : Function pointers used to access above functions - all calls
|
||||
* come through these
|
||||
*/
|
||||
|
||||
.type xscale_processor_functions, #object
|
||||
ENTRY(xscale_processor_functions)
|
||||
.word v5t_early_abort
|
||||
.word legacy_pabort
|
||||
.word cpu_xscale_proc_init
|
||||
.word cpu_xscale_proc_fin
|
||||
.word cpu_xscale_reset
|
||||
.word cpu_xscale_do_idle
|
||||
.word cpu_xscale_dcache_clean_area
|
||||
.word cpu_xscale_switch_mm
|
||||
.word cpu_xscale_set_pte_ext
|
||||
.word cpu_xscale_suspend_size
|
||||
.word cpu_xscale_do_suspend
|
||||
.word cpu_xscale_do_resume
|
||||
.size xscale_processor_functions, . - xscale_processor_functions
|
||||
@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
|
||||
define_processor_functions xscale, dabort=v5t_early_abort, pabort=legacy_pabort, suspend=1
|
||||
|
||||
.section ".rodata"
|
||||
|
||||
.type cpu_arch_name, #object
|
||||
cpu_arch_name:
|
||||
.asciz "armv5te"
|
||||
.size cpu_arch_name, . - cpu_arch_name
|
||||
string cpu_arch_name, "armv5te"
|
||||
string cpu_elf_name, "v5"
|
||||
|
||||
.type cpu_elf_name, #object
|
||||
cpu_elf_name:
|
||||
.asciz "v5"
|
||||
.size cpu_elf_name, . - cpu_elf_name
|
||||
|
||||
.type cpu_80200_A0_A1_name, #object
|
||||
cpu_80200_A0_A1_name:
|
||||
.asciz "XScale-80200 A0/A1"
|
||||
.size cpu_80200_A0_A1_name, . - cpu_80200_A0_A1_name
|
||||
|
||||
.type cpu_80200_name, #object
|
||||
cpu_80200_name:
|
||||
.asciz "XScale-80200"
|
||||
.size cpu_80200_name, . - cpu_80200_name
|
||||
|
||||
.type cpu_80219_name, #object
|
||||
cpu_80219_name:
|
||||
.asciz "XScale-80219"
|
||||
.size cpu_80219_name, . - cpu_80219_name
|
||||
|
||||
.type cpu_8032x_name, #object
|
||||
cpu_8032x_name:
|
||||
.asciz "XScale-IOP8032x Family"
|
||||
.size cpu_8032x_name, . - cpu_8032x_name
|
||||
|
||||
.type cpu_8033x_name, #object
|
||||
cpu_8033x_name:
|
||||
.asciz "XScale-IOP8033x Family"
|
||||
.size cpu_8033x_name, . - cpu_8033x_name
|
||||
|
||||
.type cpu_pxa250_name, #object
|
||||
cpu_pxa250_name:
|
||||
.asciz "XScale-PXA250"
|
||||
.size cpu_pxa250_name, . - cpu_pxa250_name
|
||||
|
||||
.type cpu_pxa210_name, #object
|
||||
cpu_pxa210_name:
|
||||
.asciz "XScale-PXA210"
|
||||
.size cpu_pxa210_name, . - cpu_pxa210_name
|
||||
|
||||
.type cpu_ixp42x_name, #object
|
||||
cpu_ixp42x_name:
|
||||
.asciz "XScale-IXP42x Family"
|
||||
.size cpu_ixp42x_name, . - cpu_ixp42x_name
|
||||
|
||||
.type cpu_ixp43x_name, #object
|
||||
cpu_ixp43x_name:
|
||||
.asciz "XScale-IXP43x Family"
|
||||
.size cpu_ixp43x_name, . - cpu_ixp43x_name
|
||||
|
||||
.type cpu_ixp46x_name, #object
|
||||
cpu_ixp46x_name:
|
||||
.asciz "XScale-IXP46x Family"
|
||||
.size cpu_ixp46x_name, . - cpu_ixp46x_name
|
||||
|
||||
.type cpu_ixp2400_name, #object
|
||||
cpu_ixp2400_name:
|
||||
.asciz "XScale-IXP2400"
|
||||
.size cpu_ixp2400_name, . - cpu_ixp2400_name
|
||||
|
||||
.type cpu_ixp2800_name, #object
|
||||
cpu_ixp2800_name:
|
||||
.asciz "XScale-IXP2800"
|
||||
.size cpu_ixp2800_name, . - cpu_ixp2800_name
|
||||
|
||||
.type cpu_pxa255_name, #object
|
||||
cpu_pxa255_name:
|
||||
.asciz "XScale-PXA255"
|
||||
.size cpu_pxa255_name, . - cpu_pxa255_name
|
||||
|
||||
.type cpu_pxa270_name, #object
|
||||
cpu_pxa270_name:
|
||||
.asciz "XScale-PXA270"
|
||||
.size cpu_pxa270_name, . - cpu_pxa270_name
|
||||
string cpu_80200_A0_A1_name, "XScale-80200 A0/A1"
|
||||
string cpu_80200_name, "XScale-80200"
|
||||
string cpu_80219_name, "XScale-80219"
|
||||
string cpu_8032x_name, "XScale-IOP8032x Family"
|
||||
string cpu_8033x_name, "XScale-IOP8033x Family"
|
||||
string cpu_pxa250_name, "XScale-PXA250"
|
||||
string cpu_pxa210_name, "XScale-PXA210"
|
||||
string cpu_ixp42x_name, "XScale-IXP42x Family"
|
||||
string cpu_ixp43x_name, "XScale-IXP43x Family"
|
||||
string cpu_ixp46x_name, "XScale-IXP46x Family"
|
||||
string cpu_ixp2400_name, "XScale-IXP2400"
|
||||
string cpu_ixp2800_name, "XScale-IXP2800"
|
||||
string cpu_pxa255_name, "XScale-PXA255"
|
||||
string cpu_pxa270_name, "XScale-PXA270"
|
||||
|
||||
.align
|
||||
|
||||
.section ".proc.info.init", #alloc, #execinstr
|
||||
|
||||
.type __80200_A0_A1_proc_info,#object
|
||||
__80200_A0_A1_proc_info:
|
||||
.long 0x69052000
|
||||
.long 0xfffffffe
|
||||
.long PMD_TYPE_SECT | \
|
||||
.macro xscale_proc_info name:req, cpu_val:req, cpu_mask:req, cpu_name:req, cache
|
||||
.type __\name\()_proc_info,#object
|
||||
__\name\()_proc_info:
|
||||
.long \cpu_val
|
||||
.long \cpu_mask
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_BUFFERABLE | \
|
||||
PMD_SECT_CACHEABLE | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
.long PMD_TYPE_SECT | \
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
b __xscale_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
|
||||
.long cpu_80200_name
|
||||
.long \cpu_name
|
||||
.long xscale_processor_functions
|
||||
.long v4wbi_tlb_fns
|
||||
.long xscale_mc_user_fns
|
||||
.long xscale_80200_A0_A1_cache_fns
|
||||
.size __80200_A0_A1_proc_info, . - __80200_A0_A1_proc_info
|
||||
|
||||
.type __80200_proc_info,#object
|
||||
__80200_proc_info:
|
||||
.long 0x69052000
|
||||
.long 0xfffffff0
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_BUFFERABLE | \
|
||||
PMD_SECT_CACHEABLE | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
b __xscale_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
|
||||
.long cpu_80200_name
|
||||
.long xscale_processor_functions
|
||||
.long v4wbi_tlb_fns
|
||||
.long xscale_mc_user_fns
|
||||
.long xscale_cache_fns
|
||||
.size __80200_proc_info, . - __80200_proc_info
|
||||
|
||||
.type __80219_proc_info,#object
|
||||
__80219_proc_info:
|
||||
.long 0x69052e20
|
||||
.long 0xffffffe0
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_BUFFERABLE | \
|
||||
PMD_SECT_CACHEABLE | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
b __xscale_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
|
||||
.long cpu_80219_name
|
||||
.long xscale_processor_functions
|
||||
.long v4wbi_tlb_fns
|
||||
.long xscale_mc_user_fns
|
||||
.long xscale_cache_fns
|
||||
.size __80219_proc_info, . - __80219_proc_info
|
||||
|
||||
.type __8032x_proc_info,#object
|
||||
__8032x_proc_info:
|
||||
.long 0x69052420
|
||||
.long 0xfffff7e0
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_BUFFERABLE | \
|
||||
PMD_SECT_CACHEABLE | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
b __xscale_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
|
||||
.long cpu_8032x_name
|
||||
.long xscale_processor_functions
|
||||
.long v4wbi_tlb_fns
|
||||
.long xscale_mc_user_fns
|
||||
.long xscale_cache_fns
|
||||
.size __8032x_proc_info, . - __8032x_proc_info
|
||||
|
||||
.type __8033x_proc_info,#object
|
||||
__8033x_proc_info:
|
||||
.long 0x69054010
|
||||
.long 0xfffffd30
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_BUFFERABLE | \
|
||||
PMD_SECT_CACHEABLE | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
b __xscale_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
|
||||
.long cpu_8033x_name
|
||||
.long xscale_processor_functions
|
||||
.long v4wbi_tlb_fns
|
||||
.long xscale_mc_user_fns
|
||||
.long xscale_cache_fns
|
||||
.size __8033x_proc_info, . - __8033x_proc_info
|
||||
|
||||
.type __pxa250_proc_info,#object
|
||||
__pxa250_proc_info:
|
||||
.long 0x69052100
|
||||
.long 0xfffff7f0
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_BUFFERABLE | \
|
||||
PMD_SECT_CACHEABLE | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
b __xscale_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
|
||||
.long cpu_pxa250_name
|
||||
.long xscale_processor_functions
|
||||
.long v4wbi_tlb_fns
|
||||
.long xscale_mc_user_fns
|
||||
.long xscale_cache_fns
|
||||
.size __pxa250_proc_info, . - __pxa250_proc_info
|
||||
|
||||
.type __pxa210_proc_info,#object
|
||||
__pxa210_proc_info:
|
||||
.long 0x69052120
|
||||
.long 0xfffff3f0
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_BUFFERABLE | \
|
||||
PMD_SECT_CACHEABLE | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
b __xscale_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
|
||||
.long cpu_pxa210_name
|
||||
.long xscale_processor_functions
|
||||
.long v4wbi_tlb_fns
|
||||
.long xscale_mc_user_fns
|
||||
.long xscale_cache_fns
|
||||
.size __pxa210_proc_info, . - __pxa210_proc_info
|
||||
|
||||
.type __ixp2400_proc_info, #object
|
||||
__ixp2400_proc_info:
|
||||
.long 0x69054190
|
||||
.long 0xfffffff0
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_BUFFERABLE | \
|
||||
PMD_SECT_CACHEABLE | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
b __xscale_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
|
||||
.long cpu_ixp2400_name
|
||||
.long xscale_processor_functions
|
||||
.long v4wbi_tlb_fns
|
||||
.long xscale_mc_user_fns
|
||||
.long xscale_cache_fns
|
||||
.size __ixp2400_proc_info, . - __ixp2400_proc_info
|
||||
|
||||
.type __ixp2800_proc_info, #object
|
||||
__ixp2800_proc_info:
|
||||
.long 0x690541a0
|
||||
.long 0xfffffff0
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_BUFFERABLE | \
|
||||
PMD_SECT_CACHEABLE | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
b __xscale_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
|
||||
.long cpu_ixp2800_name
|
||||
.long xscale_processor_functions
|
||||
.long v4wbi_tlb_fns
|
||||
.long xscale_mc_user_fns
|
||||
.long xscale_cache_fns
|
||||
.size __ixp2800_proc_info, . - __ixp2800_proc_info
|
||||
|
||||
.type __ixp42x_proc_info, #object
|
||||
__ixp42x_proc_info:
|
||||
.long 0x690541c0
|
||||
.long 0xffffffc0
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_BUFFERABLE | \
|
||||
PMD_SECT_CACHEABLE | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
b __xscale_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
|
||||
.long cpu_ixp42x_name
|
||||
.long xscale_processor_functions
|
||||
.long v4wbi_tlb_fns
|
||||
.long xscale_mc_user_fns
|
||||
.long xscale_cache_fns
|
||||
.size __ixp42x_proc_info, . - __ixp42x_proc_info
|
||||
|
||||
.type __ixp43x_proc_info, #object
|
||||
__ixp43x_proc_info:
|
||||
.long 0x69054040
|
||||
.long 0xfffffff0
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_BUFFERABLE | \
|
||||
PMD_SECT_CACHEABLE | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
b __xscale_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
|
||||
.long cpu_ixp43x_name
|
||||
.long xscale_processor_functions
|
||||
.long v4wbi_tlb_fns
|
||||
.long xscale_mc_user_fns
|
||||
.long xscale_cache_fns
|
||||
.size __ixp43x_proc_info, . - __ixp43x_proc_info
|
||||
|
||||
.type __ixp46x_proc_info, #object
|
||||
__ixp46x_proc_info:
|
||||
.long 0x69054200
|
||||
.long 0xffffff00
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_BUFFERABLE | \
|
||||
PMD_SECT_CACHEABLE | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
b __xscale_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
|
||||
.long cpu_ixp46x_name
|
||||
.long xscale_processor_functions
|
||||
.long v4wbi_tlb_fns
|
||||
.long xscale_mc_user_fns
|
||||
.long xscale_cache_fns
|
||||
.size __ixp46x_proc_info, . - __ixp46x_proc_info
|
||||
|
||||
.type __pxa255_proc_info,#object
|
||||
__pxa255_proc_info:
|
||||
.long 0x69052d00
|
||||
.long 0xfffffff0
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_BUFFERABLE | \
|
||||
PMD_SECT_CACHEABLE | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
b __xscale_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
|
||||
.long cpu_pxa255_name
|
||||
.long xscale_processor_functions
|
||||
.long v4wbi_tlb_fns
|
||||
.long xscale_mc_user_fns
|
||||
.long xscale_cache_fns
|
||||
.size __pxa255_proc_info, . - __pxa255_proc_info
|
||||
|
||||
.type __pxa270_proc_info,#object
|
||||
__pxa270_proc_info:
|
||||
.long 0x69054110
|
||||
.long 0xfffffff0
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_BUFFERABLE | \
|
||||
PMD_SECT_CACHEABLE | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
.long PMD_TYPE_SECT | \
|
||||
PMD_SECT_AP_WRITE | \
|
||||
PMD_SECT_AP_READ
|
||||
b __xscale_setup
|
||||
.long cpu_arch_name
|
||||
.long cpu_elf_name
|
||||
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
|
||||
.long cpu_pxa270_name
|
||||
.long xscale_processor_functions
|
||||
.long v4wbi_tlb_fns
|
||||
.long xscale_mc_user_fns
|
||||
.long xscale_cache_fns
|
||||
.size __pxa270_proc_info, . - __pxa270_proc_info
|
||||
.ifb \cache
|
||||
.long xscale_cache_fns
|
||||
.else
|
||||
.long \cache
|
||||
.endif
|
||||
.size __\name\()_proc_info, . - __\name\()_proc_info
|
||||
.endm
|
||||
|
||||
xscale_proc_info 80200_A0_A1, 0x69052000, 0xfffffffe, cpu_80200_name, \
|
||||
cache=xscale_80200_A0_A1_cache_fns
|
||||
xscale_proc_info 80200, 0x69052000, 0xfffffff0, cpu_80200_name
|
||||
xscale_proc_info 80219, 0x69052e20, 0xffffffe0, cpu_80219_name
|
||||
xscale_proc_info 8032x, 0x69052420, 0xfffff7e0, cpu_8032x_name
|
||||
xscale_proc_info 8033x, 0x69054010, 0xfffffd30, cpu_8033x_name
|
||||
xscale_proc_info pxa250, 0x69052100, 0xfffff7f0, cpu_pxa250_name
|
||||
xscale_proc_info pxa210, 0x69052120, 0xfffff3f0, cpu_pxa210_name
|
||||
xscale_proc_info ixp2400, 0x69054190, 0xfffffff0, cpu_ixp2400_name
|
||||
xscale_proc_info ixp2800, 0x690541a0, 0xfffffff0, cpu_ixp2800_name
|
||||
xscale_proc_info ixp42x, 0x690541c0, 0xffffffc0, cpu_ixp42x_name
|
||||
xscale_proc_info ixp43x, 0x69054040, 0xfffffff0, cpu_ixp43x_name
|
||||
xscale_proc_info ixp46x, 0x69054200, 0xffffff00, cpu_ixp46x_name
|
||||
xscale_proc_info pxa255, 0x69052d00, 0xfffffff0, cpu_pxa255_name
|
||||
xscale_proc_info pxa270, 0x69054110, 0xfffffff0, cpu_pxa270_name
|
||||
|
|
|
@ -65,9 +65,5 @@ ENTRY(fa_flush_kern_tlb_range)
|
|||
|
||||
__INITDATA
|
||||
|
||||
.type fa_tlb_fns, #object
|
||||
ENTRY(fa_tlb_fns)
|
||||
.long fa_flush_user_tlb_range
|
||||
.long fa_flush_kern_tlb_range
|
||||
.long fa_tlb_flags
|
||||
.size fa_tlb_fns, . - fa_tlb_fns
|
||||
/* define struct cpu_tlb_fns (see <asm/tlbflush.h> and proc-macros.S) */
|
||||
define_tlb_functions fa, fa_tlb_flags
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue