summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorJean-Paul Etienne <fractalclone@gmail.com>2017-01-11 00:24:30 +0100
committerAndrew Boie <andrew.p.boie@intel.com>2017-01-13 19:57:51 +0000
commitdae36b97e8fa2da5c4dbda2ddf53a98765a3fc0f (patch)
tree3a80409774dc9337c424a0b071713c991fae7ef2 /arch
parent9f418fe94400a69b89298c4831ee1ba41f1dbccc (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/Kbuild7
-rw-r--r--arch/riscv32/soc/riscv32-qemu/Kconfig.defconfig43
-rw-r--r--arch/riscv32/soc/riscv32-qemu/Kconfig.soc2
-rw-r--r--arch/riscv32/soc/riscv32-qemu/Makefile1
-rw-r--r--arch/riscv32/soc/riscv32-qemu/linker.ld21
-rw-r--r--arch/riscv32/soc/riscv32-qemu/qemu_irq.c72
-rw-r--r--arch/riscv32/soc/riscv32-qemu/soc.h82
-rw-r--r--arch/riscv32/soc/riscv32-qemu/soc_irq.S62
-rw-r--r--arch/riscv32/soc/riscv32-qemu/vector.S83
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