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 s3, initstack_end 227 mv sp, s3 228 229 /* Allocate space for thread0 PCB and riscv_bootparams */ 230 addi sp, sp, -(PCB_SIZE + RISCV_BOOTPARAMS_SIZE) & ~STACKALIGNBYTES 231 232 /* Clear BSS */ 233 la s0, _C_LABEL(__bss_start) 234 la s1, _C_LABEL(_end) 2351: 236 sd zero, 0(s0) 237 addi s0, s0, 8 238 bltu s0, s1, 1b 239 240 /* Fill riscv_bootparams */ 241 la t0, pagetable_l1 242 sd t0, RISCV_BOOTPARAMS_KERN_L1PT(sp) 243 sd s9, RISCV_BOOTPARAMS_KERN_PHYS(sp) 244 245 la t0, initstack 246 sd t0, RISCV_BOOTPARAMS_KERN_STACK(sp) 247 248 li t0, (VM_EARLY_DTB_ADDRESS) 249 /* Add offset of DTB within superpage */ 250 li t1, (L2_OFFSET) 251 and t1, a1, t1 252 add t0, t0, t1 253 sd t0, RISCV_BOOTPARAMS_DTBP_VIRT(sp) 254 sd a1, RISCV_BOOTPARAMS_DTBP_PHYS(sp) 255 256 sd a0, RISCV_BOOTPARAMS_MODULEP(sp) 257 258 mv a0, sp 259 call _C_LABEL(initriscv) /* Off we go */ 260 call _C_LABEL(mi_startup) 261 262/* 263 * Get the physical address the kernel is loaded to. Returned in s9. 264 */ 265get_physmem: 266 lla t0, virt_map /* physical address of virt_map */ 267 ld t1, 0(t0) /* virtual address of virt_map */ 268 sub t1, t1, t0 /* calculate phys->virt delta */ 269 li t2, KERNBASE 270 sub s9, t2, t1 /* s9 = physmem base */ 271 ret 272 273 .align 4 274initstack: 275 .space (PAGE_SIZE * KSTACK_PAGES) 276initstack_end: 277 278ENTRY(sigcode) 279 mv a0, sp 280 addi a0, a0, SF_UC 281 2821: 283 li t0, SYS_sigreturn 284 ecall 285 286 /* sigreturn failed, exit */ 287 li t0, SYS_exit 288 ecall 289 290 j 1b 291END(sigcode) 292 /* This may be copied to the stack, keep it 16-byte aligned */ 293 .align 3 294esigcode: 295 296 .data 297 .align 3 298 .global szsigcode 299szsigcode: 300 .quad esigcode - sigcode 301 302 .align 12 303pagetable_l1: 304 .space PAGE_SIZE 305pagetable_l2: 306 .space PAGE_SIZE 307pagetable_l2_devmap: 308 .space PAGE_SIZE 309 310 .align 3 311virt_map: 312 .quad virt_map 313hart_lottery: 314 .space 4 315 316 .globl init_pt_va 317init_pt_va: 318 .quad pagetable_l2 /* XXX: Keep page tables VA */ 319 320#ifndef SMP 321ENTRY(mpentry) 3221: 323 wfi 324 j 1b 325END(mpentry) 326#else 327/* 328 * mpentry(unsigned long) 329 * 330 * Called by a core when it is being brought online. 331 */ 332ENTRY(mpentry) 333 /* 334 * Calculate the offset to __riscv_boot_ap 335 * for the current core, cpuid is in a0. 336 */ 337 li t1, 4 338 mulw t1, t1, a0 339 /* Get the pointer */ 340 lla t0, __riscv_boot_ap 341 add t0, t0, t1 342 3431: 344 /* Wait the kernel to be ready */ 345 lw t1, 0(t0) 346 beqz t1, 1b 347 348 /* Setup stack pointer */ 349 lla t0, bootstack 350 ld sp, 0(t0) 351 352 /* Get the kernel's load address */ 353 jal get_physmem 354 355 /* Setup supervisor trap vector */ 356 lla t0, mpva 357 sub t0, t0, s9 358 li t1, KERNBASE 359 add t0, t0, t1 360 csrw stvec, t0 361 362 /* Set page tables base register */ 363 lla s2, pagetable_l1 364 srli s2, s2, PAGE_SHIFT 365 li t0, SATP_MODE_SV39 366 or s2, s2, t0 367 sfence.vma 368 csrw satp, s2 369 370 .align 2 371mpva: 372 /* Set the global pointer again, this time with the virtual address. */ 373.option push 374.option norelax 375 lla gp, __global_pointer$ 376.option pop 377 378 /* Setup supervisor trap vector */ 379 la t0, cpu_exception_handler 380 csrw stvec, t0 381 382 /* Ensure sscratch is zero */ 383 li t0, 0 384 csrw sscratch, t0 385 386 call init_secondary 387END(mpentry) 388#endif 389