PageRenderTime 52ms CodeModel.GetById 15ms app.highlight 30ms RepoModel.GetById 1ms app.codeStats 0ms

/arch/unicore32/kernel/head.S

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