| 
									
										
										
										
											2012-03-05 11:49:28 +00:00
										 |  |  | /* | 
					
						
							|  |  |  |  * Based on arch/arm/mm/proc.S | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2001 Deep Blue Solutions Ltd. | 
					
						
							|  |  |  |  * Copyright (C) 2012 ARM Ltd. | 
					
						
							|  |  |  |  * Author: Catalin Marinas <catalin.marinas@arm.com>
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 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. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  * along with this program.  If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/init.h> | 
					
						
							|  |  |  | #include <linux/linkage.h> | 
					
						
							|  |  |  | #include <asm/assembler.h> | 
					
						
							|  |  |  | #include <asm/asm-offsets.h> | 
					
						
							|  |  |  | #include <asm/hwcap.h> | 
					
						
							|  |  |  | #include <asm/pgtable-hwdef.h> | 
					
						
							|  |  |  | #include <asm/pgtable.h> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "proc-macros.S" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-02 17:55:40 +01:00
										 |  |  | #ifdef CONFIG_ARM64_64K_PAGES | 
					
						
							|  |  |  | #define TCR_TG_FLAGS	TCR_TG0_64K | TCR_TG1_64K | 
					
						
							|  |  |  | #else | 
					
						
							|  |  |  | #define TCR_TG_FLAGS	TCR_TG0_4K | TCR_TG1_4K | 
					
						
							|  |  |  | #endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef CONFIG_SMP | 
					
						
							|  |  |  | #define TCR_SMP_FLAGS	TCR_SHARED | 
					
						
							| 
									
										
										
										
											2012-03-05 11:49:28 +00:00
										 |  |  | #else | 
					
						
							| 
									
										
										
										
											2014-04-02 17:55:40 +01:00
										 |  |  | #define TCR_SMP_FLAGS	0 | 
					
						
							| 
									
										
										
										
											2012-03-05 11:49:28 +00:00
										 |  |  | #endif | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-02 17:55:40 +01:00
										 |  |  | /* PTWs cacheable, inner/outer WBWA */ | 
					
						
							|  |  |  | #define TCR_CACHE_FLAGS	TCR_IRGN_WBWA | TCR_ORGN_WBWA | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-05 11:49:28 +00:00
										 |  |  | #define MAIR(attr, mt)	((attr) << ((mt) * 8)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  *	cpu_cache_off() | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *	Turn the CPU D-cache off. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | ENTRY(cpu_cache_off) | 
					
						
							|  |  |  | 	mrs	x0, sctlr_el1 | 
					
						
							|  |  |  | 	bic	x0, x0, #1 << 2			// clear SCTLR.C | 
					
						
							|  |  |  | 	msr	sctlr_el1, x0 | 
					
						
							|  |  |  | 	isb | 
					
						
							|  |  |  | 	ret | 
					
						
							|  |  |  | ENDPROC(cpu_cache_off) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  *	cpu_reset(loc) | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *	Perform a soft reset of the system.  Put the CPU into the same state | 
					
						
							|  |  |  |  *	as it would be if it had been reset, and branch to what would be the | 
					
						
							|  |  |  |  *	reset vector. It must be executed with the flat identity mapping. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *	- loc   - location to jump to for soft reset | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 	.align	5
 | 
					
						
							|  |  |  | ENTRY(cpu_reset) | 
					
						
							|  |  |  | 	mrs	x1, sctlr_el1 | 
					
						
							|  |  |  | 	bic	x1, x1, #1 | 
					
						
							|  |  |  | 	msr	sctlr_el1, x1			// disable the MMU | 
					
						
							|  |  |  | 	isb | 
					
						
							|  |  |  | 	ret	x0 | 
					
						
							|  |  |  | ENDPROC(cpu_reset) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												arm64: convert part of soft_restart() to assembly
The current soft_restart() and setup_restart implementations incorrectly
assume that compiler will not spill/fill values to/from stack. However
this assumption seems to be wrong, revealed by the disassembly of the
currently existing code (v3.16) built with Linaro GCC 4.9-2014.05.
ffffffc000085224 <soft_restart>:
ffffffc000085224:  a9be7bfd  stp    x29, x30, [sp,#-32]!
ffffffc000085228:  910003fd  mov    x29, sp
ffffffc00008522c:  f9000fa0  str    x0, [x29,#24]
ffffffc000085230:  94003d21  bl     ffffffc0000946b4 <setup_mm_for_reboot>
ffffffc000085234:  94003b33  bl     ffffffc000093f00 <flush_cache_all>
ffffffc000085238:  94003dfa  bl     ffffffc000094a20 <cpu_cache_off>
ffffffc00008523c:  94003b31  bl     ffffffc000093f00 <flush_cache_all>
ffffffc000085240:  b0003321  adrp   x1, ffffffc0006ea000 <reset_devices>
ffffffc000085244:  f9400fa0  ldr    x0, [x29,#24] ----> spilled addr
ffffffc000085248:  f942fc22  ldr    x2, [x1,#1528] ----> global memstart_addr
ffffffc00008524c:  f0000061  adrp   x1, ffffffc000094000 <__inval_cache_range+0x40>
ffffffc000085250:  91290021  add    x1, x1, #0xa40
ffffffc000085254:  8b010041  add    x1, x2, x1
ffffffc000085258:  d2c00802  mov    x2, #0x4000000000           // #274877906944
ffffffc00008525c:  8b020021  add    x1, x1, x2
ffffffc000085260:  d63f0020  blr    x1
...
Here the compiler generates memory accesses after the cache is disabled,
loading stale values for the spilled value and global variable. As we cannot
control when the compiler will access memory we must rewrite the
functions in assembly to stash values we need in registers prior to
disabling the cache, avoiding the use of memory.
Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Arun Chandran <achandran@mvista.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
											
										 
											2014-08-18 10:06:58 +01:00
										 |  |  | ENTRY(cpu_soft_restart) | 
					
						
							|  |  |  | 	/* Save address of cpu_reset() and reset address */ | 
					
						
							|  |  |  | 	mov	x19, x0 | 
					
						
							|  |  |  | 	mov	x20, x1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Turn D-cache off */ | 
					
						
							|  |  |  | 	bl	cpu_cache_off | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Push out all dirty data, and ensure cache is empty */ | 
					
						
							|  |  |  | 	bl	flush_cache_all | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mov	x0, x20 | 
					
						
							|  |  |  | 	ret	x19 | 
					
						
							|  |  |  | ENDPROC(cpu_soft_restart) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-05 11:49:28 +00:00
										 |  |  | /* | 
					
						
							|  |  |  |  *	cpu_do_idle() | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *	Idle the processor (wait for interrupt). | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | ENTRY(cpu_do_idle) | 
					
						
							|  |  |  | 	dsb	sy				// WFI may enter a low-power mode | 
					
						
							|  |  |  | 	wfi | 
					
						
							|  |  |  | 	ret | 
					
						
							|  |  |  | ENDPROC(cpu_do_idle) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-26 18:33:44 +00:00
										 |  |  | #ifdef CONFIG_CPU_PM | 
					
						
							| 
									
										
										
										
											2013-07-17 10:14:45 +01:00
										 |  |  | /** | 
					
						
							|  |  |  |  * cpu_do_suspend - save CPU registers context | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * x0: virtual address of context pointer | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | ENTRY(cpu_do_suspend) | 
					
						
							|  |  |  | 	mrs	x2, tpidr_el0 | 
					
						
							|  |  |  | 	mrs	x3, tpidrro_el0 | 
					
						
							|  |  |  | 	mrs	x4, contextidr_el1 | 
					
						
							|  |  |  | 	mrs	x5, mair_el1 | 
					
						
							|  |  |  | 	mrs	x6, cpacr_el1 | 
					
						
							|  |  |  | 	mrs	x7, ttbr1_el1 | 
					
						
							|  |  |  | 	mrs	x8, tcr_el1 | 
					
						
							|  |  |  | 	mrs	x9, vbar_el1 | 
					
						
							|  |  |  | 	mrs	x10, mdscr_el1 | 
					
						
							|  |  |  | 	mrs	x11, oslsr_el1 | 
					
						
							|  |  |  | 	mrs	x12, sctlr_el1 | 
					
						
							|  |  |  | 	stp	x2, x3, [x0] | 
					
						
							|  |  |  | 	stp	x4, x5, [x0, #16] | 
					
						
							|  |  |  | 	stp	x6, x7, [x0, #32] | 
					
						
							|  |  |  | 	stp	x8, x9, [x0, #48] | 
					
						
							|  |  |  | 	stp	x10, x11, [x0, #64] | 
					
						
							|  |  |  | 	str	x12, [x0, #80] | 
					
						
							|  |  |  | 	ret | 
					
						
							|  |  |  | ENDPROC(cpu_do_suspend) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * cpu_do_resume - restore CPU register context | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * x0: Physical address of context pointer | 
					
						
							|  |  |  |  * x1: ttbr0_el1 to be restored | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Returns: | 
					
						
							|  |  |  |  *	sctlr_el1 value in x0 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | ENTRY(cpu_do_resume) | 
					
						
							|  |  |  | 	/* | 
					
						
							|  |  |  | 	 * Invalidate local tlb entries before turning on MMU | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	tlbi	vmalle1 | 
					
						
							|  |  |  | 	ldp	x2, x3, [x0] | 
					
						
							|  |  |  | 	ldp	x4, x5, [x0, #16] | 
					
						
							|  |  |  | 	ldp	x6, x7, [x0, #32] | 
					
						
							|  |  |  | 	ldp	x8, x9, [x0, #48] | 
					
						
							|  |  |  | 	ldp	x10, x11, [x0, #64] | 
					
						
							|  |  |  | 	ldr	x12, [x0, #80] | 
					
						
							|  |  |  | 	msr	tpidr_el0, x2 | 
					
						
							|  |  |  | 	msr	tpidrro_el0, x3 | 
					
						
							|  |  |  | 	msr	contextidr_el1, x4 | 
					
						
							|  |  |  | 	msr	mair_el1, x5 | 
					
						
							|  |  |  | 	msr	cpacr_el1, x6 | 
					
						
							|  |  |  | 	msr	ttbr0_el1, x1 | 
					
						
							|  |  |  | 	msr	ttbr1_el1, x7 | 
					
						
							|  |  |  | 	msr	tcr_el1, x8 | 
					
						
							|  |  |  | 	msr	vbar_el1, x9 | 
					
						
							|  |  |  | 	msr	mdscr_el1, x10 | 
					
						
							|  |  |  | 	/* | 
					
						
							|  |  |  | 	 * Restore oslsr_el1 by writing oslar_el1 | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	ubfx	x11, x11, #1, #1 | 
					
						
							|  |  |  | 	msr	oslar_el1, x11 | 
					
						
							|  |  |  | 	mov	x0, x12 | 
					
						
							|  |  |  | 	dsb	nsh		// Make sure local tlb invalidation completed | 
					
						
							|  |  |  | 	isb | 
					
						
							|  |  |  | 	ret | 
					
						
							|  |  |  | ENDPROC(cpu_do_resume) | 
					
						
							|  |  |  | #endif | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-05 11:49:28 +00:00
										 |  |  | /* | 
					
						
							| 
									
										
										
										
											2014-01-27 07:19:32 +00:00
										 |  |  |  *	cpu_do_switch_mm(pgd_phys, tsk) | 
					
						
							| 
									
										
										
										
											2012-03-05 11:49:28 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  *	Set the translation table base pointer to be pgd_phys. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *	- pgd_phys - physical address of new TTB | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | ENTRY(cpu_do_switch_mm) | 
					
						
							|  |  |  | 	mmid	w1, x1				// get mm->context.id | 
					
						
							|  |  |  | 	bfi	x0, x1, #48, #16		// set the ASID | 
					
						
							|  |  |  | 	msr	ttbr0_el1, x0			// set TTBR0 | 
					
						
							|  |  |  | 	isb | 
					
						
							|  |  |  | 	ret | 
					
						
							|  |  |  | ENDPROC(cpu_do_switch_mm) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.section ".text.init", #alloc, #execinstr | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  |  *	__cpu_setup | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *	Initialise the processor for turning the MMU on.  Return in x0 the | 
					
						
							|  |  |  |  *	value of the SCTLR_EL1 register. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | ENTRY(__cpu_setup) | 
					
						
							|  |  |  | 	ic	iallu				// I+BTB cache invalidate | 
					
						
							| 
									
										
										
										
											2013-12-02 16:11:00 +00:00
										 |  |  | 	tlbi	vmalle1is			// invalidate I + D TLBs | 
					
						
							| 
									
										
										
										
											2014-05-02 16:24:15 +01:00
										 |  |  | 	dsb	ish | 
					
						
							| 
									
										
										
										
											2012-03-05 11:49:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	mov	x0, #3 << 20 | 
					
						
							|  |  |  | 	msr	cpacr_el1, x0			// Enable FP/ASIMD | 
					
						
							| 
									
										
										
										
											2013-05-08 17:01:12 +01:00
										 |  |  | 	msr	mdscr_el1, xzr			// Reset mdscr_el1 | 
					
						
							| 
									
										
										
										
											2012-03-05 11:49:28 +00:00
										 |  |  | 	/* | 
					
						
							|  |  |  | 	 * Memory region attributes for LPAE: | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 *   n = AttrIndx[2:0] | 
					
						
							|  |  |  | 	 *			n	MAIR | 
					
						
							|  |  |  | 	 *   DEVICE_nGnRnE	000	00000000 | 
					
						
							|  |  |  | 	 *   DEVICE_nGnRE	001	00000100 | 
					
						
							|  |  |  | 	 *   DEVICE_GRE		010	00001100 | 
					
						
							|  |  |  | 	 *   NORMAL_NC		011	01000100 | 
					
						
							|  |  |  | 	 *   NORMAL		100	11111111 | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	ldr	x5, =MAIR(0x00, MT_DEVICE_nGnRnE) | \ | 
					
						
							|  |  |  | 		     MAIR(0x04, MT_DEVICE_nGnRE) | \ | 
					
						
							|  |  |  | 		     MAIR(0x0c, MT_DEVICE_GRE) | \ | 
					
						
							|  |  |  | 		     MAIR(0x44, MT_NORMAL_NC) | \ | 
					
						
							|  |  |  | 		     MAIR(0xff, MT_NORMAL) | 
					
						
							|  |  |  | 	msr	mair_el1, x5 | 
					
						
							|  |  |  | 	/* | 
					
						
							|  |  |  | 	 * Prepare SCTLR | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	adr	x5, crval | 
					
						
							|  |  |  | 	ldp	w5, w6, [x5] | 
					
						
							|  |  |  | 	mrs	x0, sctlr_el1 | 
					
						
							|  |  |  | 	bic	x0, x0, x5			// clear bits | 
					
						
							|  |  |  | 	orr	x0, x0, x6			// set bits | 
					
						
							|  |  |  | 	/* | 
					
						
							|  |  |  | 	 * Set/prepare TCR and TTBR. We use 512GB (39-bit) address range for | 
					
						
							|  |  |  | 	 * both user and kernel. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2014-04-02 17:55:40 +01:00
										 |  |  | 	ldr	x10, =TCR_TxSZ(VA_BITS) | TCR_CACHE_FLAGS | TCR_SMP_FLAGS | \ | 
					
						
							|  |  |  | 			TCR_TG_FLAGS | TCR_ASID16 | TCR_TBI0 | 
					
						
							| 
									
										
										
										
											2014-03-07 08:49:25 +00:00
										 |  |  | 	/* | 
					
						
							|  |  |  | 	 * Read the PARange bits from ID_AA64MMFR0_EL1 and set the IPS bits in | 
					
						
							|  |  |  | 	 * TCR_EL1. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	mrs	x9, ID_AA64MMFR0_EL1 | 
					
						
							|  |  |  | 	bfi	x10, x9, #32, #3 | 
					
						
							| 
									
										
										
										
											2012-03-05 11:49:28 +00:00
										 |  |  | 	msr	tcr_el1, x10 | 
					
						
							|  |  |  | 	ret					// return to head.S | 
					
						
							|  |  |  | ENDPROC(__cpu_setup) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* | 
					
						
							| 
									
										
										
										
											2014-12-17 15:50:21 +00:00
										 |  |  | 	 * We set the desired value explicitly, including those of the | 
					
						
							|  |  |  | 	 * reserved bits. The values of bits EE & E0E were set early in | 
					
						
							|  |  |  | 	 * el2_setup, which are left untouched below. | 
					
						
							|  |  |  | 	 * | 
					
						
							| 
									
										
										
										
											2012-03-05 11:49:28 +00:00
										 |  |  | 	 *                 n n            T | 
					
						
							|  |  |  | 	 *       U E      WT T UD     US IHBS | 
					
						
							|  |  |  | 	 *       CE0      XWHW CZ     ME TEEA S | 
					
						
							|  |  |  | 	 * .... .IEE .... NEAI TE.I ..AD DEN0 ACAM | 
					
						
							| 
									
										
										
										
											2014-12-17 15:50:21 +00:00
										 |  |  | 	 * 0011 0... 1101 ..0. ..0. 10.. .0.. .... < hardware reserved | 
					
						
							|  |  |  | 	 * .... .1.. .... 01.1 11.1 ..01 0.01 1101 < software settings | 
					
						
							| 
									
										
										
										
											2012-03-05 11:49:28 +00:00
										 |  |  | 	 */ | 
					
						
							|  |  |  | 	.type	crval, #object | 
					
						
							|  |  |  | crval: | 
					
						
							| 
									
										
										
										
											2014-12-17 15:50:21 +00:00
										 |  |  | 	.word	0xfcffffff			// clear | 
					
						
							|  |  |  | 	.word	0x34d5d91d			// set |