1d2912cb1SThomas Gleixner/* SPDX-License-Identifier: GPL-2.0-only */ 21da177e4SLinus Torvalds/* 31da177e4SLinus Torvalds * linux/arch/arm/kernel/head.S 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (C) 1994-2002 Russell King 6e65f38edSRussell King * Copyright (c) 2003 ARM Limited 7e65f38edSRussell King * All Rights Reserved 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * Kernel startup code for all 32-bit CPUs 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds#include <linux/linkage.h> 121da177e4SLinus Torvalds#include <linux/init.h> 1365fddcfcSMike Rapoport#include <linux/pgtable.h> 141da177e4SLinus Torvalds 151da177e4SLinus Torvalds#include <asm/assembler.h> 16195864cfSRussell King#include <asm/cp15.h> 171da177e4SLinus Torvalds#include <asm/domain.h> 181da177e4SLinus Torvalds#include <asm/ptrace.h> 19e6ae744dSSam Ravnborg#include <asm/asm-offsets.h> 20a9ff6961SLinus Walleij#include <asm/page.h> 214f7a1812SRussell King#include <asm/thread_info.h> 221da177e4SLinus Torvalds 2391a9fec0SRob Herring#if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_SEMIHOSTING) 2491a9fec0SRob Herring#include CONFIG_DEBUG_LL_INCLUDE 25c293393fSJeremy Kerr#endif 261da177e4SLinus Torvalds/* 2737d07b72SNicolas Pitre * swapper_pg_dir is the virtual address of the initial page table. 28f06b97ffSRussell King * We place the page tables 16K below KERNEL_RAM_VADDR. Therefore, we must 29f06b97ffSRussell King * make sure that KERNEL_RAM_VADDR is correctly set. Currently, we expect 3037d07b72SNicolas Pitre * the least significant 16 bits to be 0x8000, but we could probably 31f06b97ffSRussell King * relax this restriction to KERNEL_RAM_VADDR >= PAGE_OFFSET + 0x4000. 321da177e4SLinus Torvalds */ 33b78f63f4SLinus Walleij#define KERNEL_RAM_VADDR (KERNEL_OFFSET + TEXT_OFFSET) 34f06b97ffSRussell King#if (KERNEL_RAM_VADDR & 0xffff) != 0x8000 35f06b97ffSRussell King#error KERNEL_RAM_VADDR must start at 0xXXXX8000 361da177e4SLinus Torvalds#endif 371da177e4SLinus Torvalds 381b6ba46bSCatalin Marinas#ifdef CONFIG_ARM_LPAE 391b6ba46bSCatalin Marinas /* LPAE requires an additional page for the PGD */ 401b6ba46bSCatalin Marinas#define PG_DIR_SIZE 0x5000 4139114538SMike Rapoport#define PMD_ENTRY_ORDER 3 /* PMD entry size is 2^PMD_ENTRY_ORDER */ 421b6ba46bSCatalin Marinas#else 43e73fc88eSCatalin Marinas#define PG_DIR_SIZE 0x4000 4439114538SMike Rapoport#define PMD_ENTRY_ORDER 2 451b6ba46bSCatalin Marinas#endif 46e73fc88eSCatalin Marinas 471da177e4SLinus Torvalds .globl swapper_pg_dir 48e73fc88eSCatalin Marinas .equ swapper_pg_dir, KERNEL_RAM_VADDR - PG_DIR_SIZE 491da177e4SLinus Torvalds 50a91da545SLinus Walleij /* 51a91da545SLinus Walleij * This needs to be assigned at runtime when the linker symbols are 52463dbba4SLinus Walleij * resolved. These are unsigned 64bit really, but in this assembly code 53463dbba4SLinus Walleij * We store them as 32bit. 54a91da545SLinus Walleij */ 55a91da545SLinus Walleij .pushsection .data 56a91da545SLinus Walleij .align 2 57a91da545SLinus Walleij .globl kernel_sec_start 58a91da545SLinus Walleij .globl kernel_sec_end 59a91da545SLinus Walleijkernel_sec_start: 60a91da545SLinus Walleij .long 0 61463dbba4SLinus Walleij .long 0 62a91da545SLinus Walleijkernel_sec_end: 63a91da545SLinus Walleij .long 0 64463dbba4SLinus Walleij .long 0 65a91da545SLinus Walleij .popsection 66a91da545SLinus Walleij 6772a20e22SRussell King .macro pgtbl, rd, phys 682ab4e8c0SChristopher Covington add \rd, \phys, #TEXT_OFFSET 692ab4e8c0SChristopher Covington sub \rd, \rd, #PG_DIR_SIZE 701da177e4SLinus Torvalds .endm 7137d07b72SNicolas Pitre 721da177e4SLinus Torvalds/* 731da177e4SLinus Torvalds * Kernel startup entry point. 741da177e4SLinus Torvalds * --------------------------- 751da177e4SLinus Torvalds * 761da177e4SLinus Torvalds * This is normally called from the decompressor code. The requirements 771da177e4SLinus Torvalds * are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0, 784c2896e8SGrant Likely * r1 = machine nr, r2 = atags or dtb pointer. 791da177e4SLinus Torvalds * 801da177e4SLinus Torvalds * This code is mostly position independent, so if you link the kernel at 811da177e4SLinus Torvalds * 0xc0008000, you call this at __pa(0xc0008000). 821da177e4SLinus Torvalds * 831da177e4SLinus Torvalds * See linux/arch/arm/tools/mach-types for the complete list of machine 841da177e4SLinus Torvalds * numbers for r1. 851da177e4SLinus Torvalds * 861da177e4SLinus Torvalds * We're trying to keep crap to a minimum; DO NOT add any machine specific 871da177e4SLinus Torvalds * crap here - that's what the boot loader (or in extreme, well justified 881da177e4SLinus Torvalds * circumstances, zImage) is for. 891da177e4SLinus Torvalds */ 90540b5738SDave Martin .arm 91540b5738SDave Martin 922abc1c50STim Abbott __HEAD 931da177e4SLinus TorvaldsENTRY(stext) 9497bcb0feSBen Dooks ARM_BE8(setend be ) @ ensure we are in BE8 mode 95540b5738SDave Martin 9614327c66SRussell King THUMB( badr r9, 1f ) @ Kernel is always entered in ARM. 97540b5738SDave Martin THUMB( bx r9 ) @ If this is a Thumb-2 kernel, 98540b5738SDave Martin THUMB( .thumb ) @ switch to Thumb now. 99540b5738SDave Martin THUMB(1: ) 100540b5738SDave Martin 10180c59dafSDave Martin#ifdef CONFIG_ARM_VIRT_EXT 10280c59dafSDave Martin bl __hyp_stub_install 10380c59dafSDave Martin#endif 10480c59dafSDave Martin @ ensure svc mode and all interrupts masked 10580c59dafSDave Martin safe_svcmode_maskall r9 10680c59dafSDave Martin 1070f44ba1dSRussell King mrc p15, 0, r9, c0, c0 @ get processor id 1081da177e4SLinus Torvalds bl __lookup_processor_type @ r5=procinfo r9=cpuid 1091da177e4SLinus Torvalds movs r10, r5 @ invalid processor (r5=0)? 110a75e5248SDave Martin THUMB( it eq ) @ force fixup-able long branch encoding 1111da177e4SLinus Torvalds beq __error_p @ yes, error 'p' 1120eb0511dSRussell King 113294064f5SCatalin Marinas#ifdef CONFIG_ARM_LPAE 114294064f5SCatalin Marinas mrc p15, 0, r3, c0, c1, 4 @ read ID_MMFR0 115294064f5SCatalin Marinas and r3, r3, #0xf @ extract VMSA support 116294064f5SCatalin Marinas cmp r3, #5 @ long-descriptor translation table format? 117294064f5SCatalin Marinas THUMB( it lo ) @ force fixup-able long branch encoding 118b3634575SThomas Petazzoni blo __error_lpae @ only classic page table format 119294064f5SCatalin Marinas#endif 120294064f5SCatalin Marinas 12172a20e22SRussell King#ifndef CONFIG_XIP_KERNEL 1223bcf906bSArd Biesheuvel adr_l r8, _text @ __pa(_text) 1233bcf906bSArd Biesheuvel sub r8, r8, #TEXT_OFFSET @ PHYS_OFFSET 12472a20e22SRussell King#else 125b713aa0bSRussell King ldr r8, =PLAT_PHYS_OFFSET @ always constant in this case 12672a20e22SRussell King#endif 12772a20e22SRussell King 1280eb0511dSRussell King /* 1294c2896e8SGrant Likely * r1 = machine no, r2 = atags or dtb, 13072a20e22SRussell King * r8 = phys_offset, r9 = cpuid, r10 = procinfo 1310eb0511dSRussell King */ 1329d20fdd5SBill Gatliff bl __vet_atags 133f00ec48fSRussell King#ifdef CONFIG_SMP_ON_UP 134f00ec48fSRussell King bl __fixup_smp 135f00ec48fSRussell King#endif 136dc21af99SRussell King#ifdef CONFIG_ARM_PATCH_PHYS_VIRT 137dc21af99SRussell King bl __fixup_pv_table 138dc21af99SRussell King#endif 1391da177e4SLinus Torvalds bl __create_page_tables 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds /* 1421da177e4SLinus Torvalds * The following calls CPU specific code in a position independent 1431da177e4SLinus Torvalds * manner. See arch/arm/mm/proc-*.S for details. r10 = base of 1446fc31d54SRussell King * xxx_proc_info structure selected by __lookup_processor_type 145b2c3e38aSRussell King * above. 146b2c3e38aSRussell King * 147b2c3e38aSRussell King * The processor init function will be called with: 148b2c3e38aSRussell King * r1 - machine type 149b2c3e38aSRussell King * r2 - boot data (atags/dt) pointer 150b2c3e38aSRussell King * r4 - translation table base (low word) 151b2c3e38aSRussell King * r5 - translation table base (high word, if LPAE) 152b2c3e38aSRussell King * r8 - translation table base 1 (pfn if LPAE) 153b2c3e38aSRussell King * r9 - cpuid 154b2c3e38aSRussell King * r13 - virtual address for __enable_mmu -> __turn_mmu_on 155b2c3e38aSRussell King * 156b2c3e38aSRussell King * On return, the CPU will be ready for the MMU to be turned on, 157b2c3e38aSRussell King * r0 will hold the CPU control register value, r1, r2, r4, and 158b2c3e38aSRussell King * r9 will be preserved. r5 will also be preserved if LPAE. 1591da177e4SLinus Torvalds */ 160a4ae4134SRussell King ldr r13, =__mmap_switched @ address to jump to after 1611da177e4SLinus Torvalds @ mmu has been enabled 16214327c66SRussell King badr lr, 1f @ return (PIC) address 163b2c3e38aSRussell King#ifdef CONFIG_ARM_LPAE 164b2c3e38aSRussell King mov r5, #0 @ high TTBR0 165b2c3e38aSRussell King mov r8, r4, lsr #12 @ TTBR1 is swapper_pg_dir pfn 166b2c3e38aSRussell King#else 167d427958aSCatalin Marinas mov r8, r4 @ set TTBR1 to swapper_pg_dir 168b2c3e38aSRussell King#endif 169bf35706fSArd Biesheuvel ldr r12, [r10, #PROCINFO_INITFUNC] 170bf35706fSArd Biesheuvel add r12, r12, r10 171bf35706fSArd Biesheuvel ret r12 17200945010SRussell King1: b __enable_mmu 17393ed3970SCatalin MarinasENDPROC(stext) 174a4ae4134SRussell King .ltorg 1751da177e4SLinus Torvalds 1761da177e4SLinus Torvalds/* 1771da177e4SLinus Torvalds * Setup the initial page tables. We only setup the barest 1781da177e4SLinus Torvalds * amount which are required to get the kernel running, which 1791da177e4SLinus Torvalds * generally means mapping in the kernel code. 1801da177e4SLinus Torvalds * 18172a20e22SRussell King * r8 = phys_offset, r9 = cpuid, r10 = procinfo 1821da177e4SLinus Torvalds * 1831da177e4SLinus Torvalds * Returns: 184786f1b73SRussell King * r0, r3, r5-r7 corrupted 185b2c3e38aSRussell King * r4 = physical page table address 1861da177e4SLinus Torvalds */ 1871da177e4SLinus Torvalds__create_page_tables: 18872a20e22SRussell King pgtbl r4, r8 @ page table address 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds /* 191e73fc88eSCatalin Marinas * Clear the swapper page table 1921da177e4SLinus Torvalds */ 1931da177e4SLinus Torvalds mov r0, r4 1941da177e4SLinus Torvalds mov r3, #0 195e73fc88eSCatalin Marinas add r6, r0, #PG_DIR_SIZE 1961da177e4SLinus Torvalds1: str r3, [r0], #4 1971da177e4SLinus Torvalds str r3, [r0], #4 1981da177e4SLinus Torvalds str r3, [r0], #4 1991da177e4SLinus Torvalds str r3, [r0], #4 2001da177e4SLinus Torvalds teq r0, r6 2011da177e4SLinus Torvalds bne 1b 2021da177e4SLinus Torvalds 2031b6ba46bSCatalin Marinas#ifdef CONFIG_ARM_LPAE 2041b6ba46bSCatalin Marinas /* 2051b6ba46bSCatalin Marinas * Build the PGD table (first level) to point to the PMD table. A PGD 2061b6ba46bSCatalin Marinas * entry is 64-bit wide. 2071b6ba46bSCatalin Marinas */ 2081b6ba46bSCatalin Marinas mov r0, r4 2091b6ba46bSCatalin Marinas add r3, r4, #0x1000 @ first PMD table address 2101b6ba46bSCatalin Marinas orr r3, r3, #3 @ PGD block type 2111b6ba46bSCatalin Marinas mov r6, #4 @ PTRS_PER_PGD 2121b6ba46bSCatalin Marinas mov r7, #1 << (55 - 32) @ L_PGD_SWAPPER 213d61947a1SWill Deacon1: 214d61947a1SWill Deacon#ifdef CONFIG_CPU_ENDIAN_BE8 2151b6ba46bSCatalin Marinas str r7, [r0], #4 @ set top PGD entry bits 216d61947a1SWill Deacon str r3, [r0], #4 @ set bottom PGD entry bits 217d61947a1SWill Deacon#else 218d61947a1SWill Deacon str r3, [r0], #4 @ set bottom PGD entry bits 219d61947a1SWill Deacon str r7, [r0], #4 @ set top PGD entry bits 220d61947a1SWill Deacon#endif 2211b6ba46bSCatalin Marinas add r3, r3, #0x1000 @ next PMD table 2221b6ba46bSCatalin Marinas subs r6, r6, #1 2231b6ba46bSCatalin Marinas bne 1b 2241b6ba46bSCatalin Marinas 2251b6ba46bSCatalin Marinas add r4, r4, #0x1000 @ point to the PMD tables 226d61947a1SWill Deacon#ifdef CONFIG_CPU_ENDIAN_BE8 227d61947a1SWill Deacon add r4, r4, #4 @ we only write the bottom word 228d61947a1SWill Deacon#endif 2291b6ba46bSCatalin Marinas#endif 2301b6ba46bSCatalin Marinas 2318799ee9fSRussell King ldr r7, [r10, #PROCINFO_MM_MMUFLAGS] @ mm_mmuflags 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvalds /* 234786f1b73SRussell King * Create identity mapping to cater for __enable_mmu. 235786f1b73SRussell King * This identity mapping will be removed by paging_init(). 2361da177e4SLinus Torvalds */ 237172c34c9SArd Biesheuvel adr_l r5, __turn_mmu_on @ _pa(__turn_mmu_on) 238172c34c9SArd Biesheuvel adr_l r6, __turn_mmu_on_end @ _pa(__turn_mmu_on_end) 239e73fc88eSCatalin Marinas mov r5, r5, lsr #SECTION_SHIFT 240e73fc88eSCatalin Marinas mov r6, r6, lsr #SECTION_SHIFT 241786f1b73SRussell King 242e73fc88eSCatalin Marinas1: orr r3, r7, r5, lsl #SECTION_SHIFT @ flags + kernel base 24339114538SMike Rapoport str r3, [r4, r5, lsl #PMD_ENTRY_ORDER] @ identity mapping 244e73fc88eSCatalin Marinas cmp r5, r6 245e73fc88eSCatalin Marinas addlo r5, r5, #1 @ next section 246e73fc88eSCatalin Marinas blo 1b 2471da177e4SLinus Torvalds 2481da177e4SLinus Torvalds /* 249a91da545SLinus Walleij * The main matter: map in the kernel using section mappings, and 250a91da545SLinus Walleij * set two variables to indicate the physical start and end of the 251a91da545SLinus Walleij * kernel. 2521da177e4SLinus Torvalds */ 25339114538SMike Rapoport add r0, r4, #KERNEL_OFFSET >> (SECTION_SHIFT - PMD_ENTRY_ORDER) 2549fa16b77SNicolas Pitre ldr r6, =(_end - 1) 2554b9fb3aeSHarith G 2564b9fb3aeSHarith G /* For XIP, kernel_sec_start/kernel_sec_end are currently in RO memory */ 2574b9fb3aeSHarith G#ifndef CONFIG_XIP_KERNEL 258a91da545SLinus Walleij adr_l r5, kernel_sec_start @ _pa(kernel_sec_start) 25900568b8aSLABBE Corentin#if defined CONFIG_CPU_ENDIAN_BE8 || defined CONFIG_CPU_ENDIAN_BE32 260463dbba4SLinus Walleij str r8, [r5, #4] @ Save physical start of kernel (BE) 261463dbba4SLinus Walleij#else 262463dbba4SLinus Walleij str r8, [r5] @ Save physical start of kernel (LE) 263463dbba4SLinus Walleij#endif 2644b9fb3aeSHarith G#endif 265a91da545SLinus Walleij orr r3, r8, r7 @ Add the MMU flags 26639114538SMike Rapoport add r6, r4, r6, lsr #(SECTION_SHIFT - PMD_ENTRY_ORDER) 26739114538SMike Rapoport1: str r3, [r0], #1 << PMD_ENTRY_ORDER 2689fa16b77SNicolas Pitre add r3, r3, #1 << SECTION_SHIFT 2699fa16b77SNicolas Pitre cmp r0, r6 2709fa16b77SNicolas Pitre bls 1b 2714b9fb3aeSHarith G#ifndef CONFIG_XIP_KERNEL 272a91da545SLinus Walleij eor r3, r3, r7 @ Remove the MMU flags 273a91da545SLinus Walleij adr_l r5, kernel_sec_end @ _pa(kernel_sec_end) 27400568b8aSLABBE Corentin#if defined CONFIG_CPU_ENDIAN_BE8 || defined CONFIG_CPU_ENDIAN_BE32 275463dbba4SLinus Walleij str r3, [r5, #4] @ Save physical end of kernel (BE) 276463dbba4SLinus Walleij#else 277463dbba4SLinus Walleij str r3, [r5] @ Save physical end of kernel (LE) 278463dbba4SLinus Walleij#endif 2794b9fb3aeSHarith G#else 2809fa16b77SNicolas Pitre /* 2819fa16b77SNicolas Pitre * Map the kernel image separately as it is not located in RAM. 2829fa16b77SNicolas Pitre */ 2839fa16b77SNicolas Pitre#define XIP_START XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR) 284786f1b73SRussell King mov r3, pc 285e73fc88eSCatalin Marinas mov r3, r3, lsr #SECTION_SHIFT 286e73fc88eSCatalin Marinas orr r3, r7, r3, lsl #SECTION_SHIFT 28739114538SMike Rapoport add r0, r4, #(XIP_START & 0xff000000) >> (SECTION_SHIFT - PMD_ENTRY_ORDER) 28839114538SMike Rapoport str r3, [r0, #((XIP_START & 0x00f00000) >> SECTION_SHIFT) << PMD_ENTRY_ORDER]! 2899fa16b77SNicolas Pitre ldr r6, =(_edata_loc - 1) 29039114538SMike Rapoport add r0, r0, #1 << PMD_ENTRY_ORDER 29139114538SMike Rapoport add r6, r4, r6, lsr #(SECTION_SHIFT - PMD_ENTRY_ORDER) 292e98ff7f6SNicolas Pitre1: cmp r0, r6 293e73fc88eSCatalin Marinas add r3, r3, #1 << SECTION_SHIFT 29439114538SMike Rapoport strls r3, [r0], #1 << PMD_ENTRY_ORDER 295e98ff7f6SNicolas Pitre bls 1b 296ec3622d9SNicolas Pitre#endif 297ec3622d9SNicolas Pitre 2981da177e4SLinus Torvalds /* 2999fa16b77SNicolas Pitre * Then map boot params address in r2 if specified. 3006f16f499SNicolas Pitre * We map 2 sections in case the ATAGs/DTB crosses a section boundary. 3011da177e4SLinus Torvalds */ 302e73fc88eSCatalin Marinas mov r0, r2, lsr #SECTION_SHIFT 30310fce53cSArd Biesheuvel cmp r2, #0 30439114538SMike Rapoport ldrne r3, =FDT_FIXED_BASE >> (SECTION_SHIFT - PMD_ENTRY_ORDER) 3057a1be318SArd Biesheuvel addne r3, r3, r4 30610fce53cSArd Biesheuvel orrne r6, r7, r0, lsl #SECTION_SHIFT 30739114538SMike Rapoport strne r6, [r3], #1 << PMD_ENTRY_ORDER 3086f16f499SNicolas Pitre addne r6, r6, #1 << SECTION_SHIFT 3099fa16b77SNicolas Pitre strne r6, [r3] 3101da177e4SLinus Torvalds 3114e1db26aSPaul Bolle#if defined(CONFIG_ARM_LPAE) && defined(CONFIG_CPU_ENDIAN_BE8) 312d61947a1SWill Deacon sub r4, r4, #4 @ Fixup page table pointer 313d61947a1SWill Deacon @ for 64-bit descriptors 314d61947a1SWill Deacon#endif 315d61947a1SWill Deacon 316c77b0427SRussell King#ifdef CONFIG_DEBUG_LL 3179b5a146aSNicolas Pitre#if !defined(CONFIG_DEBUG_ICEDCC) && !defined(CONFIG_DEBUG_SEMIHOSTING) 3181da177e4SLinus Torvalds /* 3191da177e4SLinus Torvalds * Map in IO space for serial debugging. 3201da177e4SLinus Torvalds * This allows debug messages to be output 3211da177e4SLinus Torvalds * via a serial console before paging_init. 3221da177e4SLinus Torvalds */ 323639da5eeSNicolas Pitre addruart r7, r3, r0 324c293393fSJeremy Kerr 325e73fc88eSCatalin Marinas mov r3, r3, lsr #SECTION_SHIFT 32639114538SMike Rapoport mov r3, r3, lsl #PMD_ENTRY_ORDER 327c293393fSJeremy Kerr 3281da177e4SLinus Torvalds add r0, r4, r3 329e73fc88eSCatalin Marinas mov r3, r7, lsr #SECTION_SHIFT 330c293393fSJeremy Kerr ldr r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags 331e73fc88eSCatalin Marinas orr r3, r7, r3, lsl #SECTION_SHIFT 3321b6ba46bSCatalin Marinas#ifdef CONFIG_ARM_LPAE 3331b6ba46bSCatalin Marinas mov r7, #1 << (54 - 32) @ XN 334d61947a1SWill Deacon#ifdef CONFIG_CPU_ENDIAN_BE8 335d61947a1SWill Deacon str r7, [r0], #4 336d61947a1SWill Deacon str r3, [r0], #4 337d61947a1SWill Deacon#else 338d61947a1SWill Deacon str r3, [r0], #4 339d61947a1SWill Deacon str r7, [r0], #4 340d61947a1SWill Deacon#endif 3411b6ba46bSCatalin Marinas#else 3421b6ba46bSCatalin Marinas orr r3, r3, #PMD_SECT_XN 343f67860a7SNicolas Pitre str r3, [r0], #4 3441b6ba46bSCatalin Marinas#endif 345c293393fSJeremy Kerr 3469b5a146aSNicolas Pitre#else /* CONFIG_DEBUG_ICEDCC || CONFIG_DEBUG_SEMIHOSTING */ 3479b5a146aSNicolas Pitre /* we don't need any serial debugging mappings */ 348c293393fSJeremy Kerr ldr r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags 3499b5a146aSNicolas Pitre#endif 350c293393fSJeremy Kerr 35150f6f34eSArnd Bergmann#if defined(CONFIG_ARCH_NETWINDER) 3521da177e4SLinus Torvalds /* 3533c0bdac3SRussell King * If we're using the NetWinder or CATS, we also need to map 3543c0bdac3SRussell King * in the 16550-type serial port for the debug messages 3551da177e4SLinus Torvalds */ 35639114538SMike Rapoport add r0, r4, #0xff000000 >> (SECTION_SHIFT - PMD_ENTRY_ORDER) 357c77b0427SRussell King orr r3, r7, #0x7c000000 358c77b0427SRussell King str r3, [r0] 3591da177e4SLinus Torvalds#endif 3601da177e4SLinus Torvalds#ifdef CONFIG_ARCH_RPC 3611da177e4SLinus Torvalds /* 3621da177e4SLinus Torvalds * Map in screen at 0x02000000 & SCREEN2_BASE 3631da177e4SLinus Torvalds * Similar reasons here - for debug. This is 3641da177e4SLinus Torvalds * only for Acorn RiscPC architectures. 3651da177e4SLinus Torvalds */ 36639114538SMike Rapoport add r0, r4, #0x02000000 >> (SECTION_SHIFT - PMD_ENTRY_ORDER) 367c77b0427SRussell King orr r3, r7, #0x02000000 3681da177e4SLinus Torvalds str r3, [r0] 36939114538SMike Rapoport add r0, r4, #0xd8000000 >> (SECTION_SHIFT - PMD_ENTRY_ORDER) 3701da177e4SLinus Torvalds str r3, [r0] 3711da177e4SLinus Torvalds#endif 372c77b0427SRussell King#endif 3731b6ba46bSCatalin Marinas#ifdef CONFIG_ARM_LPAE 3741b6ba46bSCatalin Marinas sub r4, r4, #0x1000 @ point to the PGD table 3751b6ba46bSCatalin Marinas#endif 3766ebbf2ceSRussell King ret lr 37793ed3970SCatalin MarinasENDPROC(__create_page_tables) 3781da177e4SLinus Torvalds .ltorg 3791da177e4SLinus Torvalds 38000945010SRussell King#if defined(CONFIG_SMP) 3812449189bSRussell King .text 382bafe5865SStephen Boyd .arm 383c07b5fd0SYingjoe ChenENTRY(secondary_startup_arm) 38414327c66SRussell King THUMB( badr r9, 1f ) @ Kernel is entered in ARM. 385bafe5865SStephen Boyd THUMB( bx r9 ) @ If this is a Thumb-2 kernel, 386bafe5865SStephen Boyd THUMB( .thumb ) @ switch to Thumb now. 387bafe5865SStephen Boyd THUMB(1: ) 38800945010SRussell KingENTRY(secondary_startup) 38900945010SRussell King /* 39000945010SRussell King * Common entry point for secondary CPUs. 39100945010SRussell King * 39200945010SRussell King * Ensure that we're in SVC mode, and IRQs are disabled. Lookup 39300945010SRussell King * the processor type - there is no need to check the machine type 39400945010SRussell King * as it has already been validated by the primary processor. 39500945010SRussell King */ 39697bcb0feSBen Dooks 39797bcb0feSBen Dooks ARM_BE8(setend be) @ ensure we are in BE8 mode 39897bcb0feSBen Dooks 39980c59dafSDave Martin#ifdef CONFIG_ARM_VIRT_EXT 4006e484be1SMarc Zyngier bl __hyp_stub_install_secondary 40180c59dafSDave Martin#endif 40280c59dafSDave Martin safe_svcmode_maskall r9 40380c59dafSDave Martin 40400945010SRussell King mrc p15, 0, r9, c0, c0 @ get processor id 40500945010SRussell King bl __lookup_processor_type 40600945010SRussell King movs r10, r5 @ invalid processor? 40700945010SRussell King moveq r0, #'p' @ yes, error 'p' 408a75e5248SDave Martin THUMB( it eq ) @ force fixup-able long branch encoding 40900945010SRussell King beq __error_p 41000945010SRussell King 41100945010SRussell King /* 41200945010SRussell King * Use the page tables supplied from __cpu_up. 41300945010SRussell King */ 414*2abc2bd5SHarith G#ifdef CONFIG_XIP_KERNEL 415*2abc2bd5SHarith G ldr r3, =(secondary_data + PLAT_PHYS_OFFSET - PAGE_OFFSET) 416*2abc2bd5SHarith G#else 41791580f0dSArd Biesheuvel adr_l r3, secondary_data 418*2abc2bd5SHarith G#endif 41991580f0dSArd Biesheuvel mov_l r12, __secondary_switched 420bc2eca9aSNicolas Pitre ldrd r4, r5, [r3, #0] @ get secondary_data.pgdir 421998ef5d8SGregory CLEMENTARM_BE8(eor r4, r4, r5) @ Swap r5 and r4 in BE: 422998ef5d8SGregory CLEMENTARM_BE8(eor r5, r4, r5) @ it can be done in 3 steps 423998ef5d8SGregory CLEMENTARM_BE8(eor r4, r4, r5) @ without using a temp reg. 424b2c3e38aSRussell King ldr r8, [r3, #8] @ get secondary_data.swapper_pg_dir 42514327c66SRussell King badr lr, __enable_mmu @ return address 42600945010SRussell King mov r13, r12 @ __secondary_switched address 427bf35706fSArd Biesheuvel ldr r12, [r10, #PROCINFO_INITFUNC] 428bf35706fSArd Biesheuvel add r12, r12, r10 @ initialise processor 42900945010SRussell King @ (return control reg) 430bf35706fSArd Biesheuvel ret r12 43100945010SRussell KingENDPROC(secondary_startup) 432bafe5865SStephen BoydENDPROC(secondary_startup_arm) 43300945010SRussell King 43400945010SRussell KingENTRY(__secondary_switched) 4358b806b82SArd Biesheuvel#if defined(CONFIG_VMAP_STACK) && !defined(CONFIG_ARM_LPAE) 4368b806b82SArd Biesheuvel @ Before using the vmap'ed stack, we have to switch to swapper_pg_dir 4378b806b82SArd Biesheuvel @ as the ID map does not cover the vmalloc region. 4388b806b82SArd Biesheuvel mrc p15, 0, ip, c2, c0, 1 @ read TTBR1 4398b806b82SArd Biesheuvel mcr p15, 0, ip, c2, c0, 0 @ set TTBR0 4408b806b82SArd Biesheuvel instr_sync 4418b806b82SArd Biesheuvel#endif 44219f29aebSKeith Packard adr_l r7, secondary_data + 12 @ get secondary_data.stack 44319f29aebSKeith Packard ldr sp, [r7] 44419f29aebSKeith Packard ldr r0, [r7, #4] @ get secondary_data.task 44500945010SRussell King mov fp, #0 44600945010SRussell King b secondary_start_kernel 44700945010SRussell KingENDPROC(__secondary_switched) 44800945010SRussell King 44900945010SRussell King#endif /* defined(CONFIG_SMP) */ 45000945010SRussell King 45100945010SRussell King 45200945010SRussell King 45300945010SRussell King/* 45400945010SRussell King * Setup common bits before finally enabling the MMU. Essentially 45500945010SRussell King * this is just loading the page table pointer and domain access 456b2c3e38aSRussell King * registers. All these registers need to be preserved by the 457b2c3e38aSRussell King * processor setup function (or set in the case of r0) 458865a4faeSRussell King * 459865a4faeSRussell King * r0 = cp#15 control register 460865a4faeSRussell King * r1 = machine ID 4614c2896e8SGrant Likely * r2 = atags or dtb pointer 462b2c3e38aSRussell King * r4 = TTBR pointer (low word) 463b2c3e38aSRussell King * r5 = TTBR pointer (high word if LPAE) 464865a4faeSRussell King * r9 = processor ID 465865a4faeSRussell King * r13 = *virtual* address to jump to upon completion 46600945010SRussell King */ 46700945010SRussell King__enable_mmu: 4688428e84dSCatalin Marinas#if defined(CONFIG_ALIGNMENT_TRAP) && __LINUX_ARM_ARCH__ < 6 46900945010SRussell King orr r0, r0, #CR_A 47000945010SRussell King#else 47100945010SRussell King bic r0, r0, #CR_A 47200945010SRussell King#endif 47300945010SRussell King#ifdef CONFIG_CPU_DCACHE_DISABLE 47400945010SRussell King bic r0, r0, #CR_C 47500945010SRussell King#endif 47600945010SRussell King#ifdef CONFIG_CPU_BPREDICT_DISABLE 47700945010SRussell King bic r0, r0, #CR_Z 47800945010SRussell King#endif 47900945010SRussell King#ifdef CONFIG_CPU_ICACHE_DISABLE 48000945010SRussell King bic r0, r0, #CR_I 48100945010SRussell King#endif 482b2c3e38aSRussell King#ifdef CONFIG_ARM_LPAE 483b2c3e38aSRussell King mcrr p15, 0, r4, r5, c2 @ load TTBR0 484b2c3e38aSRussell King#else 4850171356aSRussell King mov r5, #DACR_INIT 48600945010SRussell King mcr p15, 0, r5, c3, c0, 0 @ load domain access register 48700945010SRussell King mcr p15, 0, r4, c2, c0, 0 @ load page table pointer 4881b6ba46bSCatalin Marinas#endif 48900945010SRussell King b __turn_mmu_on 49000945010SRussell KingENDPROC(__enable_mmu) 49100945010SRussell King 49200945010SRussell King/* 49300945010SRussell King * Enable the MMU. This completely changes the structure of the visible 49400945010SRussell King * memory space. You will not be able to trace execution through this. 49500945010SRussell King * If you have an enquiry about this, *please* check the linux-arm-kernel 49600945010SRussell King * mailing list archives BEFORE sending another post to the list. 49700945010SRussell King * 49800945010SRussell King * r0 = cp#15 control register 499865a4faeSRussell King * r1 = machine ID 5004c2896e8SGrant Likely * r2 = atags or dtb pointer 501865a4faeSRussell King * r9 = processor ID 50200945010SRussell King * r13 = *virtual* address to jump to upon completion 50300945010SRussell King * 50400945010SRussell King * other registers depend on the function called upon completion 50500945010SRussell King */ 50600945010SRussell King .align 5 5074e8ee7deSWill Deacon .pushsection .idmap.text, "ax" 5084e8ee7deSWill DeaconENTRY(__turn_mmu_on) 50900945010SRussell King mov r0, r0 510d675d0bcSWill Deacon instr_sync 51100945010SRussell King mcr p15, 0, r0, c1, c0, 0 @ write control reg 51200945010SRussell King mrc p15, 0, r3, c0, c0, 0 @ read id reg 513d675d0bcSWill Deacon instr_sync 51400945010SRussell King mov r3, r3 51500945010SRussell King mov r3, r13 5166ebbf2ceSRussell King ret r3 51772662e01SWill Deacon__turn_mmu_on_end: 51800945010SRussell KingENDPROC(__turn_mmu_on) 5194e8ee7deSWill Deacon .popsection 52000945010SRussell King 5211da177e4SLinus Torvalds 522f00ec48fSRussell King#ifdef CONFIG_SMP_ON_UP 5231dc5455fSRob Herring __HEAD 524f00ec48fSRussell King__fixup_smp: 525e98ff0f5SRussell King and r3, r9, #0x000f0000 @ architecture version 526e98ff0f5SRussell King teq r3, #0x000f0000 @ CPU ID supported? 527f00ec48fSRussell King bne __fixup_smp_on_up @ no, assume UP 528f00ec48fSRussell King 529e98ff0f5SRussell King bic r3, r9, #0x00ff0000 530e98ff0f5SRussell King bic r3, r3, #0x0000000f @ mask 0xff00fff0 531e98ff0f5SRussell King mov r4, #0x41000000 5320eb0511dSRussell King orr r4, r4, #0x0000b000 533e98ff0f5SRussell King orr r4, r4, #0x00000020 @ val 0x4100b020 534e98ff0f5SRussell King teq r3, r4 @ ARM 11MPCore? 5356ebbf2ceSRussell King reteq lr @ yes, assume SMP 536f00ec48fSRussell King 537f00ec48fSRussell King mrc p15, 0, r0, c0, c0, 5 @ read MPIDR 538e98ff0f5SRussell King and r0, r0, #0xc0000000 @ multiprocessing extensions and 539e98ff0f5SRussell King teq r0, #0x80000000 @ not part of a uniprocessor system? 540bc41b872SSantosh Shilimkar bne __fixup_smp_on_up @ no, assume UP 541bc41b872SSantosh Shilimkar 542bc41b872SSantosh Shilimkar @ Core indicates it is SMP. Check for Aegis SOC where a single 543bc41b872SSantosh Shilimkar @ Cortex-A9 CPU is present but SMP operations fault. 544bc41b872SSantosh Shilimkar mov r4, #0x41000000 545bc41b872SSantosh Shilimkar orr r4, r4, #0x0000c000 546bc41b872SSantosh Shilimkar orr r4, r4, #0x00000090 547bc41b872SSantosh Shilimkar teq r3, r4 @ Check for ARM Cortex-A9 5486ebbf2ceSRussell King retne lr @ Not ARM Cortex-A9, 549bc41b872SSantosh Shilimkar 550bc41b872SSantosh Shilimkar @ If a future SoC *does* use 0x0 as the PERIPH_BASE, then the 551bc41b872SSantosh Shilimkar @ below address check will need to be #ifdef'd or equivalent 552bc41b872SSantosh Shilimkar @ for the Aegis platform. 553bc41b872SSantosh Shilimkar mrc p15, 4, r0, c15, c0 @ get SCU base address 554bc41b872SSantosh Shilimkar teq r0, #0x0 @ '0' on actual UP A9 hardware 555bc41b872SSantosh Shilimkar beq __fixup_smp_on_up @ So its an A9 UP 556bc41b872SSantosh Shilimkar ldr r0, [r0, #4] @ read SCU Config 55710593b2eSVictor KamenskyARM_BE8(rev r0, r0) @ byteswap if big endian 558bc41b872SSantosh Shilimkar and r0, r0, #0x3 @ number of CPUs 559bc41b872SSantosh Shilimkar teq r0, #0x0 @ is 1? 5606ebbf2ceSRussell King retne lr 561f00ec48fSRussell King 562f00ec48fSRussell King__fixup_smp_on_up: 56359d2f282SArd Biesheuvel adr_l r4, __smpalt_begin 56459d2f282SArd Biesheuvel adr_l r5, __smpalt_end 5654a9cb360SRussell King b __do_fixup_smp_on_up 566f00ec48fSRussell KingENDPROC(__fixup_smp) 567f00ec48fSRussell King 568f00ec48fSRussell King .pushsection .data 5691abd3502SRussell King .align 2 570f00ec48fSRussell King .globl smp_on_up 571f00ec48fSRussell Kingsmp_on_up: 572f00ec48fSRussell King ALT_SMP(.long 1) 573f00ec48fSRussell King ALT_UP(.long 0) 574f00ec48fSRussell King .popsection 575f00ec48fSRussell King#endif 576f00ec48fSRussell King 5774a9cb360SRussell King .text 5784a9cb360SRussell King__do_fixup_smp_on_up: 5794a9cb360SRussell King cmp r4, r5 5806ebbf2ceSRussell King reths lr 581450abd38SArd Biesheuvel ldmia r4, {r0, r6} 582450abd38SArd Biesheuvel ARM( str r6, [r0, r4] ) 583450abd38SArd Biesheuvel THUMB( add r0, r0, r4 ) 584450abd38SArd Biesheuvel add r4, r4, #8 5854a9cb360SRussell King#ifdef __ARMEB__ 5864a9cb360SRussell King THUMB( mov r6, r6, ror #16 ) @ Convert word order for big-endian. 5874a9cb360SRussell King#endif 5884a9cb360SRussell King THUMB( strh r6, [r0], #2 ) @ For Thumb-2, store as two halfwords 589450abd38SArd Biesheuvel THUMB( mov r6, r6, lsr #16 ) @ to be robust against misaligned r0. 5904a9cb360SRussell King THUMB( strh r6, [r0] ) 5914a9cb360SRussell King b __do_fixup_smp_on_up 5924a9cb360SRussell KingENDPROC(__do_fixup_smp_on_up) 5934a9cb360SRussell King 5944a9cb360SRussell KingENTRY(fixup_smp) 5954a9cb360SRussell King stmfd sp!, {r4 - r6, lr} 5964a9cb360SRussell King mov r4, r0 5974a9cb360SRussell King add r5, r0, r1 5984a9cb360SRussell King bl __do_fixup_smp_on_up 5994a9cb360SRussell King ldmfd sp!, {r4 - r6, pc} 6004a9cb360SRussell KingENDPROC(fixup_smp) 6014a9cb360SRussell King 60275d90832SHyok S. Choi#include "head-common.S" 603