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, L2_SHIFT /* Div physmem base by 2 MiB */ 139 li t2, 512 /* Build 512 entries */ 140 add t3, t4, t2 141 li t0, (PTE_KERN | PTE_X) 1421: 143 slli t2, t4, PTE_PPN1_S /* << PTE_PPN1_S */ 144 or t5, t0, t2 145 sd t5, (s1) /* Store PTE entry to position */ 146 addi s1, s1, PTE_SIZE 147 148 addi t4, t4, 1 149 bltu t4, t3, 1b 150 151 /* Create an L1 page for early devmap */ 152 lla s1, pagetable_l1 153 lla s2, pagetable_l2_devmap /* Link to next level PN */ 154 srli s2, s2, PAGE_SHIFT 155 156 li a5, (VM_MAX_KERNEL_ADDRESS - L2_SIZE) 157 srli a5, a5, L1_SHIFT /* >> L1_SHIFT */ 158 andi a5, a5, 0x1ff /* & 0x1ff */ 159 li t4, PTE_V 160 slli t5, s2, PTE_PPN0_S /* (s2 << PTE_PPN0_S) */ 161 or t6, t4, t5 162 163 /* Store single level1 PTE entry to position */ 164 li a6, PTE_SIZE 165 mulw a5, a5, a6 166 add t0, s1, a5 167 sd t6, (t0) 168 169 /* Check if we have a DTB that needs to be mapped */ 170 beqz a1, 2f 171 172 /* Create an L2 page superpage for DTB */ 173 lla s1, pagetable_l2_devmap 174 mv s2, a1 175 srli s2, s2, PAGE_SHIFT 176 /* Mask off any bits that aren't aligned */ 177 andi s2, s2, ~((1 << (PTE_PPN1_S - PTE_PPN0_S)) - 1) 178 179 li t0, (PTE_KERN) 180 slli t2, s2, PTE_PPN0_S /* << PTE_PPN0_S */ 181 or t0, t0, t2 182 183 /* Store PTE entry to position */ 184 li a6, PTE_SIZE 185 li a5, 510 186 mulw a5, a5, a6 187 add t1, s1, a5 188 sd t0, (t1) 189 190 /* Page tables END */ 191 192 /* Setup supervisor trap vector */ 1932: 194 lla t0, va 195 sub t0, t0, s9 196 li t1, KERNBASE 197 add t0, t0, t1 198 csrw stvec, t0 199 200 /* Set page tables base register */ 201 lla s2, pagetable_l1 202 srli s2, s2, PAGE_SHIFT 203 li t0, SATP_MODE_SV39 204 or s2, s2, t0 205 sfence.vma 206 csrw satp, s2 207 208 .align 2 209va: 210 /* Set the global pointer again, this time with the virtual address. */ 211.option push 212.option norelax 213 lla gp, __global_pointer$ 214.option pop 215 216 /* Setup supervisor trap vector */ 217 la t0, cpu_exception_handler 218 csrw stvec, t0 219 220 /* Ensure sscratch is zero */ 221 li t0, 0 222 csrw sscratch, t0 223 224 /* Initialize stack pointer */ 225 la sp, initstack_end 226 227 /* Clear frame pointer */ 228 mv s0, zero 229 230 /* Allocate space for thread0 PCB and riscv_bootparams */ 231 addi sp, sp, -(PCB_SIZE + RISCV_BOOTPARAMS_SIZE) & ~STACKALIGNBYTES 232 233 /* Clear BSS */ 234 la t0, _C_LABEL(__bss_start) 235 la t1, _C_LABEL(_end) 2361: 237 sd zero, 0(t0) 238 addi t0, t0, 8 239 bltu t0, t1, 1b 240 241 /* Fill riscv_bootparams */ 242 la t0, pagetable_l1 243 sd t0, RISCV_BOOTPARAMS_KERN_L1PT(sp) 244 sd s9, RISCV_BOOTPARAMS_KERN_PHYS(sp) 245 246 la t0, initstack 247 sd t0, RISCV_BOOTPARAMS_KERN_STACK(sp) 248 249 li t0, (VM_EARLY_DTB_ADDRESS) 250 /* Add offset of DTB within superpage */ 251 li t1, (L2_OFFSET) 252 and t1, a1, t1 253 add t0, t0, t1 254 sd t0, RISCV_BOOTPARAMS_DTBP_VIRT(sp) 255 sd a1, RISCV_BOOTPARAMS_DTBP_PHYS(sp) 256 257 sd a0, RISCV_BOOTPARAMS_MODULEP(sp) 258 259 mv a0, sp 260 call _C_LABEL(initriscv) /* Off we go */ 261 call _C_LABEL(mi_startup) 262 263 /* We should never reach here, but if so just hang. */ 2642: 265 wfi 266 j 2b 267 268/* 269 * Get the physical address the kernel is loaded to. Returned in s9. 270 */ 271get_physmem: 272 lla t0, virt_map /* physical address of virt_map */ 273 ld t1, 0(t0) /* virtual address of virt_map */ 274 sub t1, t1, t0 /* calculate phys->virt delta */ 275 li t2, KERNBASE 276 sub s9, t2, t1 /* s9 = physmem base */ 277 ret 278 279 .align 4 280initstack: 281 .space (PAGE_SIZE * KSTACK_PAGES) 282initstack_end: 283 284ENTRY(sigcode) 285 mv a0, sp 286 addi a0, a0, SF_UC 287 2881: 289 li t0, SYS_sigreturn 290 ecall 291 292 /* sigreturn failed, exit */ 293 li t0, SYS_exit 294 ecall 295 296 j 1b 297END(sigcode) 298 /* This may be copied to the stack, keep it 16-byte aligned */ 299 .align 3 300esigcode: 301 302 .data 303 .align 3 304 .global szsigcode 305szsigcode: 306 .quad esigcode - sigcode 307 308 .align 12 309pagetable_l1: 310 .space PAGE_SIZE 311pagetable_l2: 312 .space PAGE_SIZE 313pagetable_l2_devmap: 314 .space PAGE_SIZE 315 316 .align 3 317virt_map: 318 .quad virt_map 319hart_lottery: 320 .space 4 321 322 .globl init_pt_va 323init_pt_va: 324 .quad pagetable_l2 /* XXX: Keep page tables VA */ 325 326#ifndef SMP 327ENTRY(mpentry) 3281: 329 wfi 330 j 1b 331END(mpentry) 332#else 333/* 334 * mpentry(unsigned long) 335 * 336 * Called by a core when it is being brought online. 337 */ 338ENTRY(mpentry) 339 /* 340 * Calculate the offset to __riscv_boot_ap 341 * for the current core, cpuid is in a0. 342 */ 343 li t1, 4 344 mulw t1, t1, a0 345 /* Get the pointer */ 346 lla t0, __riscv_boot_ap 347 add t0, t0, t1 348 3491: 350 /* Wait the kernel to be ready */ 351 lw t1, 0(t0) 352 beqz t1, 1b 353 354 /* Setup stack pointer */ 355 lla t0, bootstack 356 ld sp, 0(t0) 357 358 /* Get the kernel's load address */ 359 jal get_physmem 360 361 /* Setup supervisor trap vector */ 362 lla t0, mpva 363 sub t0, t0, s9 364 li t1, KERNBASE 365 add t0, t0, t1 366 csrw stvec, t0 367 368 /* Set page tables base register */ 369 lla s2, pagetable_l1 370 srli s2, s2, PAGE_SHIFT 371 li t0, SATP_MODE_SV39 372 or s2, s2, t0 373 sfence.vma 374 csrw satp, s2 375 376 .align 2 377mpva: 378 /* Set the global pointer again, this time with the virtual address. */ 379.option push 380.option norelax 381 lla gp, __global_pointer$ 382.option pop 383 384 /* Setup supervisor trap vector */ 385 la t0, cpu_exception_handler 386 csrw stvec, t0 387 388 /* Ensure sscratch is zero */ 389 li t0, 0 390 csrw sscratch, t0 391 392 call init_secondary 393END(mpentry) 394#endif 395