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