.extern hart0_boot .extern hart0_early_boot .section .text.start .global _start .type _start, STT_FUNC _start: ## Have harts other than hart0 spin until hart0 wakes them up. As a ## side effect, load every hart's thread pointer register with MHARTID. csrr tp, mhartid bnez tp, wait_for_hart0 ### Set up trap handling. ## Set MENVCFG.STCE, to enable the Sstc extension, which will allow us ## to delegate timer interrupts to Supervisor mode. li t0, 1<<63 csrs menvcfg, t0 ## Set MCOUNTEREN.{CY, TM, IR} to 1, enabling Supervisor mode accesses ## to the cycle, time, stimecmp, and instret MSRs. li t0, 0b111 csrs mcounteren, t0 ## Set MIE.{SSIE, STIE, SEIE} to 1, enabling software, timer, and ## exception traps in Supervisor mode. li t0, 0b1000100010 csrs mie, t0 ## Delegate all exceptions to Supervisor mode. li t0, 0xffff csrw medeleg, t0 csrw mideleg, t0 ### Go from Machine mode to Supervisor mode by fictitiously returning from a ### trap. ## First, set MSTATUS.MPP to Supervisor, so that when we execute mret, ## the privilege level will lower to Supervisor. li t0, 0b11 << 11 csrc mstatus, t0 li t0, 0b01 << 11 csrs mstatus, t0 ## Next, set MEPC to the address of hart0_full_boot, so that when we ## execute mret, execution will continue there. la t0, hart0_full_boot csrw mepc, t0 ## Set SATP.MODE to Bare, and clear the rest of the bits. This disables ## paging in Supervisor mode. csrw satp, zero ## Set PMP0CFG.{R, W, X} to 1, PMP0CFG.A to TOR, and PMP0ADDR to the ## maximum value. This allows supervisor mode to access all of physical ## memory. li t0, (0b01 << 3) | 0b111 csrw pmpcfg0, t0 li t0, -1 csrw pmpaddr0, t0 ## Since we adjusted PMP settings, we need to issue an SFENCE.VMA. sfence.vma ## Jump to supervisor mode. mret .size _start, . - _start .section .text .type hart0_full_boot, STT_FUNC hart0_full_boot: ## Set up hart0's stack, leaving room for the EarlyBootAddrs and CPULocals. la tp, hart0_initial_stack_top - (4 * 8) addi sp, tp, -(9 * 8) ## Write a canary to the bottom of hart0's stack. li t0, 0xdead0bad0defaced la t1, hart0_initial_stack sd t0, (t1) ## Store the DeviceTree and the appropriate addresses into the ## EarlyBootAddrs. sd a1, (0 * 8)(sp) la t0, kernel_start sd t0, (1 * 8)(sp) la t0, kernel_end sd t0, (2 * 8)(sp) la t0, kernel_rx_end sd t0, (3 * 8)(sp) la t0, kernel_ro_end sd t0, (4 * 8)(sp) la t0, kernel_rw_end sd t0, (5 * 8)(sp) sd t1, (6 * 8)(sp) # This is still hart0_initial_stack from above. la t0, hart0_initial_stack_top sd t0, (7 * 8)(sp) la t0, trampoline_start sd t0, (8 * 8)(sp) ## Call hart0_early_boot, passing it the DeviceTree we received and ## getting back the address of a stack to switch to. mv a0, sp call hart0_early_boot ## Switch to the returned stack. mv sp, a0 ## Load the canary back from hart0's stack. la t0, hart0_initial_stack ld a0, (t0) ## Jump to hart0_boot. j hart0_boot .size hart0_full_boot, . - hart0_full_boot .section .text .type wait_for_hart0, STT_FUNC wait_for_hart0: ## TODO wfi j wait_for_hart0 .size wait_for_hart0, . - wait_for_hart0 .section .trampoline_page trap_handler: ## TODO wfi j trap_handler