XIP (eXecute In Place) kernel image is the image that can be run directly from ROM, using RAM only for writable data. XIP xtensa kernel differs from regular xtensa kernel in the following ways: - it has exception/IRQ vectors merged into text section. No vectors relocation takes place at kernel startup. - .data/.bss location must be specified in the kernel configuration, its content is copied there in the _startup function. - .init.text is merged with the rest of text and is executed from ROM. - when MMU is used the virtual address where the kernel will be mapped must be specified in the kernel configuration. It may be in the KSEG or in the KIO, __pa macro is adjusted to be able to handle both. Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
		
			
				
	
	
		
			383 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			383 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
| /*
 | |
|  * arch/xtensa/kernel/head.S
 | |
|  *
 | |
|  * Xtensa Processor startup code.
 | |
|  *
 | |
|  * This file is subject to the terms and conditions of the GNU General Public
 | |
|  * License.  See the file "COPYING" in the main directory of this archive
 | |
|  * for more details.
 | |
|  *
 | |
|  * Copyright (C) 2001 - 2008 Tensilica Inc.
 | |
|  *
 | |
|  * Chris Zankel <chris@zankel.net>
 | |
|  * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca>
 | |
|  * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
 | |
|  * Kevin Chea
 | |
|  */
 | |
| 
 | |
| #include <asm/processor.h>
 | |
| #include <asm/page.h>
 | |
| #include <asm/cacheasm.h>
 | |
| #include <asm/initialize_mmu.h>
 | |
| #include <asm/mxregs.h>
 | |
| 
 | |
| #include <linux/init.h>
 | |
| #include <linux/linkage.h>
 | |
| 
 | |
| /*
 | |
|  * This module contains the entry code for kernel images. It performs the
 | |
|  * minimal setup needed to call the generic C routines.
 | |
|  *
 | |
|  * Prerequisites:
 | |
|  *
 | |
|  * - The kernel image has been loaded to the actual address where it was
 | |
|  *   compiled to.
 | |
|  * - a2 contains either 0 or a pointer to a list of boot parameters.
 | |
|  *   (see setup.c for more details)
 | |
|  *
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  *  _start
 | |
|  *
 | |
|  *  The bootloader passes a pointer to a list of boot parameters in a2.
 | |
|  */
 | |
| 
 | |
| 	/* The first bytes of the kernel image must be an instruction, so we
 | |
| 	 * manually allocate and define the literal constant we need for a jx
 | |
| 	 * instruction.
 | |
| 	 */
 | |
| 
 | |
| 	__HEAD
 | |
| 	.begin	no-absolute-literals
 | |
| 
 | |
| ENTRY(_start)
 | |
| 
 | |
| 	/* Preserve the pointer to the boot parameter list in EXCSAVE_1 */
 | |
| 	wsr     a2, excsave1
 | |
| 	_j	_SetupOCD
 | |
| 
 | |
| 	.align	4
 | |
| 	.literal_position
 | |
| _SetupOCD:
 | |
| 	/*
 | |
| 	 * Initialize WB, WS, and clear PS.EXCM (to allow loop instructions).
 | |
| 	 * Set Interrupt Level just below XCHAL_DEBUGLEVEL to allow
 | |
| 	 * xt-gdb to single step via DEBUG exceptions received directly
 | |
| 	 * by ocd.
 | |
| 	 */
 | |
| 	movi	a1, 1
 | |
| 	movi	a0, 0
 | |
| 	wsr	a1, windowstart
 | |
| 	wsr	a0, windowbase
 | |
| 	rsync
 | |
| 
 | |
| 	movi	a1, LOCKLEVEL
 | |
| 	wsr	a1, ps
 | |
| 	rsync
 | |
| 
 | |
| 	.global _SetupMMU
 | |
| _SetupMMU:
 | |
| 	Offset = _SetupMMU - _start
 | |
| 
 | |
| #ifdef CONFIG_INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX
 | |
| 	initialize_mmu
 | |
| #if defined(CONFIG_MMU) && XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY
 | |
| 	rsr	a2, excsave1
 | |
| 	movi	a3, XCHAL_KSEG_PADDR
 | |
| 	bltu	a2, a3, 1f
 | |
| 	sub	a2, a2, a3
 | |
| 	movi	a3, XCHAL_KSEG_SIZE
 | |
| 	bgeu	a2, a3, 1f
 | |
| 	movi	a3, XCHAL_KSEG_CACHED_VADDR
 | |
| 	add	a2, a2, a3
 | |
| 	wsr	a2, excsave1
 | |
| 1:
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
| 	movi	a0, _startup
 | |
| 	jx	a0
 | |
| 
 | |
| ENDPROC(_start)
 | |
| 	.end	no-absolute-literals
 | |
| 
 | |
| 	__REF
 | |
| 	.literal_position
 | |
| 
 | |
| ENTRY(_startup)
 | |
| 
 | |
| 	/* Set a0 to 0 for the remaining initialization. */
 | |
| 
 | |
| 	movi	a0, 0
 | |
| 
 | |
| #if XCHAL_HAVE_VECBASE
 | |
| 	movi    a2, VECBASE_VADDR
 | |
| 	wsr	a2, vecbase
 | |
| #endif
 | |
| 
 | |
| 	/* Clear debugging registers. */
 | |
| 
 | |
| #if XCHAL_HAVE_DEBUG
 | |
| #if XCHAL_NUM_IBREAK > 0
 | |
| 	wsr	a0, ibreakenable
 | |
| #endif
 | |
| 	wsr	a0, icount
 | |
| 	movi	a1, 15
 | |
| 	wsr	a0, icountlevel
 | |
| 
 | |
| 	.set	_index, 0
 | |
| 	.rept	XCHAL_NUM_DBREAK
 | |
| 	wsr	a0, SREG_DBREAKC + _index
 | |
| 	.set	_index, _index + 1
 | |
| 	.endr
 | |
| #endif
 | |
| 
 | |
| 	/* Clear CCOUNT (not really necessary, but nice) */
 | |
| 
 | |
| 	wsr	a0, ccount	# not really necessary, but nice
 | |
| 
 | |
| 	/* Disable zero-loops. */
 | |
| 
 | |
| #if XCHAL_HAVE_LOOPS
 | |
| 	wsr	a0, lcount
 | |
| #endif
 | |
| 
 | |
| 	/* Disable all timers. */
 | |
| 
 | |
| 	.set	_index, 0
 | |
| 	.rept	XCHAL_NUM_TIMERS
 | |
| 	wsr	a0, SREG_CCOMPARE + _index
 | |
| 	.set	_index, _index + 1
 | |
| 	.endr
 | |
| 
 | |
| 	/* Interrupt initialization. */
 | |
| 
 | |
| 	movi	a2, XCHAL_INTTYPE_MASK_SOFTWARE | XCHAL_INTTYPE_MASK_EXTERN_EDGE
 | |
| 	wsr	a0, intenable
 | |
| 	wsr	a2, intclear
 | |
| 
 | |
| 	/* Disable coprocessors. */
 | |
| 
 | |
| #if XCHAL_HAVE_CP
 | |
| 	wsr	a0, cpenable
 | |
| #endif
 | |
| 
 | |
| 	/*  Initialize the caches.
 | |
| 	 *  a2, a3 are just working registers (clobbered).
 | |
| 	 */
 | |
| 
 | |
| #if XCHAL_DCACHE_LINE_LOCKABLE
 | |
| 	___unlock_dcache_all a2 a3
 | |
| #endif
 | |
| 
 | |
| #if XCHAL_ICACHE_LINE_LOCKABLE
 | |
| 	___unlock_icache_all a2 a3
 | |
| #endif
 | |
| 
 | |
| 	___invalidate_dcache_all a2 a3
 | |
| 	___invalidate_icache_all a2 a3
 | |
| 
 | |
| 	isync
 | |
| 
 | |
| 	initialize_cacheattr
 | |
| 
 | |
| #ifdef CONFIG_HAVE_SMP
 | |
| 	movi	a2, CCON	# MX External Register to Configure Cache
 | |
| 	movi	a3, 1
 | |
| 	wer	a3, a2
 | |
| #endif
 | |
| 
 | |
| 	/* Setup stack and enable window exceptions (keep irqs disabled) */
 | |
| 
 | |
| 	movi	a1, start_info
 | |
| 	l32i	a1, a1, 0
 | |
| 
 | |
| 	movi	a2, PS_WOE_MASK | LOCKLEVEL
 | |
| 					# WOE=1, INTLEVEL=LOCKLEVEL, UM=0
 | |
| 	wsr	a2, ps			# (enable reg-windows; progmode stack)
 | |
| 	rsync
 | |
| 
 | |
| #ifdef CONFIG_SMP
 | |
| 	/*
 | |
| 	 * Notice that we assume with SMP that cores have PRID
 | |
| 	 * supported by the cores.
 | |
| 	 */
 | |
| 	rsr	a2, prid
 | |
| 	bnez	a2, .Lboot_secondary
 | |
| 
 | |
| #endif  /* CONFIG_SMP */
 | |
| 
 | |
| 	/* Unpack data sections
 | |
| 	 *
 | |
| 	 * The linker script used to build the Linux kernel image
 | |
| 	 * creates a table located at __boot_reloc_table_start
 | |
| 	 * that contans the information what data needs to be unpacked.
 | |
| 	 *
 | |
| 	 * Uses a2-a7.
 | |
| 	 */
 | |
| 
 | |
| 	movi	a2, __boot_reloc_table_start
 | |
| 	movi	a3, __boot_reloc_table_end
 | |
| 
 | |
| 1:	beq	a2, a3, 3f	# no more entries?
 | |
| 	l32i	a4, a2, 0	# start destination (in RAM)
 | |
| 	l32i	a5, a2, 4	# end desination (in RAM)
 | |
| 	l32i	a6, a2, 8	# start source (in ROM)
 | |
| 	addi	a2, a2, 12	# next entry
 | |
| 	beq	a4, a5, 1b	# skip, empty entry
 | |
| 	beq	a4, a6, 1b	# skip, source and dest. are the same
 | |
| 
 | |
| 2:	l32i	a7, a6, 0	# load word
 | |
| 	addi	a6, a6, 4
 | |
| 	s32i	a7, a4, 0	# store word
 | |
| 	addi	a4, a4, 4
 | |
| 	bltu	a4, a5, 2b
 | |
| 	j	1b
 | |
| 
 | |
| 3:
 | |
| 	/* All code and initialized data segments have been copied.
 | |
| 	 * Now clear the BSS segment.
 | |
| 	 */
 | |
| 
 | |
| 	movi	a2, __bss_start	# start of BSS
 | |
| 	movi	a3, __bss_stop	# end of BSS
 | |
| 
 | |
| 	__loopt	a2, a3, a4, 2
 | |
| 	s32i	a0, a2, 0
 | |
| 	__endla	a2, a3, 4
 | |
| 
 | |
| #if XCHAL_DCACHE_IS_WRITEBACK
 | |
| 
 | |
| 	/* After unpacking, flush the writeback cache to memory so the
 | |
| 	 * instructions/data are available.
 | |
| 	 */
 | |
| 
 | |
| 	___flush_dcache_all a2 a3
 | |
| #endif
 | |
| 	memw
 | |
| 	isync
 | |
| 	___invalidate_icache_all a2 a3
 | |
| 	isync
 | |
| 
 | |
| #ifdef CONFIG_XIP_KERNEL
 | |
| 	/* Setup bootstrap CPU stack in XIP kernel */
 | |
| 
 | |
| 	movi	a1, start_info
 | |
| 	l32i	a1, a1, 0
 | |
| #endif
 | |
| 
 | |
| 	movi	a6, 0
 | |
| 	xsr	a6, excsave1
 | |
| 
 | |
| 	/* init_arch kick-starts the linux kernel */
 | |
| 
 | |
| 	call4	init_arch
 | |
| 	call4	start_kernel
 | |
| 
 | |
| should_never_return:
 | |
| 	j	should_never_return
 | |
| 
 | |
| #ifdef CONFIG_SMP
 | |
| .Lboot_secondary:
 | |
| 
 | |
| 	movi	a2, cpu_start_ccount
 | |
| 1:
 | |
| 	memw
 | |
| 	l32i	a3, a2, 0
 | |
| 	beqi	a3, 0, 1b
 | |
| 	movi	a3, 0
 | |
| 	s32i	a3, a2, 0
 | |
| 1:
 | |
| 	memw
 | |
| 	l32i	a3, a2, 0
 | |
| 	beqi	a3, 0, 1b
 | |
| 	wsr	a3, ccount
 | |
| 	movi	a3, 0
 | |
| 	s32i	a3, a2, 0
 | |
| 	memw
 | |
| 
 | |
| 	movi	a6, 0
 | |
| 	wsr	a6, excsave1
 | |
| 
 | |
| 	call4	secondary_start_kernel
 | |
| 	j	should_never_return
 | |
| 
 | |
| #endif  /* CONFIG_SMP */
 | |
| 
 | |
| ENDPROC(_startup)
 | |
| 
 | |
| #ifdef CONFIG_HOTPLUG_CPU
 | |
| 
 | |
| ENTRY(cpu_restart)
 | |
| 
 | |
| #if XCHAL_DCACHE_IS_WRITEBACK
 | |
| 	___flush_invalidate_dcache_all a2 a3
 | |
| #else
 | |
| 	___invalidate_dcache_all a2 a3
 | |
| #endif
 | |
| 	memw
 | |
| 	movi	a2, CCON	# MX External Register to Configure Cache
 | |
| 	movi	a3, 0
 | |
| 	wer	a3, a2
 | |
| 	extw
 | |
| 
 | |
| 	rsr	a0, prid
 | |
| 	neg	a2, a0
 | |
| 	movi	a3, cpu_start_id
 | |
| 	memw
 | |
| 	s32i	a2, a3, 0
 | |
| #if XCHAL_DCACHE_IS_WRITEBACK
 | |
| 	dhwbi	a3, 0
 | |
| #endif
 | |
| 1:
 | |
| 	memw
 | |
| 	l32i	a2, a3, 0
 | |
| 	dhi	a3, 0
 | |
| 	bne	a2, a0, 1b
 | |
| 
 | |
| 	/*
 | |
| 	 * Initialize WB, WS, and clear PS.EXCM (to allow loop instructions).
 | |
| 	 * Set Interrupt Level just below XCHAL_DEBUGLEVEL to allow
 | |
| 	 * xt-gdb to single step via DEBUG exceptions received directly
 | |
| 	 * by ocd.
 | |
| 	 */
 | |
| 	movi	a1, 1
 | |
| 	movi	a0, 0
 | |
| 	wsr	a1, windowstart
 | |
| 	wsr	a0, windowbase
 | |
| 	rsync
 | |
| 
 | |
| 	movi	a1, LOCKLEVEL
 | |
| 	wsr	a1, ps
 | |
| 	rsync
 | |
| 
 | |
| 	j	_startup
 | |
| 
 | |
| ENDPROC(cpu_restart)
 | |
| 
 | |
| #endif  /* CONFIG_HOTPLUG_CPU */
 | |
| 
 | |
| /*
 | |
|  * DATA section
 | |
|  */
 | |
| 
 | |
| 	__REFDATA
 | |
| 	.align  4
 | |
| ENTRY(start_info)
 | |
| 	.long	init_thread_union + KERNEL_STACK_SIZE
 | |
| 
 | |
| /*
 | |
|  * BSS section
 | |
|  */
 | |
| 	
 | |
| __PAGE_ALIGNED_BSS
 | |
| #ifdef CONFIG_MMU
 | |
| ENTRY(swapper_pg_dir)
 | |
| 	.fill	PAGE_SIZE, 1, 0
 | |
| END(swapper_pg_dir)
 | |
| #endif
 | |
| ENTRY(empty_zero_page)
 | |
| 	.fill	PAGE_SIZE, 1, 0
 | |
| END(empty_zero_page)
 |