zephyr/arch/riscv32/soc/riscv-privilege/riscv32-qemu/vector.S

72 lines
2.1 KiB
ArmAsm

/*
* Copyright (c) 2016 Jean-Paul Etienne <fractalclone@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <toolchain.h>
/* imports */
GTEXT(__reset)
GTEXT(__irq_wrapper)
/*
* following riscv32-qemu specs
* IVT is placed at 0x000001000 and is mapped as follows:
* 0x00001000: reset
* 0x00001004: non-maskable interrupt (nmi) vector
* 0x00001010: machine trap (mt) vector
*
* Call __irq_wrapper to handle all interrupts/exceptions/faults
*/
SECTION_FUNC(vectors, vinit)
.option norvc;
/*
* jal instruction cannot be used to jump to address whose offset
* is > 12-bits wide. In this case, we have to use a call or tail
* instruction to jump to a far-away sub-routine.
*
* Given that IVT is found at a different address-space than the
* RAM in riscv32-qemu, we have to use call or tail instructions
* to jump to __reset or __isr_wrapper subroutines.
* However, call or tail instructions are pseudo instructions,
* which generate two base-instructions upon compilation. In this case,
* using them at a particular entry in the IVT will overwrite the next
* entry in the IVT. For example, using tail instruction in the
* reset vector, will overwrite the nmi-vector entry. To prevent this,
* perform a two-phase jump instructions to __reset or __irq_wrapper
* subroutines. The first jump performs a jal instruction, which will
* jump to an offset in the same vector address-space, but outside the
* IVT. The second jump performs a tail instruction to the __reset
* or __irq_wrapper subroutines.
*/
/* Call __reset for reset vector */
jal x0, do_reset
/* Call __irq_wrapper for nmi vector */
jal x0, do_irq_wrapper
.org 0x10
/* Call __irq_wrapper for mt vector */
jal x0, do_irq_wrapper
.org 0x400 /* we are outside IVT */
do_reset:
/*
* Set mtvec (Machine Trap-Vector Base-Address Register)
* to __irq_wrapper, so that we jump directly to __irq_wrapper,
* instead to the default machine trap vector address in IVT.
* This will preserve us from performing two jump instructions upon
* an interrupt.
*/
la t0, __irq_wrapper
csrw mtvec, t0
/* Jump to __reset */
tail __reset
do_irq_wrapper:
tail __irq_wrapper