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