11da177e4SLinus Torvalds/* 21da177e4SLinus Torvalds * linux/arch/arm/kernel/head.S 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 1994-2002 Russell King 5e65f38edSRussell King * Copyright (c) 2003 ARM Limited 6e65f38edSRussell King * All Rights Reserved 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 91da177e4SLinus Torvalds * it under the terms of the GNU General Public License version 2 as 101da177e4SLinus Torvalds * published by the Free Software Foundation. 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * Kernel startup code for all 32-bit CPUs 131da177e4SLinus Torvalds */ 141da177e4SLinus Torvalds#include <linux/linkage.h> 151da177e4SLinus Torvalds#include <linux/init.h> 161da177e4SLinus Torvalds 171da177e4SLinus Torvalds#include <asm/assembler.h> 181da177e4SLinus Torvalds#include <asm/domain.h> 191da177e4SLinus Torvalds#include <asm/ptrace.h> 20e6ae744dSSam Ravnborg#include <asm/asm-offsets.h> 21f09b9979SNicolas Pitre#include <asm/memory.h> 224f7a1812SRussell King#include <asm/thread_info.h> 231da177e4SLinus Torvalds#include <asm/system.h> 241da177e4SLinus Torvalds 25c293393fSJeremy Kerr#ifdef CONFIG_DEBUG_LL 26c293393fSJeremy Kerr#include <mach/debug-macro.S> 27c293393fSJeremy Kerr#endif 28c293393fSJeremy Kerr 291da177e4SLinus Torvalds/* 3037d07b72SNicolas Pitre * swapper_pg_dir is the virtual address of the initial page table. 31f06b97ffSRussell King * We place the page tables 16K below KERNEL_RAM_VADDR. Therefore, we must 32f06b97ffSRussell King * make sure that KERNEL_RAM_VADDR is correctly set. Currently, we expect 3337d07b72SNicolas Pitre * the least significant 16 bits to be 0x8000, but we could probably 34f06b97ffSRussell King * relax this restriction to KERNEL_RAM_VADDR >= PAGE_OFFSET + 0x4000. 351da177e4SLinus Torvalds */ 3672a20e22SRussell King#define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET) 37f06b97ffSRussell King#if (KERNEL_RAM_VADDR & 0xffff) != 0x8000 38f06b97ffSRussell King#error KERNEL_RAM_VADDR must start at 0xXXXX8000 391da177e4SLinus Torvalds#endif 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds .globl swapper_pg_dir 42f06b97ffSRussell King .equ swapper_pg_dir, KERNEL_RAM_VADDR - 0x4000 431da177e4SLinus Torvalds 4472a20e22SRussell King .macro pgtbl, rd, phys 4572a20e22SRussell King add \rd, \phys, #TEXT_OFFSET - 0x4000 461da177e4SLinus Torvalds .endm 4737d07b72SNicolas Pitre 4837d07b72SNicolas Pitre#ifdef CONFIG_XIP_KERNEL 49e98ff7f6SNicolas Pitre#define KERNEL_START XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR) 50e98ff7f6SNicolas Pitre#define KERNEL_END _edata_loc 511da177e4SLinus Torvalds#else 52e98ff7f6SNicolas Pitre#define KERNEL_START KERNEL_RAM_VADDR 53e98ff7f6SNicolas Pitre#define KERNEL_END _end 541da177e4SLinus Torvalds#endif 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds/* 571da177e4SLinus Torvalds * Kernel startup entry point. 581da177e4SLinus Torvalds * --------------------------- 591da177e4SLinus Torvalds * 601da177e4SLinus Torvalds * This is normally called from the decompressor code. The requirements 611da177e4SLinus Torvalds * are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0, 629d20fdd5SBill Gatliff * r1 = machine nr, r2 = atags pointer. 631da177e4SLinus Torvalds * 641da177e4SLinus Torvalds * This code is mostly position independent, so if you link the kernel at 651da177e4SLinus Torvalds * 0xc0008000, you call this at __pa(0xc0008000). 661da177e4SLinus Torvalds * 671da177e4SLinus Torvalds * See linux/arch/arm/tools/mach-types for the complete list of machine 681da177e4SLinus Torvalds * numbers for r1. 691da177e4SLinus Torvalds * 701da177e4SLinus Torvalds * We're trying to keep crap to a minimum; DO NOT add any machine specific 711da177e4SLinus Torvalds * crap here - that's what the boot loader (or in extreme, well justified 721da177e4SLinus Torvalds * circumstances, zImage) is for. 731da177e4SLinus Torvalds */ 742abc1c50STim Abbott __HEAD 751da177e4SLinus TorvaldsENTRY(stext) 76b86040a5SCatalin Marinas setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode 771da177e4SLinus Torvalds @ and irqs disabled 780f44ba1dSRussell King mrc p15, 0, r9, c0, c0 @ get processor id 791da177e4SLinus Torvalds bl __lookup_processor_type @ r5=procinfo r9=cpuid 801da177e4SLinus Torvalds movs r10, r5 @ invalid processor (r5=0)? 81a75e5248SDave Martin THUMB( it eq ) @ force fixup-able long branch encoding 821da177e4SLinus Torvalds beq __error_p @ yes, error 'p' 830eb0511dSRussell King 8472a20e22SRussell King#ifndef CONFIG_XIP_KERNEL 8572a20e22SRussell King adr r3, 2f 8672a20e22SRussell King ldmia r3, {r4, r8} 8772a20e22SRussell King sub r4, r3, r4 @ (PHYS_OFFSET - PAGE_OFFSET) 8872a20e22SRussell King add r8, r8, r4 @ PHYS_OFFSET 8972a20e22SRussell King#else 9072a20e22SRussell King ldr r8, =PLAT_PHYS_OFFSET 9172a20e22SRussell King#endif 9272a20e22SRussell King 930eb0511dSRussell King /* 940eb0511dSRussell King * r1 = machine no, r2 = atags, 9572a20e22SRussell King * r8 = phys_offset, r9 = cpuid, r10 = procinfo 960eb0511dSRussell King */ 979d20fdd5SBill Gatliff bl __vet_atags 98f00ec48fSRussell King#ifdef CONFIG_SMP_ON_UP 99f00ec48fSRussell King bl __fixup_smp 100f00ec48fSRussell King#endif 101dc21af99SRussell King#ifdef CONFIG_ARM_PATCH_PHYS_VIRT 102dc21af99SRussell King bl __fixup_pv_table 103dc21af99SRussell King#endif 1041da177e4SLinus Torvalds bl __create_page_tables 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds /* 1071da177e4SLinus Torvalds * The following calls CPU specific code in a position independent 1081da177e4SLinus Torvalds * manner. See arch/arm/mm/proc-*.S for details. r10 = base of 1096fc31d54SRussell King * xxx_proc_info structure selected by __lookup_processor_type 1101da177e4SLinus Torvalds * above. On return, the CPU will be ready for the MMU to be 1111da177e4SLinus Torvalds * turned on, and r0 will hold the CPU control register value. 1121da177e4SLinus Torvalds */ 113a4ae4134SRussell King ldr r13, =__mmap_switched @ address to jump to after 1141da177e4SLinus Torvalds @ mmu has been enabled 11500945010SRussell King adr lr, BSYM(1f) @ return (PIC) address 116d427958aSCatalin Marinas mov r8, r4 @ set TTBR1 to swapper_pg_dir 117b86040a5SCatalin Marinas ARM( add pc, r10, #PROCINFO_INITFUNC ) 118b86040a5SCatalin Marinas THUMB( add r12, r10, #PROCINFO_INITFUNC ) 119b86040a5SCatalin Marinas THUMB( mov pc, r12 ) 12000945010SRussell King1: b __enable_mmu 12193ed3970SCatalin MarinasENDPROC(stext) 122a4ae4134SRussell King .ltorg 12372a20e22SRussell King#ifndef CONFIG_XIP_KERNEL 12472a20e22SRussell King2: .long . 12572a20e22SRussell King .long PAGE_OFFSET 12672a20e22SRussell King#endif 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds/* 1291da177e4SLinus Torvalds * Setup the initial page tables. We only setup the barest 1301da177e4SLinus Torvalds * amount which are required to get the kernel running, which 1311da177e4SLinus Torvalds * generally means mapping in the kernel code. 1321da177e4SLinus Torvalds * 13372a20e22SRussell King * r8 = phys_offset, r9 = cpuid, r10 = procinfo 1341da177e4SLinus Torvalds * 1351da177e4SLinus Torvalds * Returns: 136786f1b73SRussell King * r0, r3, r5-r7 corrupted 1371da177e4SLinus Torvalds * r4 = physical page table address 1381da177e4SLinus Torvalds */ 1391da177e4SLinus Torvalds__create_page_tables: 14072a20e22SRussell King pgtbl r4, r8 @ page table address 1411da177e4SLinus Torvalds 1421da177e4SLinus Torvalds /* 1431da177e4SLinus Torvalds * Clear the 16K level 1 swapper page table 1441da177e4SLinus Torvalds */ 1451da177e4SLinus Torvalds mov r0, r4 1461da177e4SLinus Torvalds mov r3, #0 1471da177e4SLinus Torvalds add r6, r0, #0x4000 1481da177e4SLinus Torvalds1: str r3, [r0], #4 1491da177e4SLinus Torvalds str r3, [r0], #4 1501da177e4SLinus Torvalds str r3, [r0], #4 1511da177e4SLinus Torvalds str r3, [r0], #4 1521da177e4SLinus Torvalds teq r0, r6 1531da177e4SLinus Torvalds bne 1b 1541da177e4SLinus Torvalds 1558799ee9fSRussell King ldr r7, [r10, #PROCINFO_MM_MMUFLAGS] @ mm_mmuflags 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds /* 158786f1b73SRussell King * Create identity mapping to cater for __enable_mmu. 159786f1b73SRussell King * This identity mapping will be removed by paging_init(). 1601da177e4SLinus Torvalds */ 161786f1b73SRussell King adr r0, __enable_mmu_loc 162786f1b73SRussell King ldmia r0, {r3, r5, r6} 163786f1b73SRussell King sub r0, r0, r3 @ virt->phys offset 164786f1b73SRussell King add r5, r5, r0 @ phys __enable_mmu 165786f1b73SRussell King add r6, r6, r0 @ phys __enable_mmu_end 166786f1b73SRussell King mov r5, r5, lsr #20 167786f1b73SRussell King mov r6, r6, lsr #20 168786f1b73SRussell King 169786f1b73SRussell King1: orr r3, r7, r5, lsl #20 @ flags + kernel base 170786f1b73SRussell King str r3, [r4, r5, lsl #2] @ identity mapping 171786f1b73SRussell King teq r5, r6 172786f1b73SRussell King addne r5, r5, #1 @ next section 173786f1b73SRussell King bne 1b 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds /* 1761da177e4SLinus Torvalds * Now setup the pagetables for our kernel direct 1772552fc27SLennert Buytenhek * mapped region. 1781da177e4SLinus Torvalds */ 179786f1b73SRussell King mov r3, pc 180786f1b73SRussell King mov r3, r3, lsr #20 181786f1b73SRussell King orr r3, r7, r3, lsl #20 182e98ff7f6SNicolas Pitre add r0, r4, #(KERNEL_START & 0xff000000) >> 18 183e98ff7f6SNicolas Pitre str r3, [r0, #(KERNEL_START & 0x00f00000) >> 18]! 184e98ff7f6SNicolas Pitre ldr r6, =(KERNEL_END - 1) 185e98ff7f6SNicolas Pitre add r0, r0, #4 186e98ff7f6SNicolas Pitre add r6, r4, r6, lsr #18 187e98ff7f6SNicolas Pitre1: cmp r0, r6 188e98ff7f6SNicolas Pitre add r3, r3, #1 << 20 189e98ff7f6SNicolas Pitre strls r3, [r0], #4 190e98ff7f6SNicolas Pitre bls 1b 1911da177e4SLinus Torvalds 192ec3622d9SNicolas Pitre#ifdef CONFIG_XIP_KERNEL 193ec3622d9SNicolas Pitre /* 194ec3622d9SNicolas Pitre * Map some ram to cover our .data and .bss areas. 195ec3622d9SNicolas Pitre */ 19672a20e22SRussell King add r3, r8, #TEXT_OFFSET 19772a20e22SRussell King orr r3, r3, r7 198ec3622d9SNicolas Pitre add r0, r4, #(KERNEL_RAM_VADDR & 0xff000000) >> 18 199ec3622d9SNicolas Pitre str r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00000) >> 18]! 200ec3622d9SNicolas Pitre ldr r6, =(_end - 1) 201ec3622d9SNicolas Pitre add r0, r0, #4 202ec3622d9SNicolas Pitre add r6, r4, r6, lsr #18 203ec3622d9SNicolas Pitre1: cmp r0, r6 204ec3622d9SNicolas Pitre add r3, r3, #1 << 20 205ec3622d9SNicolas Pitre strls r3, [r0], #4 206ec3622d9SNicolas Pitre bls 1b 207ec3622d9SNicolas Pitre#endif 208ec3622d9SNicolas Pitre 2091da177e4SLinus Torvalds /* 2104d901c42SRob Herring * Then map boot params address in r2 or 2114d901c42SRob Herring * the first 1MB of ram if boot params address is not specified. 2121da177e4SLinus Torvalds */ 2134d901c42SRob Herring mov r0, r2, lsr #20 2144d901c42SRob Herring movs r0, r0, lsl #20 2154d901c42SRob Herring moveq r0, r8 2164d901c42SRob Herring sub r3, r0, r8 2174d901c42SRob Herring add r3, r3, #PAGE_OFFSET 2184d901c42SRob Herring add r3, r4, r3, lsr #18 2194d901c42SRob Herring orr r6, r7, r0 2204d901c42SRob Herring str r6, [r3] 2211da177e4SLinus Torvalds 222c77b0427SRussell King#ifdef CONFIG_DEBUG_LL 223c293393fSJeremy Kerr#ifndef CONFIG_DEBUG_ICEDCC 2241da177e4SLinus Torvalds /* 2251da177e4SLinus Torvalds * Map in IO space for serial debugging. 2261da177e4SLinus Torvalds * This allows debug messages to be output 2271da177e4SLinus Torvalds * via a serial console before paging_init. 2281da177e4SLinus Torvalds */ 229c293393fSJeremy Kerr addruart r7, r3 230c293393fSJeremy Kerr 231c293393fSJeremy Kerr mov r3, r3, lsr #20 232c293393fSJeremy Kerr mov r3, r3, lsl #2 233c293393fSJeremy Kerr 2341da177e4SLinus Torvalds add r0, r4, r3 2351da177e4SLinus Torvalds rsb r3, r3, #0x4000 @ PTRS_PER_PGD*sizeof(long) 2361da177e4SLinus Torvalds cmp r3, #0x0800 @ limit to 512MB 2371da177e4SLinus Torvalds movhi r3, #0x0800 2381da177e4SLinus Torvalds add r6, r0, r3 239c293393fSJeremy Kerr mov r3, r7, lsr #20 240c293393fSJeremy Kerr ldr r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags 241c293393fSJeremy Kerr orr r3, r7, r3, lsl #20 2421da177e4SLinus Torvalds1: str r3, [r0], #4 2431da177e4SLinus Torvalds add r3, r3, #1 << 20 2441da177e4SLinus Torvalds teq r0, r6 2451da177e4SLinus Torvalds bne 1b 246c293393fSJeremy Kerr 247c293393fSJeremy Kerr#else /* CONFIG_DEBUG_ICEDCC */ 248c293393fSJeremy Kerr /* we don't need any serial debugging mappings for ICEDCC */ 249c293393fSJeremy Kerr ldr r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags 250c293393fSJeremy Kerr#endif /* !CONFIG_DEBUG_ICEDCC */ 251c293393fSJeremy Kerr 2521da177e4SLinus Torvalds#if defined(CONFIG_ARCH_NETWINDER) || defined(CONFIG_ARCH_CATS) 2531da177e4SLinus Torvalds /* 2543c0bdac3SRussell King * If we're using the NetWinder or CATS, we also need to map 2553c0bdac3SRussell King * in the 16550-type serial port for the debug messages 2561da177e4SLinus Torvalds */ 257c77b0427SRussell King add r0, r4, #0xff000000 >> 18 258c77b0427SRussell King orr r3, r7, #0x7c000000 259c77b0427SRussell King str r3, [r0] 2601da177e4SLinus Torvalds#endif 2611da177e4SLinus Torvalds#ifdef CONFIG_ARCH_RPC 2621da177e4SLinus Torvalds /* 2631da177e4SLinus Torvalds * Map in screen at 0x02000000 & SCREEN2_BASE 2641da177e4SLinus Torvalds * Similar reasons here - for debug. This is 2651da177e4SLinus Torvalds * only for Acorn RiscPC architectures. 2661da177e4SLinus Torvalds */ 267c77b0427SRussell King add r0, r4, #0x02000000 >> 18 268c77b0427SRussell King orr r3, r7, #0x02000000 2691da177e4SLinus Torvalds str r3, [r0] 270c77b0427SRussell King add r0, r4, #0xd8000000 >> 18 2711da177e4SLinus Torvalds str r3, [r0] 2721da177e4SLinus Torvalds#endif 273c77b0427SRussell King#endif 2741da177e4SLinus Torvalds mov pc, lr 27593ed3970SCatalin MarinasENDPROC(__create_page_tables) 2761da177e4SLinus Torvalds .ltorg 2774f79a5ddSDave Martin .align 278786f1b73SRussell King__enable_mmu_loc: 279786f1b73SRussell King .long . 280786f1b73SRussell King .long __enable_mmu 281786f1b73SRussell King .long __enable_mmu_end 2821da177e4SLinus Torvalds 28300945010SRussell King#if defined(CONFIG_SMP) 28400945010SRussell King __CPUINIT 28500945010SRussell KingENTRY(secondary_startup) 28600945010SRussell King /* 28700945010SRussell King * Common entry point for secondary CPUs. 28800945010SRussell King * 28900945010SRussell King * Ensure that we're in SVC mode, and IRQs are disabled. Lookup 29000945010SRussell King * the processor type - there is no need to check the machine type 29100945010SRussell King * as it has already been validated by the primary processor. 29200945010SRussell King */ 29300945010SRussell King setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 29400945010SRussell King mrc p15, 0, r9, c0, c0 @ get processor id 29500945010SRussell King bl __lookup_processor_type 29600945010SRussell King movs r10, r5 @ invalid processor? 29700945010SRussell King moveq r0, #'p' @ yes, error 'p' 298a75e5248SDave Martin THUMB( it eq ) @ force fixup-able long branch encoding 29900945010SRussell King beq __error_p 30000945010SRussell King 30100945010SRussell King /* 30200945010SRussell King * Use the page tables supplied from __cpu_up. 30300945010SRussell King */ 30400945010SRussell King adr r4, __secondary_data 30500945010SRussell King ldmia r4, {r5, r7, r12} @ address to jump to after 306d427958aSCatalin Marinas sub lr, r4, r5 @ mmu has been enabled 307d427958aSCatalin Marinas ldr r4, [r7, lr] @ get secondary_data.pgdir 308d427958aSCatalin Marinas add r7, r7, #4 309d427958aSCatalin Marinas ldr r8, [r7, lr] @ get secondary_data.swapper_pg_dir 31000945010SRussell King adr lr, BSYM(__enable_mmu) @ return address 31100945010SRussell King mov r13, r12 @ __secondary_switched address 31200945010SRussell King ARM( add pc, r10, #PROCINFO_INITFUNC ) @ initialise processor 31300945010SRussell King @ (return control reg) 31400945010SRussell King THUMB( add r12, r10, #PROCINFO_INITFUNC ) 31500945010SRussell King THUMB( mov pc, r12 ) 31600945010SRussell KingENDPROC(secondary_startup) 31700945010SRussell King 31800945010SRussell King /* 31900945010SRussell King * r6 = &secondary_data 32000945010SRussell King */ 32100945010SRussell KingENTRY(__secondary_switched) 32200945010SRussell King ldr sp, [r7, #4] @ get secondary_data.stack 32300945010SRussell King mov fp, #0 32400945010SRussell King b secondary_start_kernel 32500945010SRussell KingENDPROC(__secondary_switched) 32600945010SRussell King 3274f79a5ddSDave Martin .align 3284f79a5ddSDave Martin 32900945010SRussell King .type __secondary_data, %object 33000945010SRussell King__secondary_data: 33100945010SRussell King .long . 33200945010SRussell King .long secondary_data 33300945010SRussell King .long __secondary_switched 33400945010SRussell King#endif /* defined(CONFIG_SMP) */ 33500945010SRussell King 33600945010SRussell King 33700945010SRussell King 33800945010SRussell King/* 33900945010SRussell King * Setup common bits before finally enabling the MMU. Essentially 34000945010SRussell King * this is just loading the page table pointer and domain access 34100945010SRussell King * registers. 342865a4faeSRussell King * 343865a4faeSRussell King * r0 = cp#15 control register 344865a4faeSRussell King * r1 = machine ID 345865a4faeSRussell King * r2 = atags pointer 346865a4faeSRussell King * r4 = page table pointer 347865a4faeSRussell King * r9 = processor ID 348865a4faeSRussell King * r13 = *virtual* address to jump to upon completion 34900945010SRussell King */ 35000945010SRussell King__enable_mmu: 35100945010SRussell King#ifdef CONFIG_ALIGNMENT_TRAP 35200945010SRussell King orr r0, r0, #CR_A 35300945010SRussell King#else 35400945010SRussell King bic r0, r0, #CR_A 35500945010SRussell King#endif 35600945010SRussell King#ifdef CONFIG_CPU_DCACHE_DISABLE 35700945010SRussell King bic r0, r0, #CR_C 35800945010SRussell King#endif 35900945010SRussell King#ifdef CONFIG_CPU_BPREDICT_DISABLE 36000945010SRussell King bic r0, r0, #CR_Z 36100945010SRussell King#endif 36200945010SRussell King#ifdef CONFIG_CPU_ICACHE_DISABLE 36300945010SRussell King bic r0, r0, #CR_I 36400945010SRussell King#endif 36500945010SRussell King mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \ 36600945010SRussell King domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \ 36700945010SRussell King domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \ 36800945010SRussell King domain_val(DOMAIN_IO, DOMAIN_CLIENT)) 36900945010SRussell King mcr p15, 0, r5, c3, c0, 0 @ load domain access register 37000945010SRussell King mcr p15, 0, r4, c2, c0, 0 @ load page table pointer 37100945010SRussell King b __turn_mmu_on 37200945010SRussell KingENDPROC(__enable_mmu) 37300945010SRussell King 37400945010SRussell King/* 37500945010SRussell King * Enable the MMU. This completely changes the structure of the visible 37600945010SRussell King * memory space. You will not be able to trace execution through this. 37700945010SRussell King * If you have an enquiry about this, *please* check the linux-arm-kernel 37800945010SRussell King * mailing list archives BEFORE sending another post to the list. 37900945010SRussell King * 38000945010SRussell King * r0 = cp#15 control register 381865a4faeSRussell King * r1 = machine ID 382865a4faeSRussell King * r2 = atags pointer 383865a4faeSRussell King * r9 = processor ID 38400945010SRussell King * r13 = *virtual* address to jump to upon completion 38500945010SRussell King * 38600945010SRussell King * other registers depend on the function called upon completion 38700945010SRussell King */ 38800945010SRussell King .align 5 38900945010SRussell King__turn_mmu_on: 39000945010SRussell King mov r0, r0 39100945010SRussell King mcr p15, 0, r0, c1, c0, 0 @ write control reg 39200945010SRussell King mrc p15, 0, r3, c0, c0, 0 @ read id reg 39300945010SRussell King mov r3, r3 39400945010SRussell King mov r3, r13 39500945010SRussell King mov pc, r3 39600945010SRussell King__enable_mmu_end: 39700945010SRussell KingENDPROC(__turn_mmu_on) 39800945010SRussell King 3991da177e4SLinus Torvalds 400f00ec48fSRussell King#ifdef CONFIG_SMP_ON_UP 4014a9cb360SRussell King __INIT 402f00ec48fSRussell King__fixup_smp: 403e98ff0f5SRussell King and r3, r9, #0x000f0000 @ architecture version 404e98ff0f5SRussell King teq r3, #0x000f0000 @ CPU ID supported? 405f00ec48fSRussell King bne __fixup_smp_on_up @ no, assume UP 406f00ec48fSRussell King 407e98ff0f5SRussell King bic r3, r9, #0x00ff0000 408e98ff0f5SRussell King bic r3, r3, #0x0000000f @ mask 0xff00fff0 409e98ff0f5SRussell King mov r4, #0x41000000 4100eb0511dSRussell King orr r4, r4, #0x0000b000 411e98ff0f5SRussell King orr r4, r4, #0x00000020 @ val 0x4100b020 412e98ff0f5SRussell King teq r3, r4 @ ARM 11MPCore? 413f00ec48fSRussell King moveq pc, lr @ yes, assume SMP 414f00ec48fSRussell King 415f00ec48fSRussell King mrc p15, 0, r0, c0, c0, 5 @ read MPIDR 416e98ff0f5SRussell King and r0, r0, #0xc0000000 @ multiprocessing extensions and 417e98ff0f5SRussell King teq r0, #0x80000000 @ not part of a uniprocessor system? 418e98ff0f5SRussell King moveq pc, lr @ yes, assume SMP 419f00ec48fSRussell King 420f00ec48fSRussell King__fixup_smp_on_up: 421f00ec48fSRussell King adr r0, 1f 4220eb0511dSRussell King ldmia r0, {r3 - r5} 423f00ec48fSRussell King sub r3, r0, r3 4240eb0511dSRussell King add r4, r4, r3 4250eb0511dSRussell King add r5, r5, r3 4264a9cb360SRussell King b __do_fixup_smp_on_up 427f00ec48fSRussell KingENDPROC(__fixup_smp) 428f00ec48fSRussell King 4294f79a5ddSDave Martin .align 430f00ec48fSRussell King1: .word . 431f00ec48fSRussell King .word __smpalt_begin 432f00ec48fSRussell King .word __smpalt_end 433f00ec48fSRussell King 434f00ec48fSRussell King .pushsection .data 435f00ec48fSRussell King .globl smp_on_up 436f00ec48fSRussell Kingsmp_on_up: 437f00ec48fSRussell King ALT_SMP(.long 1) 438f00ec48fSRussell King ALT_UP(.long 0) 439f00ec48fSRussell King .popsection 440f00ec48fSRussell King#endif 441f00ec48fSRussell King 4424a9cb360SRussell King .text 4434a9cb360SRussell King__do_fixup_smp_on_up: 4444a9cb360SRussell King cmp r4, r5 4454a9cb360SRussell King movhs pc, lr 4464a9cb360SRussell King ldmia r4!, {r0, r6} 4474a9cb360SRussell King ARM( str r6, [r0, r3] ) 4484a9cb360SRussell King THUMB( add r0, r0, r3 ) 4494a9cb360SRussell King#ifdef __ARMEB__ 4504a9cb360SRussell King THUMB( mov r6, r6, ror #16 ) @ Convert word order for big-endian. 4514a9cb360SRussell King#endif 4524a9cb360SRussell King THUMB( strh r6, [r0], #2 ) @ For Thumb-2, store as two halfwords 4534a9cb360SRussell King THUMB( mov r6, r6, lsr #16 ) @ to be robust against misaligned r3. 4544a9cb360SRussell King THUMB( strh r6, [r0] ) 4554a9cb360SRussell King b __do_fixup_smp_on_up 4564a9cb360SRussell KingENDPROC(__do_fixup_smp_on_up) 4574a9cb360SRussell King 4584a9cb360SRussell KingENTRY(fixup_smp) 4594a9cb360SRussell King stmfd sp!, {r4 - r6, lr} 4604a9cb360SRussell King mov r4, r0 4614a9cb360SRussell King add r5, r0, r1 4624a9cb360SRussell King mov r3, #0 4634a9cb360SRussell King bl __do_fixup_smp_on_up 4644a9cb360SRussell King ldmfd sp!, {r4 - r6, pc} 4654a9cb360SRussell KingENDPROC(fixup_smp) 4664a9cb360SRussell King 467dc21af99SRussell King#ifdef CONFIG_ARM_PATCH_PHYS_VIRT 468dc21af99SRussell King 469dc21af99SRussell King/* __fixup_pv_table - patch the stub instructions with the delta between 470dc21af99SRussell King * PHYS_OFFSET and PAGE_OFFSET, which is assumed to be 16MiB aligned and 471dc21af99SRussell King * can be expressed by an immediate shifter operand. The stub instruction 472dc21af99SRussell King * has a form of '(add|sub) rd, rn, #imm'. 473dc21af99SRussell King */ 474dc21af99SRussell King __HEAD 475dc21af99SRussell King__fixup_pv_table: 476dc21af99SRussell King adr r0, 1f 477dc21af99SRussell King ldmia r0, {r3-r5, r7} 478dc21af99SRussell King sub r3, r0, r3 @ PHYS_OFFSET - PAGE_OFFSET 479dc21af99SRussell King add r4, r4, r3 @ adjust table start address 480dc21af99SRussell King add r5, r5, r3 @ adjust table end address 481b511d75dSNicolas Pitre add r7, r7, r3 @ adjust __pv_phys_offset address 482b511d75dSNicolas Pitre str r8, [r7] @ save computed PHYS_OFFSET to __pv_phys_offset 483cada3c08SRussell King#ifndef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT 484dc21af99SRussell King mov r6, r3, lsr #24 @ constant for add/sub instructions 485dc21af99SRussell King teq r3, r6, lsl #24 @ must be 16MiB aligned 486cada3c08SRussell King#else 487cada3c08SRussell King mov r6, r3, lsr #16 @ constant for add/sub instructions 488cada3c08SRussell King teq r3, r6, lsl #16 @ must be 64kiB aligned 489cada3c08SRussell King#endif 490b511d75dSNicolas PitreTHUMB( it ne @ cross section branch ) 491dc21af99SRussell King bne __error 492dc21af99SRussell King str r6, [r7, #4] @ save to __pv_offset 493dc21af99SRussell King b __fixup_a_pv_table 494dc21af99SRussell KingENDPROC(__fixup_pv_table) 495dc21af99SRussell King 496dc21af99SRussell King .align 497dc21af99SRussell King1: .long . 498dc21af99SRussell King .long __pv_table_begin 499dc21af99SRussell King .long __pv_table_end 500dc21af99SRussell King2: .long __pv_phys_offset 501dc21af99SRussell King 502dc21af99SRussell King .text 503dc21af99SRussell King__fixup_a_pv_table: 504b511d75dSNicolas Pitre#ifdef CONFIG_THUMB2_KERNEL 505b511d75dSNicolas Pitre#ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT 506b511d75dSNicolas Pitre lsls r0, r6, #24 507b511d75dSNicolas Pitre lsr r6, #8 508b511d75dSNicolas Pitre beq 1f 509b511d75dSNicolas Pitre clz r7, r0 510b511d75dSNicolas Pitre lsr r0, #24 511b511d75dSNicolas Pitre lsl r0, r7 512b511d75dSNicolas Pitre bic r0, 0x0080 513b511d75dSNicolas Pitre lsrs r7, #1 514b511d75dSNicolas Pitre orrcs r0, #0x0080 515b511d75dSNicolas Pitre orr r0, r0, r7, lsl #12 516b511d75dSNicolas Pitre#endif 517b511d75dSNicolas Pitre1: lsls r6, #24 518b511d75dSNicolas Pitre beq 4f 519b511d75dSNicolas Pitre clz r7, r6 520b511d75dSNicolas Pitre lsr r6, #24 521b511d75dSNicolas Pitre lsl r6, r7 522b511d75dSNicolas Pitre bic r6, #0x0080 523b511d75dSNicolas Pitre lsrs r7, #1 524b511d75dSNicolas Pitre orrcs r6, #0x0080 525b511d75dSNicolas Pitre orr r6, r6, r7, lsl #12 526b511d75dSNicolas Pitre orr r6, #0x4000 527b511d75dSNicolas Pitre b 4f 528b511d75dSNicolas Pitre2: @ at this point the C flag is always clear 529b511d75dSNicolas Pitre add r7, r3 530b511d75dSNicolas Pitre#ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT 531b511d75dSNicolas Pitre ldrh ip, [r7] 532b511d75dSNicolas Pitre tst ip, 0x0400 @ the i bit tells us LS or MS byte 533b511d75dSNicolas Pitre beq 3f 534b511d75dSNicolas Pitre cmp r0, #0 @ set C flag, and ... 535b511d75dSNicolas Pitre biceq ip, 0x0400 @ immediate zero value has a special encoding 536b511d75dSNicolas Pitre streqh ip, [r7] @ that requires the i bit cleared 537b511d75dSNicolas Pitre#endif 538b511d75dSNicolas Pitre3: ldrh ip, [r7, #2] 539b511d75dSNicolas Pitre and ip, 0x8f00 540b511d75dSNicolas Pitre orrcc ip, r6 @ mask in offset bits 31-24 541b511d75dSNicolas Pitre orrcs ip, r0 @ mask in offset bits 23-16 542b511d75dSNicolas Pitre strh ip, [r7, #2] 543b511d75dSNicolas Pitre4: cmp r4, r5 544b511d75dSNicolas Pitre ldrcc r7, [r4], #4 @ use branch for delay slot 545b511d75dSNicolas Pitre bcc 2b 546b511d75dSNicolas Pitre bx lr 547b511d75dSNicolas Pitre#else 548cada3c08SRussell King#ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT 549cada3c08SRussell King and r0, r6, #255 @ offset bits 23-16 550cada3c08SRussell King mov r6, r6, lsr #8 @ offset bits 31-24 551cada3c08SRussell King#else 552cada3c08SRussell King mov r0, #0 @ just in case... 553cada3c08SRussell King#endif 554dc21af99SRussell King b 3f 555dc21af99SRussell King2: ldr ip, [r7, r3] 556dc21af99SRussell King bic ip, ip, #0x000000ff 557cada3c08SRussell King tst ip, #0x400 @ rotate shift tells us LS or MS byte 558cada3c08SRussell King orrne ip, ip, r6 @ mask in offset bits 31-24 559cada3c08SRussell King orreq ip, ip, r0 @ mask in offset bits 23-16 560dc21af99SRussell King str ip, [r7, r3] 561dc21af99SRussell King3: cmp r4, r5 562dc21af99SRussell King ldrcc r7, [r4], #4 @ use branch for delay slot 563dc21af99SRussell King bcc 2b 564dc21af99SRussell King mov pc, lr 565b511d75dSNicolas Pitre#endif 566dc21af99SRussell KingENDPROC(__fixup_a_pv_table) 567dc21af99SRussell King 568dc21af99SRussell KingENTRY(fixup_pv_table) 569dc21af99SRussell King stmfd sp!, {r4 - r7, lr} 570dc21af99SRussell King ldr r2, 2f @ get address of __pv_phys_offset 571dc21af99SRussell King mov r3, #0 @ no offset 572dc21af99SRussell King mov r4, r0 @ r0 = table start 573dc21af99SRussell King add r5, r0, r1 @ r1 = table size 574dc21af99SRussell King ldr r6, [r2, #4] @ get __pv_offset 575dc21af99SRussell King bl __fixup_a_pv_table 576dc21af99SRussell King ldmfd sp!, {r4 - r7, pc} 577dc21af99SRussell KingENDPROC(fixup_pv_table) 578dc21af99SRussell King 579dc21af99SRussell King .align 580dc21af99SRussell King2: .long __pv_phys_offset 581dc21af99SRussell King 582dc21af99SRussell King .data 583dc21af99SRussell King .globl __pv_phys_offset 584dc21af99SRussell King .type __pv_phys_offset, %object 585dc21af99SRussell King__pv_phys_offset: 586dc21af99SRussell King .long 0 587dc21af99SRussell King .size __pv_phys_offset, . - __pv_phys_offset 588dc21af99SRussell King__pv_offset: 589dc21af99SRussell King .long 0 590dc21af99SRussell King#endif 591dc21af99SRussell King 59275d90832SHyok S. Choi#include "head-common.S" 593