1
0
Fork 0
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:
Inochi Amaoto 2024-05-12 20:16:37 +08:00 committed by Alan Carvalho de Assis
parent 5f70307111
commit b35f7aed48
7 changed files with 248 additions and 40 deletions

View file

@ -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>`_.

View file

@ -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"

View 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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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;
}

View file

@ -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;