diff options
author | Jean-Paul Etienne <fractalclone@gmail.com> | 2017-01-11 00:24:30 +0100 |
---|---|---|
committer | Andrew Boie <andrew.p.boie@intel.com> | 2017-01-13 19:57:51 +0000 |
commit | dae36b97e8fa2da5c4dbda2ddf53a98765a3fc0f (patch) | |
tree | 3a80409774dc9337c424a0b071713c991fae7ef2 /arch | |
parent | 9f418fe94400a69b89298c4831ee1ba41f1dbccc (diff) |
riscv32: added support for the riscv32-qemu soc
Change-Id: I7cf71f7a99fed7c83ed761ead9295697929d767d
Signed-off-by: Jean-Paul Etienne <fractalclone@gmail.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/riscv32/soc/riscv32-qemu/Kbuild | 7 | ||||
-rw-r--r-- | arch/riscv32/soc/riscv32-qemu/Kconfig.defconfig | 43 | ||||
-rw-r--r-- | arch/riscv32/soc/riscv32-qemu/Kconfig.soc | 2 | ||||
-rw-r--r-- | arch/riscv32/soc/riscv32-qemu/Makefile | 1 | ||||
-rw-r--r-- | arch/riscv32/soc/riscv32-qemu/linker.ld | 21 | ||||
-rw-r--r-- | arch/riscv32/soc/riscv32-qemu/qemu_irq.c | 72 | ||||
-rw-r--r-- | arch/riscv32/soc/riscv32-qemu/soc.h | 82 | ||||
-rw-r--r-- | arch/riscv32/soc/riscv32-qemu/soc_irq.S | 62 | ||||
-rw-r--r-- | arch/riscv32/soc/riscv32-qemu/vector.S | 83 |
9 files changed, 373 insertions, 0 deletions
diff --git a/arch/riscv32/soc/riscv32-qemu/Kbuild b/arch/riscv32/soc/riscv32-qemu/Kbuild new file mode 100644 index 000000000..950299147 --- /dev/null +++ b/arch/riscv32/soc/riscv32-qemu/Kbuild @@ -0,0 +1,7 @@ +ccflags-y +=-I$(srctree)/include +ccflags-y +=-I$(srctree)/include/drivers +ccflags-y +=-I$(srctree)/drivers + +asflags-y := ${ccflags-y} + +obj-y = soc_irq.o vector.o qemu_irq.o diff --git a/arch/riscv32/soc/riscv32-qemu/Kconfig.defconfig b/arch/riscv32/soc/riscv32-qemu/Kconfig.defconfig new file mode 100644 index 000000000..e2a0f3d31 --- /dev/null +++ b/arch/riscv32/soc/riscv32-qemu/Kconfig.defconfig @@ -0,0 +1,43 @@ +if SOC_RISCV32_QEMU + +config SOC + string + default "riscv32-qemu" + +config SYS_CLOCK_HW_CYCLES_PER_SEC + int + default 10000000 + +config RISCV_SOC_INTERRUPT_INIT + bool + default y + +config INCLUDE_RESET_VECTOR + bool + default y + +config NUM_IRQS + int + default 32 + +config ATOMIC_OPERATIONS_C + bool + default y + +config VECTOR_BASE_ADDR + hex + default 0x00001000 + +config VECTOR_SIZE + hex + default 0x1000 + +config RAM_BASE_ADDR + hex + default 0x80000000 + +config RAM_SIZE_MB + int + default 32 + +endif # SOC_RISCV32_QEMU diff --git a/arch/riscv32/soc/riscv32-qemu/Kconfig.soc b/arch/riscv32/soc/riscv32-qemu/Kconfig.soc new file mode 100644 index 000000000..dd57df075 --- /dev/null +++ b/arch/riscv32/soc/riscv32-qemu/Kconfig.soc @@ -0,0 +1,2 @@ +config SOC_RISCV32_QEMU + bool "riscv32_qemu SOC implementation" diff --git a/arch/riscv32/soc/riscv32-qemu/Makefile b/arch/riscv32/soc/riscv32-qemu/Makefile new file mode 100644 index 000000000..8bca0cb66 --- /dev/null +++ b/arch/riscv32/soc/riscv32-qemu/Makefile @@ -0,0 +1 @@ +soc-cflags := -I/$(srctree)/arch/$(ARCH)/soc/$(SOC_PATH)/ diff --git a/arch/riscv32/soc/riscv32-qemu/linker.ld b/arch/riscv32/soc/riscv32-qemu/linker.ld new file mode 100644 index 000000000..71320cb58 --- /dev/null +++ b/arch/riscv32/soc/riscv32-qemu/linker.ld @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2016 Jean-Paul Etienne <fractalclone@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @brief Linker script for riscv32-qemu + */ + +#include <arch/riscv32/riscv32-qemu/linker.ld> diff --git a/arch/riscv32/soc/riscv32-qemu/qemu_irq.c b/arch/riscv32/soc/riscv32-qemu/qemu_irq.c new file mode 100644 index 000000000..3e6e8ba33 --- /dev/null +++ b/arch/riscv32/soc/riscv32-qemu/qemu_irq.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2016 Jean-Paul Etienne <fractalclone@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * @brief riscv32-qemu interrupt management code + */ +#include <irq.h> +#include <soc.h> + +void _arch_irq_enable(unsigned int irq) +{ + uint32_t mie; + + /* + * Since only internal Timer device has interrupt within in + * riscv32-qemu, use only mie CSR register to enable device interrupt. + * CSR mie register is updated using atomic instruction csrrs + * (atomic read and set bits in CSR register) + */ + __asm__ volatile ("csrrs %0, mie, %1\n" + : "=r" (mie) + : "r" (1 << irq)); +} + +void _arch_irq_disable(unsigned int irq) +{ + uint32_t mie; + + /* + * Use atomic instruction csrrc to disable device interrupt in mie CSR. + * (atomic read and clear bits in CSR register) + */ + __asm__ volatile ("csrrc %0, mie, %1\n" + : "=r" (mie) + : "r" (1 << irq)); +}; + +int _arch_irq_is_enabled(unsigned int irq) +{ + uint32_t mie; + + __asm__ volatile ("csrr %0, mie" : "=r" (mie)); + + return !!(mie & (1 << irq)); +} + +#if defined(CONFIG_RISCV_SOC_INTERRUPT_INIT) +void soc_interrupt_init(void) +{ + /* ensure that all interrupts are disabled */ + (void)irq_lock(); + + __asm__ volatile ("csrwi mie, 0\n" + "csrwi sie, 0\n" + "csrwi mip, 0\n" + "csrwi sip, 0\n"); +} +#endif diff --git a/arch/riscv32/soc/riscv32-qemu/soc.h b/arch/riscv32/soc/riscv32-qemu/soc.h new file mode 100644 index 000000000..1adcff161 --- /dev/null +++ b/arch/riscv32/soc/riscv32-qemu/soc.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2016 Jean-Paul Etienne <fractalclone@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file SoC configuration macros for the riscv-qemu + */ + +#ifndef __RISCV32_QEMU_SOC_H_ +#define __RISCV32_QEMU_SOC_H_ + +/* CSR Registers */ +#define RISCV_QEMU_MSTATUS mstatus /* Machine Status Register */ + +/* IRQ numbers */ +#define RISCV_QEMU_TIMER_IRQ 7 /* Timer Interrupt */ + +/* Exception numbers */ +#define RISCV_QEMU_ECALL_EXP 11 /* ECALL Instruction */ + +/* + * SOC-specific MSTATUS related info + */ +/* MSTATUS register to save/restore upon interrupt/exception/context switch */ +#define SOC_MSTATUS_REG RISCV_QEMU_MSTATUS + +#define SOC_MSTATUS_IEN (1 << 3) /* Machine Interrupt Enable bit */ + +/* Previous Privilege Mode - Machine Mode */ +#define SOC_MSTATUS_MPP_M_MODE (3 << 11) +/* Interrupt Enable Bit in Previous Privilege Mode */ +#define SOC_MSTATUS_MPIE (1 << 7) + +/* + * Default MSTATUS register value to restore from stack + * upon scheduling a thread for the first time + */ +#define SOC_MSTATUS_DEF_RESTORE (SOC_MSTATUS_MPP_M_MODE | SOC_MSTATUS_MPIE) + + +/* SOC-specific MCAUSE bitfields */ +/* Exception code Mask */ +#define SOC_MCAUSE_IRQ_MASK 0x7FFFFFFF +/* ECALL exception number */ +#define SOC_MCAUSE_ECALL_EXP RISCV_QEMU_ECALL_EXP + +/* SOC-Specific EXIT ISR command */ +#define SOC_ERET mret + +/* UART configuration */ +#define RISCV_QEMU_UART_BASE 0x40002000 + +/* Timer configuration */ +#define RISCV_QEMU_TIMER_BASE 0x40000000 + +#ifndef _ASMLANGUAGE +#include <irq.h> +#include <misc/util.h> + +#if defined(CONFIG_RISCV_SOC_INTERRUPT_INIT) +void soc_interrupt_init(void); +#endif + +/* lib-c hooks required RAM defined variables */ +#define RISCV_RAM_BASE CONFIG_RAM_BASE_ADDR +#define RISCV_RAM_SIZE MB(CONFIG_RAM_SIZE_MB) + +#endif /* !_ASMLANGUAGE */ + +#endif /* __RISCV32_QEMU_SOC_H_ */ diff --git a/arch/riscv32/soc/riscv32-qemu/soc_irq.S b/arch/riscv32/soc/riscv32-qemu/soc_irq.S new file mode 100644 index 000000000..bc673cd6b --- /dev/null +++ b/arch/riscv32/soc/riscv32-qemu/soc_irq.S @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2016 Jean-Paul Etienne <fractalclone@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _ASMLANGUAGE + +#include <kernel_structs.h> +#include <offsets.h> +#include <toolchain.h> +#include <sections.h> +#include <soc.h> + +/* exports */ +GTEXT(__soc_is_irq) +GTEXT(__soc_handle_irq) + +/* + * SOC-specific function to handle pending IRQ number generating the interrupt. + * Exception number is given as parameter via register a0. + */ +SECTION_FUNC(exception.other, __soc_handle_irq) + /* Clear exception number from CSR mip register */ + li t1, 1 + sll t0, t1, a0 + csrrc t1, mip, t0 + + /* Return */ + jalr x0, ra + + +/* + * SOC-specific function to determine if the exception is the result of a + * an interrupt or an exception + * return 1 (interrupt) or 0 (exception) + */ +SECTION_FUNC(exception.other, __soc_is_irq) + /* Get exception number from the mcause CSR register. */ + csrr t0, mcause + li t1, SOC_MCAUSE_IRQ_MASK + and t0, t0, t1 + + /* if IRQ number != RISCV_QEMU_TIMER_IRQ, not interrupt */ + li t1, RISCV_QEMU_TIMER_IRQ + addi a0, x0, 0 + bne t0, t1, not_interrupt + addi a0, a0, 1 + +not_interrupt: + /* return */ + jalr x0, ra diff --git a/arch/riscv32/soc/riscv32-qemu/vector.S b/arch/riscv32/soc/riscv32-qemu/vector.S new file mode 100644 index 000000000..761b2fddb --- /dev/null +++ b/arch/riscv32/soc/riscv32-qemu/vector.S @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2016 Jean-Paul Etienne <fractalclone@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _ASMLANGUAGE + +#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 |