blob: 8de9ca9c5b39c9de9e0100d2746acbb128b856ec [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#include "hw/top_earlgrey/sw/autogen/top_earlgrey_memory.h"
/**
* Mask ROM Interrupt Vector
*/
.section .vectors, "ax"
.option push
// Disable RISC-V instruction compression: we need all instructions to
// be exactly word wide in the interrupt vector.
.option norvc
// Disable RISC-V linker relaxation, as it can compress instructions at
// link-time, which we also really don't want.
.option norelax
/**
* `_mask_rom_interrupt_vector` is the boot-defined interrupt vector for Ibex,
* for the Mask ROM.
*
* The Mask ROM does not use interrupts, so there are only entries for Ibex's
* non-maskable interrupts, and for the hardware exception handler.
*
* Interrupt vectors in Ibex have 32 entries for 32 possible interrupts. The
* vector must be 256-byte aligned, as Ibex's vectoring mechanism requires that.
* Ibex uses the instruction directly after the boot interrupt vector when
* starting execution from reset, which we choose to make look like an extra
* entry.
*
* Thus this vector has exactly 33 4-byte entries.
*
* Only the following will be used by Ibex:
* - Exception Handler (Entry 0)
* - Machine Software Interrupt Handler (Entry 3)
* - Machine Timer Interrupt Handler (Entry 7)
* - Machine External Interrupt Handler (Entry 11)
* - Vendor Interrupt Handlers (Entries 16-31)
* - Reset Handler (Entry 32)
*
* More information about Ibex's interrupts can be found here:
* https://ibex-core.readthedocs.io/en/latest/exception_interrupts.html
*/
.balign 256
.globl _mask_rom_interrupt_vector
.type _mask_rom_interrupt_vector, @function
_mask_rom_interrupt_vector:
// RISC-V Standard (Vectored) Interrupt Handlers:
// Exception and User Software Interrupt Handler.
.extern mask_rom_exception_handler
j mask_rom_exception_handler
// Supervisor Software Interrupt Handler.
unimp
// Reserved.
unimp
// Machine Software Interrupt Handler.
unimp
// User Timer Interrupt Handler.
unimp
// Supervisor Timer Interrupt Handler.
unimp
// Reserved.
unimp
// Machine Timer Interrupt Handler.
unimp
// User External Interrupt Handler.
unimp
// Supervisor External Interrupt Handler.
unimp
// Reserved.
unimp
// Machine External Interrupt Handler.
unimp
// Reserved.
unimp
unimp
unimp
unimp
// Vendor Interrupt Handlers:
// On Ibex interrupt ids 30-16 are for "fast" interrupts.
.rept 15
unimp
.endr
// On Ibex interrupt id 31 is for non-maskable interrupts.
.extern mask_rom_nmi_handler
j mask_rom_nmi_handler
// Ibex Reset Handler:
j _mask_rom_start_boot
// Set size so this vector can be disassembled.
.size _mask_rom_interrupt_vector, .-_mask_rom_interrupt_vector
// Re-enable compressed instructions, linker relaxation.
.option pop
/**
* Mask ROM runtime initialization code.
*/
// NOTE: The "ax" flag below is necessary to ensure that this section
// is allocated executable space in ROM by the linker.
.section .crt, "ax"
// Linker Relaxation is disabled until `__global_pointer$` is setup, below,
// because otherwise some sequences may be turned into gp-relative sequences,
// which is incorrect when `gp` is not initialized.
.option push
.option norelax
/**
* Entry point after reset. This symbol is jumped to from the handler
* for IRQ 32.
*
* then jumps to `mask_rom_boot
*/
.globl _mask_rom_start_boot
.type _mask_rom_start_boot, @function
_mask_rom_start_boot:
/**
* Disable Interrupts.
*
* We cannot disable exceptions, or Ibex's non-maskable interrupts (interrupt
* 31), so we still need to be careful.
*/
// Clear `MIE` field of `mstatus`.
csrci mstatus, 0x8
// Clear all the machine-defined interrupts, `MEIE`, `MTIE`, and `MSIE` fields
// of `mie`.
li t0, 0xFFFF0888
csrc mie, t0
// Set up the stack pointer.
//
// If an exception fires, the handler is conventionaly only allowed to clobber
// memory at addresses below `sp`.
la sp, _stack_start
/**
* Set well-defined interrupt/exception handlers
*
* We actually booted with this value of `mtvec`, so we shouldn't need to do
* this.
*
* The lowest two bits should be `0b01` to ensure we use vectored interrupts.
*/
la t0, _mask_rom_interrupt_vector
andi t0, t0, -4
ori t0, t0, 0b01
csrw mtvec, t0
/**
* Clean Device State Part 1
*/
// Zero all writable registers except x2 (sp).
mv x1, zero
// NOT x2 (sp) - We have already set it to the right value above.
mv x3, zero
mv x4, zero
mv x5, zero
mv x6, zero
mv x7, zero
mv x8, zero
mv x9, zero
mv x10, zero
mv x11, zero
mv x12, zero
mv x13, zero
mv x14, zero
mv x15, zero
mv x16, zero
mv x17, zero
mv x18, zero
mv x19, zero
mv x20, zero
mv x21, zero
mv x22, zero
mv x23, zero
mv x24, zero
mv x25, zero
mv x26, zero
mv x27, zero
mv x28, zero
mv x29, zero
mv x30, zero
mv x31, zero
// TODO: Setup SRAM Scrambling
// Temporarily: Zero out ram_main
//
// `t0` is the address to start zeroing at.
// `t1` is the address to stop zeroing at.
li t0, TOP_EARLGREY_RAM_MAIN_BASE_ADDR
li t1, (TOP_EARLGREY_RAM_MAIN_BASE_ADDR + TOP_EARLGREY_RAM_MAIN_SIZE_BYTES)
bgeu t0, t1, sram_zero_end
sram_zero_loop:
// TODO: Unroll loop
sw zero, 0x0(t0)
addi t0, t0, 0x4
bltu t0, t1, sram_zero_loop
sram_zero_end:
/**
* Setup C Runtime
*/
// Initialize the `.data` section.
//
// `t0` is the start address of `.data` (in RAM).
// `t1` is the end address of `.data` (in RAM).
// `t2` is the start address of `.data` (in ROM).
// `t3` is a scratch register for the copy.
la t0, _data_start
la t1, _data_end
la t2, _data_init_start
bgeu t0, t1, data_copy_loop_end
data_copy_loop:
// TODO: Unroll this loop
lw t3, 0x0(t2)
sw t3, 0x0(t0)
addi t0, t0, 0x4
addi t2, t2, 0x4
bltu t0, t1, data_copy_loop
data_copy_loop_end:
// Initialize the `.bss` section.
//
// We do this despite zeroing all of SRAM above, so that we still zero `.bss`
// once we've enabled SRAM scrambling.
//
// `t0` is the address to start zeroing at.
// `t1` is the address to stop zeroing at.
la t0, _bss_start
la t1, _bss_end
bgeu t0, t1, bss_zero_end
bss_zero_loop:
// TODO: Unroll loop
sw zero, 0x0(t0)
addi t0, t0, 0x4
bltu t0, t1, bss_zero_loop
bss_zero_end:
// Re-clobber all of the registers used to Setup the C Runtime.
mv t0, zero
mv t1, zero
mv t2, zero
mv t3, zero
// Setup global pointer.
//
// This requires that we disable linker relaxations, or it will be relaxed to
// `mv gp, gp`, so we disabled relaxations for all of `_mask_rom_start_boot`.
la gp, __global_pointer$
/**
* Jump to C Code
*/
.extern mask_rom_boot
call mask_rom_boot
// Loop forever if mask_rom_boot somehow returns.
1:
wfi
j 1b
// Set size so this function can be disassembled.
.size _mask_rom_start_boot, .-_mask_rom_start_boot
// Re-enable linker relaxation.
.option pop