From b35f7aed4891920a387bfdc3b8f3b9f5f60b5e55 Mon Sep 17 00:00:00 2001 From: Inochi Amaoto Date: Sun, 12 May 2024 20:16:37 +0800 Subject: [PATCH] arch/risc-v: qemu: add AIA support Implement AIA support for qemu rv-virt. Signed-off-by: Inochi Amaoto --- .../risc-v/qemu-rv/boards/rv-virt/index.rst | 16 ++- arch/risc-v/src/qemu-rv/chip.h | 1 + .../src/qemu-rv/hardware/qemu_rv_aplic.h | 36 +++++ .../src/qemu-rv/hardware/qemu_rv_clint.h | 2 + .../src/qemu-rv/hardware/qemu_rv_memorymap.h | 8 ++ arch/risc-v/src/qemu-rv/qemu_rv_irq.c | 99 +++++++++++++- .../risc-v/src/qemu-rv/qemu_rv_irq_dispatch.c | 126 +++++++++++++----- 7 files changed, 248 insertions(+), 40 deletions(-) create mode 100644 arch/risc-v/src/qemu-rv/hardware/qemu_rv_aplic.h diff --git a/Documentation/platforms/risc-v/qemu-rv/boards/rv-virt/index.rst b/Documentation/platforms/risc-v/qemu-rv/boards/rv-virt/index.rst index 9a17aae940..cc9b7aa0b9 100644 --- a/Documentation/platforms/risc-v/qemu-rv/boards/rv-virt/index.rst +++ b/Documentation/platforms/risc-v/qemu-rv/boards/rv-virt/index.rst @@ -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 `_. diff --git a/arch/risc-v/src/qemu-rv/chip.h b/arch/risc-v/src/qemu-rv/chip.h index 604aca3c2f..005ce39459 100644 --- a/arch/risc-v/src/qemu-rv/chip.h +++ b/arch/risc-v/src/qemu-rv/chip.h @@ -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" diff --git a/arch/risc-v/src/qemu-rv/hardware/qemu_rv_aplic.h b/arch/risc-v/src/qemu-rv/hardware/qemu_rv_aplic.h new file mode 100644 index 0000000000..699757abaa --- /dev/null +++ b/arch/risc-v/src/qemu-rv/hardware/qemu_rv_aplic.h @@ -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 + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define QEMU_RV_APLIC_NR_IRQ 0x60 + +#endif /* __ARCH_RISCV_SRC_QEMU_RV_HARDWARE_QEMU_RV_APLIC_H */ diff --git a/arch/risc-v/src/qemu-rv/hardware/qemu_rv_clint.h b/arch/risc-v/src/qemu-rv/hardware/qemu_rv_clint.h index 65014cc26c..b385ebd08c 100644 --- a/arch/risc-v/src/qemu-rv/hardware/qemu_rv_clint.h +++ b/arch/risc-v/src/qemu-rv/hardware/qemu_rv_clint.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 */ diff --git a/arch/risc-v/src/qemu-rv/hardware/qemu_rv_memorymap.h b/arch/risc-v/src/qemu-rv/hardware/qemu_rv_memorymap.h index ce821fe32c..420cefefe9 100644 --- a/arch/risc-v/src/qemu-rv/hardware/qemu_rv_memorymap.h +++ b/arch/risc-v/src/qemu-rv/hardware/qemu_rv_memorymap.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 */ diff --git a/arch/risc-v/src/qemu-rv/qemu_rv_irq.c b/arch/risc-v/src/qemu-rv/qemu_rv_irq.c index 202cedab44..145a56d591 100644 --- a/arch/risc-v/src/qemu-rv/qemu_rv_irq.c +++ b/arch/risc-v/src/qemu-rv/qemu_rv_irq.c @@ -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; } diff --git a/arch/risc-v/src/qemu-rv/qemu_rv_irq_dispatch.c b/arch/risc-v/src/qemu-rv/qemu_rv_irq_dispatch.c index e397d74223..1821a4cd5b 100644 --- a/arch/risc-v/src/qemu-rv/qemu_rv_irq_dispatch.c +++ b/arch/risc-v/src/qemu-rv/qemu_rv_irq_dispatch.c @@ -32,6 +32,7 @@ #include #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;