1/* 2 * Copyright (C) 2012 Regents of the University of California 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation, version 2. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 */ 13 14#include <asm/thread_info.h> 15#include <asm/asm-offsets.h> 16#include <asm/asm.h> 17#include <linux/init.h> 18#include <linux/linkage.h> 19#include <asm/thread_info.h> 20#include <asm/page.h> 21#include <asm/csr.h> 22 23__INIT 24ENTRY(_start) 25 /* Mask all interrupts */ 26 csrw sie, zero 27 28 /* Load the global pointer */ 29.option push 30.option norelax 31 la gp, __global_pointer$ 32.option pop 33 34 /* 35 * Disable FPU to detect illegal usage of 36 * floating point in kernel space 37 */ 38 li t0, SR_FS 39 csrc sstatus, t0 40 41 /* Pick one hart to run the main boot sequence */ 42 la a3, hart_lottery 43 li a2, 1 44 amoadd.w a3, a2, (a3) 45 bnez a3, .Lsecondary_start 46 47 /* Save hart ID and DTB physical address */ 48 mv s0, a0 49 mv s1, a1 50 51 /* Initialize page tables and relocate to virtual addresses */ 52 la sp, init_thread_union + THREAD_SIZE 53 call setup_vm 54 call relocate 55 56 /* Restore C environment */ 57 la tp, init_task 58 sw s0, TASK_TI_CPU(tp) 59 60 la sp, init_thread_union 61 li a0, ASM_THREAD_SIZE 62 add sp, sp, a0 63 64 /* Start the kernel */ 65 mv a0, s0 66 mv a1, s1 67 call sbi_save 68 tail start_kernel 69 70relocate: 71 /* Relocate return address */ 72 li a1, PAGE_OFFSET 73 la a0, _start 74 sub a1, a1, a0 75 add ra, ra, a1 76 77 /* Point stvec to virtual address of intruction after sptbr write */ 78 la a0, 1f 79 add a0, a0, a1 80 csrw stvec, a0 81 82 /* Compute sptbr for kernel page tables, but don't load it yet */ 83 la a2, swapper_pg_dir 84 srl a2, a2, PAGE_SHIFT 85 li a1, SPTBR_MODE 86 or a2, a2, a1 87 88 /* 89 * Load trampoline page directory, which will cause us to trap to 90 * stvec if VA != PA, or simply fall through if VA == PA 91 */ 92 la a0, trampoline_pg_dir 93 srl a0, a0, PAGE_SHIFT 94 or a0, a0, a1 95 sfence.vma 96 csrw sptbr, a0 971: 98 /* Set trap vector to spin forever to help debug */ 99 la a0, .Lsecondary_park 100 csrw stvec, a0 101 102 /* Reload the global pointer */ 103.option push 104.option norelax 105 la gp, __global_pointer$ 106.option pop 107 108 /* Switch to kernel page tables */ 109 csrw sptbr, a2 110 111 ret 112 113.Lsecondary_start: 114#ifdef CONFIG_SMP 115 li a1, CONFIG_NR_CPUS 116 bgeu a0, a1, .Lsecondary_park 117 118 /* Set trap vector to spin forever to help debug */ 119 la a3, .Lsecondary_park 120 csrw stvec, a3 121 122 slli a3, a0, LGREG 123 la a1, __cpu_up_stack_pointer 124 la a2, __cpu_up_task_pointer 125 add a1, a3, a1 126 add a2, a3, a2 127 128 /* 129 * This hart didn't win the lottery, so we wait for the winning hart to 130 * get far enough along the boot process that it should continue. 131 */ 132.Lwait_for_cpu_up: 133 /* FIXME: We should WFI to save some energy here. */ 134 REG_L sp, (a1) 135 REG_L tp, (a2) 136 beqz sp, .Lwait_for_cpu_up 137 beqz tp, .Lwait_for_cpu_up 138 fence 139 140 /* Enable virtual memory and relocate to virtual address */ 141 call relocate 142 143 tail smp_callin 144#endif 145 146.Lsecondary_park: 147 /* We lack SMP support or have too many harts, so park this hart */ 148 wfi 149 j .Lsecondary_park 150END(_start) 151 152__PAGE_ALIGNED_BSS 153 /* Empty zero page */ 154 .balign PAGE_SIZE 155