/*1* linux/arch/unicore32/kernel/head.S2*3* Code specific to PKUnity SoC and UniCore ISA4*5* Copyright (C) 2001-2010 GUAN Xue-tao6*7* This program is free software; you can redistribute it and/or modify8* it under the terms of the GNU General Public License version 2 as9* published by the Free Software Foundation.10*/11#include <linux/linkage.h>12#include <linux/init.h>1314#include <asm/assembler.h>15#include <asm/ptrace.h>16#include <generated/asm-offsets.h>17#include <asm/memory.h>18#include <asm/thread_info.h>19#include <asm/system.h>20#include <asm/pgtable-hwdef.h>2122#if (PHYS_OFFSET & 0x003fffff)23#error "PHYS_OFFSET must be at an even 4MiB boundary!"24#endif2526#define KERNEL_RAM_VADDR (PAGE_OFFSET + KERNEL_IMAGE_START)27#define KERNEL_RAM_PADDR (PHYS_OFFSET + KERNEL_IMAGE_START)2829#define KERNEL_PGD_PADDR (KERNEL_RAM_PADDR - 0x1000)30#define KERNEL_PGD_VADDR (KERNEL_RAM_VADDR - 0x1000)3132#define KERNEL_START KERNEL_RAM_VADDR33#define KERNEL_END _end3435/*36* swapper_pg_dir is the virtual address of the initial page table.37* We place the page tables 4K below KERNEL_RAM_VADDR. Therefore, we must38* make sure that KERNEL_RAM_VADDR is correctly set. Currently, we expect39* the least significant 16 bits to be 0x8000, but we could probably40* relax this restriction to KERNEL_RAM_VADDR >= PAGE_OFFSET + 0x1000.41*/42#if (KERNEL_RAM_VADDR & 0xffff) != 0x800043#error KERNEL_RAM_VADDR must start at 0xXXXX800044#endif4546.globl swapper_pg_dir47.equ swapper_pg_dir, KERNEL_RAM_VADDR - 0x10004849/*50* Kernel startup entry point.51* ---------------------------52*53* This is normally called from the decompressor code. The requirements54* are: MMU = off, D-cache = off, I-cache = dont care55*56* This code is mostly position independent, so if you link the kernel at57* 0xc0008000, you call this at __pa(0xc0008000).58*/59__HEAD60ENTRY(stext)61@ set asr62mov r0, #PRIV_MODE @ ensure priv mode63or r0, #PSR_R_BIT | PSR_I_BIT @ disable irqs64mov.a asr, r06566@ process identify67movc r0, p0.c0, #0 @ cpuid68movl r1, 0xff00ffff @ mask69movl r2, 0x4d000863 @ value70and r0, r1, r071cxor.a r0, r272bne __error_p @ invalid processor id7374/*75* Clear the 4K level 1 swapper page table76*/77movl r0, #KERNEL_PGD_PADDR @ page table address78mov r1, #079add r2, r0, #0x100080101: stw.w r1, [r0]+, #481stw.w r1, [r0]+, #482stw.w r1, [r0]+, #483stw.w r1, [r0]+, #484cxor.a r0, r285bne 101b8687movl r4, #KERNEL_PGD_PADDR @ page table address88mov r7, #PMD_TYPE_SECT | PMD_PRESENT @ page size: section89or r7, r7, #PMD_SECT_CACHEABLE @ cacheable90or r7, r7, #PMD_SECT_READ | PMD_SECT_WRITE | PMD_SECT_EXEC9192/*93* Create identity mapping for first 4MB of kernel to94* cater for the MMU enable. This identity mapping95* will be removed by paging_init(). We use our current program96* counter to determine corresponding section base address.97*/98mov r6, pc99mov r6, r6 >> #22 @ start of kernel section100or r1, r7, r6 << #22 @ flags + kernel base101stw r1, [r4+], r6 << #2 @ identity mapping102103/*104* Now setup the pagetables for our kernel direct105* mapped region.106*/107add r0, r4, #(KERNEL_START & 0xff000000) >> 20108stw.w r1, [r0+], #(KERNEL_START & 0x00c00000) >> 20109movl r6, #(KERNEL_END - 1)110add r0, r0, #4111add r6, r4, r6 >> #20112102: csub.a r0, r6113add r1, r1, #1 << 22114bua 103f115stw.w r1, [r0]+, #4116b 102b117103:118/*119* Then map first 4MB of ram in case it contains our boot params.120*/121add r0, r4, #PAGE_OFFSET >> 20122or r6, r7, #(PHYS_OFFSET & 0xffc00000)123stw r6, [r0]124125ldw r15, __switch_data @ address to jump to after126127/*128* Initialise TLB, Caches, and MMU state ready to switch the MMU129* on.130*/131mov r0, #0132movc p0.c5, r0, #28 @ cache invalidate all133nop8134movc p0.c6, r0, #6 @ TLB invalidate all135nop8136137/*138* ..V. .... ..TB IDAM139* ..1. .... ..01 1111140*/141movl r0, #0x201f @ control register setting142143/*144* Setup common bits before finally enabling the MMU. Essentially145* this is just loading the page table pointer and domain access146* registers.147*/148#ifndef CONFIG_ALIGNMENT_TRAP149andn r0, r0, #CR_A150#endif151#ifdef CONFIG_CPU_DCACHE_DISABLE152andn r0, r0, #CR_D153#endif154#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH155andn r0, r0, #CR_B156#endif157#ifdef CONFIG_CPU_ICACHE_DISABLE158andn r0, r0, #CR_I159#endif160161movc p0.c2, r4, #0 @ set pgd162b __turn_mmu_on163ENDPROC(stext)164165/*166* Enable the MMU. This completely changes the structure of the visible167* memory space. You will not be able to trace execution through this.168*169* r0 = cp#0 control register170* r15 = *virtual* address to jump to upon completion171*/172.align 5173__turn_mmu_on:174mov r0, r0175movc p0.c1, r0, #0 @ write control reg176nop @ fetch inst by phys addr177mov pc, r15178nop8 @ fetch inst by phys addr179ENDPROC(__turn_mmu_on)180181/*182* Setup the initial page tables. We only setup the barest183* amount which are required to get the kernel running, which184* generally means mapping in the kernel code.185*186* r9 = cpuid187* r10 = procinfo188*189* Returns:190* r0, r3, r6, r7 corrupted191* r4 = physical page table address192*/193.ltorg194195.align 2196.type __switch_data, %object197__switch_data:198.long __mmap_switched199.long __bss_start @ r6200.long _end @ r7201.long cr_alignment @ r8202.long init_thread_union + THREAD_START_SP @ sp203204/*205* The following fragment of code is executed with the MMU on in MMU mode,206* and uses absolute addresses; this is not position independent.207*208* r0 = cp#0 control register209*/210__mmap_switched:211adr r3, __switch_data + 4212213ldm.w (r6, r7, r8), [r3]+214ldw sp, [r3]215216mov fp, #0 @ Clear BSS (and zero fp)217203: csub.a r6, r7218bea 204f219stw.w fp, [r6]+,#4220b 203b221204:222andn r1, r0, #CR_A @ Clear 'A' bit223stm (r0, r1), [r8]+ @ Save control register values224b start_kernel225ENDPROC(__mmap_switched)226227/*228* Exception handling. Something went wrong and we can't proceed. We229* ought to tell the user, but since we don't have any guarantee that230* we're even running on the right architecture, we do virtually nothing.231*232* If CONFIG_DEBUG_LL is set we try to print out something about the error233* and hope for the best (useful if bootloader fails to pass a proper234* machine ID for example).235*/236__error_p:237#ifdef CONFIG_DEBUG_LL238adr r0, str_p1239b.l printascii240mov r0, r9241b.l printhex8242adr r0, str_p2243b.l printascii244901: nop8245b 901b246str_p1: .asciz "\nError: unrecognized processor variant (0x"247str_p2: .asciz ").\n"248.align249#endif250ENDPROC(__error_p)251252253254