1/* 2 * linux/arch/unicore32/kernel/head.S 3 * 4 * Code specific to PKUnity SoC and UniCore ISA 5 * 6 * Copyright (C) 2001-2010 GUAN Xue-tao 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 */ 12#include <linux/linkage.h> 13#include <linux/init.h> 14 15#include <asm/assembler.h> 16#include <asm/ptrace.h> 17#include <generated/asm-offsets.h> 18#include <asm/memory.h> 19#include <asm/thread_info.h> 20#include <asm/hwdef-copro.h> 21#include <asm/pgtable-hwdef.h> 22 23#if (PHYS_OFFSET & 0x003fffff) 24#error "PHYS_OFFSET must be at an even 4MiB boundary!" 25#endif 26 27#define KERNEL_RAM_VADDR (PAGE_OFFSET + KERNEL_IMAGE_START) 28#define KERNEL_RAM_PADDR (PHYS_OFFSET + KERNEL_IMAGE_START) 29 30#define KERNEL_PGD_PADDR (KERNEL_RAM_PADDR - 0x1000) 31#define KERNEL_PGD_VADDR (KERNEL_RAM_VADDR - 0x1000) 32 33#define KERNEL_START KERNEL_RAM_VADDR 34#define KERNEL_END _end 35 36/* 37 * swapper_pg_dir is the virtual address of the initial page table. 38 * We place the page tables 4K below KERNEL_RAM_VADDR. Therefore, we must 39 * make sure that KERNEL_RAM_VADDR is correctly set. Currently, we expect 40 * the least significant 16 bits to be 0x8000, but we could probably 41 * relax this restriction to KERNEL_RAM_VADDR >= PAGE_OFFSET + 0x1000. 42 */ 43#if (KERNEL_RAM_VADDR & 0xffff) != 0x8000 44#error KERNEL_RAM_VADDR must start at 0xXXXX8000 45#endif 46 47 .globl swapper_pg_dir 48 .equ swapper_pg_dir, KERNEL_RAM_VADDR - 0x1000 49 50/* 51 * Kernel startup entry point. 52 * --------------------------- 53 * 54 * This is normally called from the decompressor code. The requirements 55 * are: MMU = off, D-cache = off, I-cache = dont care 56 * 57 * This code is mostly position independent, so if you link the kernel at 58 * 0xc0008000, you call this at __pa(0xc0008000). 59 */ 60 __HEAD 61ENTRY(stext) 62 @ set asr 63 mov r0, #PRIV_MODE @ ensure priv mode 64 or r0, #PSR_R_BIT | PSR_I_BIT @ disable irqs 65 mov.a asr, r0 66 67 @ process identify 68 movc r0, p0.c0, #0 @ cpuid 69 movl r1, 0xff00ffff @ mask 70 movl r2, 0x4d000863 @ value 71 and r0, r1, r0 72 cxor.a r0, r2 73 bne __error_p @ invalid processor id 74 75 /* 76 * Clear the 4K level 1 swapper page table 77 */ 78 movl r0, #KERNEL_PGD_PADDR @ page table address 79 mov r1, #0 80 add r2, r0, #0x1000 81101: stw.w r1, [r0]+, #4 82 stw.w r1, [r0]+, #4 83 stw.w r1, [r0]+, #4 84 stw.w r1, [r0]+, #4 85 cxor.a r0, r2 86 bne 101b 87 88 movl r4, #KERNEL_PGD_PADDR @ page table address 89 mov r7, #PMD_TYPE_SECT | PMD_PRESENT @ page size: section 90 or r7, r7, #PMD_SECT_CACHEABLE @ cacheable 91 or r7, r7, #PMD_SECT_READ | PMD_SECT_WRITE | PMD_SECT_EXEC 92 93 /* 94 * Create identity mapping for first 4MB of kernel to 95 * cater for the MMU enable. This identity mapping 96 * will be removed by paging_init(). We use our current program 97 * counter to determine corresponding section base address. 98 */ 99 mov r6, pc 100 mov r6, r6 >> #22 @ start of kernel section 101 or r1, r7, r6 << #22 @ flags + kernel base 102 stw r1, [r4+], r6 << #2 @ identity mapping 103 104 /* 105 * Now setup the pagetables for our kernel direct 106 * mapped region. 107 */ 108 add r0, r4, #(KERNEL_START & 0xff000000) >> 20 109 stw.w r1, [r0+], #(KERNEL_START & 0x00c00000) >> 20 110 movl r6, #(KERNEL_END - 1) 111 add r0, r0, #4 112 add r6, r4, r6 >> #20 113102: csub.a r0, r6 114 add r1, r1, #1 << 22 115 bua 103f 116 stw.w r1, [r0]+, #4 117 b 102b 118103: 119 /* 120 * Then map first 4MB of ram in case it contains our boot params. 121 */ 122 add r0, r4, #PAGE_OFFSET >> 20 123 or r6, r7, #(PHYS_OFFSET & 0xffc00000) 124 stw r6, [r0] 125 126 ldw r15, __switch_data @ address to jump to after 127 128 /* 129 * Initialise TLB, Caches, and MMU state ready to switch the MMU 130 * on. 131 */ 132 mov r0, #0 133 movc p0.c5, r0, #28 @ cache invalidate all 134 nop8 135 movc p0.c6, r0, #6 @ TLB invalidate all 136 nop8 137 138 /* 139 * ..V. .... ..TB IDAM 140 * ..1. .... ..01 1111 141 */ 142 movl r0, #0x201f @ control register setting 143 144 /* 145 * Setup common bits before finally enabling the MMU. Essentially 146 * this is just loading the page table pointer and domain access 147 * registers. 148 */ 149 #ifndef CONFIG_ALIGNMENT_TRAP 150 andn r0, r0, #CR_A 151 #endif 152 #ifdef CONFIG_CPU_DCACHE_DISABLE 153 andn r0, r0, #CR_D 154 #endif 155 #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH 156 andn r0, r0, #CR_B 157 #endif 158 #ifdef CONFIG_CPU_ICACHE_DISABLE 159 andn r0, r0, #CR_I 160 #endif 161 162 movc p0.c2, r4, #0 @ set pgd 163 b __turn_mmu_on 164ENDPROC(stext) 165 166/* 167 * Enable the MMU. This completely changes the structure of the visible 168 * memory space. You will not be able to trace execution through this. 169 * 170 * r0 = cp#0 control register 171 * r15 = *virtual* address to jump to upon completion 172 */ 173 .align 5 174__turn_mmu_on: 175 mov r0, r0 176 movc p0.c1, r0, #0 @ write control reg 177 nop @ fetch inst by phys addr 178 mov pc, r15 179 nop8 @ fetch inst by phys addr 180ENDPROC(__turn_mmu_on) 181 182/* 183 * Setup the initial page tables. We only setup the barest 184 * amount which are required to get the kernel running, which 185 * generally means mapping in the kernel code. 186 * 187 * r9 = cpuid 188 * r10 = procinfo 189 * 190 * Returns: 191 * r0, r3, r6, r7 corrupted 192 * r4 = physical page table address 193 */ 194 .ltorg 195 196 .align 2 197 .type __switch_data, %object 198__switch_data: 199 .long __mmap_switched 200 .long __bss_start @ r6 201 .long _end @ r7 202 .long cr_alignment @ r8 203 .long init_thread_union + THREAD_START_SP @ sp 204 205/* 206 * The following fragment of code is executed with the MMU on in MMU mode, 207 * and uses absolute addresses; this is not position independent. 208 * 209 * r0 = cp#0 control register 210 */ 211__mmap_switched: 212 adr r3, __switch_data + 4 213 214 ldm.w (r6, r7, r8), [r3]+ 215 ldw sp, [r3] 216 217 mov fp, #0 @ Clear BSS (and zero fp) 218203: csub.a r6, r7 219 bea 204f 220 stw.w fp, [r6]+,#4 221 b 203b 222204: 223 andn r1, r0, #CR_A @ Clear 'A' bit 224 stm (r0, r1), [r8]+ @ Save control register values 225 b start_kernel 226ENDPROC(__mmap_switched) 227 228/* 229 * Exception handling. Something went wrong and we can't proceed. We 230 * ought to tell the user, but since we don't have any guarantee that 231 * we're even running on the right architecture, we do virtually nothing. 232 * 233 * If CONFIG_DEBUG_LL is set we try to print out something about the error 234 * and hope for the best (useful if bootloader fails to pass a proper 235 * machine ID for example). 236 */ 237__error_p: 238#ifdef CONFIG_DEBUG_LL 239 adr r0, str_p1 240 b.l printascii 241 mov r0, r9 242 b.l printhex8 243 adr r0, str_p2 244 b.l printascii 245901: nop8 246 b 901b 247str_p1: .asciz "\nError: unrecognized processor variant (0x" 248str_p2: .asciz ").\n" 249 .align 250#endif 251ENDPROC(__error_p) 252 253