1/*
2 * Copyright (c) 2015 Travis Geiselbrecht
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8#include <lk/asm.h>
9#include <arch/defines.h>
10#include <arch/riscv/asm.h>
11#include <arch/riscv/mmu.h>
12#include "config.h"
13
14.section ".text.boot"
15FUNCTION(_start)
16.option push
17.option norelax
18    // set the global pointer
19    lla     gp, __global_pointer$
20.option pop
21
22#if RISCV_M_MODE
23    // copy the hart id into a0 which we'll use later
24    // supervisor mode should already have hart id in a0
25    csrr    a0, mhartid
26#endif
27
28    // cpu lottery: whoever sets this first gets to be cpu 0
29    lla     t0, _boot_lottery
30    li      t1, 1
31    amoadd.w a2, t1, (t0)
32
33    // a2 now holds the logical cpu number. a2 is used because it is
34    // the first unused argument register on SBI based systems,
35    // which seem to use a0 and a1.
36
37    // if this cpu is out of range, trap it
38    li      t0, SMP_MAX_CPUS
39    ble     t0, a2, hart_trap
40
41    // set the default stack per cpu
42    lla     sp, default_stack_top
43    // default stack locations for each cpu:
44    // LOW ------------ HIGH
45    // [cpu2][cpu1][cpu0]
46    li      t1, ARCH_DEFAULT_STACK_SIZE
47    mul     t1, t1, a2
48    sub     sp, sp, t1
49
50    // if we aren't cpu 0, go hang out in secondary cpu purgatory for now
51    bne     a2, zero, secondary_trap
52
53#if ARCH_RISCV_TWOSEGMENT
54    // copy preinitialized data from flash to memory
55    lla     t0, __data_start_rom
56    lla     t1, __data_start
57    lla     t2, __data_end
58    beq     t0, t1, 1f
59
600:
61    LDR     t3, (t0)
62    STR     t3, (t1)
63    add     t0, t0, RISCV_XLEN_BYTES
64    add     t1, t1, RISCV_XLEN_BYTES
65    bne     t1, t2, 0b
66#endif
67
68    // zero bss
691:
70    lla     t0, __bss_start
71    lla     t1, __bss_end
72    beq     t0, t1, 1f
730:
74    STR     zero, (t0)
75    add     t0, t0, RISCV_XLEN_BYTES
76    bne     t0, t1, 0b
771:
78
79#if WITH_SMP
80    // Save a copy of _start in physical space. This is later used
81    // as the entry point for secondary cpus.
82    lla     t0, _start
83    STR     t0, (_start_physical), t1
84#endif
85
86#if RISCV_MMU
87    call    _mmu_init
88#endif
89
90#if WITH_SMP
91    // Release any other harts into riscv_secondary_entry
92    fence   w, w
93    li      t0, 1
94    sb      t0, (_boot_status), t1
95    fence
96#endif
97
98    // call into early C code to set up the percpu structure
99    mv      s0, a0
100    mv      s1, a1
101    mv      s2, a2
102    mv      s3, a3
103    call    riscv_configure_percpu_early
104    mv      a0, s0
105    mv      a1, s1
106    mv      a2, s2
107    mv      a3, s3
108
109    // call main
110    call    lk_main
111
112    // should never return here
113    j       .
114END_FUNCTION(_start)
115
116LOCAL_FUNCTION(secondary_trap)
117#if WITH_SMP
118    // wait for _boot_status to be nonzero, then go into riscv_secondary_entry
119    lb      t0, (_boot_status)
120    beqz    t0, secondary_trap
121
122    // we've been released by the main cpu and/or we've been booted after the
123    // system has been running a while.
124
125#if RISCV_MMU
126    // enable the mmu on this core
127    call    .Lenable_mmu
128#endif
129
130    // a0 == hart id
131    // a2 == assigned cpu id (may not be the same)
132
133    // set the per cpu structure before getting into the secondary boot path
134    call    riscv_configure_percpu_early
135
136    // bootstrap the secondary cpus
137    call    riscv_secondary_entry
138#endif
139    // fallthrough if either no SMP or riscv_secondary_entry returns
140END_FUNCTION(secondary_trap)
141
142LOCAL_FUNCTION(hart_trap)
143    // cpus with too high of a hart id go here and spin forever
144    wfi
145    j       hart_trap
146END_FUNCTION(hart_trap)
147
148#if RISCV_MMU
149    // initialize the kernel page tables
150    // for all MMU versions, identity map some amount of memory near 0 and
151    // the same amount at the bottom of the kernel's address space
152LOCAL_FUNCTION(_mmu_init)
153    lla     t0, trampoline_pgtable
154
155    // store the physical address of the pgtable for future use
156    sd      t0, (trampoline_pgtable_phys), t1
157
158    // do the same for the main kernel pgtable
159    lla     t2, kernel_pgtable
160    sd      t2, (kernel_pgtable_phys), t1
161
162    // and the 2nd level tables
163    lla     t2, kernel_l2_pgtable
164    sd      t2, (kernel_l2_pgtable_phys), t1
165
166    // compute kernel pgtable pointer (index 256)
167    addi    t1, t0, (8 * 128)
168    addi    t1, t1, (8 * 128)
169
170    // page table entry: address 0, A, D, G, XWR, V
171    li      t2, (0 | (1<<7) | (1<<6) | (1<<5) | (1<<3) | (1<<2) | (1<<1) | (1<<0))
172
173    // num interations and increment count
174#if RISCV_MMU == 48 || RISCV_MMU == 39
175    // RV48: map the first 512GB of the physical address space at the
176    // bottom of the kernel address space using a single terapage
177    // RV39: map the first 64GB of the physical address space at the
178    // bottom of the kernel address space using 64 1GB gigapages
179    li      t3, RISCV_MMU_PHYSMAP_PAGE_COUNT
180    li      t4, (RISCV_MMU_PHYSMAP_PAGE_SIZE >> 2)
181#else
182#error implement sv32
183#endif
184
185    // loop, writing t3 entries out and incrementing by t4 address.
186    // write both to t0 (index 0 of the kernel page table) and
187    // t1 (starting index of kernel space)
1880:
189    sd      t2, (t1)
190    sd      t2, (t0)
191    add     t2, t2, t4
192    addi    t0, t0, 8
193    addi    t1, t1, 8
194    addi    t3, t3, -1
195    bnez    t3, 0b
196
197    // ensure it's written out
198    fence   w,w
199
200.Lenable_mmu:
201    // set the satp register and enable the mmu
202    // ASID 0, trampoline_pgtable address
203    lla     t0, trampoline_pgtable
204    srli    t1, t0, 12
205#if RISCV_MMU == 48
206    li      t2, (RISCV_SATP_MODE_SV48 << RISCV_SATP_MODE_SHIFT)
207#elif RISCV_MMU == 39
208    li      t2, (RISCV_SATP_MODE_SV39 << RISCV_SATP_MODE_SHIFT)
209#else
210#error implement
211#endif
212    or      t1, t1, t2
213    csrw    satp, t1
214
215    // global tlb fence
216    sfence.vma  zero, zero
217
218    // mmu is initialized and we're running out of an identity physical map
219
220    // save the physical address of .Lhigh
221    lla     t1, .Lhigh
222
223    // bounce to the high address
224    ld      t0, (.Lhigh_addr)
225    jr      t0
226
227    // the full virtual address of the .Lhigh label
228.Lhigh_addr:
229    .quad   .Lhigh
230.Lhigh:
231
232    // we're now running at the high virtual address
233    // compute the delta between the old physical and newer high addresses
234    sub     t0, t0, t1
235
236    // fix up the gp, stack pointer, and return address
237    add     gp, gp, t0
238    add     sp, sp, t0
239    add     ra, ra, t0
240    ret
241END_FUNCTION(_mmu_init)
242#endif // RISCV_MMU
243
244.bss
245.align 4
246LOCAL_DATA(default_stack)
247    .skip ARCH_DEFAULT_STACK_SIZE * SMP_MAX_CPUS
248LOCAL_DATA(default_stack_top)
249
250// put boot status in .data so it doesn't get paved over during BSS initialization
251.data
252LOCAL_DATA(_boot_status)
253    .byte  0
254
255.align 2
256LOCAL_DATA(_boot_lottery)
257    .word  0
258