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