blob: e8f0b98c02eed5d9d9cfe29e4ccaf68cc54f752d [file] [log] [blame]
GuanXuetao141c9432011-01-15 18:15:45 +08001/*
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>
Guan Xuetao8978bfd2012-03-28 18:30:03 +010020#include <asm/hwdef-copro.h>
GuanXuetao141c9432011-01-15 18:15:45 +080021#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/*
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300167 * Enable the MMU. This completely changes the structure of the visible
GuanXuetao141c9432011-01-15 18:15:45 +0800168 * 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