/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2012 Regents of the University of California */ #include #include #include #include #include #include #include #include __INIT ENTRY(_start) /* Mask all interrupts */ csrw CSR_SIE, zero csrw CSR_SIP, zero /* Load the global pointer */ .option push .option norelax la gp, __global_pointer$ .option pop /* * Disable FPU to detect illegal usage of * floating point in kernel space */ li t0, SR_FS csrc sstatus, t0 /* Pick one hart to run the main boot sequence */ la a3, hart_lottery li a2, 1 amoadd.w a3, a2, (a3) bnez a3, .Lsecondary_start /* Clear BSS for flat non-ELF images */ la a3, __bss_start la a4, __bss_stop ble a4, a3, clear_bss_done clear_bss: REG_S zero, (a3) add a3, a3, RISCV_SZPTR blt a3, a4, clear_bss clear_bss_done: /* Save hart ID and DTB physical address */ mv s0, a0 mv s1, a1 la a2, boot_cpu_hartid REG_S a0, (a2) /* Initialize page tables and relocate to virtual addresses */ la sp, init_thread_union + THREAD_SIZE mv a0, s1 call setup_vm la a0, early_pg_dir call relocate /* Restore C environment */ la tp, init_task sw zero, TASK_TI_CPU(tp) la sp, init_thread_union + THREAD_SIZE /* Start the kernel */ call parse_dtb tail start_kernel relocate: /* Relocate return address */ li a1, PAGE_OFFSET la a2, _start sub a1, a1, a2 add ra, ra, a1 /* Point stvec to virtual address of intruction after satp write */ la a2, 1f add a2, a2, a1 csrw CSR_STVEC, a2 /* Compute satp for kernel page tables, but don't load it yet */ srl a2, a0, PAGE_SHIFT li a1, SATP_MODE or a2, a2, a1 /* * Load trampoline page directory, which will cause us to trap to * stvec if VA != PA, or simply fall through if VA == PA. We need a * full fence here because setup_vm() just wrote these PTEs and we need * to ensure the new translations are in use. */ la a0, trampoline_pg_dir srl a0, a0, PAGE_SHIFT or a0, a0, a1 sfence.vma csrw CSR_SATP, a0 .align 2 1: /* Set trap vector to spin forever to help debug */ la a0, .Lsecondary_park csrw CSR_STVEC, a0 /* Reload the global pointer */ .option push .option norelax la gp, __global_pointer$ .option pop /* * Switch to kernel page tables. A full fence is necessary in order to * avoid using the trampoline translations, which are only correct for * the first superpage. Fetching the fence is guarnteed to work * because that first superpage is translated the same way. */ csrw CSR_SATP, a2 sfence.vma ret .Lsecondary_start: #ifdef CONFIG_SMP li a1, CONFIG_NR_CPUS bgeu a0, a1, .Lsecondary_park /* Set trap vector to spin forever to help debug */ la a3, .Lsecondary_park csrw CSR_STVEC, a3 slli a3, a0, LGREG la a1, __cpu_up_stack_pointer la a2, __cpu_up_task_pointer add a1, a3, a1 add a2, a3, a2 /* * This hart didn't win the lottery, so we wait for the winning hart to * get far enough along the boot process that it should continue. */ .Lwait_for_cpu_up: /* FIXME: We should WFI to save some energy here. */ REG_L sp, (a1) REG_L tp, (a2) beqz sp, .Lwait_for_cpu_up beqz tp, .Lwait_for_cpu_up fence /* Enable virtual memory and relocate to virtual address */ la a0, swapper_pg_dir call relocate tail smp_callin #endif .align 2 .Lsecondary_park: /* We lack SMP support or have too many harts, so park this hart */ wfi j .Lsecondary_park END(_start) __PAGE_ALIGNED_BSS /* Empty zero page */ .balign PAGE_SIZE