| /* | 
 |  * Copyright (C) 2012 Regents of the University of California | 
 |  * | 
 |  *   This program is free software; you can redistribute it and/or | 
 |  *   modify it under the terms of the GNU General Public License | 
 |  *   as published by the Free Software Foundation, version 2. | 
 |  * | 
 |  *   This program is distributed in the hope that it will be useful, | 
 |  *   but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |  *   GNU General Public License for more details. | 
 |  */ | 
 |  | 
 | #include <asm/thread_info.h> | 
 | #include <asm/asm-offsets.h> | 
 | #include <asm/asm.h> | 
 | #include <linux/init.h> | 
 | #include <linux/linkage.h> | 
 | #include <asm/thread_info.h> | 
 | #include <asm/page.h> | 
 | #include <asm/csr.h> | 
 |  | 
 | __INIT | 
 | ENTRY(_start) | 
 | 	/* Mask all interrupts */ | 
 | 	csrw sie, zero | 
 |  | 
 | 	/* Load the global pointer */ | 
 | .option push | 
 | .option norelax | 
 | 	la gp, __global_pointer$ | 
 | .option pop | 
 |  | 
 | 	/* | 
 | 	 * Disable FPU to detect illegal usage of | 
 | 	 * floating point in kernel space | 
 | 	 */ | 
 | 	li t0, SR_FS | 
 | 	csrc sstatus, t0 | 
 |  | 
 | 	/* Pick one hart to run the main boot sequence */ | 
 | 	la a3, hart_lottery | 
 | 	li a2, 1 | 
 | 	amoadd.w a3, a2, (a3) | 
 | 	bnez a3, .Lsecondary_start | 
 |  | 
 | 	/* Save hart ID and DTB physical address */ | 
 | 	mv s0, a0 | 
 | 	mv s1, a1 | 
 | 	la a2, boot_cpu_hartid | 
 | 	REG_S a0, (a2) | 
 |  | 
 | 	/* Initialize page tables and relocate to virtual addresses */ | 
 | 	la sp, init_thread_union + THREAD_SIZE | 
 | 	call setup_vm | 
 | 	call relocate | 
 |  | 
 | 	/* Restore C environment */ | 
 | 	la tp, init_task | 
 | 	sw zero, TASK_TI_CPU(tp) | 
 |  | 
 | 	la sp, init_thread_union | 
 | 	li a0, ASM_THREAD_SIZE | 
 | 	add sp, sp, a0 | 
 |  | 
 | 	/* Start the kernel */ | 
 | 	mv a0, s0 | 
 | 	mv a1, s1 | 
 | 	call parse_dtb | 
 | 	tail start_kernel | 
 |  | 
 | relocate: | 
 | 	/* Relocate return address */ | 
 | 	li a1, PAGE_OFFSET | 
 | 	la a0, _start | 
 | 	sub a1, a1, a0 | 
 | 	add ra, ra, a1 | 
 |  | 
 | 	/* Point stvec to virtual address of intruction after satp write */ | 
 | 	la a0, 1f | 
 | 	add a0, a0, a1 | 
 | 	csrw stvec, a0 | 
 |  | 
 | 	/* Compute satp for kernel page tables, but don't load it yet */ | 
 | 	la a2, swapper_pg_dir | 
 | 	srl a2, a2, PAGE_SHIFT | 
 | 	li a1, SATP_MODE | 
 | 	or a2, a2, a1 | 
 |  | 
 | 	/* | 
 | 	 * Load trampoline page directory, which will cause us to trap to | 
 | 	 * stvec if VA != PA, or simply fall through if VA == PA | 
 | 	 */ | 
 | 	la a0, trampoline_pg_dir | 
 | 	srl a0, a0, PAGE_SHIFT | 
 | 	or a0, a0, a1 | 
 | 	sfence.vma | 
 | 	csrw sptbr, a0 | 
 | .align 2 | 
 | 1: | 
 | 	/* Set trap vector to spin forever to help debug */ | 
 | 	la a0, .Lsecondary_park | 
 | 	csrw stvec, a0 | 
 |  | 
 | 	/* Reload the global pointer */ | 
 | .option push | 
 | .option norelax | 
 | 	la gp, __global_pointer$ | 
 | .option pop | 
 |  | 
 | 	/* Switch to kernel page tables */ | 
 | 	csrw sptbr, a2 | 
 |  | 
 | 	ret | 
 |  | 
 | .Lsecondary_start: | 
 | #ifdef CONFIG_SMP | 
 | 	li a1, CONFIG_NR_CPUS | 
 | 	bgeu a0, a1, .Lsecondary_park | 
 |  | 
 | 	/* Set trap vector to spin forever to help debug */ | 
 | 	la a3, .Lsecondary_park | 
 | 	csrw stvec, a3 | 
 |  | 
 | 	slli a3, a0, LGREG | 
 | 	la a1, __cpu_up_stack_pointer | 
 | 	la a2, __cpu_up_task_pointer | 
 | 	add a1, a3, a1 | 
 | 	add a2, a3, a2 | 
 |  | 
 | 	/* | 
 | 	 * This hart didn't win the lottery, so we wait for the winning hart to | 
 | 	 * get far enough along the boot process that it should continue. | 
 | 	 */ | 
 | .Lwait_for_cpu_up: | 
 | 	/* FIXME: We should WFI to save some energy here. */ | 
 | 	REG_L sp, (a1) | 
 | 	REG_L tp, (a2) | 
 | 	beqz sp, .Lwait_for_cpu_up | 
 | 	beqz tp, .Lwait_for_cpu_up | 
 | 	fence | 
 |  | 
 | 	/* Enable virtual memory and relocate to virtual address */ | 
 | 	call relocate | 
 |  | 
 | 	tail smp_callin | 
 | #endif | 
 |  | 
 | .align 2 | 
 | .Lsecondary_park: | 
 | 	/* We lack SMP support or have too many harts, so park this hart */ | 
 | 	wfi | 
 | 	j .Lsecondary_park | 
 | END(_start) | 
 |  | 
 | __PAGE_ALIGNED_BSS | 
 | 	/* Empty zero page */ | 
 | 	.balign PAGE_SIZE |