1/*- 2 * Copyright (c) 2015-2018 Ruslan Bukin <br@bsdpad.com> 3 * All rights reserved. 4 * 5 * Portions of this software were developed by SRI International and the 6 * University of Cambridge Computer Laboratory under DARPA/AFRL contract 7 * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. 8 * 9 * Portions of this software were developed by the University of Cambridge 10 * Computer Laboratory as part of the CTSRD Project, with support from the 11 * UK Higher Education Innovation Fund (HEIF). 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * $FreeBSD$ 35 */ 36 37#include "assym.inc" 38 39#include <sys/syscall.h> 40#include <machine/asm.h> 41#include <machine/param.h> 42#include <machine/trap.h> 43#include <machine/riscvreg.h> 44#include <machine/pte.h> 45 46 .globl kernbase 47 .set kernbase, KERNBASE 48 49 .text 50/* 51 * Alternate entry point. Used when booting via SBI firmware. It must be placed 52 * at the beginning of the .text section. Arguments are as follows: 53 * - a0 = hart ID 54 * - a1 = dtbp 55 * 56 * Multiple CPUs might enter from this point, so we perform a hart lottery and 57 * send the losers to mpentry. 58 */ 59 .globl _alt_start 60_alt_start: 61 /* Set the global pointer */ 62.option push 63.option norelax 64 lla gp, __global_pointer$ 65.option pop 66 67 /* Pick a hart to run the boot process. */ 68 lla t0, hart_lottery 69 li t1, 1 70 amoadd.w t0, t1, 0(t0) 71 72 /* 73 * We must jump to mpentry in the non-BSP case because the offset is 74 * too large to fit in a 12-bit branch immediate. 75 */ 76 beqz t0, 1f 77 j mpentry 781: 79 /* Store the boot hart */ 80 lla t0, boot_hart 81 sw a0, 0(t0) 82 83 /* Load zero as modulep */ 84 mv a0, zero 85 j pagetables 86 87/* 88 * Main entry point. This routine is marked as the ELF entry, and is where 89 * loader(8) will enter the kernel. Arguments are as follows: 90 * - a0 = modulep 91 * - a1 = ??? 92 * 93 * It is expected that only a single CPU will enter here. 94 */ 95 .globl _start 96_start: 97 /* Set the global pointer */ 98.option push 99.option norelax 100 lla gp, __global_pointer$ 101.option pop 102 103 /* 104 * Zero a1 to indicate that we have no DTB pointer. It is already 105 * included in the loader(8) metadata. 106 */ 107 mv a1, zero 108 109 /* 110 * Page tables setup 111 * a0 - modulep or zero 112 * a1 - zero or dtbp 113 */ 114pagetables: 115 /* Get the kernel's load address */ 116 jal get_physmem 117 118 /* Add L1 entry for kernel */ 119 lla s1, pagetable_l1 120 lla s2, pagetable_l2 /* Link to next level PN */ 121 srli s2, s2, PAGE_SHIFT 122 123 li a5, KERNBASE 124 srli a5, a5, L1_SHIFT /* >> L1_SHIFT */ 125 andi a5, a5, 0x1ff /* & 0x1ff */ 126 li t4, PTE_V 127 slli t5, s2, PTE_PPN0_S /* (s2 << PTE_PPN0_S) */ 128 or t6, t4, t5 129 130 /* Store L1 PTE entry to position */ 131 li a6, PTE_SIZE 132 mulw a5, a5, a6 133 add t0, s1, a5 134 sd t6, (t0) 135 136 /* Level 2 superpages (512 x 2MiB) */ 137 lla s1, pagetable_l2 138 srli t4, s9, 21 /* Div physmem base by 2 MiB */ 139 li t2, 512 /* Build 512 entries */ 140 add t3, t4, t2 141 li t5, 0 142 li t0, (PTE_KERN | PTE_X) 1431: 144 slli t2, t4, PTE_PPN1_S /* << PTE_PPN1_S */ 145 or t5, t0, t2 146 sd t5, (s1) /* Store PTE entry to position */ 147 addi s1, s1, PTE_SIZE 148 149 addi t4, t4, 1 150 bltu t4, t3, 1b 151 152 /* Create an L1 page for early devmap */ 153 lla s1, pagetable_l1 154 lla s2, pagetable_l2_devmap /* Link to next level PN */ 155 srli s2, s2, PAGE_SHIFT 156 157 li a5, (VM_MAX_KERNEL_ADDRESS - L2_SIZE) 158 srli a5, a5, L1_SHIFT /* >> L1_SHIFT */ 159 andi a5, a5, 0x1ff /* & 0x1ff */ 160 li t4, PTE_V 161 slli t5, s2, PTE_PPN0_S /* (s2 << PTE_PPN0_S) */ 162 or t6, t4, t5 163 164 /* Store single level1 PTE entry to position */ 165 li a6, PTE_SIZE 166 mulw a5, a5, a6 167 add t0, s1, a5 168 sd t6, (t0) 169 170 /* Check if we have a DTB that needs to be mapped */ 171 beqz a1, 2f 172 173 /* Create an L2 page superpage for DTB */ 174 lla s1, pagetable_l2_devmap 175 mv s2, a1 176 srli s2, s2, PAGE_SHIFT 177 /* Mask off any bits that aren't aligned */ 178 andi s2, s2, ~((1 << (PTE_PPN1_S - PTE_PPN0_S)) - 1) 179 180 li t0, (PTE_KERN) 181 slli t2, s2, PTE_PPN0_S /* << PTE_PPN0_S */ 182 or t0, t0, t2 183 184 /* Store PTE entry to position */ 185 li a6, PTE_SIZE 186 li a5, 510 187 mulw a5, a5, a6 188 add t1, s1, a5 189 sd t0, (t1) 190 191 /* Page tables END */ 192 193 /* Setup supervisor trap vector */ 1942: 195 lla t0, va 196 sub t0, t0, s9 197 li t1, KERNBASE 198 add t0, t0, t1 199 csrw stvec, t0 200 201 /* Set page tables base register */ 202 lla s2, pagetable_l1 203 srli s2, s2, PAGE_SHIFT 204 li t0, SATP_MODE_SV39 205 or s2, s2, t0 206 sfence.vma 207 csrw satp, s2 208 209 .align 2 210va: 211 /* Set the global pointer again, this time with the virtual address. */ 212.option push 213.option norelax 214 lla gp, __global_pointer$ 215.option pop 216 217 /* Setup supervisor trap vector */ 218 la t0, cpu_exception_handler 219 csrw stvec, t0 220 221 /* Ensure sscratch is zero */ 222 li t0, 0 223 csrw sscratch, t0 224 225 /* Initialize stack pointer */ 226 la sp, initstack_end 227 228 /* Clear frame pointer */ 229 mv s0, zero 230 231 /* Allocate space for thread0 PCB and riscv_bootparams */ 232 addi sp, sp, -(PCB_SIZE + RISCV_BOOTPARAMS_SIZE) & ~STACKALIGNBYTES 233 234 /* Clear BSS */ 235 la t0, _C_LABEL(__bss_start) 236 la t1, _C_LABEL(_end) 2371: 238 sd zero, 0(t0) 239 addi t0, t0, 8 240 bltu t0, t1, 1b 241 242 /* Fill riscv_bootparams */ 243 la t0, pagetable_l1 244 sd t0, RISCV_BOOTPARAMS_KERN_L1PT(sp) 245 sd s9, RISCV_BOOTPARAMS_KERN_PHYS(sp) 246 247 la t0, initstack 248 sd t0, RISCV_BOOTPARAMS_KERN_STACK(sp) 249 250 li t0, (VM_EARLY_DTB_ADDRESS) 251 /* Add offset of DTB within superpage */ 252 li t1, (L2_OFFSET) 253 and t1, a1, t1 254 add t0, t0, t1 255 sd t0, RISCV_BOOTPARAMS_DTBP_VIRT(sp) 256 sd a1, RISCV_BOOTPARAMS_DTBP_PHYS(sp) 257 258 sd a0, RISCV_BOOTPARAMS_MODULEP(sp) 259 260 mv a0, sp 261 call _C_LABEL(initriscv) /* Off we go */ 262 call _C_LABEL(mi_startup) 263 264 /* We should never reach here, but if so just hang. */ 2652: 266 wfi 267 j 2b 268 269/* 270 * Get the physical address the kernel is loaded to. Returned in s9. 271 */ 272get_physmem: 273 lla t0, virt_map /* physical address of virt_map */ 274 ld t1, 0(t0) /* virtual address of virt_map */ 275 sub t1, t1, t0 /* calculate phys->virt delta */ 276 li t2, KERNBASE 277 sub s9, t2, t1 /* s9 = physmem base */ 278 ret 279 280 .align 4 281initstack: 282 .space (PAGE_SIZE * KSTACK_PAGES) 283initstack_end: 284 285ENTRY(sigcode) 286 mv a0, sp 287 addi a0, a0, SF_UC 288 2891: 290 li t0, SYS_sigreturn 291 ecall 292 293 /* sigreturn failed, exit */ 294 li t0, SYS_exit 295 ecall 296 297 j 1b 298END(sigcode) 299 /* This may be copied to the stack, keep it 16-byte aligned */ 300 .align 3 301esigcode: 302 303 .data 304 .align 3 305 .global szsigcode 306szsigcode: 307 .quad esigcode - sigcode 308 309 .align 12 310pagetable_l1: 311 .space PAGE_SIZE 312pagetable_l2: 313 .space PAGE_SIZE 314pagetable_l2_devmap: 315 .space PAGE_SIZE 316 317 .align 3 318virt_map: 319 .quad virt_map 320hart_lottery: 321 .space 4 322 323 .globl init_pt_va 324init_pt_va: 325 .quad pagetable_l2 /* XXX: Keep page tables VA */ 326 327#ifndef SMP 328ENTRY(mpentry) 3291: 330 wfi 331 j 1b 332END(mpentry) 333#else 334/* 335 * mpentry(unsigned long) 336 * 337 * Called by a core when it is being brought online. 338 */ 339ENTRY(mpentry) 340 /* 341 * Calculate the offset to __riscv_boot_ap 342 * for the current core, cpuid is in a0. 343 */ 344 li t1, 4 345 mulw t1, t1, a0 346 /* Get the pointer */ 347 lla t0, __riscv_boot_ap 348 add t0, t0, t1 349 3501: 351 /* Wait the kernel to be ready */ 352 lw t1, 0(t0) 353 beqz t1, 1b 354 355 /* Setup stack pointer */ 356 lla t0, bootstack 357 ld sp, 0(t0) 358 359 /* Get the kernel's load address */ 360 jal get_physmem 361 362 /* Setup supervisor trap vector */ 363 lla t0, mpva 364 sub t0, t0, s9 365 li t1, KERNBASE 366 add t0, t0, t1 367 csrw stvec, t0 368 369 /* Set page tables base register */ 370 lla s2, pagetable_l1 371 srli s2, s2, PAGE_SHIFT 372 li t0, SATP_MODE_SV39 373 or s2, s2, t0 374 sfence.vma 375 csrw satp, s2 376 377 .align 2 378mpva: 379 /* Set the global pointer again, this time with the virtual address. */ 380.option push 381.option norelax 382 lla gp, __global_pointer$ 383.option pop 384 385 /* Setup supervisor trap vector */ 386 la t0, cpu_exception_handler 387 csrw stvec, t0 388 389 /* Ensure sscratch is zero */ 390 li t0, 0 391 csrw sscratch, t0 392 393 call init_secondary 394END(mpentry) 395#endif 396