You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2023/10/12 20:56:31 UTC
[nuttx] branch master updated: arm64: Add support for FIQ interrupts
This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new cef8c598c7 arm64: Add support for FIQ interrupts
cef8c598c7 is described below
commit cef8c598c7019f04d283f8399f5314a318564b30
Author: hujun5 <hu...@xiaomi.com>
AuthorDate: Mon Sep 18 12:28:22 2023 +0800
arm64: Add support for FIQ interrupts
To compile arm64 NuttX, use the following command:
./tools/configure.sh -l qemu-armv8a:nsh_fiq
To run,use the following command
qemu-system-aarch64 -cpu cortex-a53 -nographic -machine virt,virtualization=on,gic-version=3 -net none -chardev stdio,id=con,mux=on -serial chardev:con -mon chardev=con,mode=readline -kernel ./nuttx
Signed-off-by: hujun5 <hu...@xiaomi.com>
---
arch/arm64/Kconfig | 8 ++
arch/arm64/include/irq.h | 8 ++
arch/arm64/src/common/arm64_cpustart.c | 12 ++
arch/arm64/src/common/arm64_gicv3.c | 122 +++++++++++++++++++--
arch/arm64/src/common/arm64_initialize.c | 11 ++
arch/arm64/src/common/arm64_internal.h | 11 ++
arch/arm64/src/common/arm64_vector_table.S | 6 +-
arch/arm64/src/common/arm64_vectors.S | 74 ++++++++++++-
.../qemu/qemu-armv8a/configs/nsh_fiq/defconfig | 75 +++++++++++++
9 files changed, 310 insertions(+), 17 deletions(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index fedc987820..1db0658eb4 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -233,6 +233,14 @@ config ARM_HAVE_NEON
---help---
Decide whether support NEON instruction
+config ARM64_DECODEFIQ
+ bool "FIQ Handler"
+ default n
+ ---help---
+ Select this option if your platform supports the function
+ arm_decodefiq(). This is used primarily to support secure TrustZone
+ interrupts received on the FIQ vector.
+
config ARM_GIC_VERSION
int "GIC version"
default 2 if ARCH_CHIP_A64
diff --git a/arch/arm64/include/irq.h b/arch/arm64/include/irq.h
index 5e5fa781fb..ccaf44e1b5 100644
--- a/arch/arm64/include/irq.h
+++ b/arch/arm64/include/irq.h
@@ -314,7 +314,11 @@ static inline irqstate_t up_irq_save(void)
__asm__ __volatile__
(
"mrs %0, daif\n"
+#ifdef CONFIG_ARM64_DECODEFIQ
+ "msr daifset, #3\n"
+#else
"msr daifset, #2\n"
+#endif
: "=r" (flags)
:
: "memory"
@@ -332,7 +336,11 @@ static inline irqstate_t up_irq_enable(void)
__asm__ __volatile__
(
"mrs %0, daif\n"
+#ifdef CONFIG_ARM64_DECODEFIQ
+ "msr daifclr, #3\n"
+#else
"msr daifclr, #2\n"
+#endif
: "=r" (flags)
:
: "memory"
diff --git a/arch/arm64/src/common/arm64_cpustart.c b/arch/arm64/src/common/arm64_cpustart.c
index a57eb93c09..231203276e 100644
--- a/arch/arm64/src/common/arm64_cpustart.c
+++ b/arch/arm64/src/common/arm64_cpustart.c
@@ -78,6 +78,13 @@ volatile uint64_t *g_cpu_int_stacktop[CONFIG_SMP_NCPUS] =
(uint64_t *)(g_interrupt_stacks[0] + INTSTACK_SIZE),
};
+#ifdef CONFIG_ARM64_DECODEFIQ
+volatile uint64_t *g_cpu_int_fiq_stacktop[CONFIG_SMP_NCPUS] =
+{
+ (uint64_t *)(g_interrupt_fiq_stacks[0] + INTSTACK_SIZE),
+};
+#endif
+
/****************************************************************************
* Private data
****************************************************************************/
@@ -158,6 +165,11 @@ static void arm64_start_cpu(int cpu_num, char *stack, int stack_sz,
g_cpu_int_stacktop[cpu_num] =
(uint64_t *)(g_interrupt_stacks[cpu_num] + INTSTACK_SIZE);
+#ifdef CONFIG_ARM64_DECODEFIQ
+ g_cpu_int_fiq_stacktop[cpu_num] =
+ (uint64_t *)(g_interrupt_fiq_stacks[cpu_num] + INTSTACK_SIZE);
+#endif
+
ARM64_DSB();
/* store mpid last as this is our synchronization point */
diff --git a/arch/arm64/src/common/arm64_gicv3.c b/arch/arm64/src/common/arm64_gicv3.c
index e4dc93212b..4453fc7ee9 100644
--- a/arch/arm64/src/common/arm64_gicv3.c
+++ b/arch/arm64/src/common/arm64_gicv3.c
@@ -60,6 +60,15 @@
#define IGROUPR_VAL 0xFFFFFFFFU
+#ifdef CONFIG_ARM64_DECODEFIQ
+
+/* Config SGI8 ~ SGI15 as group0, to signal fiq */
+
+#define IGROUPR_SGI_VAL 0xFFFF00FFU
+#else
+#define IGROUPR_SGI_VAL 0xFFFFFFFFU
+#endif
+
/***************************************************************************
* Private Data
***************************************************************************/
@@ -273,7 +282,7 @@ bool arm64_gic_irq_is_enabled(unsigned int intid)
return (val & mask) != 0;
}
-unsigned int arm64_gic_get_active(void)
+unsigned int arm64_gic_get_active_irq(void)
{
int intid;
@@ -284,7 +293,20 @@ unsigned int arm64_gic_get_active(void)
return intid;
}
-void arm64_gic_eoi(unsigned int intid)
+#ifdef CONFIG_ARM64_DECODEFIQ
+unsigned int arm64_gic_get_active_fiq(void)
+{
+ int intid;
+
+ /* (Pending -> Active / AP) or (AP -> AP) */
+
+ intid = read_sysreg(ICC_IAR0_EL1);
+
+ return intid;
+}
+#endif
+
+void aarm64_gic_eoi_irq(unsigned int intid)
{
/* Interrupt request deassertion from peripheral to GIC happens
* by clearing interrupt condition by a write to the peripheral
@@ -304,6 +326,28 @@ void arm64_gic_eoi(unsigned int intid)
write_sysreg(intid, ICC_EOIR1_EL1);
}
+#ifdef CONFIG_ARM64_DECODEFIQ
+void arm64_gic_eoi_fiq(unsigned int intid)
+{
+ /* Interrupt request deassertion from peripheral to GIC happens
+ * by clearing interrupt condition by a write to the peripheral
+ * register. It is desired that the write transfer is complete
+ * before the core tries to change GIC state from 'AP/Active' to
+ * a new state on seeing 'EOI write'.
+ * Since ICC interface writes are not ordered against Device
+ * memory writes, a barrier is required to ensure the ordering.
+ * The dsb will also ensure *completion* of previous writes with
+ * DEVICE nGnRnE attribute.
+ */
+
+ ARM64_DSB();
+
+ /* (AP -> Pending) Or (Active -> Inactive) or (AP to AP) nested case */
+
+ write_sysreg(intid, ICC_EOIR0_EL1);
+}
+#endif
+
static int arm64_gic_send_sgi(unsigned int sgi_id, uint64_t target_aff,
uint16_t target_list)
{
@@ -311,7 +355,10 @@ static int arm64_gic_send_sgi(unsigned int sgi_id, uint64_t target_aff,
uint32_t aff2;
uint32_t aff1;
uint64_t sgi_val;
+ uint32_t regval;
+ unsigned long base;
+ base = gic_get_rdist() + GICR_SGI_BASE_OFF;
assert(GIC_IS_SGI(sgi_id));
/* Extract affinity fields from target */
@@ -324,7 +371,18 @@ static int arm64_gic_send_sgi(unsigned int sgi_id, uint64_t target_aff,
target_list);
ARM64_DSB();
- write_sysreg(sgi_val, ICC_SGI1R);
+
+ regval = getreg32(IGROUPR(base, 0));
+
+ if (regval & BIT(sgi_id))
+ {
+ write_sysreg(sgi_val, ICC_SGI1R); /* Group 1 */
+ }
+ else
+ {
+ write_sysreg(sgi_val, ICC_SGI0R_EL1); /* Group 0 */
+ }
+
ARM64_ISB();
return 0;
@@ -416,7 +474,7 @@ static void gicv3_cpuif_init(void)
* All interrupts will be delivered as irq
*/
- putreg32(IGROUPR_VAL, IGROUPR(base, 0));
+ putreg32(IGROUPR_SGI_VAL, IGROUPR(base, 0));
putreg32(BIT64_MASK(GIC_NUM_INTR_PER_REG), IGROUPMODR(base, 0));
/* Configure default priorities for SGI 0:15 and PPI 0:15. */
@@ -455,6 +513,10 @@ static void gicv3_cpuif_init(void)
/* Allow group1 interrupts */
write_sysreg(1, ICC_IGRPEN1_EL1);
+
+#ifdef CONFIG_ARM64_DECODEFIQ
+ write_sysreg(1, ICC_IGRPEN0_EL1);
+#endif
}
static void gicv3_dist_init(void)
@@ -462,6 +524,7 @@ static void gicv3_dist_init(void)
unsigned int num_ints;
unsigned int intid;
unsigned int idx;
+ unsigned int regval;
unsigned long base = GIC_DIST_BASE;
num_ints = getreg32(GICD_TYPER);
@@ -546,14 +609,24 @@ static void gicv3_dist_init(void)
* BIT(1), we can reuse them.
*/
- putreg32(BIT(GICD_CTRL_ARE_S) | BIT(GICD_CTLR_ENABLE_G1NS),
- GICD_CTLR);
+ regval = BIT(GICD_CTRL_ARE_S) | BIT(GICD_CTLR_ENABLE_G1NS);
+
+#ifdef CONFIG_ARM64_DECODEFIQ
+ regval |= BIT(GICD_CTLR_ENABLE_G0);
+#endif
+
+ putreg32(regval, GICD_CTLR);
#else
/* Enable distributor with ARE */
- putreg32(BIT(GICD_CTRL_ARE_NS) | BIT(GICD_CTLR_ENABLE_G1NS),
- GICD_CTLR);
+ regval = BIT(GICD_CTRL_ARE_NS) | BIT(GICD_CTLR_ENABLE_G1NS);
+
+#ifdef CONFIG_ARM64_DECODEFIQ
+ regval |= BIT(GICD_CTLR_ENABLE_G0);
+#endif
+
+ putreg32(regval, GICD_CTLR);
#endif
#ifdef CONFIG_SMP
@@ -682,7 +755,35 @@ uint64_t * arm64_decodeirq(uint64_t * regs)
/* Read the interrupt acknowledge register and get the interrupt ID */
- irq = arm64_gic_get_active();
+ irq = arm64_gic_get_active_irq();
+
+ /* Ignore spurions IRQs. ICCIAR will report 1023 if there is no pending
+ * interrupt.
+ */
+
+ DEBUGASSERT(irq < NR_IRQS || irq == 1023);
+ if (irq < NR_IRQS)
+ {
+ /* Dispatch the interrupt */
+
+ regs = arm64_doirq(irq, regs);
+ }
+
+ /* Write to the end-of-interrupt register */
+
+ aarm64_gic_eoi_irq(irq);
+
+ return regs;
+}
+
+#ifdef CONFIG_ARM64_DECODEFIQ
+uint64_t * arm64_decodefiq(uint64_t * regs)
+{
+ int irq;
+
+ /* Read the interrupt acknowledge register and get the interrupt ID */
+
+ irq = arm64_gic_get_active_fiq();
/* Ignore spurions IRQs. ICCIAR will report 1023 if there is no pending
* interrupt.
@@ -698,10 +799,11 @@ uint64_t * arm64_decodeirq(uint64_t * regs)
/* Write to the end-of-interrupt register */
- arm64_gic_eoi(irq);
+ arm64_gic_eoi_fiq(irq);
return regs;
}
+#endif
static int gic_validate_dist_version(void)
{
diff --git a/arch/arm64/src/common/arm64_initialize.c b/arch/arm64/src/common/arm64_initialize.c
index 6d0f9a039f..3cb4aaa325 100644
--- a/arch/arm64/src/common/arm64_initialize.c
+++ b/arch/arm64/src/common/arm64_initialize.c
@@ -71,11 +71,22 @@ INIT_STACK_ARRAY_DEFINE(g_cpu_idlestackalloc, CONFIG_SMP_NCPUS,
SMP_STACK_SIZE);
INIT_STACK_ARRAY_DEFINE(g_interrupt_stacks, CONFIG_SMP_NCPUS,
INTSTACK_SIZE);
+
+#ifdef CONFIG_ARM64_DECODEFIQ
+INIT_STACK_ARRAY_DEFINE(g_interrupt_fiq_stacks, CONFIG_SMP_NCPUS,
+ INTSTACK_SIZE);
+#endif
+
#else
/* idle thread stack for primary core */
INIT_STACK_DEFINE(g_idle_stack, CONFIG_IDLETHREAD_STACKSIZE);
INIT_STACK_DEFINE(g_interrupt_stack, INTSTACK_SIZE);
+
+#ifdef CONFIG_ARM64_DECODEFIQ
+INIT_STACK_DEFINE(g_interrupt_fiq_stack, INTSTACK_SIZE);
+#endif
+
#endif
/****************************************************************************
diff --git a/arch/arm64/src/common/arm64_internal.h b/arch/arm64/src/common/arm64_internal.h
index 5ead8ca714..a1a98d456f 100644
--- a/arch/arm64/src/common/arm64_internal.h
+++ b/arch/arm64/src/common/arm64_internal.h
@@ -162,6 +162,12 @@ INIT_STACK_ARRAY_DEFINE_EXTERN(g_cpu_idlestackalloc, CONFIG_SMP_NCPUS,
SMP_STACK_SIZE);
INIT_STACK_ARRAY_DEFINE_EXTERN(g_interrupt_stacks, CONFIG_SMP_NCPUS,
INTSTACK_SIZE);
+
+#ifdef CONFIG_ARM64_DECODEFIQ
+INIT_STACK_ARRAY_DEFINE_EXTERN(g_interrupt_fiq_stacks, CONFIG_SMP_NCPUS,
+ INTSTACK_SIZE);
+#endif
+
uintptr_t arm64_intstack_alloc(void);
uintptr_t arm64_intstack_top(void);
#else
@@ -169,6 +175,11 @@ uintptr_t arm64_intstack_top(void);
INIT_STACK_DEFINE_EXTERN(g_idle_stack, CONFIG_IDLETHREAD_STACKSIZE);
INIT_STACK_DEFINE_EXTERN(g_interrupt_stack, INTSTACK_SIZE);
+
+#ifdef CONFIG_ARM64_DECODEFIQ
+INIT_STACK_DEFINE_EXTERN(g_interrupt_fiq_stack, INTSTACK_SIZE);
+#endif
+
#endif
/* This is the beginning of heap as provided from arm64_head.S.
diff --git a/arch/arm64/src/common/arm64_vector_table.S b/arch/arm64/src/common/arm64_vector_table.S
index f153bbe69f..1f9fd33243 100644
--- a/arch/arm64/src/common/arm64_vector_table.S
+++ b/arch/arm64/src/common/arm64_vector_table.S
@@ -151,7 +151,7 @@ SECTION_SUBSEC_FUNC(exc_vector_table,_vector_table_section,_vector_table)
.align 7
arm64_enter_exception x0, x1
- b arm64_irq_spurious
+ b arm64_fiq_handler
/* Current EL with SP0 / SError */
@@ -175,7 +175,7 @@ SECTION_SUBSEC_FUNC(exc_vector_table,_vector_table_section,_vector_table)
.align 7
arm64_enter_exception x0, x1
- b arm64_irq_spurious
+ b arm64_fiq_handler
/* Current EL with SPx / SError */
@@ -199,7 +199,7 @@ SECTION_SUBSEC_FUNC(exc_vector_table,_vector_table_section,_vector_table)
.align 7
arm64_enter_exception x0, x1
- b arm64_irq_spurious
+ b arm64_fiq_handler
/* Lower EL using AArch64 / SError */
diff --git a/arch/arm64/src/common/arm64_vectors.S b/arch/arm64/src/common/arm64_vectors.S
index e44ef8aa69..08b6a6f901 100644
--- a/arch/arm64/src/common/arm64_vectors.S
+++ b/arch/arm64/src/common/arm64_vectors.S
@@ -336,7 +336,7 @@ exc_handle:
GTEXT(arm64_irq_handler)
SECTION_FUNC(text, arm64_irq_handler)
- /* switch to IRQ stack and save current sp on it. */
+ /* Switch to IRQ stack and save current sp on it. */
#ifdef CONFIG_SMP
get_cpu_id x1
ldr x0, =(g_cpu_int_stacktop)
@@ -345,7 +345,7 @@ SECTION_FUNC(text, arm64_irq_handler)
#else
ldr x0, =(g_interrupt_stack + CONFIG_ARCH_INTERRUPTSTACK)
#endif
- /* save the task's stack and switch irq stack */
+ /* Save the task's stack and switch irq stack */
mov x1, sp
mov sp, x0
@@ -427,8 +427,9 @@ SECTION_FUNC(text, arm64_mode32_error)
b arm64_exit_exception
-GTEXT(arm64_irq_spurious)
-SECTION_FUNC(text, arm64_irq_spurious)
+GTEXT(arm64_fiq_handler)
+SECTION_FUNC(text, arm64_fiq_handler)
+#ifndef CONFIG_ARM64_DECODEFIQ
arm64_exception_context_save x0 x1 sp
mov x1, sp
@@ -439,3 +440,68 @@ SECTION_FUNC(text, arm64_irq_spurious)
/* Return here only in case of recoverable error */
b arm64_exit_exception
+#else
+ /* Switch to FIQ stack and save current sp on it. */
+#ifdef CONFIG_SMP
+ get_cpu_id x1
+ ldr x0, =(g_cpu_int_fiq_stacktop)
+ lsl x1, x1, #3
+ ldr x0, [x0, x1]
+#else
+ ldr x0, =(g_interrupt_fiq_stack + CONFIG_ARCH_INTERRUPTSTACK)
+#endif
+ /* Save the task's stack and switch fiq stack */
+
+ mov x1, sp
+ mov sp, x0
+ str x1, [sp, #-16]!
+
+ mov x0, x1 /* x0 = reg frame */
+
+ /* Call arm64_decodefiq() on the interrupt stack
+ * with interrupts disabled
+ */
+
+ bl arm64_decodefiq
+
+ /* Upon return from arm64_decodefiq, x0 holds the pointer to the
+ * call reg context area, which can be use to restore context.
+ * This may or may not be the same value that was passed to arm64_decodefiq:
+ * It will differ if a context switch is required.
+ */
+
+ ldr x1, [sp], #16
+
+ /* retrieve the task's stack. */
+
+ mov sp, x1
+
+ cmp x0, x1
+ beq fiq_exit
+
+
+#ifdef CONFIG_SMP
+ /* Notes:
+ * Complete any pending TLB or cache maintenance on this CPU in case
+ * the thread migrates to a different CPU.
+ * This full barrier is also required by the membarrier system
+ * call.
+ */
+ dsb ish
+
+#endif
+
+ /* Switch thread
+ * - x0: restore task reg context, return by arm64_decodefiq,
+ * - x1: save task reg context, save before call arm64_decodefiq
+ * call arm64_context_switch(x0) to switch
+ */
+ bl arm64_context_switch
+#ifdef CONFIG_ARCH_FPU
+ /* when the fpu trap is handled */
+
+ b arm64_exit_exc_fpu_done
+#endif
+fiq_exit:
+ b arm64_exit_exception
+#endif
diff --git a/boards/arm64/qemu/qemu-armv8a/configs/nsh_fiq/defconfig b/boards/arm64/qemu/qemu-armv8a/configs/nsh_fiq/defconfig
new file mode 100644
index 0000000000..8976c6914c
--- /dev/null
+++ b/boards/arm64/qemu/qemu-armv8a/configs/nsh_fiq/defconfig
@@ -0,0 +1,75 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed .config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that includes your
+# modifications.
+#
+CONFIG_ARCH="arm64"
+CONFIG_ARCH_ARM64=y
+CONFIG_ARCH_BOARD="qemu-armv8a"
+CONFIG_ARCH_BOARD_QEMU_ARMV8A=y
+CONFIG_ARCH_CHIP="qemu"
+CONFIG_ARCH_CHIP_QEMU=y
+CONFIG_ARCH_CHIP_QEMU_A53=y
+CONFIG_ARCH_EARLY_PRINT=y
+CONFIG_ARCH_INTERRUPTSTACK=4096
+CONFIG_ARM64_DECODEFIQ=y
+CONFIG_ARM64_SEMIHOSTING_HOSTFS=y
+CONFIG_ARM64_SEMIHOSTING_HOSTFS_CACHE_COHERENCE=y
+CONFIG_ARM64_STRING_FUNCTION=y
+CONFIG_BUILTIN=y
+CONFIG_DEBUG_ASSERTIONS=y
+CONFIG_DEBUG_FEATURES=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SCHED=y
+CONFIG_DEBUG_SCHED_ERROR=y
+CONFIG_DEBUG_SCHED_INFO=y
+CONFIG_DEBUG_SCHED_WARN=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DEFAULT_TASK_STACKSIZE=8192
+CONFIG_DEVICE_TREE=y
+CONFIG_DEV_ZERO=y
+CONFIG_EXAMPLES_HELLO=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_FS_HOSTFS=y
+CONFIG_FS_PROCFS=y
+CONFIG_FS_PROCFS_REGISTER=y
+CONFIG_FS_ROMFS=y
+CONFIG_HAVE_CXX=y
+CONFIG_HAVE_CXXINITIALIZE=y
+CONFIG_IDLETHREAD_STACKSIZE=8192
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_INTELHEX_BINARY=y
+CONFIG_LIBC_FDT=y
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_FILEIOSIZE=512
+CONFIG_NSH_READLINE=y
+CONFIG_NSH_ROMFSETC=y
+CONFIG_PREALLOC_TIMERS=4
+CONFIG_PTHREAD_STACK_MIN=8192
+CONFIG_RAMLOG=y
+CONFIG_RAM_SIZE=134217728
+CONFIG_RAM_START=0x40000000
+CONFIG_RAW_BINARY=y
+CONFIG_READLINE_CMD_HISTORY=y
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_HPWORK=y
+CONFIG_SCHED_HPWORKPRIORITY=192
+CONFIG_SPINLOCK=y
+CONFIG_STACK_COLORATION=y
+CONFIG_START_MONTH=3
+CONFIG_START_YEAR=2022
+CONFIG_SYMTAB_ORDEREDBYNAME=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_SYSTEM_SYSTEM=y
+CONFIG_SYSTEM_TIME64=y
+CONFIG_TESTING_GETPRIME=y
+CONFIG_TESTING_OSTEST=y
+CONFIG_UART1_BASE=0x9000000
+CONFIG_UART1_IRQ=33
+CONFIG_UART1_PL011=y
+CONFIG_UART1_SERIAL_CONSOLE=y
+CONFIG_UART_PL011=y
+CONFIG_USEC_PER_TICK=1000