mirror of
https://github.com/apache/nuttx.git
synced 2026-05-30 21:36:28 +08:00
Feature k210 smp (#71)
* arch: risc-v: Remove unused typedef for irqstate_t
NOTE: irqstate_t is defined in arch/risc-v/include/types.h
* arch: risc-v: Add typedef irqstate_t for __LP64__
* arch: risc-v: Add SMP support to K210 (RV64GC) processor
* boards: maxi-bit: Update READMEs and add smp/defconfig
This commit is contained in:
committed by
Gregory Nutt
parent
237c0cca09
commit
29d3ed2ec1
@@ -19,6 +19,9 @@ config ARCH_CHIP_FE310
|
|||||||
config ARCH_CHIP_K210
|
config ARCH_CHIP_K210
|
||||||
bool "Kendryte K210"
|
bool "Kendryte K210"
|
||||||
select ARCH_RV64GC
|
select ARCH_RV64GC
|
||||||
|
select ARCH_HAVE_TESTSET
|
||||||
|
select ARCH_HAVE_MULTICPU
|
||||||
|
select ARCH_GLOBAL_IRQDISABLE
|
||||||
---help---
|
---help---
|
||||||
Kendryte K210 processor (RISC-V 64bit core with GC extensions)
|
Kendryte K210 processor (RISC-V 64bit core with GC extensions)
|
||||||
|
|
||||||
|
|||||||
@@ -57,18 +57,4 @@
|
|||||||
# include <arch/rv64gc/irq.h>
|
# include <arch/rv64gc/irq.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Pre-processor Definitions
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
typedef uint32_t irqstate_t;
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Public Types
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Public Variables
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#endif /* __ARCH_RISCV_INCLUDE_IRQ_H */
|
#endif /* __ARCH_RISCV_INCLUDE_IRQ_H */
|
||||||
|
|||||||
@@ -51,6 +51,7 @@
|
|||||||
|
|
||||||
/* In mie (machine interrupt enable) register */
|
/* In mie (machine interrupt enable) register */
|
||||||
|
|
||||||
|
#define MIE_MSIE (0x1 << 3) /* Machine Software Interrupt Enable */
|
||||||
#define MIE_MTIE (0x1 << 7) /* Machine Timer Interrupt Enable */
|
#define MIE_MTIE (0x1 << 7) /* Machine Timer Interrupt Enable */
|
||||||
#define MIE_MEIE (0x1 << 11) /* Machine External Interrupt Enable */
|
#define MIE_MEIE (0x1 << 11) /* Machine External Interrupt Enable */
|
||||||
|
|
||||||
@@ -81,7 +82,11 @@
|
|||||||
|
|
||||||
/* Machine Grobal External Interrupt */
|
/* Machine Grobal External Interrupt */
|
||||||
|
|
||||||
|
#ifdef CONFIG_K210_WITH_QEMU
|
||||||
|
#define K210_IRQ_UART0 (K210_IRQ_MEXT + 4)
|
||||||
|
#else
|
||||||
#define K210_IRQ_UART0 (K210_IRQ_MEXT + 33)
|
#define K210_IRQ_UART0 (K210_IRQ_MEXT + 33)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Total number of IRQs */
|
/* Total number of IRQs */
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,131 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* arch/risc-v/include/spinlock.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 Masayuki Ishikawa. All rights reserved.
|
||||||
|
* Author: Masayuki Ishikawa <masayuki.ishikawa@gmail.com>
|
||||||
|
*
|
||||||
|
* Based on arch/arm/include/armv7-m/spinlock.h
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __ARCH_RISCV_INCLUDE_SPINLOCK_H
|
||||||
|
#define __ARCH_RISCV_INCLUDE_SPINLOCK_H
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Included Files
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __ASSEMBLY__
|
||||||
|
# include <stdint.h>
|
||||||
|
#endif /* __ASSEMBLY__ */
|
||||||
|
|
||||||
|
/* Include RISC-V architecture-specific IRQ definitions (including register
|
||||||
|
* save structure and up_irq_save()/up_irq_restore() functions)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Pre-processor Definitions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* Spinlock states */
|
||||||
|
|
||||||
|
#define SP_UNLOCKED 0 /* The Un-locked state */
|
||||||
|
#define SP_LOCKED 1 /* The Locked state */
|
||||||
|
|
||||||
|
/* Memory barriers for use with NuttX spinlock logic
|
||||||
|
*
|
||||||
|
* Data Memory Barrier (DMB) acts as a memory barrier. It ensures that all
|
||||||
|
* explicit memory accesses that appear in program order before the DMB
|
||||||
|
* instruction are observed before any explicit memory accesses that appear
|
||||||
|
* in program order after the DMB instruction. It does not affect the
|
||||||
|
* ordering of any other instructions executing on the processor
|
||||||
|
*
|
||||||
|
* Data Synchronization Barrier (DSB) acts as a special kind of memory
|
||||||
|
* barrier. No instruction in program order after this instruction executes
|
||||||
|
* until this instruction completes. This instruction completes when: (1) All
|
||||||
|
* explicit memory accesses before this instruction complete, and (2) all
|
||||||
|
* Cache, Branch predictor and TLB maintenance operations before this
|
||||||
|
* instruction complete.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SP_DSB(n) __asm__ __volatile__ ("fence")
|
||||||
|
#define SP_DMB(n) __asm__ __volatile__ ("fence")
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Types
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
|
/* The Type of a spinlock.
|
||||||
|
*
|
||||||
|
* RISC-V architecture introuced the concept of exclusive accesses to memory
|
||||||
|
* locations in the form of the Load-Reserved (LR) and Store-Conditional
|
||||||
|
* (SC) instructions. RV64 supports doubleword aligned data only but others
|
||||||
|
* supports word aligned data.
|
||||||
|
*
|
||||||
|
* RISC-V architecture supports fence instruction to ensure memory ordering
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __LP64__
|
||||||
|
typedef uint64_t spinlock_t;
|
||||||
|
#else
|
||||||
|
typedef uint32_t spinlock_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: up_testset
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Perform an atomic test and set operation on the provided spinlock.
|
||||||
|
*
|
||||||
|
* This function must be provided via the architecture-specific logic.
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* lock - The address of spinlock object.
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* The spinlock is always locked upon return. The value of previous value
|
||||||
|
* of the spinlock variable is returned, either SP_LOCKED if the spinlock
|
||||||
|
* as previously locked (meaning that the test-and-set operation failed to
|
||||||
|
* obtain the lock) or SP_UNLOCKED if the spinlock was previously unlocked
|
||||||
|
* (meaning that we successfully obtained the lock)
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* See prototype in nuttx/include/nuttx/spinlock.h */
|
||||||
|
|
||||||
|
#endif /* __ASSEMBLY__ */
|
||||||
|
#endif /* __ARCH_RISCV_INCLUDE_SPINLOCK_H */
|
||||||
@@ -81,16 +81,20 @@ typedef unsigned long long _uint64_t;
|
|||||||
|
|
||||||
typedef signed long _intptr_t;
|
typedef signed long _intptr_t;
|
||||||
typedef unsigned long _uintptr_t;
|
typedef unsigned long _uintptr_t;
|
||||||
|
|
||||||
|
/* This is the size of the interrupt state save returned by irqsave(). */
|
||||||
|
|
||||||
|
typedef unsigned long long irqstate_t;
|
||||||
#else
|
#else
|
||||||
/* A pointer is 4 bytes */
|
/* A pointer is 4 bytes */
|
||||||
|
|
||||||
typedef signed int _intptr_t;
|
typedef signed int _intptr_t;
|
||||||
typedef unsigned int _uintptr_t;
|
typedef unsigned int _uintptr_t;
|
||||||
#endif
|
|
||||||
|
|
||||||
/* This is the size of the interrupt state save returned by irqsave(). */
|
/* This is the size of the interrupt state save returned by irqsave(). */
|
||||||
|
|
||||||
typedef unsigned int irqstate_t;
|
typedef unsigned int irqstate_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* __ASSEMBLY__ */
|
#endif /* __ASSEMBLY__ */
|
||||||
|
|
||||||
|
|||||||
@@ -70,11 +70,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef CONFIG_ARCH_RV64GC
|
#ifdef CONFIG_ARCH_RV64GC
|
||||||
#define up_savestate(regs) up_copystate(regs, (uint64_t*)g_current_regs)
|
#define up_savestate(regs) up_copystate(regs, (uint64_t*)CURRENT_REGS)
|
||||||
|
#define up_restorestate(regs) (CURRENT_REGS = regs)
|
||||||
#else
|
#else
|
||||||
#define up_savestate(regs) up_copystate(regs, (uint32_t*)g_current_regs)
|
#define up_savestate(regs) up_copystate(regs, (uint32_t*)g_current_regs)
|
||||||
#endif
|
|
||||||
#define up_restorestate(regs) (g_current_regs = regs)
|
#define up_restorestate(regs) (g_current_regs = regs)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Determine which (if any) console driver to use. If a console is enabled
|
/* Determine which (if any) console driver to use. If a console is enabled
|
||||||
* and no other console device is specified, then a serial console is
|
* and no other console device is specified, then a serial console is
|
||||||
@@ -118,7 +119,13 @@ extern "C"
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_ARCH_RV64GC
|
#ifdef CONFIG_ARCH_RV64GC
|
||||||
EXTERN volatile uint64_t *g_current_regs;
|
#ifdef CONFIG_SMP
|
||||||
|
EXTERN volatile uint64_t *g_current_regs[CONFIG_SMP_NCPUS];
|
||||||
|
# define CURRENT_REGS (g_current_regs[up_cpu_index()])
|
||||||
|
#else
|
||||||
|
EXTERN volatile uint64_t *g_current_regs[1];
|
||||||
|
# define CURRENT_REGS (g_current_regs[0])
|
||||||
|
#endif
|
||||||
EXTERN uintptr_t g_idle_topstack;
|
EXTERN uintptr_t g_idle_topstack;
|
||||||
#else
|
#else
|
||||||
EXTERN volatile uint32_t *g_current_regs;
|
EXTERN volatile uint32_t *g_current_regs;
|
||||||
|
|||||||
@@ -66,5 +66,9 @@
|
|||||||
|
|
||||||
bool up_interrupt_context(void)
|
bool up_interrupt_context(void)
|
||||||
{
|
{
|
||||||
return g_current_regs != NULL;
|
#ifdef CONFIG_ARCH_RV64GC
|
||||||
|
return CURRENT_REGS != NULL;
|
||||||
|
#else
|
||||||
|
return g_current_regs != NULL;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,3 +26,11 @@ config K210_UART0
|
|||||||
select K210_UART
|
select K210_UART
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
|
menu "K210 Others"
|
||||||
|
|
||||||
|
config K210_WITH_QEMU
|
||||||
|
bool "qemu support"
|
||||||
|
default n
|
||||||
|
|
||||||
|
endmenu
|
||||||
|
|||||||
@@ -37,9 +37,11 @@ HEAD_ASRC = k210_vectors.S
|
|||||||
# Specify our general Assembly files
|
# Specify our general Assembly files
|
||||||
CHIP_ASRCS = k210_head.S up_syscall.S
|
CHIP_ASRCS = k210_head.S up_syscall.S
|
||||||
|
|
||||||
|
CMN_ASRCS += up_testset.S
|
||||||
|
|
||||||
# Specify C code within the common directory to be included
|
# Specify C code within the common directory to be included
|
||||||
CMN_CSRCS += up_initialize.c up_swint.c
|
CMN_CSRCS += up_initialize.c up_swint.c
|
||||||
CMN_CSRCS += up_allocateheap.c up_createstack.c up_exit.c
|
CMN_CSRCS += up_allocateheap.c up_createstack.c up_exit.c up_fault.c
|
||||||
CMN_CSRCS += up_assert.c up_blocktask.c up_copystate.c up_initialstate.c
|
CMN_CSRCS += up_assert.c up_blocktask.c up_copystate.c up_initialstate.c
|
||||||
CMN_CSRCS += up_interruptcontext.c up_modifyreg32.c up_puts.c
|
CMN_CSRCS += up_interruptcontext.c up_modifyreg32.c up_puts.c
|
||||||
CMN_CSRCS += up_releasepending.c up_reprioritizertr.c
|
CMN_CSRCS += up_releasepending.c up_reprioritizertr.c
|
||||||
@@ -60,3 +62,7 @@ CHIP_CSRCS += k210_idle.c k210_irq.c k210_irq_dispatch.c
|
|||||||
CHIP_CSRCS += k210_lowputc.c k210_serial.c
|
CHIP_CSRCS += k210_lowputc.c k210_serial.c
|
||||||
CHIP_CSRCS += k210_start.c k210_timerisr.c
|
CHIP_CSRCS += k210_start.c k210_timerisr.c
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_SMP), y)
|
||||||
|
CHIP_CSRCS += k210_cpuidlestack.c k210_cpuindex.c
|
||||||
|
CHIP_CSRCS += k210_cpupause.c k210_cpustart.c
|
||||||
|
endif
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
* Pre-processor Definitions
|
* Pre-processor Definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
#define K210_CLINT_MSIP (K210_CLINT_BASE + 0x0000)
|
||||||
#define K210_CLINT_MTIMECMP (K210_CLINT_BASE + 0x4000)
|
#define K210_CLINT_MTIMECMP (K210_CLINT_BASE + 0x4000)
|
||||||
#define K210_CLINT_MTIME (K210_CLINT_BASE + 0xbff8)
|
#define K210_CLINT_MTIME (K210_CLINT_BASE + 0xbff8)
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,11 @@
|
|||||||
#define K210_CLINT_BASE 0x02000000
|
#define K210_CLINT_BASE 0x02000000
|
||||||
#define K210_PLIC_BASE 0x0c000000
|
#define K210_PLIC_BASE 0x0c000000
|
||||||
|
|
||||||
|
#ifdef CONFIG_K210_WITH_QEMU
|
||||||
|
#define K210_UART0_BASE 0x10010000
|
||||||
|
#else
|
||||||
#define K210_UART0_BASE 0x38000000
|
#define K210_UART0_BASE 0x38000000
|
||||||
|
#endif
|
||||||
#define K210_GPIO_BASE 0x38001000
|
#define K210_GPIO_BASE 0x38001000
|
||||||
|
|
||||||
#endif /* __ARCH_RISCV_SRC_K210_HARDWARE_K210_MEMORYMAP_H */
|
#endif /* __ARCH_RISCV_SRC_K210_HARDWARE_K210_MEMORYMAP_H */
|
||||||
|
|||||||
@@ -0,0 +1,106 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* arch/risc-v/src/k210/k210_cpuidlestack.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 Masayuki Ishikawa. All rights reserved.
|
||||||
|
* Author: Masayuki Ishikawa <masayuki.ishikawa@gmail.com>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Included Files
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <nuttx/arch.h>
|
||||||
|
#include <nuttx/sched.h>
|
||||||
|
|
||||||
|
#include "up_internal.h"
|
||||||
|
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: up_cpu_idlestack
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Allocate a stack for the CPU[n] IDLE task (n > 0) if appropriate and
|
||||||
|
* setup up stack-related information in the IDLE task's TCB. This
|
||||||
|
* function is always called before up_cpu_start(). This function is
|
||||||
|
* only called for the CPU's initial IDLE task; up_create_task is used for
|
||||||
|
* all normal tasks, pthreads, and kernel threads for all CPUs.
|
||||||
|
*
|
||||||
|
* The initial IDLE task is a special case because the CPUs can be started
|
||||||
|
* in different wans in different environments:
|
||||||
|
*
|
||||||
|
* 1. The CPU may already have been started and waiting in a low power
|
||||||
|
* state for up_cpu_start(). In this case, the IDLE thread's stack
|
||||||
|
* has already been allocated and is already in use. Here
|
||||||
|
* up_cpu_idlestack() only has to provide information about the
|
||||||
|
* already allocated stack.
|
||||||
|
*
|
||||||
|
* 2. The CPU may be disabled but started when up_cpu_start() is called.
|
||||||
|
* In this case, a new stack will need to be created for the IDLE
|
||||||
|
* thread and this function is then equivalent to:
|
||||||
|
*
|
||||||
|
* return up_create_stack(tcb, stack_size, TCB_FLAG_TTYPE_KERNEL);
|
||||||
|
*
|
||||||
|
* The following TCB fields must be initialized by this function:
|
||||||
|
*
|
||||||
|
* - adj_stack_size: Stack size after adjustment for hardware, processor,
|
||||||
|
* etc. This value is retained only for debug purposes.
|
||||||
|
* - stack_alloc_ptr: Pointer to allocated stack
|
||||||
|
* - adj_stack_ptr: Adjusted stack_alloc_ptr for HW. The initial value of
|
||||||
|
* the stack pointer.
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* - cpu: CPU index that indicates which CPU the IDLE task is
|
||||||
|
* being created for.
|
||||||
|
* - tcb: The TCB of new CPU IDLE task
|
||||||
|
* - stack_size: The requested stack size for the IDLE task. At least
|
||||||
|
* this much must be allocated. This should be
|
||||||
|
* CONFIG_SMP_STACK_SIZE.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int up_cpu_idlestack(int cpu, FAR struct tcb_s *tcb, size_t stack_size)
|
||||||
|
{
|
||||||
|
#if CONFIG_SMP_NCPUS > 1
|
||||||
|
(void)up_create_stack(tcb, stack_size, TCB_FLAG_TTYPE_KERNEL);
|
||||||
|
#endif
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_SMP */
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* arch/risc-v/src/k210/k210_cpuindex.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 Masayuki Ishikawa. All rights reserved.
|
||||||
|
* Author: Masayuki Ishikawa <masayuki.ishikawa@gmail.com>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Included Files
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <nuttx/config.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <nuttx/arch.h>
|
||||||
|
|
||||||
|
#include "up_arch.h"
|
||||||
|
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: up_cpu_index
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Return an index in the range of 0 through (CONFIG_SMP_NCPUS-1) that
|
||||||
|
* corresponds to the currently executing CPU.
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* An integer index in the range of 0 through (CONFIG_SMP_NCPUS-1) that
|
||||||
|
* corresponds to the currently executing CPU.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int up_cpu_index(void)
|
||||||
|
{
|
||||||
|
int mhartid;
|
||||||
|
|
||||||
|
asm volatile ("csrr %0, mhartid": "=r" (mhartid));
|
||||||
|
return mhartid;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_SMP */
|
||||||
@@ -0,0 +1,332 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* arch/risc-v/src/k210/k210_cpupause.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 Masayuki Ishikawa. All rights reserved.
|
||||||
|
* Author: Masayuki Ishikawa <masayuki.ishikawa@gmail.com>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Included Files
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <debug.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <nuttx/arch.h>
|
||||||
|
#include <nuttx/spinlock.h>
|
||||||
|
#include <nuttx/sched_note.h>
|
||||||
|
|
||||||
|
#include "up_arch.h"
|
||||||
|
#include "sched/sched.h"
|
||||||
|
#include "up_internal.h"
|
||||||
|
#include "chip.h"
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Pre-processor Definitions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#define DPRINTF(fmt, args...) llinfo(fmt, ##args)
|
||||||
|
#else
|
||||||
|
#define DPRINTF(fmt, args...) do {} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Data
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* These spinlocks are used in the SMP configuration in order to implement
|
||||||
|
* up_cpu_pause(). The protocol for CPUn to pause CPUm is as follows
|
||||||
|
*
|
||||||
|
* 1. The up_cpu_pause() implementation on CPUn locks both g_cpu_wait[m]
|
||||||
|
* and g_cpu_paused[m]. CPUn then waits spinning on g_cpu_paused[m].
|
||||||
|
* 2. CPUm receives the interrupt it (1) unlocks g_cpu_paused[m] and
|
||||||
|
* (2) locks g_cpu_wait[m]. The first unblocks CPUn and the second
|
||||||
|
* blocks CPUm in the interrupt handler.
|
||||||
|
*
|
||||||
|
* When CPUm resumes, CPUn unlocks g_cpu_wait[m] and the interrupt handler
|
||||||
|
* on CPUm continues. CPUm must, of course, also then unlock g_cpu_wait[m]
|
||||||
|
* so that it will be ready for the next pause operation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
volatile spinlock_t g_cpu_wait[CONFIG_SMP_NCPUS];
|
||||||
|
volatile spinlock_t g_cpu_paused[CONFIG_SMP_NCPUS];
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: up_cpu_pausereq
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Return true if a pause request is pending for this CPU.
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* cpu - The index of the CPU to be queried
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* true = a pause request is pending.
|
||||||
|
* false = no pasue request is pending.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
bool up_cpu_pausereq(int cpu)
|
||||||
|
{
|
||||||
|
return spin_islocked(&g_cpu_paused[cpu]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: up_cpu_paused
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Handle a pause request from another CPU. Normally, this logic is
|
||||||
|
* executed from interrupt handling logic within the architecture-specific
|
||||||
|
* However, it is sometimes necessary necessary to perform the pending
|
||||||
|
* pause operation in other contexts where the interrupt cannot be taken
|
||||||
|
* in order to avoid deadlocks.
|
||||||
|
*
|
||||||
|
* This function performs the following operations:
|
||||||
|
*
|
||||||
|
* 1. It saves the current task state at the head of the current assigned
|
||||||
|
* task list.
|
||||||
|
* 2. It waits on a spinlock, then
|
||||||
|
* 3. Returns from interrupt, restoring the state of the new task at the
|
||||||
|
* head of the ready to run list.
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* cpu - The index of the CPU to be paused
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* On success, OK is returned. Otherwise, a negated errno value indicating
|
||||||
|
* the nature of the failure is returned.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int up_cpu_paused(int cpu)
|
||||||
|
{
|
||||||
|
FAR struct tcb_s *tcb = this_task();
|
||||||
|
|
||||||
|
/* Update scheduler parameters */
|
||||||
|
|
||||||
|
sched_suspend_scheduler(tcb);
|
||||||
|
|
||||||
|
#ifdef CONFIG_SCHED_INSTRUMENTATION
|
||||||
|
/* Notify that we are paused */
|
||||||
|
|
||||||
|
sched_note_cpu_paused(tcb);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Save the current context at CURRENT_REGS into the TCB at the head
|
||||||
|
* of the assigned task list for this CPU.
|
||||||
|
*/
|
||||||
|
|
||||||
|
up_savestate(tcb->xcp.regs);
|
||||||
|
|
||||||
|
/* Wait for the spinlock to be released */
|
||||||
|
|
||||||
|
spin_unlock(&g_cpu_paused[cpu]);
|
||||||
|
spin_lock(&g_cpu_wait[cpu]);
|
||||||
|
|
||||||
|
/* Restore the exception context of the tcb at the (new) head of the
|
||||||
|
* assigned task list.
|
||||||
|
*/
|
||||||
|
|
||||||
|
tcb = this_task();
|
||||||
|
|
||||||
|
#ifdef CONFIG_SCHED_INSTRUMENTATION
|
||||||
|
/* Notify that we have resumed */
|
||||||
|
|
||||||
|
sched_note_cpu_resumed(tcb);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Reset scheduler parameters */
|
||||||
|
|
||||||
|
sched_resume_scheduler(tcb);
|
||||||
|
|
||||||
|
/* Then switch contexts. Any necessary address environment changes
|
||||||
|
* will be made when the interrupt returns.
|
||||||
|
*/
|
||||||
|
|
||||||
|
up_restorestate(tcb->xcp.regs);
|
||||||
|
|
||||||
|
spin_unlock(&g_cpu_wait[cpu]);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: riscv_pause_handler
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Inter-CPU interrupt handler
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* Standard interrupt handler inputs
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* Should always return OK
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int riscv_pause_handler(int irq, void *c, FAR void *arg)
|
||||||
|
{
|
||||||
|
int cpu = up_cpu_index();
|
||||||
|
|
||||||
|
/* Clear machine software interrupt */
|
||||||
|
|
||||||
|
putreg32(0, (uintptr_t)K210_CLINT_MSIP + (4 * cpu));
|
||||||
|
|
||||||
|
/* Check for false alarms. Such false could occur as a consequence of
|
||||||
|
* some deadlock breaking logic that might have already serviced the SG2
|
||||||
|
* interrupt by calling up_cpu_paused.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (spin_islocked(&g_cpu_paused[cpu]))
|
||||||
|
{
|
||||||
|
return up_cpu_paused(cpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: up_cpu_pause
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Save the state of the current task at the head of the
|
||||||
|
* g_assignedtasks[cpu] task list and then pause task execution on the
|
||||||
|
* CPU.
|
||||||
|
*
|
||||||
|
* This function is called by the OS when the logic executing on one CPU
|
||||||
|
* needs to modify the state of the g_assignedtasks[cpu] list for another
|
||||||
|
* CPU.
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* cpu - The index of the CPU to be stopped/
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* Zero on success; a negated errno value on failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int up_cpu_pause(int cpu)
|
||||||
|
{
|
||||||
|
DPRINTF("cpu=%d\n", cpu);
|
||||||
|
|
||||||
|
#ifdef CONFIG_SCHED_INSTRUMENTATION
|
||||||
|
/* Notify of the pause event */
|
||||||
|
|
||||||
|
sched_note_cpu_pause(this_task(), cpu);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS && cpu != this_cpu());
|
||||||
|
|
||||||
|
/* Take the both spinlocks. The g_cpu_wait spinlock will prevent the SGI2
|
||||||
|
* handler from returning until up_cpu_resume() is called; g_cpu_paused
|
||||||
|
* is a handshake that will prefent this function from returning until
|
||||||
|
* the CPU is actually paused.
|
||||||
|
*/
|
||||||
|
|
||||||
|
DEBUGASSERT(!spin_islocked(&g_cpu_wait[cpu]) &&
|
||||||
|
!spin_islocked(&g_cpu_paused[cpu]));
|
||||||
|
|
||||||
|
spin_lock(&g_cpu_wait[cpu]);
|
||||||
|
spin_lock(&g_cpu_paused[cpu]);
|
||||||
|
|
||||||
|
/* Execute Pause IRQ to CPU(cpu) */
|
||||||
|
|
||||||
|
putreg32(1, (uintptr_t)K210_CLINT_MSIP + (4 * cpu));
|
||||||
|
|
||||||
|
/* Wait for the other CPU to unlock g_cpu_paused meaning that
|
||||||
|
* it is fully paused and ready for up_cpu_resume();
|
||||||
|
*/
|
||||||
|
|
||||||
|
spin_lock(&g_cpu_paused[cpu]);
|
||||||
|
|
||||||
|
spin_unlock(&g_cpu_paused[cpu]);
|
||||||
|
|
||||||
|
/* On successful return g_cpu_wait will be locked, the other CPU will be
|
||||||
|
* spinninf on g_cpu_wait and will not continue until g_cpu_resume() is
|
||||||
|
* called. g_cpu_paused will be unlocked in any case.
|
||||||
|
*/
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: up_cpu_resume
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Restart the cpu after it was paused via up_cpu_pause(), restoring the
|
||||||
|
* state of the task at the head of the g_assignedtasks[cpu] list, and
|
||||||
|
* resume normal tasking.
|
||||||
|
*
|
||||||
|
* This function is called after up_cpu_pause in order resume operation of
|
||||||
|
* the CPU after modifying its g_assignedtasks[cpu] list.
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* cpu - The index of the CPU being re-started.
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* Zero on success; a negated errno value on failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int up_cpu_resume(int cpu)
|
||||||
|
{
|
||||||
|
DPRINTF("cpu=%d\n", cpu);
|
||||||
|
|
||||||
|
#ifdef CONFIG_SCHED_INSTRUMENTATION
|
||||||
|
/* Notify of the resume event */
|
||||||
|
|
||||||
|
sched_note_cpu_resume(this_task(), cpu);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS && cpu != this_cpu());
|
||||||
|
|
||||||
|
/* Release the spinlock. Releasing the spinlock will cause the SGI2
|
||||||
|
* handler on 'cpu' to continue and return from interrupt to the newly
|
||||||
|
* established thread.
|
||||||
|
*/
|
||||||
|
|
||||||
|
DEBUGASSERT(spin_islocked(&g_cpu_wait[cpu]) &&
|
||||||
|
!spin_islocked(&g_cpu_paused[cpu]));
|
||||||
|
|
||||||
|
spin_unlock(&g_cpu_wait[cpu]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,193 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* arch/risc-v/src/k210/k210_cpustart.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 Masayuki Ishikawa. All rights reserved.
|
||||||
|
* Author: Masayuki Ishikawa <masayuki.ishikawa@gmail.com>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Included Files
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <debug.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <nuttx/arch.h>
|
||||||
|
#include <nuttx/spinlock.h>
|
||||||
|
#include <nuttx/sched_note.h>
|
||||||
|
|
||||||
|
#include "up_arch.h"
|
||||||
|
#include "sched/sched.h"
|
||||||
|
#include "init/init.h"
|
||||||
|
#include "up_internal.h"
|
||||||
|
#include "chip.h"
|
||||||
|
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Pre-processor Definitions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
# define DPRINTF(fmt, args...) _err(fmt, ##args)
|
||||||
|
#else
|
||||||
|
# define DPRINTF(fmt, args...) do {} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEBUG_FEATURES
|
||||||
|
# define showprogress(c) up_lowputc(c)
|
||||||
|
#else
|
||||||
|
# define showprogress(c)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Data
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
extern volatile bool g_serial_ok;
|
||||||
|
extern int riscv_pause_handler(int irq, void *c, FAR void *arg);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: k210_cpu_boot
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Boot handler for cpu1
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
void k210_cpu_boot(int cpu)
|
||||||
|
{
|
||||||
|
if (1 < cpu)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait for g_serial_ok set by cpu0 when booting */
|
||||||
|
|
||||||
|
while (!g_serial_ok)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear machine software interrupt for CPU(cpu) */
|
||||||
|
|
||||||
|
putreg32(0, (uintptr_t)K210_CLINT_MSIP + (4 * cpu));
|
||||||
|
|
||||||
|
/* Enable machine software interrupt for IPI to boot */
|
||||||
|
|
||||||
|
up_enable_irq(K210_IRQ_MSOFT);
|
||||||
|
|
||||||
|
/* Wait interrupt */
|
||||||
|
|
||||||
|
asm("WFI");
|
||||||
|
|
||||||
|
showprogress('b');
|
||||||
|
DPRINTF("CPU%d Started\n", this_cpu());
|
||||||
|
|
||||||
|
/* TODO: Setup FPU */
|
||||||
|
|
||||||
|
/* Clear machine software interrupt for CPU(cpu) */
|
||||||
|
|
||||||
|
putreg32(0, (uintptr_t)K210_CLINT_MSIP + (4 * cpu));
|
||||||
|
|
||||||
|
#ifdef CONFIG_SCHED_INSTRUMENTATION
|
||||||
|
/* Notify that this CPU has started */
|
||||||
|
|
||||||
|
sched_note_cpu_started(this_task());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
(void)up_irq_enable();
|
||||||
|
|
||||||
|
/* Then transfer control to the IDLE task */
|
||||||
|
|
||||||
|
(void)nx_idle_task(0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: up_cpu_start
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* In an SMP configution, only one CPU is initially active (CPU 0). System
|
||||||
|
* initialization occurs on that single thread. At the completion of the
|
||||||
|
* initialization of the OS, just before beginning normal multitasking,
|
||||||
|
* the additional CPUs would be started by calling this function.
|
||||||
|
*
|
||||||
|
* Each CPU is provided the entry point to is IDLE task when started. A
|
||||||
|
* TCB for each CPU's IDLE task has been initialized and placed in the
|
||||||
|
* CPU's g_assignedtasks[cpu] list. Not stack has been alloced or
|
||||||
|
* initialized.
|
||||||
|
*
|
||||||
|
* The OS initialization logic calls this function repeatedly until each
|
||||||
|
* CPU has been started, 1 through (CONFIG_SMP_NCPUS-1).
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* cpu - The index of the CPU being started. This will be a numeric
|
||||||
|
* value in the range of from one to (CONFIG_SMP_NCPUS-1). (CPU
|
||||||
|
* 0 is already active)
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* Zero on success; a negated errno value on failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int up_cpu_start(int cpu)
|
||||||
|
{
|
||||||
|
DPRINTF("cpu=%d\n", cpu);
|
||||||
|
|
||||||
|
#ifdef CONFIG_SCHED_INSTRUMENTATION
|
||||||
|
/* Notify of the start event */
|
||||||
|
|
||||||
|
sched_note_cpu_start(this_task(), cpu);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Send IPI to CPU(cpu) */
|
||||||
|
|
||||||
|
putreg32(1, (uintptr_t)K210_CLINT_MSIP + (cpu * 4));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_SMP */
|
||||||
@@ -54,9 +54,18 @@
|
|||||||
|
|
||||||
__start:
|
__start:
|
||||||
|
|
||||||
|
/* Load mhartid (cpuid) */
|
||||||
|
|
||||||
|
csrr a0, mhartid
|
||||||
|
|
||||||
/* Set stack pointer to the idle thread stack */
|
/* Set stack pointer to the idle thread stack */
|
||||||
|
|
||||||
la sp, K210_IDLESTACK_TOP
|
bnez a0, 1f
|
||||||
|
la sp, K210_IDLESTACK0_TOP
|
||||||
|
j 2f
|
||||||
|
1:
|
||||||
|
la sp, K210_IDLESTACK1_TOP
|
||||||
|
2:
|
||||||
|
|
||||||
/* Disable all interrupts (i.e. timer, external) in mie */
|
/* Disable all interrupts (i.e. timer, external) in mie */
|
||||||
|
|
||||||
@@ -67,9 +76,9 @@ __start:
|
|||||||
la t0, __trap_vec
|
la t0, __trap_vec
|
||||||
csrw mtvec, t0
|
csrw mtvec, t0
|
||||||
|
|
||||||
/* Jump to __k210_start */
|
/* Jump to __k210_start with mhartid */
|
||||||
|
|
||||||
jal x1, __k210_start
|
j __k210_start
|
||||||
|
|
||||||
/* We shouldn't return from __k210_start */
|
/* We shouldn't return from __k210_start */
|
||||||
|
|
||||||
@@ -89,6 +98,16 @@ _fini:
|
|||||||
|
|
||||||
exception_common:
|
exception_common:
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
csrr gp, mcause /* exception cause */
|
||||||
|
addi tp, zero, 10 /* 10 = machine ecall */
|
||||||
|
bgtu gp, tp, normal_irq
|
||||||
|
ld sp, g_fstack_top /* Set sp to fault stack */
|
||||||
|
|
||||||
|
normal_irq:
|
||||||
|
addi gp, zero, 0 /* clear */
|
||||||
|
#endif
|
||||||
|
|
||||||
addi sp, sp, -XCPTCONTEXT_SIZE
|
addi sp, sp, -XCPTCONTEXT_SIZE
|
||||||
|
|
||||||
sd x1, 1*8(sp) /* ra */
|
sd x1, 1*8(sp) /* ra */
|
||||||
@@ -137,9 +156,20 @@ exception_common:
|
|||||||
mv a1, sp /* context = sp */
|
mv a1, sp /* context = sp */
|
||||||
|
|
||||||
#if CONFIG_ARCH_INTERRUPTSTACK > 3
|
#if CONFIG_ARCH_INTERRUPTSTACK > 3
|
||||||
|
/* Load mhartid (cpuid) */
|
||||||
|
|
||||||
|
csrr s0, mhartid
|
||||||
|
|
||||||
/* Switch to interrupt stack */
|
/* Switch to interrupt stack */
|
||||||
|
|
||||||
|
bnez s0, 3f
|
||||||
la sp, g_intstackbase
|
la sp, g_intstackbase
|
||||||
|
j 4f
|
||||||
|
3:
|
||||||
|
la sp, g_intstackbase
|
||||||
|
addi sp, sp, -((CONFIG_ARCH_INTERRUPTSTACK) & ~7)
|
||||||
|
4:
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Call interrupt handler in C */
|
/* Call interrupt handler in C */
|
||||||
@@ -205,9 +235,9 @@ exception_common:
|
|||||||
.type g_intstackalloc, object
|
.type g_intstackalloc, object
|
||||||
.type g_intstackbase, object
|
.type g_intstackbase, object
|
||||||
g_intstackalloc:
|
g_intstackalloc:
|
||||||
.skip ((CONFIG_ARCH_INTERRUPTSTACK & ~7))
|
.skip (((CONFIG_ARCH_INTERRUPTSTACK * 2) & ~7))
|
||||||
g_intstackbase:
|
g_intstackbase:
|
||||||
.skip 8
|
.skip 8
|
||||||
.size g_intstackbase, 8
|
.size g_intstackbase, 8
|
||||||
.size g_intstackalloc, (CONFIG_ARCH_INTERRUPTSTACK & ~7)
|
.size g_intstackalloc, ((CONFIG_ARCH_INTERRUPTSTACK * 2) & ~7)
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -51,6 +51,24 @@
|
|||||||
|
|
||||||
#include "k210.h"
|
#include "k210.h"
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Data
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
/* For the case of configurations with multiple CPUs, then there must be one
|
||||||
|
* such value for each processor that can receive an interrupt.
|
||||||
|
*/
|
||||||
|
|
||||||
|
volatile uint64_t *g_current_regs[CONFIG_SMP_NCPUS];
|
||||||
|
#else
|
||||||
|
volatile uint64_t *g_current_regs[1];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
extern int riscv_pause_handler(int irq, void *c, FAR void *arg);
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -98,12 +116,23 @@ void up_irqinitialize(void)
|
|||||||
|
|
||||||
/* currents_regs is non-NULL only while processing an interrupt */
|
/* currents_regs is non-NULL only while processing an interrupt */
|
||||||
|
|
||||||
g_current_regs = NULL;
|
CURRENT_REGS = NULL;
|
||||||
|
|
||||||
/* Attach the ecall interrupt handler */
|
/* Attach the ecall interrupt handler */
|
||||||
|
|
||||||
irq_attach(K210_IRQ_ECALLM, up_swint, NULL);
|
irq_attach(K210_IRQ_ECALLM, up_swint, NULL);
|
||||||
|
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
/* Clear MSOFT for CPU0 */
|
||||||
|
|
||||||
|
putreg32(0, K210_CLINT_MSIP);
|
||||||
|
|
||||||
|
/* Setup MSOFT for CPU0 with pause handler */
|
||||||
|
|
||||||
|
irq_attach(K210_IRQ_MSOFT, riscv_pause_handler, NULL);
|
||||||
|
up_enable_irq(K210_IRQ_MSOFT);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef CONFIG_SUPPRESS_INTERRUPTS
|
#ifndef CONFIG_SUPPRESS_INTERRUPTS
|
||||||
|
|
||||||
/* And finally, enable interrupts */
|
/* And finally, enable interrupts */
|
||||||
@@ -123,9 +152,15 @@ void up_irqinitialize(void)
|
|||||||
void up_disable_irq(int irq)
|
void up_disable_irq(int irq)
|
||||||
{
|
{
|
||||||
int extirq;
|
int extirq;
|
||||||
uint32_t oldstat;
|
uint64_t oldstat;
|
||||||
|
|
||||||
if (irq == K210_IRQ_MTIMER)
|
if (irq == K210_IRQ_MSOFT)
|
||||||
|
{
|
||||||
|
/* Read mstatus & clear machine software interrupt enable in mie */
|
||||||
|
|
||||||
|
asm volatile ("csrrc %0, mie, %1": "=r" (oldstat) : "r"(MIE_MSIE));
|
||||||
|
}
|
||||||
|
else if (irq == K210_IRQ_MTIMER)
|
||||||
{
|
{
|
||||||
/* Read mstatus & clear machine timer interrupt enable in mie */
|
/* Read mstatus & clear machine timer interrupt enable in mie */
|
||||||
|
|
||||||
@@ -160,9 +195,15 @@ void up_disable_irq(int irq)
|
|||||||
void up_enable_irq(int irq)
|
void up_enable_irq(int irq)
|
||||||
{
|
{
|
||||||
int extirq;
|
int extirq;
|
||||||
uint32_t oldstat;
|
uint64_t oldstat;
|
||||||
|
|
||||||
if (irq == K210_IRQ_MTIMER)
|
if (irq == K210_IRQ_MSOFT)
|
||||||
|
{
|
||||||
|
/* Read mstatus & set machine software interrupt enable in mie */
|
||||||
|
|
||||||
|
asm volatile ("csrrs %0, mie, %1": "=r" (oldstat) : "r"(MIE_MSIE));
|
||||||
|
}
|
||||||
|
else if (irq == K210_IRQ_MTIMER)
|
||||||
{
|
{
|
||||||
/* Read mstatus & set machine timer interrupt enable in mie */
|
/* Read mstatus & set machine timer interrupt enable in mie */
|
||||||
|
|
||||||
@@ -225,7 +266,7 @@ void up_ack_irq(int irq)
|
|||||||
|
|
||||||
irqstate_t up_irq_save(void)
|
irqstate_t up_irq_save(void)
|
||||||
{
|
{
|
||||||
uint32_t oldstat;
|
uint64_t oldstat;
|
||||||
|
|
||||||
/* Read mstatus & clear machine interrupt enable (MIE) in mstatus */
|
/* Read mstatus & clear machine interrupt enable (MIE) in mstatus */
|
||||||
|
|
||||||
@@ -258,7 +299,7 @@ void up_irq_restore(irqstate_t flags)
|
|||||||
|
|
||||||
irqstate_t up_irq_enable(void)
|
irqstate_t up_irq_enable(void)
|
||||||
{
|
{
|
||||||
uint32_t oldstat;
|
uint64_t oldstat;
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
/* Enable MEIE (machine external interrupt enable) */
|
/* Enable MEIE (machine external interrupt enable) */
|
||||||
|
|||||||
@@ -53,7 +53,7 @@
|
|||||||
* Public Data
|
* Public Data
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
volatile uint64_t * g_current_regs;
|
extern void up_fault(int irq, uint64_t *regs);
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
@@ -68,6 +68,13 @@ void *k210_dispatch_irq(uint64_t vector, uint64_t *regs)
|
|||||||
uint32_t irq = (vector >> (27 + 32)) | (vector & 0xf);
|
uint32_t irq = (vector >> (27 + 32)) | (vector & 0xf);
|
||||||
uint64_t *mepc = regs;
|
uint64_t *mepc = regs;
|
||||||
|
|
||||||
|
/* Check if fault happened */
|
||||||
|
|
||||||
|
if (vector < 11)
|
||||||
|
{
|
||||||
|
up_fault((int)irq, regs);
|
||||||
|
}
|
||||||
|
|
||||||
/* Firstly, check if the irq is machine external interrupt */
|
/* Firstly, check if the irq is machine external interrupt */
|
||||||
|
|
||||||
if (K210_IRQ_MEXT == irq)
|
if (K210_IRQ_MEXT == irq)
|
||||||
@@ -94,17 +101,22 @@ void *k210_dispatch_irq(uint64_t vector, uint64_t *regs)
|
|||||||
PANIC();
|
PANIC();
|
||||||
#else
|
#else
|
||||||
/* Current regs non-zero indicates that we are processing an interrupt;
|
/* Current regs non-zero indicates that we are processing an interrupt;
|
||||||
* g_current_regs is also used to manage interrupt level context switches.
|
* CURRENT_REGS is also used to manage interrupt level context switches.
|
||||||
*
|
*
|
||||||
* Nested interrupts are not supported
|
* Nested interrupts are not supported
|
||||||
*/
|
*/
|
||||||
|
|
||||||
DEBUGASSERT(g_current_regs == NULL);
|
ASSERT(CURRENT_REGS == NULL);
|
||||||
g_current_regs = regs;
|
CURRENT_REGS = regs;
|
||||||
|
|
||||||
/* Deliver the IRQ */
|
/* MEXT means no interrupt */
|
||||||
|
|
||||||
irq_dispatch(irq, regs);
|
if (K210_IRQ_MEXT != irq)
|
||||||
|
{
|
||||||
|
/* Deliver the IRQ */
|
||||||
|
|
||||||
|
irq_dispatch(irq, regs);
|
||||||
|
}
|
||||||
|
|
||||||
if (K210_IRQ_MEXT <= irq)
|
if (K210_IRQ_MEXT <= irq)
|
||||||
{
|
{
|
||||||
@@ -115,13 +127,13 @@ void *k210_dispatch_irq(uint64_t vector, uint64_t *regs)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* If a context switch occurred while processing the interrupt then
|
/* If a context switch occurred while processing the interrupt then
|
||||||
* g_current_regs may have change value. If we return any value different
|
* CURRENT_REGS may have change value. If we return any value different
|
||||||
* from the input regs, then the lower level will know that a context
|
* from the input regs, then the lower level will know that a context
|
||||||
* switch occurred during interrupt processing.
|
* switch occurred during interrupt processing.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
regs = (uint64_t *)g_current_regs;
|
regs = (uint64_t *)CURRENT_REGS;
|
||||||
g_current_regs = NULL;
|
CURRENT_REGS = NULL;
|
||||||
|
|
||||||
return regs;
|
return regs;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,11 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define K210_IDLESTACK_SIZE (CONFIG_IDLETHREAD_STACKSIZE & ~7)
|
#define K210_IDLESTACK_SIZE (CONFIG_IDLETHREAD_STACKSIZE & ~7)
|
||||||
#define K210_IDLESTACK_TOP (K210_IDLESTACK_BASE + K210_IDLESTACK_SIZE)
|
|
||||||
|
#define K210_IDLESTACK0_TOP (K210_IDLESTACK_BASE + K210_IDLESTACK_SIZE)
|
||||||
|
#define K210_IDLESTACK1_TOP (K210_IDLESTACK0_TOP + K210_IDLESTACK_SIZE)
|
||||||
|
|
||||||
|
#define K210_IDLESTACK_TOP (K210_IDLESTACK1_TOP)
|
||||||
|
|
||||||
#endif /* _ARCH_RISCV_SRC_K210_K210_MEMORYMAP_H */
|
#endif /* _ARCH_RISCV_SRC_K210_K210_MEMORYMAP_H */
|
||||||
|
|
||||||
|
|||||||
@@ -36,8 +36,10 @@
|
|||||||
|
|
||||||
#include <nuttx/config.h>
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <nuttx/arch.h>
|
||||||
#include <arch/board/board.h>
|
#include <arch/board/board.h>
|
||||||
|
|
||||||
|
#include "up_arch.h"
|
||||||
#include "k210_clockconfig.h"
|
#include "k210_clockconfig.h"
|
||||||
#include "k210.h"
|
#include "k210.h"
|
||||||
#include "chip.h"
|
#include "chip.h"
|
||||||
@@ -67,6 +69,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
uintptr_t g_idle_topstack = K210_IDLESTACK_TOP;
|
uintptr_t g_idle_topstack = K210_IDLESTACK_TOP;
|
||||||
|
volatile bool g_serial_ok = false;
|
||||||
|
|
||||||
|
extern void k210_cpu_boot(uint32_t);
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
@@ -76,11 +81,18 @@ uintptr_t g_idle_topstack = K210_IDLESTACK_TOP;
|
|||||||
* Name: k210_start
|
* Name: k210_start
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
void __k210_start(void)
|
void __k210_start(uint32_t mhartid)
|
||||||
{
|
{
|
||||||
const uint32_t *src;
|
const uint32_t *src;
|
||||||
uint32_t *dest;
|
uint32_t *dest;
|
||||||
|
|
||||||
|
g_serial_ok = false;
|
||||||
|
|
||||||
|
if (0 < mhartid)
|
||||||
|
{
|
||||||
|
goto cpu1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Clear .bss. We'll do this inline (vs. calling memset) just to be
|
/* Clear .bss. We'll do this inline (vs. calling memset) just to be
|
||||||
* certain that there are no issues with the state of global variables.
|
* certain that there are no issues with the state of global variables.
|
||||||
*/
|
*/
|
||||||
@@ -117,6 +129,8 @@ void __k210_start(void)
|
|||||||
|
|
||||||
showprogress('B');
|
showprogress('B');
|
||||||
|
|
||||||
|
g_serial_ok = true;
|
||||||
|
|
||||||
/* Do board initialization */
|
/* Do board initialization */
|
||||||
|
|
||||||
k210_boardinitialize();
|
k210_boardinitialize();
|
||||||
@@ -127,7 +141,16 @@ void __k210_start(void)
|
|||||||
|
|
||||||
nx_start();
|
nx_start();
|
||||||
|
|
||||||
/* Shouldn't get here */
|
cpu1:
|
||||||
|
|
||||||
for (; ; );
|
showprogress('a');
|
||||||
|
|
||||||
|
#if defined(CONFIG_SMP) && (CONFIG_SMP_NCPUS == 2)
|
||||||
|
k210_cpu_boot(mhartid);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
asm("WFI");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,11 @@
|
|||||||
#define getreg64(a) (*(volatile uint64_t *)(a))
|
#define getreg64(a) (*(volatile uint64_t *)(a))
|
||||||
#define putreg64(v,a) (*(volatile uint64_t *)(a) = (v))
|
#define putreg64(v,a) (*(volatile uint64_t *)(a) = (v))
|
||||||
|
|
||||||
|
#ifdef CONFIG_K210_WITH_QEMU
|
||||||
|
#define TICK_COUNT (10000000 / TICK_PER_SEC)
|
||||||
|
#else
|
||||||
#define TICK_COUNT ((k210_get_cpuclk() / 50) / TICK_PER_SEC)
|
#define TICK_COUNT ((k210_get_cpuclk() / 50) / TICK_PER_SEC)
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Data
|
* Private Data
|
||||||
|
|||||||
@@ -53,6 +53,8 @@
|
|||||||
#include "up_internal.h"
|
#include "up_internal.h"
|
||||||
#include "up_arch.h"
|
#include "up_arch.h"
|
||||||
|
|
||||||
|
#include "irq/irq.h"
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -90,10 +92,11 @@
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CONFIG_SMP
|
||||||
void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||||
{
|
{
|
||||||
irqstate_t flags;
|
irqstate_t flags;
|
||||||
uint32_t int_ctx;
|
uint64_t int_ctx;
|
||||||
|
|
||||||
sinfo("tcb=0x%p sigdeliver=0x%p\n", tcb, sigdeliver);
|
sinfo("tcb=0x%p sigdeliver=0x%p\n", tcb, sigdeliver);
|
||||||
|
|
||||||
@@ -109,8 +112,8 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
|||||||
* being delivered to the currently executing task.
|
* being delivered to the currently executing task.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
sinfo("rtcb=0x%p g_current_regs=0x%p\n",
|
sinfo("rtcb=0x%p CURRENT_REGS=0x%p\n",
|
||||||
this_task(), g_current_regs);
|
this_task(), CURRENT_REGS);
|
||||||
|
|
||||||
if (tcb == this_task())
|
if (tcb == this_task())
|
||||||
{
|
{
|
||||||
@@ -118,7 +121,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
|||||||
* a task is signalling itself for some reason.
|
* a task is signalling itself for some reason.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!g_current_regs)
|
if (!CURRENT_REGS)
|
||||||
{
|
{
|
||||||
/* In this case just deliver the signal now. */
|
/* In this case just deliver the signal now. */
|
||||||
|
|
||||||
@@ -134,7 +137,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
|||||||
* logic would fail in the strange case where we are in an
|
* logic would fail in the strange case where we are in an
|
||||||
* interrupt handler, the thread is signalling itself, but
|
* interrupt handler, the thread is signalling itself, but
|
||||||
* a context switch to another task has occurred so that
|
* a context switch to another task has occurred so that
|
||||||
* g_current_regs does not refer to the thread of this_task()!
|
* CURRENT_REGS does not refer to the thread of this_task()!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
else
|
else
|
||||||
@@ -145,19 +148,19 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
tcb->xcp.sigdeliver = sigdeliver;
|
tcb->xcp.sigdeliver = sigdeliver;
|
||||||
tcb->xcp.saved_epc = g_current_regs[REG_EPC];
|
tcb->xcp.saved_epc = CURRENT_REGS[REG_EPC];
|
||||||
tcb->xcp.saved_int_ctx = g_current_regs[REG_INT_CTX];
|
tcb->xcp.saved_int_ctx = CURRENT_REGS[REG_INT_CTX];
|
||||||
|
|
||||||
/* Then set up to vector to the trampoline with interrupts
|
/* Then set up to vector to the trampoline with interrupts
|
||||||
* disabled
|
* disabled
|
||||||
*/
|
*/
|
||||||
|
|
||||||
g_current_regs[REG_EPC] = (uintptr_t)up_sigdeliver;
|
CURRENT_REGS[REG_EPC] = (uintptr_t)up_sigdeliver;
|
||||||
|
|
||||||
int_ctx = g_current_regs[REG_INT_CTX];
|
int_ctx = CURRENT_REGS[REG_INT_CTX];
|
||||||
int_ctx &= ~MSTATUS_MIE;
|
int_ctx &= ~MSTATUS_MIE;
|
||||||
|
|
||||||
g_current_regs[REG_INT_CTX] = int_ctx;
|
CURRENT_REGS[REG_INT_CTX] = int_ctx;
|
||||||
|
|
||||||
/* And make sure that the saved context in the TCB
|
/* And make sure that the saved context in the TCB
|
||||||
* is the same as the interrupt return context.
|
* is the same as the interrupt return context.
|
||||||
@@ -165,9 +168,9 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
|||||||
|
|
||||||
up_savestate(tcb->xcp.regs);
|
up_savestate(tcb->xcp.regs);
|
||||||
|
|
||||||
sinfo("PC/STATUS Saved: %08x/%08x New: %08x/%08x\n",
|
sinfo("PC/STATUS Saved: %016x/%016x New: %016x/%016x\n",
|
||||||
tcb->xcp.saved_epc, tcb->xcp.saved_status,
|
tcb->xcp.saved_epc, tcb->xcp.saved_status,
|
||||||
g_current_regs[REG_EPC], g_current_regs[REG_INT_CTX]);
|
CURRENT_REGS[REG_EPC], CURRENT_REGS[REG_INT_CTX]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,7 +202,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
|||||||
|
|
||||||
tcb->xcp.regs[REG_INT_CTX] = int_ctx;
|
tcb->xcp.regs[REG_INT_CTX] = int_ctx;
|
||||||
|
|
||||||
sinfo("PC/STATUS Saved: %08x/%08x New: %08x/%08x\n",
|
sinfo("PC/STATUS Saved: %016x/%016x New: %016x/%016x\n",
|
||||||
tcb->xcp.saved_epc, tcb->xcp.saved_status,
|
tcb->xcp.saved_epc, tcb->xcp.saved_status,
|
||||||
tcb->xcp.regs[REG_EPC], tcb->xcp.regs[REG_INT_CTX]);
|
tcb->xcp.regs[REG_EPC], tcb->xcp.regs[REG_INT_CTX]);
|
||||||
}
|
}
|
||||||
@@ -207,3 +210,192 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
|||||||
|
|
||||||
leave_critical_section(flags);
|
leave_critical_section(flags);
|
||||||
}
|
}
|
||||||
|
#endif /* !CONFIG_SMP */
|
||||||
|
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
|
||||||
|
{
|
||||||
|
irqstate_t flags;
|
||||||
|
uint64_t int_ctx;
|
||||||
|
int cpu;
|
||||||
|
int me;
|
||||||
|
|
||||||
|
sinfo("tcb=0x%p sigdeliver=0x%p\n", tcb, sigdeliver);
|
||||||
|
|
||||||
|
/* Make sure that interrupts are disabled */
|
||||||
|
|
||||||
|
flags = enter_critical_section();
|
||||||
|
|
||||||
|
/* Refuse to handle nested signal actions */
|
||||||
|
|
||||||
|
if (!tcb->xcp.sigdeliver)
|
||||||
|
{
|
||||||
|
/* First, handle some special cases when the signal is being delivered
|
||||||
|
* to task that is currently executing on any CPU.
|
||||||
|
*/
|
||||||
|
|
||||||
|
sinfo("rtcb=0x%p CURRENT_REGS=0x%p\n", this_task(), CURRENT_REGS);
|
||||||
|
|
||||||
|
if (tcb->task_state == TSTATE_TASK_RUNNING)
|
||||||
|
{
|
||||||
|
me = this_cpu();
|
||||||
|
cpu = tcb->cpu;
|
||||||
|
|
||||||
|
/* CASE 1: We are not in an interrupt handler and a task is
|
||||||
|
* signaling itself for some reason.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (cpu == me && !CURRENT_REGS)
|
||||||
|
{
|
||||||
|
/* In this case just deliver the signal now.
|
||||||
|
* REVISIT: Signal handler will run in a critical section!
|
||||||
|
*/
|
||||||
|
|
||||||
|
sigdeliver(tcb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CASE 2: The task that needs to receive the signal is running.
|
||||||
|
* This could happen if the task is running on another CPU OR if
|
||||||
|
* we are in an interrupt handler and the task is running on this
|
||||||
|
* CPU. In the former case, we will have to PAUSE the other CPU
|
||||||
|
* first. But in either case, we will have to modify the return
|
||||||
|
* state as well as the state in the TCB.
|
||||||
|
*/
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* If we signaling a task running on the other CPU, we have
|
||||||
|
* to PAUSE the other CPU.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (cpu != me)
|
||||||
|
{
|
||||||
|
/* Pause the CPU */
|
||||||
|
|
||||||
|
up_cpu_pause(cpu);
|
||||||
|
|
||||||
|
/* Wait while the pause request is pending */
|
||||||
|
|
||||||
|
while (up_cpu_pausereq(cpu))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now tcb on the other CPU can be accessed safely */
|
||||||
|
|
||||||
|
/* Copy tcb->xcp.regs to tcp.xcp.saved. These will be restored
|
||||||
|
* by the signal trampoline after the signal has been delivered.
|
||||||
|
*/
|
||||||
|
|
||||||
|
tcb->xcp.sigdeliver = (FAR void *)sigdeliver;
|
||||||
|
tcb->xcp.saved_epc = tcb->xcp.regs[REG_EPC];
|
||||||
|
tcb->xcp.saved_int_ctx = tcb->xcp.regs[REG_INT_CTX];
|
||||||
|
|
||||||
|
/* Then set up vector to the trampoline with interrupts
|
||||||
|
* disabled. We must already be in privileged thread mode
|
||||||
|
* to be here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
tcb->xcp.regs[REG_EPC] = (uintptr_t)up_sigdeliver;
|
||||||
|
|
||||||
|
int_ctx = tcb->xcp.regs[REG_INT_CTX];
|
||||||
|
int_ctx &= ~MSTATUS_MIE;
|
||||||
|
|
||||||
|
tcb->xcp.regs[REG_INT_CTX] = int_ctx;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* tcb is running on the same CPU */
|
||||||
|
|
||||||
|
/* Save the return EPC and STATUS registers. These will be
|
||||||
|
* restored by the signal trampoline after the signal has been
|
||||||
|
* delivered.
|
||||||
|
*/
|
||||||
|
|
||||||
|
tcb->xcp.sigdeliver = (FAR void *)sigdeliver;
|
||||||
|
tcb->xcp.saved_epc = CURRENT_REGS[REG_EPC];
|
||||||
|
tcb->xcp.saved_int_ctx = CURRENT_REGS[REG_INT_CTX];
|
||||||
|
|
||||||
|
/* Then set up vector to the trampoline with interrupts
|
||||||
|
* disabled. The kernel-space trampoline must run in
|
||||||
|
* privileged thread mode.
|
||||||
|
*/
|
||||||
|
|
||||||
|
CURRENT_REGS[REG_EPC] = (uintptr_t)up_sigdeliver;
|
||||||
|
|
||||||
|
int_ctx = CURRENT_REGS[REG_INT_CTX];
|
||||||
|
int_ctx &= ~MSTATUS_MIE;
|
||||||
|
|
||||||
|
CURRENT_REGS[REG_INT_CTX] = int_ctx;
|
||||||
|
|
||||||
|
/* And make sure that the saved context in the TCB is the same
|
||||||
|
* as the interrupt return context.
|
||||||
|
*/
|
||||||
|
|
||||||
|
up_savestate(tcb->xcp.regs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Increment the IRQ lock count so that when the task is restarted,
|
||||||
|
* it will hold the IRQ spinlock.
|
||||||
|
*/
|
||||||
|
|
||||||
|
DEBUGASSERT(tcb->irqcount < INT16_MAX);
|
||||||
|
tcb->irqcount++;
|
||||||
|
|
||||||
|
/* In an SMP configuration, the interrupt disable logic also
|
||||||
|
* involves spinlocks that are configured per the TCB irqcount
|
||||||
|
* field. This is logically equivalent to enter_critical_section().
|
||||||
|
* The matching call to leave_critical_section() will be
|
||||||
|
* performed in up_sigdeliver().
|
||||||
|
*/
|
||||||
|
|
||||||
|
spin_setbit(&g_cpu_irqset, cpu, &g_cpu_irqsetlock,
|
||||||
|
&g_cpu_irqlock);
|
||||||
|
|
||||||
|
/* RESUME the other CPU if it was PAUSED */
|
||||||
|
|
||||||
|
if (cpu != me)
|
||||||
|
{
|
||||||
|
up_cpu_resume(cpu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, we are (1) signaling a task is not running from an
|
||||||
|
* interrupt handler or (2) we are not in an interrupt handler and the
|
||||||
|
* running task is signaling some other non-running task.
|
||||||
|
*/
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Save the return EPC and STATUS registers. These will be
|
||||||
|
* by the signal trampoline after the signal has been delivered.
|
||||||
|
*/
|
||||||
|
|
||||||
|
tcb->xcp.sigdeliver = (FAR void *)sigdeliver;
|
||||||
|
tcb->xcp.saved_epc = tcb->xcp.regs[REG_EPC];
|
||||||
|
tcb->xcp.saved_int_ctx = tcb->xcp.regs[REG_INT_CTX];
|
||||||
|
|
||||||
|
/* Increment the IRQ lock count so that when the task is restarted,
|
||||||
|
* it will hold the IRQ spinlock.
|
||||||
|
*/
|
||||||
|
|
||||||
|
DEBUGASSERT(tcb->irqcount < INT16_MAX);
|
||||||
|
tcb->irqcount++;
|
||||||
|
|
||||||
|
/* Then set up to vector to the trampoline with interrupts
|
||||||
|
* disabled. We must already be in privileged thread mode to be
|
||||||
|
* here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
tcb->xcp.regs[REG_EPC] = (uintptr_t)up_sigdeliver;
|
||||||
|
|
||||||
|
int_ctx = tcb->xcp.regs[REG_INT_CTX];
|
||||||
|
int_ctx &= ~MSTATUS_MIE;
|
||||||
|
|
||||||
|
tcb->xcp.regs[REG_INT_CTX] = int_ctx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
leave_critical_section(flags);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_SMP */
|
||||||
|
|||||||
@@ -52,8 +52,10 @@
|
|||||||
|
|
||||||
#include <arch/board/board.h>
|
#include <arch/board/board.h>
|
||||||
|
|
||||||
#include "up_arch.h"
|
|
||||||
#include "sched/sched.h"
|
#include "sched/sched.h"
|
||||||
|
#include "irq/irq.h"
|
||||||
|
|
||||||
|
#include "up_arch.h"
|
||||||
#include "up_internal.h"
|
#include "up_internal.h"
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -156,48 +158,48 @@ static inline void up_registerdump(void)
|
|||||||
{
|
{
|
||||||
/* Are user registers available from interrupt processing? */
|
/* Are user registers available from interrupt processing? */
|
||||||
|
|
||||||
if (g_current_regs)
|
if (CURRENT_REGS)
|
||||||
{
|
{
|
||||||
_alert("EPC:%016x \n",
|
_alert("EPC:%016x \n",
|
||||||
g_current_regs[REG_EPC]);
|
CURRENT_REGS[REG_EPC]);
|
||||||
|
|
||||||
_alert("A0:%016x A1:%016x A2:%016x A3:%016x \n",
|
_alert("A0:%016x A1:%016x A2:%016x A3:%016x \n",
|
||||||
g_current_regs[REG_A0], g_current_regs[REG_A1],
|
CURRENT_REGS[REG_A0], CURRENT_REGS[REG_A1],
|
||||||
g_current_regs[REG_A2], g_current_regs[REG_A3]);
|
CURRENT_REGS[REG_A2], CURRENT_REGS[REG_A3]);
|
||||||
|
|
||||||
_alert("A4:%016x A5:%016x A6:%016x A7:%016x \n",
|
_alert("A4:%016x A5:%016x A6:%016x A7:%016x \n",
|
||||||
g_current_regs[REG_A4], g_current_regs[REG_A5],
|
CURRENT_REGS[REG_A4], CURRENT_REGS[REG_A5],
|
||||||
g_current_regs[REG_A6], g_current_regs[REG_A7]);
|
CURRENT_REGS[REG_A6], CURRENT_REGS[REG_A7]);
|
||||||
|
|
||||||
_alert("T0:%016x T1:%016x T2:%016x T3:%016x \n",
|
_alert("T0:%016x T1:%016x T2:%016x T3:%016x \n",
|
||||||
g_current_regs[REG_T0], g_current_regs[REG_T1],
|
CURRENT_REGS[REG_T0], CURRENT_REGS[REG_T1],
|
||||||
g_current_regs[REG_T2], g_current_regs[REG_T3]);
|
CURRENT_REGS[REG_T2], CURRENT_REGS[REG_T3]);
|
||||||
|
|
||||||
_alert("T4:%016x T5:%016x T6:%016x \n",
|
_alert("T4:%016x T5:%016x T6:%016x \n",
|
||||||
g_current_regs[REG_T4], g_current_regs[REG_T5],
|
CURRENT_REGS[REG_T4], CURRENT_REGS[REG_T5],
|
||||||
g_current_regs[REG_T6]);
|
CURRENT_REGS[REG_T6]);
|
||||||
|
|
||||||
_alert("S0:%016x S1:%016x S2:%016x S3:%016x \n",
|
_alert("S0:%016x S1:%016x S2:%016x S3:%016x \n",
|
||||||
g_current_regs[REG_S0], g_current_regs[REG_S1],
|
CURRENT_REGS[REG_S0], CURRENT_REGS[REG_S1],
|
||||||
g_current_regs[REG_S2], g_current_regs[REG_S3]);
|
CURRENT_REGS[REG_S2], CURRENT_REGS[REG_S3]);
|
||||||
|
|
||||||
_alert("S4:%016x S5:%016x S6:%016x S7:%016x \n",
|
_alert("S4:%016x S5:%016x S6:%016x S7:%016x \n",
|
||||||
g_current_regs[REG_S4], g_current_regs[REG_S5],
|
CURRENT_REGS[REG_S4], CURRENT_REGS[REG_S5],
|
||||||
g_current_regs[REG_S6], g_current_regs[REG_S7]);
|
CURRENT_REGS[REG_S6], CURRENT_REGS[REG_S7]);
|
||||||
|
|
||||||
_alert("S8:%016x S9:%016x S10:%016x S11:%016x \n",
|
_alert("S8:%016x S9:%016x S10:%016x S11:%016x \n",
|
||||||
g_current_regs[REG_S8], g_current_regs[REG_S9],
|
CURRENT_REGS[REG_S8], CURRENT_REGS[REG_S9],
|
||||||
g_current_regs[REG_S10], g_current_regs[REG_S11]);
|
CURRENT_REGS[REG_S10], CURRENT_REGS[REG_S11]);
|
||||||
|
|
||||||
#ifdef RISCV_SAVE_GP
|
#ifdef RISCV_SAVE_GP
|
||||||
_alert("GP:%016x SP:%016x FP:%016x TP:%016x RA:%016x \n",
|
_alert("GP:%016x SP:%016x FP:%016x TP:%016x RA:%016x \n",
|
||||||
g_current_regs[REG_GP], g_current_regs[REG_SP],
|
CURRENT_REGS[REG_GP], CURRENT_REGS[REG_SP],
|
||||||
g_current_regs[REG_FP], g_current_regs[REG_TP],
|
CURRENT_REGS[REG_FP], CURRENT_REGS[REG_TP],
|
||||||
g_current_regs[REG_RA]);
|
CURRENT_REGS[REG_RA]);
|
||||||
#else
|
#else
|
||||||
_alert("SP:%016x FP:%016x TP:%016x RA:%016x \n",
|
_alert("SP:%016x FP:%016x TP:%016x RA:%016x \n",
|
||||||
g_current_regs[REG_SP], g_current_regs[REG_FP],
|
CURRENT_REGS[REG_SP], CURRENT_REGS[REG_FP],
|
||||||
g_current_regs[REG_TP], g_current_regs[REG_RA]);
|
CURRENT_REGS[REG_TP], CURRENT_REGS[REG_RA]);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -259,10 +261,10 @@ static void up_dumpstate(void)
|
|||||||
|
|
||||||
/* Extract the user stack pointer */
|
/* Extract the user stack pointer */
|
||||||
|
|
||||||
sp = g_current_regs[REG_SP];
|
sp = CURRENT_REGS[REG_SP];
|
||||||
_alert("sp: %016x\n", sp);
|
_alert("sp: %016x\n", sp);
|
||||||
}
|
}
|
||||||
else if (g_current_regs)
|
else if (CURRENT_REGS)
|
||||||
{
|
{
|
||||||
_alert("ERROR: Stack pointer is not within the interrupt stack\n");
|
_alert("ERROR: Stack pointer is not within the interrupt stack\n");
|
||||||
up_stackdump(istackbase - istacksize, istackbase);
|
up_stackdump(istackbase - istacksize, istackbase);
|
||||||
@@ -309,11 +311,17 @@ static void _up_assert(int errorcode)
|
|||||||
|
|
||||||
/* Are we in an interrupt handler or the idle task? */
|
/* Are we in an interrupt handler or the idle task? */
|
||||||
|
|
||||||
if (g_current_regs || running_task()->flink == NULL)
|
if (CURRENT_REGS || running_task()->flink == NULL)
|
||||||
{
|
{
|
||||||
(void)up_irq_save();
|
(void)up_irq_save();
|
||||||
for (; ; )
|
for (; ; )
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
/* Try (again) to stop activity on other CPUs */
|
||||||
|
|
||||||
|
(void)spin_trylock(&g_cpu_irqlock);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if CONFIG_BOARD_RESET_ON_ASSERT >= 1
|
#if CONFIG_BOARD_RESET_ON_ASSERT >= 1
|
||||||
board_reset(CONFIG_BOARD_ASSERT_RESET_VALUE);
|
board_reset(CONFIG_BOARD_ASSERT_RESET_VALUE);
|
||||||
#endif
|
#endif
|
||||||
@@ -379,16 +387,32 @@ void up_assert(const uint8_t *filename, int lineno)
|
|||||||
|
|
||||||
(void)syslog_flush();
|
(void)syslog_flush();
|
||||||
|
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
#if CONFIG_TASK_NAME_SIZE > 0
|
||||||
|
_alert("Assertion failed CPU%d at file:%s line: %d task: %s\n",
|
||||||
|
up_cpu_index(), filename, lineno, rtcb->name);
|
||||||
|
#else
|
||||||
|
_alert("Assertion failed CPU%d at file:%s line: %d\n",
|
||||||
|
up_cpu_index(), filename, lineno);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
#if CONFIG_TASK_NAME_SIZE > 0
|
#if CONFIG_TASK_NAME_SIZE > 0
|
||||||
_alert("Assertion failed at file:%s line: %d task: %s\n",
|
_alert("Assertion failed at file:%s line: %d task: %s\n",
|
||||||
filename, lineno, rtcb->name);
|
filename, lineno, rtcb->name);
|
||||||
#else
|
#else
|
||||||
_alert("Assertion failed at file:%s line: %d\n",
|
_alert("Assertion failed at file:%s line: %d\n",
|
||||||
filename, lineno);
|
filename, lineno);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
up_dumpstate();
|
up_dumpstate();
|
||||||
|
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
/* Show the CPU number */
|
||||||
|
|
||||||
|
_alert("CPU%d:\n", up_cpu_index());
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Dump the state of all tasks (if available) */
|
/* Dump the state of all tasks (if available) */
|
||||||
|
|
||||||
up_showtasks();
|
up_showtasks();
|
||||||
|
|||||||
@@ -117,10 +117,10 @@ void up_block_task(struct tcb_s *tcb, tstate_t task_state)
|
|||||||
|
|
||||||
/* Are we in an interrupt handler? */
|
/* Are we in an interrupt handler? */
|
||||||
|
|
||||||
if (g_current_regs)
|
if (CURRENT_REGS)
|
||||||
{
|
{
|
||||||
/* Yes, then we have to do things differently.
|
/* Yes, then we have to do things differently.
|
||||||
* Just copy the g_current_regs into the OLD rtcb.
|
* Just copy the CURRENT_REGS into the OLD rtcb.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
up_savestate(rtcb->xcp.regs);
|
up_savestate(rtcb->xcp.regs);
|
||||||
|
|||||||
@@ -0,0 +1,123 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* arch/risc-v/src/rv64gc/up_fault.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 Masayuki Ishikawa. All rights reserved.
|
||||||
|
* Author: Masayuki Ishikawa <masayuki.ishikawa@gmail.com>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Included Files
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <nuttx/irq.h>
|
||||||
|
#include <nuttx/arch.h>
|
||||||
|
#include <nuttx/board.h>
|
||||||
|
#include <nuttx/syslog/syslog.h>
|
||||||
|
|
||||||
|
#include <arch/board/board.h>
|
||||||
|
|
||||||
|
#include "sched/sched.h"
|
||||||
|
#include "irq/irq.h"
|
||||||
|
|
||||||
|
#include "up_arch.h"
|
||||||
|
#include "up_internal.h"
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: up_fault
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This is Fault exception handler.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
void up_fault(int irq, uint64_t *regs)
|
||||||
|
{
|
||||||
|
CURRENT_REGS = regs;
|
||||||
|
|
||||||
|
_alert("EPC:%016x\n",
|
||||||
|
CURRENT_REGS[REG_EPC]);
|
||||||
|
|
||||||
|
_alert("Fault IRQ=%d \n", irq);
|
||||||
|
|
||||||
|
/* Dump register info */
|
||||||
|
|
||||||
|
_alert("A0:%016x A1:%016x A2:%016x A3:%016x \n",
|
||||||
|
CURRENT_REGS[REG_A0], CURRENT_REGS[REG_A1],
|
||||||
|
CURRENT_REGS[REG_A2], CURRENT_REGS[REG_A3]);
|
||||||
|
|
||||||
|
_alert("A4:%016x A5:%016x A6:%016x A7:%016x \n",
|
||||||
|
CURRENT_REGS[REG_A4], CURRENT_REGS[REG_A5],
|
||||||
|
CURRENT_REGS[REG_A6], CURRENT_REGS[REG_A7]);
|
||||||
|
|
||||||
|
_alert("T0:%016x T1:%016x T2:%016x T3:%016x \n",
|
||||||
|
CURRENT_REGS[REG_T0], CURRENT_REGS[REG_T1],
|
||||||
|
CURRENT_REGS[REG_T2], CURRENT_REGS[REG_T3]);
|
||||||
|
|
||||||
|
_alert("T4:%016x T5:%016x T6:%016x \n",
|
||||||
|
CURRENT_REGS[REG_T4], CURRENT_REGS[REG_T5],
|
||||||
|
CURRENT_REGS[REG_T6]);
|
||||||
|
|
||||||
|
_alert("S0:%016x S1:%016x S2:%016x S3:%016x \n",
|
||||||
|
CURRENT_REGS[REG_S0], CURRENT_REGS[REG_S1],
|
||||||
|
CURRENT_REGS[REG_S2], CURRENT_REGS[REG_S3]);
|
||||||
|
|
||||||
|
_alert("S4:%016x S5:%016x S6:%016x S7:%016x \n",
|
||||||
|
CURRENT_REGS[REG_S4], CURRENT_REGS[REG_S5],
|
||||||
|
CURRENT_REGS[REG_S6], CURRENT_REGS[REG_S7]);
|
||||||
|
|
||||||
|
_alert("S8:%016x S9:%016x S10:%016x S11:%016x \n",
|
||||||
|
CURRENT_REGS[REG_S8], CURRENT_REGS[REG_S9],
|
||||||
|
CURRENT_REGS[REG_S10], CURRENT_REGS[REG_S11]);
|
||||||
|
|
||||||
|
#ifdef RISCV_SAVE_GP
|
||||||
|
_alert("GP:%016x SP:%016x FP:%016x TP:%016x RA:%016x \n",
|
||||||
|
CURRENT_REGS[REG_GP], CURRENT_REGS[REG_SP],
|
||||||
|
CURRENT_REGS[REG_FP], CURRENT_REGS[REG_TP],
|
||||||
|
CURRENT_REGS[REG_RA]);
|
||||||
|
#else
|
||||||
|
_alert("SP:%016x FP:%016x TP:%016x RA:%016x \n",
|
||||||
|
CURRENT_REGS[REG_SP], CURRENT_REGS[REG_FP],
|
||||||
|
CURRENT_REGS[REG_TP], CURRENT_REGS[REG_RA]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
(void)up_irq_save();
|
||||||
|
}
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
void up_initial_state(struct tcb_s *tcb)
|
void up_initial_state(struct tcb_s *tcb)
|
||||||
{
|
{
|
||||||
struct xcptcontext *xcp = &tcb->xcp;
|
struct xcptcontext *xcp = &tcb->xcp;
|
||||||
uint32_t regval;
|
uint64_t regval;
|
||||||
|
|
||||||
/* Initialize the initial exception register context structure */
|
/* Initialize the initial exception register context structure */
|
||||||
|
|
||||||
|
|||||||
@@ -87,10 +87,10 @@ void up_release_pending(void)
|
|||||||
|
|
||||||
/* Are we operating in interrupt context? */
|
/* Are we operating in interrupt context? */
|
||||||
|
|
||||||
if (g_current_regs)
|
if (CURRENT_REGS)
|
||||||
{
|
{
|
||||||
/* Yes, then we have to do things differently.
|
/* Yes, then we have to do things differently.
|
||||||
* Just copy the g_current_regs into the OLD rtcb.
|
* Just copy the CURRENT_REGS into the OLD rtcb.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
up_savestate(rtcb->xcp.regs);
|
up_savestate(rtcb->xcp.regs);
|
||||||
|
|||||||
@@ -140,10 +140,10 @@ void up_reprioritize_rtr(struct tcb_s *tcb, uint8_t priority)
|
|||||||
|
|
||||||
/* Are we in an interrupt handler? */
|
/* Are we in an interrupt handler? */
|
||||||
|
|
||||||
if (g_current_regs)
|
if (CURRENT_REGS)
|
||||||
{
|
{
|
||||||
/* Yes, then we have to do things differently.
|
/* Yes, then we have to do things differently.
|
||||||
* Just copy the g_current_regs into the OLD rtcb.
|
* Just copy the CURRENT_REGS into the OLD rtcb.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
up_savestate(rtcb->xcp.regs);
|
up_savestate(rtcb->xcp.regs);
|
||||||
|
|||||||
@@ -84,6 +84,15 @@ void up_sigdeliver(void)
|
|||||||
|
|
||||||
int saved_errno = rtcb->pterrno;
|
int saved_errno = rtcb->pterrno;
|
||||||
|
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
/* In the SMP case, we must terminate the critical section while the signal
|
||||||
|
* handler executes, but we also need to restore the irqcount when the
|
||||||
|
* we resume the main thread of the task.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int16_t saved_irqcount;
|
||||||
|
#endif
|
||||||
|
|
||||||
board_autoled_on(LED_SIGNAL);
|
board_autoled_on(LED_SIGNAL);
|
||||||
|
|
||||||
sinfo("rtcb=%p sigdeliver=%p sigpendactionq.head=%p\n",
|
sinfo("rtcb=%p sigdeliver=%p sigpendactionq.head=%p\n",
|
||||||
@@ -94,6 +103,26 @@ void up_sigdeliver(void)
|
|||||||
|
|
||||||
up_copystate(regs, rtcb->xcp.regs);
|
up_copystate(regs, rtcb->xcp.regs);
|
||||||
|
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
/* In the SMP case, up_schedule_sigaction(0) will have incremented
|
||||||
|
* 'irqcount' in order to force us into a critical section. Save the
|
||||||
|
* pre-incremented irqcount.
|
||||||
|
*/
|
||||||
|
|
||||||
|
saved_irqcount = rtcb->irqcount - 1;
|
||||||
|
DEBUGASSERT(saved_irqcount >= 0);
|
||||||
|
|
||||||
|
/* Now we need call leave_critical_section() repeatedly to get the irqcount
|
||||||
|
* to zero, freeing all global spinlocks that enforce the critical section.
|
||||||
|
*/
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
leave_critical_section(regs[REG_INT_CTX]);
|
||||||
|
}
|
||||||
|
while (rtcb->irqcount > 0);
|
||||||
|
#endif /* CONFIG_SMP */
|
||||||
|
|
||||||
#ifndef CONFIG_SUPPRESS_INTERRUPTS
|
#ifndef CONFIG_SUPPRESS_INTERRUPTS
|
||||||
/* Then make sure that interrupts are enabled. Signal handlers must always
|
/* Then make sure that interrupts are enabled. Signal handlers must always
|
||||||
* run with interrupts enabled.
|
* run with interrupts enabled.
|
||||||
@@ -111,10 +140,28 @@ void up_sigdeliver(void)
|
|||||||
* errno that is needed by the user logic (it is probably EINTR).
|
* errno that is needed by the user logic (it is probably EINTR).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
sinfo("Resuming EPC: %08x INT_CTX: %08x\n",
|
sinfo("Resuming EPC: %016x INT_CTX: %016x\n",
|
||||||
regs[REG_EPC], regs[REG_INT_CTX]);
|
regs[REG_EPC], regs[REG_INT_CTX]);
|
||||||
|
|
||||||
|
/* Call enter_critical_section() to disable local interrupts before
|
||||||
|
* restoring local context.
|
||||||
|
*
|
||||||
|
* Here, we should not use up_irq_save() in SMP mode.
|
||||||
|
* For example, if we call up_irq_save() here and another CPU might
|
||||||
|
* have called up_cpu_pause() to this cpu, hence g_cpu_irqlock has
|
||||||
|
* been locked by the cpu, in this case, we would see a deadlock in
|
||||||
|
* later call of enter_critical_section() to restore irqcount.
|
||||||
|
* To avoid this situation, we need to call enter_critical_section().
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
(void)enter_critical_section();
|
||||||
|
#else
|
||||||
(void)up_irq_save();
|
(void)up_irq_save();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Restore the saved errno value */
|
||||||
|
|
||||||
rtcb->pterrno = saved_errno;
|
rtcb->pterrno = saved_errno;
|
||||||
|
|
||||||
/* Modify the saved return state with the actual saved values in the
|
/* Modify the saved return state with the actual saved values in the
|
||||||
@@ -131,16 +178,26 @@ void up_sigdeliver(void)
|
|||||||
regs[REG_INT_CTX] = rtcb->xcp.saved_int_ctx;
|
regs[REG_INT_CTX] = rtcb->xcp.saved_int_ctx;
|
||||||
rtcb->xcp.sigdeliver = NULL; /* Allows next handler to be scheduled */
|
rtcb->xcp.sigdeliver = NULL; /* Allows next handler to be scheduled */
|
||||||
|
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
/* Restore the saved 'irqcount' and recover the critical section
|
||||||
|
* spinlocks.
|
||||||
|
*
|
||||||
|
* REVISIT: irqcount should be one from the above call to
|
||||||
|
* enter_critical_section(). Could the saved_irqcount be zero? That
|
||||||
|
* would be a problem.
|
||||||
|
*/
|
||||||
|
|
||||||
|
DEBUGASSERT(rtcb->irqcount == 1);
|
||||||
|
while (rtcb->irqcount < saved_irqcount)
|
||||||
|
{
|
||||||
|
(void)enter_critical_section();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Then restore the correct state for this thread of
|
/* Then restore the correct state for this thread of
|
||||||
* execution.
|
* execution.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
board_autoled_off(LED_SIGNAL);
|
board_autoled_off(LED_SIGNAL);
|
||||||
up_fullcontextrestore(regs);
|
up_fullcontextrestore(regs);
|
||||||
|
|
||||||
/* up_fullcontextrestore() should not return but could if the software
|
|
||||||
* interrupts are disabled.
|
|
||||||
*/
|
|
||||||
|
|
||||||
DEBUGPANIC();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ int up_swint(int irq, FAR void *context, FAR void *arg)
|
|||||||
{
|
{
|
||||||
uint64_t *regs = (uint64_t *)context;
|
uint64_t *regs = (uint64_t *)context;
|
||||||
|
|
||||||
DEBUGASSERT(regs && regs == g_current_regs);
|
DEBUGASSERT(regs && regs == CURRENT_REGS);
|
||||||
|
|
||||||
/* Software interrupt 0 is invoked with REG_A0 (REG_X10) = system call
|
/* Software interrupt 0 is invoked with REG_A0 (REG_X10) = system call
|
||||||
* command and REG_A1-6 = variable number of
|
* command and REG_A1-6 = variable number of
|
||||||
@@ -147,16 +147,16 @@ int up_swint(int irq, FAR void *context, FAR void *arg)
|
|||||||
* A0 = SYS_restore_context
|
* A0 = SYS_restore_context
|
||||||
* A1 = restoreregs
|
* A1 = restoreregs
|
||||||
*
|
*
|
||||||
* In this case, we simply need to set g_current_regs to restore register
|
* In this case, we simply need to set CURRENT_REGS to restore register
|
||||||
* area referenced in the saved R1. context == g_current_regs is the normal
|
* area referenced in the saved R1. context == CURRENT_REGS is the normal
|
||||||
* exception return. By setting g_current_regs = context[R1], we force
|
* exception return. By setting CURRENT_REGS = context[R1], we force
|
||||||
* the return to the saved context referenced in $a1.
|
* the return to the saved context referenced in $a1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
case SYS_restore_context:
|
case SYS_restore_context:
|
||||||
{
|
{
|
||||||
DEBUGASSERT(regs[REG_A1] != 0);
|
DEBUGASSERT(regs[REG_A1] != 0);
|
||||||
g_current_regs = (uint64_t *)regs[REG_A1];
|
CURRENT_REGS = (uint64_t *)regs[REG_A1];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@ int up_swint(int irq, FAR void *context, FAR void *arg)
|
|||||||
*
|
*
|
||||||
* In this case, we save the context registers to the save register
|
* In this case, we save the context registers to the save register
|
||||||
* area referenced by the saved contents of R5 and then set
|
* area referenced by the saved contents of R5 and then set
|
||||||
* g_current_regs to the save register area referenced by the saved
|
* CURRENT_REGS to the save register area referenced by the saved
|
||||||
* contents of R6.
|
* contents of R6.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -180,7 +180,7 @@ int up_swint(int irq, FAR void *context, FAR void *arg)
|
|||||||
{
|
{
|
||||||
DEBUGASSERT(regs[REG_A1] != 0 && regs[REG_A2] != 0);
|
DEBUGASSERT(regs[REG_A1] != 0 && regs[REG_A2] != 0);
|
||||||
up_copystate((uint64_t *)regs[REG_A1], regs);
|
up_copystate((uint64_t *)regs[REG_A1], regs);
|
||||||
g_current_regs = (uint64_t *)regs[REG_A2];
|
CURRENT_REGS = (uint64_t *)regs[REG_A2];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -210,7 +210,7 @@ int up_swint(int irq, FAR void *context, FAR void *arg)
|
|||||||
* the original mode.
|
* the original mode.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
g_current_regs[REG_EPC] = rtcb->xcp.syscall[index].sysreturn;
|
CURRENT_REGS[REG_EPC] = rtcb->xcp.syscall[index].sysreturn;
|
||||||
#error "Missing logic -- need to restore the original mode"
|
#error "Missing logic -- need to restore the original mode"
|
||||||
rtcb->xcp.nsyscalls = index;
|
rtcb->xcp.nsyscalls = index;
|
||||||
|
|
||||||
@@ -237,7 +237,7 @@ int up_swint(int irq, FAR void *context, FAR void *arg)
|
|||||||
|
|
||||||
/* Verify that the SYS call number is within range */
|
/* Verify that the SYS call number is within range */
|
||||||
|
|
||||||
DEBUGASSERT(g_current_regs[REG_A0] < SYS_maxsyscall);
|
DEBUGASSERT(CURRENT_REGS[REG_A0] < SYS_maxsyscall);
|
||||||
|
|
||||||
/* Make sure that we got here that there is a no saved syscall
|
/* Make sure that we got here that there is a no saved syscall
|
||||||
* return address. We cannot yet handle nested system calls.
|
* return address. We cannot yet handle nested system calls.
|
||||||
@@ -256,7 +256,7 @@ int up_swint(int irq, FAR void *context, FAR void *arg)
|
|||||||
|
|
||||||
/* Offset R0 to account for the reserved values */
|
/* Offset R0 to account for the reserved values */
|
||||||
|
|
||||||
g_current_regs[REG_A0] -= CONFIG_SYS_RESERVED;
|
CURRENT_REGS[REG_A0] -= CONFIG_SYS_RESERVED;
|
||||||
|
|
||||||
/* Indicate that we are in a syscall handler. */
|
/* Indicate that we are in a syscall handler. */
|
||||||
|
|
||||||
@@ -271,10 +271,10 @@ int up_swint(int irq, FAR void *context, FAR void *arg)
|
|||||||
/* Report what happened. That might difficult in the case of a context switch */
|
/* Report what happened. That might difficult in the case of a context switch */
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_SYSCALL_INFO
|
#ifdef CONFIG_DEBUG_SYSCALL_INFO
|
||||||
if (regs != g_current_regs)
|
if (regs != CURRENT_REGS)
|
||||||
{
|
{
|
||||||
svcinfo("SWInt Return: Context switch!\n");
|
svcinfo("SWInt Return: Context switch!\n");
|
||||||
up_registerdump((const uint32_t *)g_current_regs);
|
up_registerdump((const uint32_t *)CURRENT_REGS);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,123 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* arch/risc-v/src/rv64gc/up_testset.S
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 Masayuki Ishikawa. All rights reserved.
|
||||||
|
* Author: Masayuki Ishikawa <masayuki.ishikawa@gmail.com>
|
||||||
|
*
|
||||||
|
* Based on arch/arm/src/armv7-m/gnu/up_testset.S
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Included Files
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <nuttx/config.h>
|
||||||
|
#include <arch/spinlock.h>
|
||||||
|
|
||||||
|
.file "arm_testset.S"
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Pre-processor Definitions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Symbols
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
.globl up_testset
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Assembly Macros
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
.text
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: up_testset
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Perform an atomic test and set operation on the provided spinlock.
|
||||||
|
*
|
||||||
|
* This function must be provided via the architecture-specific logic.
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* lock - The address of spinlock object (a0).
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* The spinlock is always locked upon return. The value of previous value
|
||||||
|
* of the spinlock variable is returned, either SP_LOCKED if the spinlock
|
||||||
|
* as previously locked (meaning that the test-and-set operation failed to
|
||||||
|
* obtain the lock) or SP_UNLOCKED if the spinlock was previously unlocked
|
||||||
|
* (meaning that we successfully obtained the lock)
|
||||||
|
*
|
||||||
|
* Modifies: a1, a2
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
.globl up_testset
|
||||||
|
.type up_testset, %function
|
||||||
|
|
||||||
|
up_testset:
|
||||||
|
|
||||||
|
li a1, SP_LOCKED
|
||||||
|
|
||||||
|
/* Test if the spinlock is locked or not */
|
||||||
|
|
||||||
|
retry:
|
||||||
|
lr.d a2, (a0) /* Test if spinlock is locked or not */
|
||||||
|
beq a2, a1, locked /* Already locked? Go to locked: */
|
||||||
|
|
||||||
|
/* Not locked ... attempt to lock it */
|
||||||
|
|
||||||
|
sc.d a2, a1, (a0) /* Attempt to set the locked state (a1) to (a0) */
|
||||||
|
bnez a2, retry /* a2 will not be zero, if sc.b failed, try again */
|
||||||
|
|
||||||
|
/* Lock acquired -- return SP_UNLOCKED */
|
||||||
|
|
||||||
|
fence /* Required before accessing protected resource */
|
||||||
|
li a0, SP_UNLOCKED
|
||||||
|
jr ra
|
||||||
|
|
||||||
|
/* Lock not acquired -- return SP_LOCKED */
|
||||||
|
|
||||||
|
locked:
|
||||||
|
li a0, SP_LOCKED
|
||||||
|
jr ra
|
||||||
|
.size up_testset, . - up_testset
|
||||||
|
.end
|
||||||
@@ -100,10 +100,10 @@ void up_unblock_task(struct tcb_s *tcb)
|
|||||||
|
|
||||||
/* Are we in an interrupt handler? */
|
/* Are we in an interrupt handler? */
|
||||||
|
|
||||||
if (g_current_regs)
|
if (CURRENT_REGS)
|
||||||
{
|
{
|
||||||
/* Yes, then we have to do things differently.
|
/* Yes, then we have to do things differently.
|
||||||
* Just copy the g_current_regs into the OLD rtcb.
|
* Just copy the CURRENT_REGS into the OLD rtcb.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
up_savestate(rtcb->xcp.regs);
|
up_savestate(rtcb->xcp.regs);
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
1. Download and install toolchain
|
||||||
|
|
||||||
|
$ curl https://static.dev.sifive.com/dev-tools/riscv64-unknown-elf-gcc-8.3.0-2019.08.0-x86_64-linux-ubuntu14.tar.gz
|
||||||
|
|
||||||
|
2. Build and install qemu
|
||||||
|
|
||||||
|
$ git clone https://github.com/qemu/qemu
|
||||||
|
$ cd qemu
|
||||||
|
$ ./configure --target-list=riscv64-softmmu
|
||||||
|
$ make
|
||||||
|
$ sudo make install
|
||||||
|
|
||||||
|
3. Modify defconfig
|
||||||
|
|
||||||
|
--- a/boards/risc-v/k210/maix-bit/configs/nsh/defconfig
|
||||||
|
+++ b/boards/risc-v/k210/maix-bit/configs/nsh/defconfig
|
||||||
|
@@ -25,6 +25,7 @@ CONFIG_EXAMPLES_HELLO=y
|
||||||
|
CONFIG_FS_PROCFS=y
|
||||||
|
CONFIG_IDLETHREAD_STACKSIZE=2048
|
||||||
|
CONFIG_INTELHEX_BINARY=y
|
||||||
|
+CONFIG_K210_WITH_QEMU=y
|
||||||
|
CONFIG_LIBC_PERROR_STDOUT=y
|
||||||
|
CONFIG_LIBC_STRERROR=y
|
||||||
|
CONFIG_MAX_TASKS=64
|
||||||
|
|
||||||
|
4. Configure and build NuttX
|
||||||
|
|
||||||
|
$ mkdir ./nuttx; cd ./nuttx
|
||||||
|
$ git clone https://bitbucket.org/nuttx/nuttx.git
|
||||||
|
$ git clone https://bitbucket.org/nuttx/apps.git
|
||||||
|
$ cd nuttx
|
||||||
|
$ make distclean
|
||||||
|
$ ./tools/configure.sh maix-bit:nsh
|
||||||
|
$ make V=1
|
||||||
|
|
||||||
|
5. Run the nuttx with qemu
|
||||||
|
|
||||||
|
$ qemu-system-riscv64 -nographic -machine sifive_u -bios ./nuttx
|
||||||
|
|
||||||
|
6. TODO
|
||||||
|
|
||||||
|
Support FPU
|
||||||
|
Support RISC-V User mode
|
||||||
@@ -32,4 +32,5 @@
|
|||||||
PLL setting (currently CPU clock freq is assumed to be 416MHz)
|
PLL setting (currently CPU clock freq is assumed to be 416MHz)
|
||||||
Boot from SPI-Flash
|
Boot from SPI-Flash
|
||||||
Support peripherals such as GPIO/SPI/I2C/...
|
Support peripherals such as GPIO/SPI/I2C/...
|
||||||
|
Support FPU
|
||||||
Support RISC-V User mode
|
Support RISC-V User mode
|
||||||
|
|||||||
@@ -57,9 +57,7 @@ CONFIG_TASK_NAME_SIZE=20
|
|||||||
CONFIG_TESTING_GETPRIME=y
|
CONFIG_TESTING_GETPRIME=y
|
||||||
CONFIG_TESTING_GETPRIME_STACKSIZE=2048
|
CONFIG_TESTING_GETPRIME_STACKSIZE=2048
|
||||||
CONFIG_TESTING_OSTEST=y
|
CONFIG_TESTING_OSTEST=y
|
||||||
CONFIG_UART0_RXBUFSIZE=8
|
|
||||||
CONFIG_UART0_SERIAL_CONSOLE=y
|
CONFIG_UART0_SERIAL_CONSOLE=y
|
||||||
CONFIG_UART0_TXBUFSIZE=8
|
|
||||||
CONFIG_USERMAIN_STACKSIZE=3072
|
CONFIG_USERMAIN_STACKSIZE=3072
|
||||||
CONFIG_USER_ENTRYPOINT="nsh_main"
|
CONFIG_USER_ENTRYPOINT="nsh_main"
|
||||||
CONFIG_WDOG_INTRESERVE=0
|
CONFIG_WDOG_INTRESERVE=0
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
#
|
||||||
|
# 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_NSH_DISABLE_LOSMART is not set
|
||||||
|
# CONFIG_STANDARD_SERIAL is not set
|
||||||
|
CONFIG_ARCH="risc-v"
|
||||||
|
CONFIG_ARCH_BOARD="maix-bit"
|
||||||
|
CONFIG_ARCH_BOARD_MAIX_BIT=y
|
||||||
|
CONFIG_ARCH_CHIP="k210"
|
||||||
|
CONFIG_ARCH_CHIP_K210=y
|
||||||
|
CONFIG_ARCH_INTERRUPTSTACK=2048
|
||||||
|
CONFIG_ARCH_RISCV=y
|
||||||
|
CONFIG_ARCH_STACKDUMP=y
|
||||||
|
CONFIG_BINFMT_DISABLE=y
|
||||||
|
CONFIG_BOARD_LOOPSPERMSEC=15000
|
||||||
|
CONFIG_BUILTIN=y
|
||||||
|
CONFIG_BUILTIN_PROXY_STACKSIZE=2048
|
||||||
|
CONFIG_DEBUG_FULLOPT=y
|
||||||
|
CONFIG_DEBUG_SYMBOLS=y
|
||||||
|
CONFIG_DEV_ZERO=y
|
||||||
|
CONFIG_EXAMPLES_HELLO=y
|
||||||
|
CONFIG_FS_PROCFS=y
|
||||||
|
CONFIG_FS_PROCFS_REGISTER=y
|
||||||
|
CONFIG_IDLETHREAD_STACKSIZE=2048
|
||||||
|
CONFIG_INTELHEX_BINARY=y
|
||||||
|
CONFIG_LIBC_PERROR_STDOUT=y
|
||||||
|
CONFIG_LIBC_STRERROR=y
|
||||||
|
CONFIG_MAX_TASKS=64
|
||||||
|
CONFIG_MAX_WDOGPARMS=2
|
||||||
|
CONFIG_NFILE_DESCRIPTORS=8
|
||||||
|
CONFIG_NFILE_STREAMS=8
|
||||||
|
CONFIG_NSH_ARCHINIT=y
|
||||||
|
CONFIG_NSH_BUILTIN_APPS=y
|
||||||
|
CONFIG_NSH_DISABLE_IFUPDOWN=y
|
||||||
|
CONFIG_NSH_DISABLE_MKDIR=y
|
||||||
|
CONFIG_NSH_DISABLE_RM=y
|
||||||
|
CONFIG_NSH_DISABLE_RMDIR=y
|
||||||
|
CONFIG_NSH_DISABLE_UMOUNT=y
|
||||||
|
CONFIG_NSH_FILEIOSIZE=64
|
||||||
|
CONFIG_NSH_READLINE=y
|
||||||
|
CONFIG_NSH_STRERROR=y
|
||||||
|
CONFIG_POSIX_SPAWN_PROXY_STACKSIZE=2048
|
||||||
|
CONFIG_PREALLOC_MQ_MSGS=4
|
||||||
|
CONFIG_PREALLOC_TIMERS=4
|
||||||
|
CONFIG_PREALLOC_WDOGS=16
|
||||||
|
CONFIG_RAM_SIZE=2097152
|
||||||
|
CONFIG_RAM_START=0x80400000
|
||||||
|
CONFIG_RAW_BINARY=y
|
||||||
|
CONFIG_READLINE_CMD_HISTORY=y
|
||||||
|
CONFIG_RR_INTERVAL=200
|
||||||
|
CONFIG_SCHED_INSTRUMENTATION=y
|
||||||
|
CONFIG_SCHED_INSTRUMENTATION_BUFFER=y
|
||||||
|
CONFIG_SCHED_WAITPID=y
|
||||||
|
CONFIG_SMP=y
|
||||||
|
CONFIG_SMP_NCPUS=2
|
||||||
|
CONFIG_SPINLOCK_IRQ=y
|
||||||
|
CONFIG_STACK_COLORATION=y
|
||||||
|
CONFIG_START_DAY=8
|
||||||
|
CONFIG_START_MONTH=1
|
||||||
|
CONFIG_START_YEAR=2020
|
||||||
|
CONFIG_SYSTEM_NSH=y
|
||||||
|
CONFIG_SYSTEM_TASKSET=y
|
||||||
|
CONFIG_TASK_NAME_SIZE=20
|
||||||
|
CONFIG_TESTING_GETPRIME=y
|
||||||
|
CONFIG_TESTING_GETPRIME_STACKSIZE=2048
|
||||||
|
CONFIG_TESTING_OSTEST=y
|
||||||
|
CONFIG_TESTING_SMP=y
|
||||||
|
CONFIG_UART0_SERIAL_CONSOLE=y
|
||||||
|
CONFIG_USERMAIN_STACKSIZE=3072
|
||||||
|
CONFIG_USER_ENTRYPOINT="nsh_main"
|
||||||
Reference in New Issue
Block a user