GNU Linux-libre 5.4.274-gnu1
[releases.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 #include <asm/image.h>
15
16 __INIT
17 ENTRY(_start)
18         /*
19          * Image header expected by Linux boot-loaders. The image header data
20          * structure is described in asm/image.h.
21          * Do not modify it without modifying the structure and all bootloaders
22          * that expects this header format!!
23          */
24         /* jump to start kernel */
25         j _start_kernel
26         /* reserved */
27         .word 0
28         .balign 8
29 #ifdef CONFIG_RISCV_M_MODE
30         /* Image load offset (0MB) from start of RAM for M-mode */
31         .dword 0
32 #else
33 #if __riscv_xlen == 64
34         /* Image load offset(2MB) from start of RAM */
35         .dword 0x200000
36 #else
37         /* Image load offset(4MB) from start of RAM */
38         .dword 0x400000
39 #endif
40 #endif
41         /* Effective size of kernel image */
42         .dword _end - _start
43         .dword __HEAD_FLAGS
44         .word RISCV_HEADER_VERSION
45         .word 0
46         .dword 0
47         .ascii RISCV_IMAGE_MAGIC
48         .balign 4
49         .ascii RISCV_IMAGE_MAGIC2
50         .word 0
51
52 .global _start_kernel
53 _start_kernel:
54         /* Mask all interrupts */
55         csrw CSR_SIE, zero
56         csrw CSR_SIP, zero
57
58         /* Load the global pointer */
59 .option push
60 .option norelax
61         la gp, __global_pointer$
62 .option pop
63
64         /*
65          * Disable FPU to detect illegal usage of
66          * floating point in kernel space
67          */
68         li t0, SR_FS
69         csrc CSR_SSTATUS, t0
70
71 #ifdef CONFIG_SMP
72         li t0, CONFIG_NR_CPUS
73         bgeu a0, t0, .Lsecondary_park
74 #endif
75
76         /* Pick one hart to run the main boot sequence */
77         la a3, hart_lottery
78         li a2, 1
79         amoadd.w a3, a2, (a3)
80         bnez a3, .Lsecondary_start
81
82         /* Clear BSS for flat non-ELF images */
83         la a3, __bss_start
84         la a4, __bss_stop
85         ble a4, a3, clear_bss_done
86 clear_bss:
87         REG_S zero, (a3)
88         add a3, a3, RISCV_SZPTR
89         blt a3, a4, clear_bss
90 clear_bss_done:
91
92         /* Save hart ID and DTB physical address */
93         mv s0, a0
94         mv s1, a1
95         la a2, boot_cpu_hartid
96         REG_S a0, (a2)
97
98         /* Initialize page tables and relocate to virtual addresses */
99         la sp, init_thread_union + THREAD_SIZE
100         mv a0, s1
101         call setup_vm
102         la a0, early_pg_dir
103         call relocate
104
105         /* Restore C environment */
106         la tp, init_task
107         sw zero, TASK_TI_CPU(tp)
108         la sp, init_thread_union + THREAD_SIZE
109
110         /* Start the kernel */
111         call parse_dtb
112         tail start_kernel
113
114 relocate:
115         /* Relocate return address */
116         li a1, PAGE_OFFSET
117         la a2, _start
118         sub a1, a1, a2
119         add ra, ra, a1
120
121         /* Point stvec to virtual address of intruction after satp write */
122         la a2, 1f
123         add a2, a2, a1
124         csrw CSR_STVEC, a2
125
126         /* Compute satp for kernel page tables, but don't load it yet */
127         srl a2, a0, PAGE_SHIFT
128         li a1, SATP_MODE
129         or a2, a2, a1
130
131         /*
132          * Load trampoline page directory, which will cause us to trap to
133          * stvec if VA != PA, or simply fall through if VA == PA.  We need a
134          * full fence here because setup_vm() just wrote these PTEs and we need
135          * to ensure the new translations are in use.
136          */
137         la a0, trampoline_pg_dir
138         srl a0, a0, PAGE_SHIFT
139         or a0, a0, a1
140         sfence.vma
141         csrw CSR_SATP, a0
142 .align 2
143 1:
144         /* Set trap vector to spin forever to help debug */
145         la a0, .Lsecondary_park
146         csrw CSR_STVEC, a0
147
148         /* Reload the global pointer */
149 .option push
150 .option norelax
151         la gp, __global_pointer$
152 .option pop
153
154         /*
155          * Switch to kernel page tables.  A full fence is necessary in order to
156          * avoid using the trampoline translations, which are only correct for
157          * the first superpage.  Fetching the fence is guarnteed to work
158          * because that first superpage is translated the same way.
159          */
160         csrw CSR_SATP, a2
161         sfence.vma
162
163         ret
164
165 .Lsecondary_start:
166 #ifdef CONFIG_SMP
167         /* Set trap vector to spin forever to help debug */
168         la a3, .Lsecondary_park
169         csrw CSR_STVEC, a3
170
171         slli a3, a0, LGREG
172         la a1, __cpu_up_stack_pointer
173         la a2, __cpu_up_task_pointer
174         add a1, a3, a1
175         add a2, a3, a2
176
177         /*
178          * This hart didn't win the lottery, so we wait for the winning hart to
179          * get far enough along the boot process that it should continue.
180          */
181 .Lwait_for_cpu_up:
182         /* FIXME: We should WFI to save some energy here. */
183         REG_L sp, (a1)
184         REG_L tp, (a2)
185         beqz sp, .Lwait_for_cpu_up
186         beqz tp, .Lwait_for_cpu_up
187         fence
188
189         /* Enable virtual memory and relocate to virtual address */
190         la a0, swapper_pg_dir
191         call relocate
192
193         tail smp_callin
194 #endif
195
196 .align 2
197 .Lsecondary_park:
198         /* We lack SMP support or have too many harts, so park this hart */
199         wfi
200         j .Lsecondary_park
201 END(_start)
202
203 __PAGE_ALIGNED_BSS
204         /* Empty zero page */
205         .balign PAGE_SIZE