forked from nuttx/nuttx-update
arch/risc-v: qemu: add AIA support
Implement AIA support for qemu rv-virt. Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
This commit is contained in:
parent
5f70307111
commit
b35f7aed48
7 changed files with 248 additions and 40 deletions
|
@ -34,7 +34,21 @@ Build and install ``qemu``::
|
|||
$ make
|
||||
$ sudo make install
|
||||
|
||||
QEMU 7.2.9 or later and OpenSBI v1.1 or later (usually shipped with QEMU) is required, to support RISC-V "Sstc" Extension. It is also recommended to use the latest QEMU and OpenSBI.
|
||||
Minimum Requirement
|
||||
===================
|
||||
|
||||
The table below lists all the minimum versions for QEMU and OpenSBI.
|
||||
For stability, it is also recommended to use the latest QEMU and OpenSBI.
|
||||
|
||||
+----------------------------+--------------+-----------------+
|
||||
| Extension | QEMU Version | OpenSBI Version |
|
||||
+============================+==============+=================+
|
||||
| No extension | 6.2.0 | v1.0 |
|
||||
+----------------------------+--------------+-----------------+
|
||||
| SSTC | 7.2.9 | v1.1 |
|
||||
+----------------------------+--------------+-----------------+
|
||||
| AIA | 8.2.0 | v1.2 |
|
||||
+----------------------------+--------------+-----------------+
|
||||
|
||||
For users who wish to use their own OpenSBI, please refer to `OpenSBI repository <https://github.com/riscv-software-src/opensbi>`_.
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "hardware/qemu_rv_clint.h"
|
||||
#include "hardware/qemu_rv_memorymap.h"
|
||||
#include "hardware/qemu_rv_plic.h"
|
||||
#include "hardware/qemu_rv_aplic.h"
|
||||
|
||||
#include "riscv_internal.h"
|
||||
#include "riscv_percpu.h"
|
||||
|
|
36
arch/risc-v/src/qemu-rv/hardware/qemu_rv_aplic.h
Normal file
36
arch/risc-v/src/qemu-rv/hardware/qemu_rv_aplic.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/****************************************************************************
|
||||
* arch/risc-v/src/qemu-rv/hardware/qemu_rv_aplic.h
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ARCH_RISCV_SRC_QEMU_RV_HARDWARE_QEMU_RV_APLIC_H
|
||||
#define __ARCH_RISCV_SRC_QEMU_RV_HARDWARE_QEMU_RV_APLIC_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define QEMU_RV_APLIC_NR_IRQ 0x60
|
||||
|
||||
#endif /* __ARCH_RISCV_SRC_QEMU_RV_HARDWARE_QEMU_RV_APLIC_H */
|
|
@ -34,10 +34,12 @@
|
|||
#define RISCV_CLINT_MSIP QEMU_RV_CLINT_MSIP
|
||||
#define RISCV_ACLINT_SSIP QEMU_RV_ACLINT_SSIP
|
||||
|
||||
#ifndef CONFIG_ARCH_RV_USE_IMSIC_IPI
|
||||
#ifdef CONFIG_ARCH_USE_S_MODE
|
||||
# define RISCV_IPI RISCV_ACLINT_SSIP
|
||||
#else
|
||||
# define RISCV_IPI RISCV_CLINT_MSIP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* __ARCH_RISCV_SRC_QEMU_RV_HARDWARE_QEMU_RV_CLINT_H */
|
||||
|
|
|
@ -33,4 +33,12 @@
|
|||
|
||||
#define QEMU_RV_RESET_BASE 0x100000
|
||||
|
||||
#ifdef CONFIG_ARCH_USE_S_MODE
|
||||
# define QEMU_RV_APLIC_BASE 0x0d000000
|
||||
# define QEMU_RV_IMSIC_BASE 0x28000000
|
||||
#else
|
||||
# define QEMU_RV_APLIC_BASE 0x0c000000
|
||||
# define QEMU_RV_IMSIC_BASE 0x24000000
|
||||
#endif
|
||||
|
||||
#endif /* __ARCH_RISCV_SRC_QEMU_RV_HARDWARE_QEMU_RV_MEMORYMAP_H */
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
#include "riscv_internal.h"
|
||||
#include "riscv_ipi.h"
|
||||
#include "riscv_aia.h"
|
||||
#include "chip.h"
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -52,8 +53,12 @@ void up_irqinitialize(void)
|
|||
|
||||
/* Disable all global interrupts */
|
||||
|
||||
#ifndef CONFIG_ARCH_RV_HAVE_APLIC
|
||||
putreg32(0x0, QEMU_RV_PLIC_ENABLE1);
|
||||
putreg32(0x0, QEMU_RV_PLIC_ENABLE2);
|
||||
#else
|
||||
riscv_aplic_disable_irqs(QEMU_RV_APLIC_BASE, QEMU_RV_APLIC_NR_IRQ);
|
||||
#endif
|
||||
|
||||
/* Colorize the interrupt stack for debug purposes */
|
||||
|
||||
|
@ -62,10 +67,31 @@ void up_irqinitialize(void)
|
|||
riscv_stack_color(g_intstackalloc, intstack_size);
|
||||
#endif
|
||||
|
||||
/* Set priority for all global interrupts to 1 (lowest) */
|
||||
|
||||
int id;
|
||||
|
||||
#ifdef CONFIG_ARCH_RV_HAVE_IMSIC
|
||||
/* Set default IRQ target hart index to 0 and EIID */
|
||||
|
||||
for (id = 0; id < QEMU_RV_APLIC_NR_IRQ; id++)
|
||||
{
|
||||
riscv_aplic_configure_irq(QEMU_RV_APLIC_BASE, id + 1, 0, id + 1);
|
||||
}
|
||||
|
||||
riscv_aplic_init_msi(QEMU_RV_APLIC_BASE, QEMU_RV_IMSIC_BASE, 0, 3, 0, 0);
|
||||
#elif defined(CONFIG_ARCH_RV_HAVE_APLIC)
|
||||
/* Set default IRQ target hart index to 0 and priority */
|
||||
|
||||
for (id = 0; id < QEMU_RV_APLIC_NR_IRQ; id++)
|
||||
{
|
||||
riscv_aplic_configure_irq(QEMU_RV_APLIC_BASE, id + 1,
|
||||
RISCV_APLIC_DEFAULT_PRIORITY, 0);
|
||||
}
|
||||
|
||||
riscv_aplic_init(QEMU_RV_APLIC_BASE, RISCV_APLIC_ENABLE_IDELIVERY,
|
||||
RISCV_APLIC_ENABLE_ITHRESHOLD);
|
||||
#else
|
||||
/* Set priority for all global interrupts to 1 (lowest) */
|
||||
|
||||
for (id = 1; id <= 52; id++)
|
||||
{
|
||||
putreg32(1, (uintptr_t)(QEMU_RV_PLIC_PRIORITY + 4 * id));
|
||||
|
@ -74,6 +100,7 @@ void up_irqinitialize(void)
|
|||
/* Set irq threshold to 0 (permits all global interrupts) */
|
||||
|
||||
putreg32(0, QEMU_RV_PLIC_THRESHOLD);
|
||||
#endif
|
||||
|
||||
/* Attach the common interrupt handler */
|
||||
|
||||
|
@ -84,8 +111,12 @@ void up_irqinitialize(void)
|
|||
|
||||
riscv_ipi_clear(0);
|
||||
|
||||
#ifdef CONFIG_ARCH_RV_USE_IMSIC_IPI
|
||||
riscv_imsic_local_eie_enable(RISCV_IMSIC_IPI_ID);
|
||||
#else
|
||||
up_enable_irq(RISCV_IRQ_SOFT);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SUPPRESS_INTERRUPTS
|
||||
|
||||
|
@ -119,6 +150,24 @@ void up_disable_irq(int irq)
|
|||
|
||||
CLEAR_CSR(CSR_IE, IE_TIE);
|
||||
}
|
||||
else if (irq == RISCV_IRQ_EXT)
|
||||
{
|
||||
/* Read m/sstatus & clear external interrupt enable in m/sie */
|
||||
|
||||
CLEAR_CSR(CSR_IE, IE_EIE);
|
||||
|
||||
#ifdef CONFIG_ARCH_RV_HAVE_IMSIC
|
||||
/* Set IMSIC irq threshold to 0 (permits all global interrupts) */
|
||||
|
||||
riscv_imsic_csr_write(ISELECT_EITHRESHOLD,
|
||||
RISCV_IMSIC_DISABLE_EITHRESHOLD);
|
||||
|
||||
/* Enable irq delivery for IMSIC */
|
||||
|
||||
riscv_imsic_csr_write(ISELECT_EIDELIVERY,
|
||||
RISCV_IMSIC_DISABLE_EIDELIVERY);
|
||||
#endif
|
||||
}
|
||||
else if (irq > RISCV_IRQ_EXT)
|
||||
{
|
||||
extirq = irq - RISCV_IRQ_EXT;
|
||||
|
@ -127,8 +176,15 @@ void up_disable_irq(int irq)
|
|||
|
||||
if (0 <= extirq && extirq <= 63)
|
||||
{
|
||||
#ifndef CONFIG_ARCH_RV_HAVE_APLIC
|
||||
modifyreg32(QEMU_RV_PLIC_ENABLE1 + (4 * (extirq / 32)),
|
||||
1 << (extirq % 32), 0);
|
||||
#else
|
||||
riscv_aplic_disable_irq(QEMU_RV_APLIC_BASE, extirq);
|
||||
#endif
|
||||
#ifdef CONFIG_ARCH_RV_HAVE_IMSIC
|
||||
riscv_imsic_local_eie_disable(extirq);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -161,6 +217,24 @@ void up_enable_irq(int irq)
|
|||
|
||||
SET_CSR(CSR_IE, IE_TIE);
|
||||
}
|
||||
else if (irq == RISCV_IRQ_EXT)
|
||||
{
|
||||
/* Read m/sstatus & set external interrupt enable in m/sie */
|
||||
|
||||
SET_CSR(CSR_IE, IE_EIE);
|
||||
|
||||
#ifdef CONFIG_ARCH_RV_HAVE_IMSIC
|
||||
/* Set IMSIC irq threshold to 0 (permits all global interrupts) */
|
||||
|
||||
riscv_imsic_csr_write(ISELECT_EITHRESHOLD,
|
||||
RISCV_IMSIC_ENABLE_EITHRESHOLD);
|
||||
|
||||
/* Enable irq delivery for IMSIC */
|
||||
|
||||
riscv_imsic_csr_write(ISELECT_EIDELIVERY,
|
||||
RISCV_IMSIC_ENABLE_EIDELIVERY);
|
||||
#endif
|
||||
}
|
||||
else if (irq > RISCV_IRQ_EXT)
|
||||
{
|
||||
extirq = irq - RISCV_IRQ_EXT;
|
||||
|
@ -169,8 +243,18 @@ void up_enable_irq(int irq)
|
|||
|
||||
if (0 <= extirq && extirq <= 63)
|
||||
{
|
||||
#ifndef CONFIG_ARCH_RV_HAVE_APLIC
|
||||
modifyreg32(QEMU_RV_PLIC_ENABLE1 + (4 * (extirq / 32)),
|
||||
0, 1 << (extirq % 32));
|
||||
#else
|
||||
riscv_aplic_configure_irq(QEMU_RV_APLIC_BASE, extirq,
|
||||
RISCV_APLIC_SOURCECFG_SM_EDGE_RISE,
|
||||
riscv_mhartid());
|
||||
#ifdef CONFIG_ARCH_RV_HAVE_IMSIC
|
||||
riscv_imsic_local_eie_enable(extirq);
|
||||
#endif
|
||||
riscv_aplic_enable_irq(QEMU_RV_APLIC_BASE, extirq);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -185,11 +269,20 @@ irqstate_t up_irq_enable(void)
|
|||
|
||||
/* Enable external interrupts (mie/sie) */
|
||||
|
||||
SET_CSR(CSR_IE, IE_EIE);
|
||||
up_enable_irq(RISCV_IRQ_EXT);
|
||||
|
||||
/* Read and enable global interrupts (M/SIE) in m/sstatus */
|
||||
|
||||
oldstat = READ_AND_SET_CSR(CSR_STATUS, STATUS_IE);
|
||||
|
||||
/* Enable APLIC irq */
|
||||
#ifdef CONFIG_ARCH_RV_HAVE_IMSIC
|
||||
modifyreg32(QEMU_RV_APLIC_BASE + RISCV_APLIC_DOMAINCFG, 0x0,
|
||||
RISCV_APLIC_DOMAINCFG_IE | RISCV_APLIC_DOMAINCFG_DM);
|
||||
#elif defined(CONFIG_ARCH_RV_HAVE_APLIC)
|
||||
modifyreg32(QEMU_RV_APLIC_BASE + RISCV_APLIC_DOMAINCFG, 0x0,
|
||||
RISCV_APLIC_DOMAINCFG_IE);
|
||||
#endif
|
||||
|
||||
return oldstat;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <sys/types.h>
|
||||
|
||||
#include "riscv_internal.h"
|
||||
#include "riscv_aia.h"
|
||||
#include "hardware/qemu_rv_memorymap.h"
|
||||
#include "hardware/qemu_rv_plic.h"
|
||||
|
||||
|
@ -39,49 +40,102 @@
|
|||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_ARCH_RV32
|
||||
# define RV_IRQ_MASK 27
|
||||
#else
|
||||
# define RV_IRQ_MASK 59
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* riscv_dispatch_irq
|
||||
****************************************************************************/
|
||||
|
||||
void *riscv_dispatch_irq(uintreg_t vector, uintreg_t *regs)
|
||||
#ifdef CONFIG_ARCH_RV_HAVE_IMSIC
|
||||
static void *riscv_dispatch_irq_ext(uintreg_t irq, uintreg_t *regs)
|
||||
{
|
||||
int irq = (vector >> RV_IRQ_MASK) | (vector & 0xf);
|
||||
int extirq;
|
||||
|
||||
/* Firstly, check if the irq is machine external interrupt */
|
||||
|
||||
if (RISCV_IRQ_EXT == irq)
|
||||
while ((extirq = SWAP_CSR(CSR_TOPEI, 0)) != 0)
|
||||
{
|
||||
uintptr_t val = getreg32(QEMU_RV_PLIC_CLAIM);
|
||||
|
||||
/* Add the value to nuttx irq which is offset to the mext */
|
||||
|
||||
irq += val;
|
||||
}
|
||||
|
||||
/* EXT means no interrupt */
|
||||
|
||||
if (RISCV_IRQ_EXT != irq)
|
||||
{
|
||||
/* Deliver the IRQ */
|
||||
|
||||
regs = riscv_doirq(irq, regs);
|
||||
}
|
||||
|
||||
if (RISCV_IRQ_EXT <= irq)
|
||||
{
|
||||
/* Then write PLIC_CLAIM to clear pending in PLIC */
|
||||
|
||||
putreg32(irq - RISCV_IRQ_EXT, QEMU_RV_PLIC_CLAIM);
|
||||
extirq = (extirq >> TOPI_IID_SHIFT) + irq;
|
||||
regs = riscv_doirq(extirq, regs);
|
||||
}
|
||||
|
||||
return regs;
|
||||
}
|
||||
#elif defined(CONFIG_ARCH_RV_HAVE_APLIC)
|
||||
static void *riscv_dispatch_irq_ext(uintreg_t irq, uintreg_t *regs)
|
||||
{
|
||||
int extirq;
|
||||
int hartid = riscv_mhartid();
|
||||
uintptr_t aplic_base = RISCV_APLIC_IDC(QEMU_RV_APLIC_BASE, hartid) +
|
||||
RISCV_APLIC_IDC_CLAIMI;
|
||||
|
||||
while ((extirq = getreg32(aplic_base)) != 0)
|
||||
{
|
||||
extirq = (extirq >> RISCV_APLIC_IDC_TOPI_ID_SHIFT) + irq;
|
||||
regs = riscv_doirq(extirq, regs);
|
||||
}
|
||||
|
||||
return regs;
|
||||
}
|
||||
#else
|
||||
static void *riscv_dispatch_irq_ext(uintreg_t irq, uintreg_t *regs)
|
||||
{
|
||||
int extirq;
|
||||
|
||||
while ((extirq = getreg32(QEMU_RV_PLIC_CLAIM)) != 0)
|
||||
{
|
||||
regs = riscv_doirq(irq + extirq, regs);
|
||||
putreg32(extirq, QEMU_RV_PLIC_CLAIM);
|
||||
}
|
||||
|
||||
return regs;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_RV_EXT_AIA
|
||||
static void *riscv_dispatch_async_irq(uintreg_t irq, uintreg_t *regs)
|
||||
{
|
||||
while ((irq = READ_CSR(CSR_TOPI)) != 0)
|
||||
{
|
||||
irq = (irq >> TOPI_IID_SHIFT) + RISCV_IRQ_ASYNC;
|
||||
|
||||
if (RISCV_IRQ_EXT == irq)
|
||||
{
|
||||
regs = riscv_dispatch_irq_ext(irq, regs);
|
||||
}
|
||||
else
|
||||
{
|
||||
regs = riscv_doirq(irq, regs);
|
||||
}
|
||||
}
|
||||
|
||||
return regs;
|
||||
}
|
||||
#else
|
||||
static void *riscv_dispatch_async_irq(uintreg_t irq, uintreg_t *regs)
|
||||
{
|
||||
irq += RISCV_IRQ_ASYNC;
|
||||
|
||||
if (irq == RISCV_IRQ_EXT)
|
||||
{
|
||||
regs = riscv_dispatch_irq_ext(irq, regs);
|
||||
}
|
||||
else
|
||||
{
|
||||
regs = riscv_doirq(irq, regs);
|
||||
}
|
||||
|
||||
return regs;
|
||||
}
|
||||
#endif
|
||||
|
||||
void *riscv_dispatch_irq(uintreg_t vector, uintreg_t *regs)
|
||||
{
|
||||
int irq = vector & (~RISCV_IRQ_BIT);
|
||||
|
||||
if ((vector & RISCV_IRQ_BIT) != 0)
|
||||
{
|
||||
regs = riscv_dispatch_async_irq(irq, regs);
|
||||
}
|
||||
else
|
||||
{
|
||||
regs = riscv_doirq(irq, regs);
|
||||
}
|
||||
|
||||
return regs;
|
||||
|
|
Loading…
Reference in a new issue