4e46f31072da59899823758581bc4599f66f4c3e
[linux-2.6-block.git] / arch / riscv / kernel / head.S
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Copyright (C) 2012 Regents of the University of California
4  */
5
6 #include <asm/thread_info.h>
7 #include <asm/asm-offsets.h>
8 #include <asm/asm.h>
9 #include <linux/init.h>
10 #include <linux/linkage.h>
11 #include <asm/thread_info.h>
12 #include <asm/page.h>
13 #include <asm/csr.h>
14
15 __INIT
16 ENTRY(_start)
17         /* Mask all interrupts */
18         csrw CSR_SIE, zero
19         csrw CSR_SIP, zero
20
21         /* Load the global pointer */
22 .option push
23 .option norelax
24         la gp, __global_pointer$
25 .option pop
26
27         /*
28          * Disable FPU to detect illegal usage of
29          * floating point in kernel space
30          */
31         li t0, SR_FS
32         csrc sstatus, t0
33
34         /* Pick one hart to run the main boot sequence */
35         la a3, hart_lottery
36         li a2, 1
37         amoadd.w a3, a2, (a3)
38         bnez a3, .Lsecondary_start
39
40         /* Clear BSS for flat non-ELF images */
41         la a3, __bss_start
42         la a4, __bss_stop
43         ble a4, a3, clear_bss_done
44 clear_bss:
45         REG_S zero, (a3)
46         add a3, a3, RISCV_SZPTR
47         blt a3, a4, clear_bss
48 clear_bss_done:
49
50         /* Save hart ID and DTB physical address */
51         mv s0, a0
52         mv s1, a1
53         la a2, boot_cpu_hartid
54         REG_S a0, (a2)
55
56         /* Initialize page tables and relocate to virtual addresses */
57         la sp, init_thread_union + THREAD_SIZE
58         call setup_vm
59         call relocate
60
61         /* Restore C environment */
62         la tp, init_task
63         sw zero, TASK_TI_CPU(tp)
64         la sp, init_thread_union + THREAD_SIZE
65
66         /* Start the kernel */
67         mv a0, s1
68         call parse_dtb
69         tail start_kernel
70
71 relocate:
72         /* Relocate return address */
73         li a1, PAGE_OFFSET
74         la a0, _start
75         sub a1, a1, a0
76         add ra, ra, a1
77
78         /* Point stvec to virtual address of intruction after satp write */
79         la a0, 1f
80         add a0, a0, a1
81         csrw CSR_STVEC, a0
82
83         /* Compute satp for kernel page tables, but don't load it yet */
84         la a2, swapper_pg_dir
85         srl a2, a2, PAGE_SHIFT
86         li a1, SATP_MODE
87         or a2, a2, a1
88
89         /*
90          * Load trampoline page directory, which will cause us to trap to
91          * stvec if VA != PA, or simply fall through if VA == PA.  We need a
92          * full fence here because setup_vm() just wrote these PTEs and we need
93          * to ensure the new translations are in use.
94          */
95         la a0, trampoline_pg_dir
96         srl a0, a0, PAGE_SHIFT
97         or a0, a0, a1
98         sfence.vma
99         csrw CSR_SATP, a0
100 .align 2
101 1:
102         /* Set trap vector to spin forever to help debug */
103         la a0, .Lsecondary_park
104         csrw CSR_STVEC, a0
105
106         /* Reload the global pointer */
107 .option push
108 .option norelax
109         la gp, __global_pointer$
110 .option pop
111
112         /*
113          * Switch to kernel page tables.  A full fence is necessary in order to
114          * avoid using the trampoline translations, which are only correct for
115          * the first superpage.  Fetching the fence is guarnteed to work
116          * because that first superpage is translated the same way.
117          */
118         csrw CSR_SATP, a2
119         sfence.vma
120
121         ret
122
123 .Lsecondary_start:
124 #ifdef CONFIG_SMP
125         li a1, CONFIG_NR_CPUS
126         bgeu a0, a1, .Lsecondary_park
127
128         /* Set trap vector to spin forever to help debug */
129         la a3, .Lsecondary_park
130         csrw CSR_STVEC, a3
131
132         slli a3, a0, LGREG
133         la a1, __cpu_up_stack_pointer
134         la a2, __cpu_up_task_pointer
135         add a1, a3, a1
136         add a2, a3, a2
137
138         /*
139          * This hart didn't win the lottery, so we wait for the winning hart to
140          * get far enough along the boot process that it should continue.
141          */
142 .Lwait_for_cpu_up:
143         /* FIXME: We should WFI to save some energy here. */
144         REG_L sp, (a1)
145         REG_L tp, (a2)
146         beqz sp, .Lwait_for_cpu_up
147         beqz tp, .Lwait_for_cpu_up
148         fence
149
150         /* Enable virtual memory and relocate to virtual address */
151         call relocate
152
153         tail smp_callin
154 #endif
155
156 .align 2
157 .Lsecondary_park:
158         /* We lack SMP support or have too many harts, so park this hart */
159         wfi
160         j .Lsecondary_park
161 END(_start)
162
163 __PAGE_ALIGNED_BSS
164         /* Empty zero page */
165         .balign PAGE_SIZE