diff options
Diffstat (limited to 'arch/arm/kernel/head.S')
| -rw-r--r-- | arch/arm/kernel/head.S | 126 | 
1 files changed, 101 insertions, 25 deletions
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 2c7cc1e0347..2c35f0ff2fd 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -52,7 +52,8 @@  	.equ	swapper_pg_dir, KERNEL_RAM_VADDR - PG_DIR_SIZE  	.macro	pgtbl, rd, phys -	add	\rd, \phys, #TEXT_OFFSET - PG_DIR_SIZE +	add	\rd, \phys, #TEXT_OFFSET +	sub	\rd, \rd, #PG_DIR_SIZE  	.endm  /* @@ -77,6 +78,7 @@  	__HEAD  ENTRY(stext) + ARM_BE8(setend	be )			@ ensure we are in BE8 mode   THUMB(	adr	r9, BSYM(1f)	)	@ Kernel is always entered in ARM.   THUMB(	bx	r9		)	@ If this is a Thumb-2 kernel, @@ -100,7 +102,7 @@ ENTRY(stext)  	and	r3, r3, #0xf			@ extract VMSA support  	cmp	r3, #5				@ long-descriptor translation table format?   THUMB( it	lo )				@ force fixup-able long branch encoding -	blo	__error_p			@ only classic page table format +	blo	__error_lpae			@ only classic page table format  #endif  #ifndef CONFIG_XIP_KERNEL @@ -109,7 +111,7 @@ ENTRY(stext)  	sub	r4, r3, r4			@ (PHYS_OFFSET - PAGE_OFFSET)  	add	r8, r8, r4			@ PHYS_OFFSET  #else -	ldr	r8, =PHYS_OFFSET		@ always constant in this case +	ldr	r8, =PLAT_PHYS_OFFSET		@ always constant in this case  #endif  	/* @@ -352,6 +354,9 @@ ENTRY(secondary_startup)  	 * the processor type - there is no need to check the machine type  	 * as it has already been validated by the primary processor.  	 */ + + ARM_BE8(setend	be)				@ ensure we are in BE8 mode +  #ifdef CONFIG_ARM_VIRT_EXT  	bl	__hyp_stub_install_secondary  #endif @@ -470,7 +475,7 @@ ENDPROC(__turn_mmu_on)  #ifdef CONFIG_SMP_ON_UP -	__INIT +	__HEAD  __fixup_smp:  	and	r3, r9, #0x000f0000	@ architecture version  	teq	r3, #0x000f0000		@ CPU ID supported? @@ -487,7 +492,27 @@ __fixup_smp:  	mrc	p15, 0, r0, c0, c0, 5	@ read MPIDR  	and	r0, r0, #0xc0000000	@ multiprocessing extensions and  	teq	r0, #0x80000000		@ not part of a uniprocessor system? -	moveq	pc, lr			@ yes, assume SMP +	bne    __fixup_smp_on_up	@ no, assume UP + +	@ Core indicates it is SMP. Check for Aegis SOC where a single +	@ Cortex-A9 CPU is present but SMP operations fault. +	mov	r4, #0x41000000 +	orr	r4, r4, #0x0000c000 +	orr	r4, r4, #0x00000090 +	teq	r3, r4			@ Check for ARM Cortex-A9 +	movne	pc, lr			@ Not ARM Cortex-A9, + +	@ If a future SoC *does* use 0x0 as the PERIPH_BASE, then the +	@ below address check will need to be #ifdef'd or equivalent +	@ for the Aegis platform. +	mrc	p15, 4, r0, c15, c0	@ get SCU base address +	teq	r0, #0x0		@ '0' on actual UP A9 hardware +	beq	__fixup_smp_on_up	@ So its an A9 UP +	ldr	r0, [r0, #4]		@ read SCU Config +ARM_BE8(rev	r0, r0)			@ byteswap if big endian +	and	r0, r0, #0x3		@ number of CPUs +	teq	r0, #0x0		@ is 1? +	movne	pc, lr  __fixup_smp_on_up:  	adr	r0, 1f @@ -536,6 +561,14 @@ ENTRY(fixup_smp)  	ldmfd	sp!, {r4 - r6, pc}  ENDPROC(fixup_smp) +#ifdef __ARMEB__ +#define LOW_OFFSET	0x4 +#define HIGH_OFFSET	0x0 +#else +#define LOW_OFFSET	0x0 +#define HIGH_OFFSET	0x4 +#endif +  #ifdef CONFIG_ARM_PATCH_PHYS_VIRT  /* __fixup_pv_table - patch the stub instructions with the delta between @@ -546,17 +579,21 @@ ENDPROC(fixup_smp)  	__HEAD  __fixup_pv_table:  	adr	r0, 1f -	ldmia	r0, {r3-r5, r7} -	sub	r3, r0, r3	@ PHYS_OFFSET - PAGE_OFFSET +	ldmia	r0, {r3-r7} +	mvn	ip, #0 +	subs	r3, r0, r3	@ PHYS_OFFSET - PAGE_OFFSET  	add	r4, r4, r3	@ adjust table start address  	add	r5, r5, r3	@ adjust table end address -	add	r7, r7, r3	@ adjust __pv_phys_offset address -	str	r8, [r7]	@ save computed PHYS_OFFSET to __pv_phys_offset +	add	r6, r6, r3	@ adjust __pv_phys_pfn_offset address +	add	r7, r7, r3	@ adjust __pv_offset address +	mov	r0, r8, lsr #12	@ convert to PFN +	str	r0, [r6]	@ save computed PHYS_OFFSET to __pv_phys_pfn_offset +	strcc	ip, [r7, #HIGH_OFFSET]	@ save to __pv_offset high bits  	mov	r6, r3, lsr #24	@ constant for add/sub instructions  	teq	r3, r6, lsl #24 @ must be 16MiB aligned  THUMB(	it	ne		@ cross section branch )  	bne	__error -	str	r6, [r7, #4]	@ save to __pv_offset +	str	r3, [r7, #LOW_OFFSET]	@ save to __pv_offset low bits  	b	__fixup_a_pv_table  ENDPROC(__fixup_pv_table) @@ -564,11 +601,20 @@ ENDPROC(__fixup_pv_table)  1:	.long	.  	.long	__pv_table_begin  	.long	__pv_table_end -2:	.long	__pv_phys_offset +2:	.long	__pv_phys_pfn_offset +	.long	__pv_offset  	.text  __fixup_a_pv_table: +	adr	r0, 3f +	ldr	r6, [r0] +	add	r6, r6, r3 +	ldr	r0, [r6, #HIGH_OFFSET]	@ pv_offset high word +	ldr	r6, [r6, #LOW_OFFSET]	@ pv_offset low word +	mov	r6, r6, lsr #24 +	cmn	r0, #1  #ifdef CONFIG_THUMB2_KERNEL +	moveq	r0, #0x200000	@ set bit 21, mov to mvn instruction  	lsls	r6, #24  	beq	2f  	clz	r7, r6 @@ -582,18 +628,46 @@ __fixup_a_pv_table:  	b	2f  1:	add     r7, r3  	ldrh	ip, [r7, #2] -	and	ip, 0x8f00 -	orr	ip, r6	@ mask in offset bits 31-24 +ARM_BE8(rev16	ip, ip) +	tst	ip, #0x4000 +	and	ip, #0x8f00 +	orrne	ip, r6	@ mask in offset bits 31-24 +	orreq	ip, r0	@ mask in offset bits 7-0 +ARM_BE8(rev16	ip, ip)  	strh	ip, [r7, #2] +	bne	2f +	ldrh	ip, [r7] +ARM_BE8(rev16	ip, ip) +	bic	ip, #0x20 +	orr	ip, ip, r0, lsr #16 +ARM_BE8(rev16	ip, ip) +	strh	ip, [r7]  2:	cmp	r4, r5  	ldrcc	r7, [r4], #4	@ use branch for delay slot  	bcc	1b  	bx	lr  #else +#ifdef CONFIG_CPU_ENDIAN_BE8 +	moveq	r0, #0x00004000	@ set bit 22, mov to mvn instruction +#else +	moveq	r0, #0x400000	@ set bit 22, mov to mvn instruction +#endif  	b	2f  1:	ldr	ip, [r7, r3] +#ifdef CONFIG_CPU_ENDIAN_BE8 +	@ in BE8, we load data in BE, but instructions still in LE +	bic	ip, ip, #0xff000000 +	tst	ip, #0x000f0000	@ check the rotation field +	orrne	ip, ip, r6, lsl #24 @ mask in offset bits 31-24 +	biceq	ip, ip, #0x00004000 @ clear bit 22 +	orreq	ip, ip, r0      @ mask in offset bits 7-0 +#else  	bic	ip, ip, #0x000000ff -	orr	ip, ip, r6	@ mask in offset bits 31-24 +	tst	ip, #0xf00	@ check the rotation field +	orrne	ip, ip, r6	@ mask in offset bits 31-24 +	biceq	ip, ip, #0x400000	@ clear bit 22 +	orreq	ip, ip, r0	@ mask in offset bits 7-0 +#endif  	str	ip, [r7, r3]  2:	cmp	r4, r5  	ldrcc	r7, [r4], #4	@ use branch for delay slot @@ -602,28 +676,30 @@ __fixup_a_pv_table:  #endif  ENDPROC(__fixup_a_pv_table) +	.align +3:	.long __pv_offset +  ENTRY(fixup_pv_table)  	stmfd	sp!, {r4 - r7, lr} -	ldr	r2, 2f			@ get address of __pv_phys_offset  	mov	r3, #0			@ no offset  	mov	r4, r0			@ r0 = table start  	add	r5, r0, r1		@ r1 = table size -	ldr	r6, [r2, #4]		@ get __pv_offset  	bl	__fixup_a_pv_table  	ldmfd	sp!, {r4 - r7, pc}  ENDPROC(fixup_pv_table) -	.align -2:	.long	__pv_phys_offset -  	.data -	.globl	__pv_phys_offset -	.type	__pv_phys_offset, %object -__pv_phys_offset: -	.long	0 -	.size	__pv_phys_offset, . - __pv_phys_offset +	.globl	__pv_phys_pfn_offset +	.type	__pv_phys_pfn_offset, %object +__pv_phys_pfn_offset: +	.word	0 +	.size	__pv_phys_pfn_offset, . -__pv_phys_pfn_offset + +	.globl	__pv_offset +	.type	__pv_offset, %object  __pv_offset: -	.long	0 +	.quad	0 +	.size	__pv_offset, . -__pv_offset  #endif  #include "head-common.S"  | 
