diff --git a/Makefile b/Makefile index ce4564ba..d75d1aef 100644 --- a/Makefile +++ b/Makefile @@ -52,7 +52,8 @@ $(eval BOARD_$(BOARD)=y) KCONFIG_FILES = \ platform/Kconfig \ kernel/Kconfig \ - loader/Kconfig + loader/Kconfig \ + user/Kconfig # Read configurations about system features and characteristics include mk/config.mk diff --git a/board/discoveryf4/defconfig b/board/discoveryf4/defconfig index 5c75ccda..61659c01 100644 --- a/board/discoveryf4/defconfig +++ b/board/discoveryf4/defconfig @@ -62,3 +62,89 @@ CONFIG_KPROBES=y CONFIG_SYMMAP=y CONFIG_PANIC_DUMP_STACK=y # CONFIG_LOADER is not set + +# +# User IRQ +# +# CONFIG_WWDG_USER_IRQ is not set +# CONFIG_PVD_USER_IRQ is not set +# CONFIG_TAMP_STAMP_USER_IRQ is not set +# CONFIG_RTC_WKUP_USER_IRQ is not set +# CONFIG_FLASH_USER_IRQ is not set +# CONFIG_RCC_USER_IRQ is not set +# CONFIG_EXTI0_USER_IRQ is not set +# CONFIG_EXTI1_USER_IRQ is not set +# CONFIG_EXTI2_USER_IRQ is not set +# CONFIG_EXTI3_USER_IRQ is not set +# CONFIG_EXTI4_USER_IRQ is not set +# CONFIG_DMA1_Stream0_USER_IRQ is not set +# CONFIG_DMA1_Stream1_USER_IRQ is not set +# CONFIG_DMA1_Stream2_USER_IRQ is not set +# CONFIG_DMA1_Stream3_USER_IRQ is not set +# CONFIG_DMA1_Stream4_USER_IRQ is not set +# CONFIG_DMA1_Stream5_USER_IRQ is not set +# CONFIG_DMA1_Stream6_USER_IRQ is not set +# CONFIG_ADC_USER_IRQ is not set +# CONFIG_CAN1_TX_USER_IRQ is not set +# CONFIG_CAN1_RX_USER_IRQ is not set +# CONFIG_CAN1_RX1_USER_IRQ is not set +# CONFIG_CAN1_SCE_USER_IRQ is not set +# CONFIG_EXTI9_5_USER_IRQ is not set +# CONFIG_TIM1_BRK_TIM9_USER_IRQ is not set +# CONFIG_TIM1_UP_TIM10_USER_IRQ is not set +# CONFIG_TIM1_TRG_COM_TIM11_USER_IRQ is not set +# CONFIG_TIM1_CC_USER_IRQ is not set +# CONFIG_TIM2_USER_IRQ is not set +# CONFIG_TIM3_USER_IRQ is not set +# CONFIG_TIM4_USER_IRQ is not set +# CONFIG_I2C1_EV_USER_IRQ is not set +# CONFIG_I2C1_ER_USER_IRQ is not set +# CONFIG_I2C2_EV_USER_IRQ is not set +# CONFIG_I2C2_ER_USER_IRQ is not set +# CONFIG_SPI1_USER_IRQ is not set +# CONFIG_SPI2_USER_IRQ is not set +# CONFIG_USART1_USER_IRQ is not set +# CONFIG_USART2_USER_IRQ is not set +# CONFIG_USART3_USER_IRQ is not set +# CONFIG_EXTI15_10_USER_IRQ is not set +# CONFIG_RTC_Alarm_USER_IRQ is not set +# CONFIG_OTG_FS_WKUP_USER_IRQ is not set +# CONFIG_TIM8_BRK_TIM12_USER_IRQ is not set +# CONFIG_TIM8_UP_TIM13_USER_IRQ is not set +# CONFIG_TIM8_TRG_COM_TIM14_USER_IRQ is not set +# CONFIG_TIM8_CC_USER_IRQ is not set +# CONFIG_DMA1_Stream7_USER_IRQ is not set +# CONFIG_FSMC_USER_IRQ is not set +# CONFIG_SDIO_USER_IRQ is not set +# CONFIG_TIM5_USER_IRQ is not set +# CONFIG_SPI3_USER_IRQ is not set +# CONFIG_UART4_USER_IRQ is not set +# CONFIG_UART5_USER_IRQ is not set +# CONFIG_TIM6_DAC_USER_IRQ is not set +# CONFIG_TIM7_USER_IRQ is not set +# CONFIG_DMA2_Stream0_USER_IRQ is not set +# CONFIG_DMA2_Stream1_USER_IRQ is not set +# CONFIG_DMA2_Stream2_USER_IRQ is not set +# CONFIG_DMA2_Stream3_USER_IRQ is not set +# CONFIG_DMA2_Stream4_USER_IRQ is not set +# CONFIG_ETH_USER_IRQ is not set +# CONFIG_ETH_WKUP_USER_IRQ is not set +# CONFIG_CAN2_TX_USER_IRQ is not set +# CONFIG_CAN2_RX0_USER_IRQ is not set +# CONFIG_CAN2_RX1_USER_IRQ is not set +# CONFIG_CAN2_SCE_USER_IRQ is not set +# CONFIG_OTG_FS_USER_IRQ is not set +# CONFIG_DMA2_Stream5_USER_IRQ is not set +# CONFIG_DMA2_Stream6_USER_IRQ is not set +# CONFIG_DMA2_Stream7_USER_IRQ is not set +# CONFIG_USART6_USER_IRQ is not set +# CONFIG_I2C3_EV_USER_IRQ is not set +# CONFIG_I2C3_ER_USER_IRQ is not set +# CONFIG_OTG_HS_EP1_OUT_USER_IRQ is not set +# CONFIG_OTG_HS_EP1_IN_USER_IRQ is not set +# CONFIG_OTG_HS_WKUP_USER_IRQ is not set +# CONFIG_OTG_HS_USER_IRQ is not set +# CONFIG_DCMI_USER_IRQ is not set +# CONFIG_CRYP_USER_IRQ is not set +# CONFIG_HASH_RNG_USER_IRQ is not set +# CONFIG_FPU_USER_IRQ is not set diff --git a/include/interrupt.h b/include/interrupt.h new file mode 100644 index 00000000..c4ead034 --- /dev/null +++ b/include/interrupt.h @@ -0,0 +1,15 @@ +#ifndef INTERRUPT_H_ +#define INTERRUPT_H_ + +#define DEFAULT_PRIORITY 1 + +void user_interrupt_config(tcb_t *from); +void user_interrupt_handler_update(tcb_t *thr); + +/* Platform depended */ +void user_irq_enable(int irq); +void user_irq_disable(int irq); +void user_irq_set_pending(int irq); +void user_irq_clear_pending(int irq); + +#endif diff --git a/include/interrupt_ipc.h b/include/interrupt_ipc.h new file mode 100644 index 00000000..2d8de9ba --- /dev/null +++ b/include/interrupt_ipc.h @@ -0,0 +1,24 @@ +#ifndef INTERRUPT_IPC_H_ +#define INTERRUPT_IPC_H_ + +/* interrupt ipc message */ +enum { + IRQ_IPC_IRQN = 0, + IRQ_IPC_TID = 1, + IRQ_IPC_HANDLER = 2, + IRQ_IPC_ACTION = 3, + IRQ_IPC_PRIORITY = 4 +}; + +#define IRQ_IPC_MSG_NUM IRQ_IPC_PRIORITY + +/* irq actions */ +enum { + USER_IRQ_ENABLE = 0, + USER_IRQ_DISABLE = 1, + USER_IRQ_FREE = 2 +}; + +#define USER_INTERRUPT_LABEL 0x928 + +#endif diff --git a/include/ipc.h b/include/ipc.h index d5268c43..8f96d977 100644 --- a/include/ipc.h +++ b/include/ipc.h @@ -12,4 +12,7 @@ void sys_ipc(uint32_t *param1); uint32_t ipc_deliver(void *data); +uint32_t ipc_read_mr(tcb_t *from, int i); +void ipc_write_mr(tcb_t *to, int i, uint32_t data); + #endif /* IPC_H_ */ diff --git a/include/platform/stm32f1/nvic.h b/include/platform/stm32f1/nvic.h index 663a7497..ce74f2dd 100644 --- a/include/platform/stm32f1/nvic.h +++ b/include/platform/stm32f1/nvic.h @@ -67,6 +67,7 @@ typedef enum IRQn { EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */ RTC_Alarm_IRQn = 41, /*!< RTC Alarm (A and B) through EXTI Line Interrupt */ OTG_FS_WKUP_IRQn = 42, /*!< USB OTG FS Wakeup through EXTI line interrupt */ + IRQn_NUM, } IRQn_Type; #define MAX_IRQn FPU_IRQn diff --git a/include/platform/stm32f4/exti.h b/include/platform/stm32f4/exti.h new file mode 100644 index 00000000..4d24628c --- /dev/null +++ b/include/platform/stm32f4/exti.h @@ -0,0 +1,28 @@ +#ifndef PLATFORM_STM32F4_EXTI_H_ +#define PLATFORM_STM32F4_EXTI_H_ + +#include +#include + +/* EXTI mode */ +#define EXTI_INTERRUPT_MODE 0x0 +#define EXTI_EVENT_MODE 0x4 + +/* EXTI trigger type */ +#define EXTI_RISING_TRIGGER 0x8 +#define EXTI_FALLING_TRIGGER 0xc +#define EXTI_RISING_FALLING_TRIGGER 0x10 + +#define EXTI_LINE(x) ((uint32_t)0x1 << x) + +struct exti_regs { + volatile uint32_t IMR; + volatile uint32_t EMR; + volatile uint32_t RTSR; + volatile uint32_t FTSR; + volatile uint32_t SWIER; + volatile uint32_t PR; +}; + + +#endif diff --git a/include/platform/stm32f4/nvic.h b/include/platform/stm32f4/nvic.h index 73650bb9..d27acbc6 100644 --- a/include/platform/stm32f4/nvic.h +++ b/include/platform/stm32f4/nvic.h @@ -106,6 +106,7 @@ typedef enum IRQn { CRYP_IRQn = 79, /*!< CRYP crypto global interrupt */ HASH_RNG_IRQn = 80, /*!< Hash and Rng global interrupt */ FPU_IRQn = 81, /*!< FPU global interrupt */ + IRQn_NUM, } IRQn_Type; #define MAX_IRQn FPU_IRQn @@ -268,4 +269,5 @@ inline static uint32_t NVIC_GetActive(IRQn_Type IRQn) (1 << ((uint32_t)(IRQn) & 0x1F))) ? 1 : 0); } +int nvic_is_setup(int irq); #endif /* __PLATFORM_STM32F4_NVIC_H__ */ diff --git a/include/platform/stm32f4/nvic_private.h b/include/platform/stm32f4/nvic_private.h index 1fbfe994..1f55ebbc 100644 --- a/include/platform/stm32f4/nvic_private.h +++ b/include/platform/stm32f4/nvic_private.h @@ -1,84 +1,410 @@ /* This header is only included internally. */ - +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_WWDG_USER_IRQ)) IRQ_VEC_N_OP(0) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_PVD_USER_IRQ)) IRQ_VEC_N_OP(1) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TAMP_STAMP_USER_IRQ)) IRQ_VEC_N_OP(2) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_RTC_WKUP_USER_IRQ)) IRQ_VEC_N_OP(3) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_FLASH_USER_IRQ)) IRQ_VEC_N_OP(4) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_RCC_USER_IRQ)) IRQ_VEC_N_OP(5) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_EXTI0_USER_IRQ)) IRQ_VEC_N_OP(6) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_EXTI1_USER_IRQ)) IRQ_VEC_N_OP(7) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_EXTI2_USER_IRQ)) IRQ_VEC_N_OP(8) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_EXTI3_USER_IRQ)) IRQ_VEC_N_OP(9) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_EXTI4_USER_IRQ)) IRQ_VEC_N_OP(10) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA1_Stream0_USER_IRQ)) IRQ_VEC_N_OP(11) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA1_Stream1_USER_IRQ)) IRQ_VEC_N_OP(12) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA1_Stream2_USER_IRQ)) IRQ_VEC_N_OP(13) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA1_Stream3_USER_IRQ)) IRQ_VEC_N_OP(14) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA1_Stream4_USER_IRQ)) IRQ_VEC_N_OP(15) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA1_Stream5_USER_IRQ)) IRQ_VEC_N_OP(16) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA1_Stream6_USER_IRQ)) IRQ_VEC_N_OP(17) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_ADC_USER_IRQ)) IRQ_VEC_N_OP(18) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_CAN1_TX_USER_IRQ)) IRQ_VEC_N_OP(19) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_CAN1_RX_USER_IRQ)) IRQ_VEC_N_OP(20) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_CAN1_RX1_USER_IRQ)) IRQ_VEC_N_OP(21) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_CAN1_SCE_USER_IRQ)) IRQ_VEC_N_OP(22) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_EXTI9_5_USER_IRQ)) IRQ_VEC_N_OP(23) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM1_BRK_TIM9_USER_IRQ)) IRQ_VEC_N_OP(24) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM1_UP_TIM10_USER_IRQ)) IRQ_VEC_N_OP(25) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM1_TRG_COM_TIM11_USER_IRQ)) IRQ_VEC_N_OP(26) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM1_CC_USER_IRQ)) IRQ_VEC_N_OP(27) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM2_USER_IRQ)) IRQ_VEC_N_OP(28) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM3_USER_IRQ)) IRQ_VEC_N_OP(29) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM4_USER_IRQ)) IRQ_VEC_N_OP(30) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_I2C1_EV_USER_IRQ)) IRQ_VEC_N_OP(31) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_I2C1_ER_USER_IRQ)) IRQ_VEC_N_OP(32) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_I2C2_EV_USER_IRQ)) IRQ_VEC_N_OP(33) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_I2C2_ER_USER_IRQ)) IRQ_VEC_N_OP(34) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_SPI1_USER_IRQ)) IRQ_VEC_N_OP(35) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_SPI2_USER_IRQ)) IRQ_VEC_N_OP(36) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_USART1_USER_IRQ)) IRQ_VEC_N_OP(37) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_USART2_USER_IRQ)) IRQ_VEC_N_OP(38) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_USART3_USER_IRQ)) IRQ_VEC_N_OP(39) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_EXTI15_10_USER_IRQ)) IRQ_VEC_N_OP(40) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_RTC_Alarm_USER_IRQ)) IRQ_VEC_N_OP(41) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_OTG_FS_WKUP_USER_IRQ)) IRQ_VEC_N_OP(42) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM8_BRK_TIM12_USER_IRQ)) IRQ_VEC_N_OP(43) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM8_UP_TIM13_USER_IRQ)) IRQ_VEC_N_OP(44) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM8_TRG_COM_TIM14_USER_IRQ)) IRQ_VEC_N_OP(45) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM8_CC_USER_IRQ)) IRQ_VEC_N_OP(46) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA1_Stream7_USER_IRQ)) IRQ_VEC_N_OP(47) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_FSMC_USER_IRQ)) IRQ_VEC_N_OP(48) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_SDIO_USER_IRQ)) IRQ_VEC_N_OP(49) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM5_USER_IRQ)) IRQ_VEC_N_OP(50) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_SPI3_USER_IRQ)) IRQ_VEC_N_OP(51) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_UART4_USER_IRQ)) IRQ_VEC_N_OP(52) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_UART5_USER_IRQ)) IRQ_VEC_N_OP(53) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM6_DAC_USER_IRQ)) IRQ_VEC_N_OP(54) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_TIM7_USER_IRQ)) IRQ_VEC_N_OP(55) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA2_Stream0_USER_IRQ)) IRQ_VEC_N_OP(56) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA2_Stream1_USER_IRQ)) IRQ_VEC_N_OP(57) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA2_Stream2_USER_IRQ)) IRQ_VEC_N_OP(58) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA2_Stream3_USER_IRQ)) IRQ_VEC_N_OP(59) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA2_Stream4_USER_IRQ)) IRQ_VEC_N_OP(60) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_ETH_USER_IRQ)) IRQ_VEC_N_OP(61) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_ETH_WKUP_USER_IRQ)) IRQ_VEC_N_OP(62) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_CAN2_TX_USER_IRQ)) IRQ_VEC_N_OP(63) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_CAN2_RX0_USER_IRQ)) IRQ_VEC_N_OP(64) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_CAN2_RX1_USER_IRQ)) IRQ_VEC_N_OP(65) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_CAN2_SCE_USER_IRQ)) IRQ_VEC_N_OP(66) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_OTG_FS_USER_IRQ)) IRQ_VEC_N_OP(67) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA2_Stream5_USER_IRQ)) IRQ_VEC_N_OP(68) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA2_Stream6_USER_IRQ)) IRQ_VEC_N_OP(69) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DMA2_Stream7_USER_IRQ)) IRQ_VEC_N_OP(70) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_USART6_USER_IRQ)) IRQ_VEC_N_OP(71) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_I2C3_EV_USER_IRQ)) IRQ_VEC_N_OP(72) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_I2C3_ER_USER_IRQ)) IRQ_VEC_N_OP(73) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_OTG_HS_EP1_OUT_USER_IRQ)) IRQ_VEC_N_OP(74) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_OTG_HS_EP1_IN_USER_IRQ)) IRQ_VEC_N_OP(75) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_OTG_HS_WKUP_USER_IRQ)) IRQ_VEC_N_OP(76) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_OTG_HS_USER_IRQ)) IRQ_VEC_N_OP(77) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_DCMI_USER_IRQ)) IRQ_VEC_N_OP(78) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_CRYP_USER_IRQ)) IRQ_VEC_N_OP(79) +#endif + +#if !defined(USER_INTERRUPT) || \ + (defined(USER_INTERRUPT) && defined(CONFIG_HASH_RNG_USER_IRQ)) IRQ_VEC_N_OP(80) +#endif + +#if !defined(USER_INTERRUPT) || (\ + defined(USER_INTERRUPT) && defined(CONFIG_FPU_USER_IRQ)) IRQ_VEC_N_OP(81) +#endif diff --git a/include/platform/stm32f429/nvic.h b/include/platform/stm32f429/nvic.h index 431639f8..4936a291 100644 --- a/include/platform/stm32f429/nvic.h +++ b/include/platform/stm32f429/nvic.h @@ -106,6 +106,7 @@ typedef enum IRQn { CRYP_IRQn = 79, /*!< CRYP crypto global interrupt */ HASH_RNG_IRQn = 80, /*!< Hash and Rng global interrupt */ FPU_IRQn = 81, /*!< FPU global interrupt */ + IRQn_NUM, } IRQn_Type; #define MAX_IRQn FPU_IRQn diff --git a/include/thread.h b/include/thread.h index 2e87c307..9346ee89 100644 --- a/include/thread.h +++ b/include/thread.h @@ -42,6 +42,8 @@ typedef enum { THREAD_IDLE, THREAD_KERNEL, THREAD_ROOT, + THREAD_INTERRUPT, + THREAD_IRQ_REQUEST, THREAD_LOG, THREAD_SYS = 16, /* Systembase */ THREAD_USER = CONFIG_INTR_THREAD_MAX /* Userbase */ diff --git a/kernel/build.mk b/kernel/build.mk index b7e04a19..35388702 100644 --- a/kernel/build.mk +++ b/kernel/build.mk @@ -17,7 +17,12 @@ kernel-y = \ syscall.o \ systhread.o \ thread.o \ - user-log.o \ + user-log.o + +ifdef CONFIG_BOARD_STM32F4DISCOVERY +kernel-y += \ + interrupt.o +endif KDB-$(CONFIG_KDB) = \ kdb.o diff --git a/kernel/interrupt.c b/kernel/interrupt.c new file mode 100644 index 00000000..6a158251 --- /dev/null +++ b/kernel/interrupt.c @@ -0,0 +1,359 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include INC_PLAT(nvic.h) + +void __interrupt_handler(int n); + +/* user interrupt vector */ +#define USER_IRQ_VEC(n) \ + void nvic_handler##n(void) __NAKED; \ + void nvic_handler##n(void) \ + { \ + irq_enter(); \ + __interrupt_handler(n); \ + request_schedule(); \ + irq_return(); \ + } + +#undef USER_INTERRUPT_USED +#define USER_INTERRUPT +#define IRQ_VEC_N_OP USER_IRQ_VEC +#include INC_PLAT(nvic_private.h) +#undef IRQ_VEC_N_OP +#undef USER_INTERRUPT + +typedef void (*irq_handler_t)(void); + +#define INVALID_IDX IRQn_NUM +#define INVALID_IRQ_NUM IRQn_NUM + +#define IS_VALID_IRQ_NUM(irq) ((irq) < INVALID_IRQ_NUM) + +struct user_irq { + tcb_t *thr; + int irq; + uint16_t action; + uint16_t priority; + irq_handler_t handler; + struct user_irq *next; +}; + +static struct user_irq *user_irqs[IRQn_NUM]; + +DECLARE_KTABLE(struct user_irq, user_irq_table, IRQn_NUM); + +struct user_irq_queue { + struct user_irq *head; + struct user_irq *tail; +}; + +static struct user_irq_queue user_irq_queue; + +static int user_irq_queue_is_empty(void) +{ + return (user_irq_queue.head == NULL); +} + +static void user_irq_queue_push(struct user_irq *uirq) +{ + if (user_irq_queue_is_empty()) { + user_irq_queue.head = user_irq_queue.tail = uirq; + } else { + user_irq_queue.tail->next = uirq; + user_irq_queue.tail = uirq; + } +} + +static struct user_irq *user_irq_queue_pop(void) +{ + struct user_irq *uirq; + if (user_irq_queue_is_empty()) + return NULL; + + uirq = user_irq_queue.head; + user_irq_queue.head = uirq->next; + uirq->next = NULL; + + return uirq; +} + +static void user_irq_queue_delete(int irq) +{ + struct user_irq **iter, *uirq; + + uirq = user_irqs[irq]; + for (iter = &user_irq_queue.head ; *iter != NULL ; iter = &(*iter)->next) { + if (*iter == uirq) { + *iter = uirq->next; + break; + } + } +} + +static inline void user_irq_reset_all(void) +{ + int i; + for (i = 0 ; i < IRQn_NUM ; i++) + user_irqs[i] = NULL; +} + +static struct user_irq *user_irq_create_default(int irq) +{ + if (IS_VALID_IRQ_NUM(irq)) { + struct user_irq *uirq; + + uirq = (struct user_irq *)ktable_alloc(&user_irq_table); + uirq->thr = NULL; + uirq->irq = irq; + uirq->action = 0; + uirq->priority = 0; + uirq->handler = NULL; + uirq->next = NULL; + + return uirq; + } + return NULL; +} + +static inline struct user_irq *user_irq_fetch(int irq) +{ + if (!user_irqs[irq]) + user_irqs[irq] = user_irq_create_default(irq); + return user_irqs[irq]; +} + +static void user_irq_release(int irq) +{ + if (IS_VALID_IRQ_NUM(irq)) { + struct user_irq *uirq = user_irqs[irq]; + + if (uirq != NULL) { + ktable_free(&user_irq_table, uirq); + user_irqs[irq] = NULL; + } + } +} + +static void irq_handler_ipc(struct user_irq *uirq) +{ + tcb_t *thr; + ipc_msg_tag_t tag; + + if (uirq == NULL || uirq->thr == NULL) + return; + + /* Prepare ipc for user interrupt thread */ + thr = uirq->thr; + tag.s.label = USER_INTERRUPT_LABEL; + tag.s.n_untyped = IRQ_IPC_MSG_NUM; + ipc_write_mr(thr, 0, tag.raw); + ipc_write_mr(thr, IRQ_IPC_IRQN + 1, (uint32_t)uirq->irq); + ipc_write_mr(thr, IRQ_IPC_HANDLER + 1, (uint32_t)uirq->handler); + ipc_write_mr(thr, IRQ_IPC_ACTION + 1, (uint32_t)uirq->action); + thr->utcb->sender = TID_TO_GLOBALID(THREAD_INTERRUPT); + thr->ipc_from = L4_NILTHREAD; +} + +static int irq_handler_enable(int irq) +{ + tcb_t *thr; + struct user_irq *uirq = user_irqs[irq]; + + assert(uirq != NULL); + + if (uirq->thr == NULL) + return -1; + + thr = uirq->thr; + + if (thr->state != T_RECV_BLOCKED) + return -1; + + irq_handler_ipc(uirq); + + return 0; +} + +/* +* Push n to irq queue. +* Select the first one in queue to run. +*/ +static void irq_schedule(int irq) +{ + struct user_irq *uirq; + + uirq = user_irq_fetch(irq); + irq_disable(); + user_irq_queue_push(uirq); + irq_enable(); + + irq_handler_enable(irq); +} + +static tcb_t *irq_handler_sched(struct sched_slot *slot) +{ + struct user_irq *uirq; + tcb_t *thr = NULL; + + irq_disable(); + uirq = user_irq_queue_pop(); + + if (uirq != NULL && (thr = uirq->thr) != NULL && + thr->state == T_RECV_BLOCKED) { + thr->state = T_RUNNABLE; + sched_slot_dispatch(SSI_INTR_THREAD, thr); + } + + irq_enable(); + + return thr; +} + +void __interrupt_handler(int irq) +{ + struct user_irq *uirq; + + uirq = user_irq_fetch(irq); + + if (uirq == NULL || + uirq->thr == NULL || + uirq->handler == NULL || + uirq->action != USER_IRQ_ENABLE) { + return; + } + + user_irq_disable(irq); /* No re-entry interrupt */ + irq_schedule(irq); +} + +void interrupt_init(void) +{ + user_irq_reset_all(); + sched_slot_set_handler(SSI_INTR_THREAD, irq_handler_sched); +} + +INIT_HOOK(interrupt_init, INIT_LEVEL_KERNEL_EARLY); + +void user_interrupt_config(tcb_t *from) +{ + ipc_msg_tag_t tag; + l4_thread_t tid; + struct user_irq *uirq; + int irq; + int action, priority; + irq_handler_t handler; + + tag.raw = ipc_read_mr(from, 0); + + if (tag.s.label != USER_INTERRUPT_LABEL) + return; + + irq = (uint16_t)from->ctx.regs[IRQ_IPC_IRQN + 1]; + tid = (l4_thread_t)from->ctx.regs[IRQ_IPC_TID + 1]; + action = (uint16_t)from->ctx.regs[IRQ_IPC_ACTION + 1]; + handler = (irq_handler_t)from->ctx.regs[IRQ_IPC_HANDLER + 1]; + priority = (uint16_t)from->ctx.regs[IRQ_IPC_PRIORITY + 1]; + + + user_irq_disable(irq); + + if (!IS_VALID_IRQ_NUM(irq)) + return; + + uirq = user_irq_fetch(irq); + + if (uirq == NULL) + return; + + /* update user irq config */ + if (tid != L4_NILTHREAD) + uirq->thr = thread_by_globalid(tid); + + uirq->action = (uint16_t)action; + + if (handler != NULL) + uirq->handler = handler; + + if (priority > 0) + uirq->priority = (uint16_t)priority; +} + +void user_interrupt_handler_update(tcb_t *thr) +{ + int irq; + + if (thr == NULL) + return; + + for (irq = 0 ; irq < IRQn_NUM ; irq++) { + struct user_irq *uirq; + uirq = user_irq_fetch(irq); + + if (uirq == NULL) + continue; + + if (uirq->thr == thr) { + /* make sure irq is cleared */ + /* clear pending bit */ + user_irq_clear_pending(irq); + switch (uirq->action) { + case USER_IRQ_ENABLE: + user_irq_enable(irq); + break; + case USER_IRQ_DISABLE: + irq_disable(); + user_irq_queue_delete(irq); + irq_enable(); + user_irq_disable(irq); + break; + case USER_IRQ_FREE: + irq_disable(); + user_irq_queue_delete(irq); + user_irq_release(irq); + irq_enable(); + /* reply ipc immediately */ + irq_handler_ipc(uirq); + thr->state = T_RUNNABLE; + break; + } + break; + } + } +} + +void user_irq_enable(int irq) +{ + if (nvic_is_setup(irq)) { + NVIC_EnableIRQ(irq); + } +} + +void user_irq_disable(int irq) +{ + if (nvic_is_setup(irq)) { + NVIC_ClearPendingIRQ(irq); + NVIC_DisableIRQ(irq); + } +} + +void user_irq_set_pending(int irq) +{ + if (nvic_is_setup(irq)) { + NVIC_SetPendingIRQ(irq); + } +} + +void user_irq_clear_pending(int irq) +{ + if (nvic_is_setup(irq)) { + NVIC_ClearPendingIRQ(irq); + } +} diff --git a/kernel/ipc.c b/kernel/ipc.c index f5b8a95b..b5f62c43 100644 --- a/kernel/ipc.c +++ b/kernel/ipc.c @@ -15,6 +15,7 @@ #include #include #include +#include extern tcb_t *caller; @@ -22,14 +23,14 @@ extern tcb_t *caller; extern tcb_t *thread_map[]; extern int thread_count; -static uint32_t ipc_read_mr(tcb_t *from, int i) +uint32_t ipc_read_mr(tcb_t *from, int i) { if (i >= 8) return from->utcb->mr[i - 8]; return from->ctx.regs[i]; } -static void ipc_write_mr(tcb_t *to, int i, uint32_t data) +void ipc_write_mr(tcb_t *to, int i, uint32_t data) { if (i >= 8) to->utcb->mr[i - 8] = data; @@ -225,6 +226,12 @@ void sys_ipc(uint32_t *param1) user_log(caller); caller->state = T_RUNNABLE; return; +#ifdef CONFIG_BOARD_STM32F4DISCOVERY + } else if (to_tid == TID_TO_GLOBALID(THREAD_IRQ_REQUEST)) { + user_interrupt_config(caller); + caller->state = T_RUNNABLE; + return; +#endif } else if ((to_thr && to_thr->state == T_RECV_BLOCKED) || to_tid == caller->t_globalid) { /* To thread who is waiting for us or sends to myself */ @@ -292,7 +299,11 @@ void sys_ipc(uint32_t *param1) return; } } +#ifdef CONFIG_BOARD_STM32F4DISCOVERY + } else if (from_tid != TID_TO_GLOBALID(THREAD_INTERRUPT)) { +#else } else { +#endif thr = thread_by_globalid(from_tid); if (thr->state == T_SEND_BLOCKED && @@ -306,6 +317,13 @@ void sys_ipc(uint32_t *param1) caller->state = T_RECV_BLOCKED; caller->ipc_from = from_tid; +#ifdef CONFIG_BOARD_STM32F4DISCOVERY + if (from_tid == TID_TO_GLOBALID(THREAD_INTERRUPT)) { + /* Threaded interrupt is ready */ + user_interrupt_handler_update(caller); + } +#endif + if (timeout) sys_ipc_timeout(timeout); @@ -328,7 +346,8 @@ uint32_t ipc_deliver(void *data) switch (thr->state) { case T_RECV_BLOCKED: if (thr->ipc_from != L4_NILTHREAD && - thr->ipc_from != L4_ANYTHREAD) { + thr->ipc_from != L4_ANYTHREAD && + thr->ipc_from != TID_TO_GLOBALID(THREAD_INTERRUPT)) { from_thr = thread_by_globalid(thr->ipc_from); if (from_thr->state == T_SEND_BLOCKED) do_ipc(from_thr, thr); diff --git a/kernel/memory.c b/kernel/memory.c index d621b99b..a6136a9f 100644 --- a/kernel/memory.c +++ b/kernel/memory.c @@ -74,7 +74,7 @@ static mempool_t memmap[] = { #endif DECLARE_MEMPOOL("APB1DEV", 0x40000000, 0x40007800, MP_UR | MP_UW | MP_DEVICES, MPT_DEVICES), - DECLARE_MEMPOOL("APB2_1DEV", 0x40010000, 0x40013400, + DECLARE_MEMPOOL("APB2_1DEV", 0x40010000, 0x40014c00, MP_UR | MP_UW | MP_DEVICES, MPT_DEVICES), DECLARE_MEMPOOL("APB2_2DEV", 0x40014000, 0x40014c00, MP_UR | MP_UW | MP_DEVICES, MPT_DEVICES), diff --git a/platform/Kconfig b/platform/Kconfig index 5e0a9e6a..40d58c62 100644 --- a/platform/Kconfig +++ b/platform/Kconfig @@ -62,4 +62,7 @@ config DBGPORT_USE_USART4 endchoice +if BOARD_STM32F4DISCOVERY +source platform/stm32f4/Kconfig +endif endmenu diff --git a/platform/stm32-common/nvic.c b/platform/stm32-common/nvic.c index 13b2bb61..bdd20820 100644 --- a/platform/stm32-common/nvic.c +++ b/platform/stm32-common/nvic.c @@ -28,6 +28,12 @@ void _undefined_handler(void) #include "platform/stm32f4/nvic_private.h" #undef IRQ_VEC_N_OP +extern void (* const g_pfnVectors[])(void); +int nvic_is_setup(int irq) +{ + return !(g_pfnVectors[irq + 16] == _undefined_handler); +} + void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup) { if (!(NVIC_PriorityGroup == NVIC_PriorityGroup_0 || diff --git a/platform/stm32f4/Kconfig b/platform/stm32f4/Kconfig new file mode 100644 index 00000000..182ce1ac --- /dev/null +++ b/platform/stm32f4/Kconfig @@ -0,0 +1,330 @@ +menu "User Interrupt Config" + +config WWDG_USER_IRQ + bool "User WWDG IRQ" + default n + +config PVD_USER_IRQ + bool "User PVD IRQ" + default n + +config TAMP_STAMP_USER_IRQ + bool "User TAMP_STAMP IRQ" + default n + +config RTC_WKUP_USER_IRQ + bool "User RTC_WKUP IRQ" + default n + +config FLASH_USER_IRQ + bool "User FLASH_USER IRQ" + default n + +config RCC_USER_IRQ + bool "User RCC IRQ" + default n + +config EXTI0_USER_IRQ + bool "User EXTI0 IRQ" + default n + +config EXTI1_USER_IRQ + bool "User EXIT1 IRQ" + default n + +config EXTI2_USER_IRQ + bool "User EXIT2 IRQ" + default n + +config EXTI3_USER_IRQ + bool "User EXIT3 IRQ" + default n + +config EXTI4_USER_IRQ + bool "User EXIT4 IRQ" + default n + +config DMA1_Stream0_USER_IRQ + bool "User DMA1_Stream0 IRQ" + default n + +config DMA1_Stream1_USER_IRQ + bool "User DMA1_Stream1 IRQ" + default n + +config DMA1_Stream2_USER_IRQ + bool "User DMA1_Stream2 IRQ" + default n + +config DMA1_Stream3_USER_IRQ + bool "User DMA1_Stream3 IRQ" + default n + +config DMA1_Stream4_USER_IRQ + bool "User DMA1_Stream4 IRQ" + default n + +config DMA1_Stream5_USER_IRQ + bool "User DMA1_Stream5 IRQ" + default n + +config DMA1_Stream6_USER_IRQ + bool "User DMA1_Stream6 IRQ" + default n + +config ADC_USER_IRQ + bool "User ADC IRQ" + default n + +config CAN1_TX_USER_IRQ + bool "CAN1 TX User IRQ" + default n + +config CAN1_RX_USER_IRQ + bool "CAN1 RX User IRQ" + default n + +config CAN1_RX1_USER_IRQ + bool "CAN1 RX1 User IRQ" + default n + +config CAN1_SCE_USER_IRQ + bool "CAN1 SEC User IRQ" + default n + +config EXTI9_5_USER_IRQ + bool "EXTI9_5 User IRQ" + default n + +config TIM1_BRK_TIM9_USER_IRQ + bool "TIM1_BRK_TIM9 User IRQ" + default n + +config TIM1_UP_TIM10_USER_IRQ + bool "TIM1_UP_TIM10 User IRQ" + default n + +config TIM1_TRG_COM_TIM11_USER_IRQ + bool "TIM1_TRG_COM_TIM11 User IRQ" + default n + +config TIM1_CC_USER_IRQ + bool "TIM1_CC User IRQ" + default n + +config TIM2_USER_IRQ + bool "TIM2 User IRQ" + default n + +config TIM3_USER_IRQ + bool "TIM3 User IRQ" + default n + +config TIM4_USER_IRQ + bool "TIM4 User IRQ" + default n + +config I2C1_EV_USER_IRQ + bool "I2C1_EV User IRQ" + default n + +config I2C1_ER_USER_IRQ + bool "I2C1_ER User IRQ" + default n + +config I2C2_EV_USER_IRQ + bool "I2C2_EV User IRQ" + default n + +config I2C2_ER_USER_IRQ + bool "I2C2_ER User IRQ" + default n + +config SPI1_USER_IRQ + bool "SPI1 User IRQ" + default n + +config SPI2_USER_IRQ + bool "SPI2 User IRQ" + default n + +config USART1_USER_IRQ + bool "USART1 User IRQ" + default n + +config USART2_USER_IRQ + bool "USART2 User IRQ" + default n + +config USART3_USER_IRQ + bool "USART3 User IRQ" + default n + +config EXTI15_10_USER_IRQ + bool "EXTI15_10 User IRQ" + default n + +config RTC_Alarm_USER_IRQ + bool "RTC Alarm User IRQ" + default n + +config OTG_FS_WKUP_USER_IRQ + bool "OTG_FS_WKUP User IRQ" + default n + +config TIM8_BRK_TIM12_USER_IRQ + bool "TIM8_BRK_TIM12 User IRQ" + default n + +config TIM8_UP_TIM13_USER_IRQ + bool "TIM8_UP_TIM13 User IRQ" + default n + +config TIM8_TRG_COM_TIM14_USER_IRQ + bool "TIM8_TRG_COM_TIM14 User IRQ" + default n + +config TIM8_CC_USER_IRQ + bool "TIM8_CC User IRQ" + default n + +config DMA1_Stream7_USER_IRQ + bool "DMA1_Stream7 User IRQ" + default n + +config FSMC_USER_IRQ + bool "FSMC User IRQ" + default n + +config SDIO_USER_IRQ + bool "SDIO User IRQ" + default n + +config TIM5_USER_IRQ + bool "TIM5 User IRQ" + default n + +config SPI3_USER_IRQ + bool "SPI3 User IRQ" + default n + +config UART4_USER_IRQ + bool "UART4 User IRQ" + default n + +config UART5_USER_IRQ + bool "UART5 User IRQ" + default n + +config TIM6_DAC_USER_IRQ + bool "TIM6_DAC User IRQ" + default n + +config TIM7_USER_IRQ + bool "TIM7 User IRQ" + default n + +config DMA2_Stream0_USER_IRQ + bool "DMA2 Stream0 User IRQ" + default n + +config DMA2_Stream1_USER_IRQ + bool "DMA2 Stream1 User IRQ" + default n + +config DMA2_Stream2_USER_IRQ + bool "DMA2 Stream2 User IRQ" + default n + +config DMA2_Stream3_USER_IRQ + bool "DMA2 Stream3 User IRQ" + default n + +config DMA2_Stream4_USER_IRQ + bool "DMA2_Stream4 User IRQ" + default n + +config ETH_USER_IRQ + bool "ETH User IRQ" + default n + +config ETH_WKUP_USER_IRQ + bool "ETH WKUP User IRQ" + default n + +config CAN2_TX_USER_IRQ + bool "CAN2 TX User IRQ" + default n + +config CAN2_RX0_USER_IRQ + bool "CAN2 RX0 User IRQ" + default n + +config CAN2_RX1_USER_IRQ + bool "CAN2 RX1 User IRQ" + default n + +config CAN2_SCE_USER_IRQ + bool "CAN2 SCE User IRQ" + default n + +config OTG_FS_USER_IRQ + bool "OTG FS User IRQ" + default n + +config DMA2_Stream5_USER_IRQ + bool "DMA2 Stream5 User IRQ" + default n + +config DMA2_Stream6_USER_IRQ + bool "DMA2 Stream6 User IRQ" + default n + +config DMA2_Stream7_USER_IRQ + bool "DMA2 Stream7 User IRQ" + default n + +config USART6_USER_IRQ + bool "USART6 User IRQ" + default n + +config I2C3_EV_USER_IRQ + bool "I2C3 EV User IRQ" + default n + +config I2C3_ER_USER_IRQ + bool "I2C3 ER User IRQ" + default n + +config OTG_HS_EP1_OUT_USER_IRQ + bool "OTG_HS_EP1_OUT User IRQ" + default n + +config OTG_HS_EP1_IN_USER_IRQ + bool "OTG_HS_EP1_IN User IRQ" + default n + +config OTG_HS_WKUP_USER_IRQ + bool "OTG_HS_WKUP User IRQ" + default n + +config OTG_HS_USER_IRQ + bool "OTG_HS User IRQ" + default n + +config DCMI_USER_IRQ + bool "DCMI User IRQ" + default n + +config CRYP_USER_IRQ + bool "CRYP User IRQ" + default n + +config HASH_RNG_USER_IRQ + bool "HASH_RNG User IRQ" + default n + +config FPU_USER_IRQ + bool "FPU User IRQ" + default n +endmenu diff --git a/user/Kconfig b/user/Kconfig new file mode 100644 index 00000000..055e6d3e --- /dev/null +++ b/user/Kconfig @@ -0,0 +1,11 @@ +# Copyright (c) 2015 The F9 Microkernel Project. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +menu "Test Case" +config EXTI_INTERRUPT_TEST + bool "EXTI interrupt test case" + default n + depends on EXTI0_USER_IRQ && EXTI1_USER_IRQ + +endmenu diff --git a/user/apps/build.mk b/user/apps/build.mk index a623963b..a4e714a0 100644 --- a/user/apps/build.mk +++ b/user/apps/build.mk @@ -6,6 +6,12 @@ user-apps-dirs = \ l4test \ pingpong + +ifdef CONFIG_EXTI_INTERRUPT_TEST +user-apps-dirs += \ + irq_test +endif + ifdef CONFIG_BOARD_STM32F429DISCOVERY user-apps-dirs += \ lcd_test diff --git a/user/apps/irq_test/build.mk b/user/apps/irq_test/build.mk new file mode 100644 index 00000000..eb26f6f0 --- /dev/null +++ b/user/apps/irq_test/build.mk @@ -0,0 +1,7 @@ +# Copyright (c) 2013 The F9 Microkernel Project. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +user-apps-irq_test-y = \ + user_exti.o \ + main.o \ diff --git a/user/apps/irq_test/main.c b/user/apps/irq_test/main.c new file mode 100644 index 00000000..88348f4d --- /dev/null +++ b/user/apps/irq_test/main.c @@ -0,0 +1,62 @@ +#include INC_PLAT(nvic.h) +#include INC_PLAT(registers.h) +#include INC_PLAT(exti.h) + +#include +#include +#include +#include +#include "user_exti.h" + +__USER_BSS +static uint32_t exti0_interrupt_num = 0; + +__USER_BSS +static uint32_t exti1_interrupt_num = 0; + +__USER_TEXT +void exti0_interrupt_handler(void) +{ + exti_clear(0); + L4_Sleep(L4_TimePeriod(500 * 1000)); + exti0_interrupt_num++; + exti_launch_sw_interrupt(1); + printf("%d: %s\n", L4_MyGlobalId(), __func__); +} + +__USER_TEXT +void exti1_interrupt_handler(void) +{ + exti_clear(1); + L4_Sleep(L4_TimePeriod(500 * 1000)); + exti1_interrupt_num++; + exti_launch_sw_interrupt(0); + printf("%d: %s\n", L4_MyGlobalId(), __func__); +} + +__USER_TEXT +static void *main(void *user) +{ + request_irq(EXTI0_IRQn, exti0_interrupt_handler, 1); + request_irq(EXTI1_IRQn, exti1_interrupt_handler, 1); + exti_config(0, EXTI_INTERRUPT_MODE, EXTI_RISING_TRIGGER); + exti_config(1, EXTI_INTERRUPT_MODE, EXTI_RISING_TRIGGER); + + exti_launch_sw_interrupt(0); + + /* Sleep 10s */ + L4_Sleep(L4_TimePeriod(10000000)); + free_irq(EXTI0_IRQn); + free_irq(EXTI1_IRQn); + + return 0; +} + +DECLARE_USER( + 128, + irq_test, + main, + DECLARE_FPAGE(0x0, 4 * (UTCB_SIZE + IRQ_STACK_SIZE)) + DECLARE_FPAGE(0x0, 512) + DECLARE_FPAGE(0x40010000, 0x4000) +); diff --git a/user/apps/irq_test/user_exti.c b/user/apps/irq_test/user_exti.c new file mode 100644 index 00000000..364626a7 --- /dev/null +++ b/user/apps/irq_test/user_exti.c @@ -0,0 +1,68 @@ +#include INC_PLAT(registers.h) +#include INC_PLAT(exti.h) +#include "user_exti.h" + +__USER_TEXT +void exti_config(uint32_t line, uint32_t mode, uint32_t trigger_type) +{ + struct exti_regs *exti_regs = (struct exti_regs *)EXTI_BASE; + + /* Clear EXTI mask */ + exti_regs->IMR &= ~EXTI_LINE(line); + exti_regs->EMR &= ~EXTI_LINE(line); + + *((volatile uint32_t *)(EXTI_BASE + mode)) |= EXTI_LINE(line); + + if (trigger_type == EXTI_RISING_FALLING_TRIGGER) { + exti_regs->RTSR |= EXTI_LINE(line); + exti_regs->FTSR |= EXTI_LINE(line); + } else { + *((volatile uint32_t *)(EXTI_BASE + mode)) |= EXTI_LINE(line); + } +} + +__USER_TEXT + void exti_enable(uint32_t line, uint32_t mode) +{ + *((volatile uint32_t *)(EXTI_BASE + mode)) |= EXTI_LINE(line); +} + +__USER_TEXT +void exti_disable(uint32_t line) +{ + struct exti_regs *exti_regs = (struct exti_regs *)EXTI_BASE; + + /* Clear EXTI mask */ + exti_regs->IMR &= ~EXTI_LINE(line); + exti_regs->EMR &= ~EXTI_LINE(line); +} + +__USER_TEXT +void exti_launch_sw_interrupt(uint32_t line) +{ + struct exti_regs *exti_regs = (struct exti_regs *)EXTI_BASE; + + exti_regs->SWIER |= EXTI_LINE(line); +} + +__USER_TEXT +void exti_clear(uint32_t line) +{ + struct exti_regs *exti_regs = (struct exti_regs *)EXTI_BASE; + + exti_regs->PR = EXTI_LINE(line); +} + +__USER_TEXT +int exti_interrupt_status(uint32_t line) +{ + struct exti_regs *exti_regs = (struct exti_regs *)EXTI_BASE; + + return (exti_regs->PR & EXTI_LINE(line)) && (exti_regs->IMR & EXTI_LINE(line)); +} + +__USER_TEXT +void exti_interrupt_status_clear(uint32_t line) +{ + exti_clear(line); +} diff --git a/user/apps/irq_test/user_exti.h b/user/apps/irq_test/user_exti.h new file mode 100644 index 00000000..dfac41fe --- /dev/null +++ b/user/apps/irq_test/user_exti.h @@ -0,0 +1,21 @@ +#ifndef USER_EXTI_H_ +#define USER_EXTI_H_ + +#include + +__USER_TEXT +void exti_config(uint32_t line, uint32_t mode, uint32_t trigger_type); + +__USER_TEXT +void exti_enable(uint32_t line, uint32_t mode); + +__USER_TEXT +void exti_disable(uint32_t line); + +__USER_TEXT +void exti_launch_sw_interrupt(uint32_t line); + +__USER_TEXT +void exti_clear(uint32_t line); + +#endif diff --git a/user/apps/pingpong/main.c b/user/apps/pingpong/main.c index 9456a9d4..c719b628 100644 --- a/user/apps/pingpong/main.c +++ b/user/apps/pingpong/main.c @@ -52,6 +52,7 @@ void *pong_thread(void *arg) printf("%p: recv ipc fails\n", L4_MyGlobalId()); printf("%p: ErrorCode = 0x%x\n", L4_MyGlobalId(), L4_ErrorCode()); } + L4_Sleep(L4_TimePeriod(500 * 1000)); } } diff --git a/user/include/user_interrupt.h b/user/include/user_interrupt.h new file mode 100644 index 00000000..eca05ace --- /dev/null +++ b/user/include/user_interrupt.h @@ -0,0 +1,29 @@ +#ifndef _USER_INTERRUPT_H_ +#define _USER_INTERRUPT_H_ +#include INC_PLAT(nvic.h) + +#include +#include +#include +#include +#include +#include +#include + +#define IRQ_STACK_SIZE 512 + +typedef void (*irq_handler_t)(void); + +__USER_TEXT +L4_Word_t request_irq(int irq, irq_handler_t handler, uint16_t priority); + +__USER_TEXT +L4_Word_t enable_irq(int irq); + +__USER_TEXT +L4_Word_t disable_irq(int irq); + +__USER_TEXT +L4_Word_t free_irq(int irq); + +#endif diff --git a/user/lib/io/build.mk b/user/lib/io/build.mk index 586cd175..983f4ee2 100644 --- a/user/lib/io/build.mk +++ b/user/lib/io/build.mk @@ -3,7 +3,8 @@ # found in the LICENSE file. user-lib-io-y = \ - l4io.o + l4io.o \ + user_interrupt.o ifeq "$(CONFIG_SEMIHOST)" "y" user-lib-io-y += \ diff --git a/user/lib/io/user_interrupt.c b/user/lib/io/user_interrupt.c new file mode 100644 index 00000000..4676af89 --- /dev/null +++ b/user/lib/io/user_interrupt.c @@ -0,0 +1,120 @@ +/* Copyright (c) 2015 The F9 Microkernel Project. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include +#include +#include +#include +#include +#include + +__USER_TEXT +static void *__interrupt_handler_thread(void *arg) +{ + do { + L4_Msg_t msg; + L4_MsgTag_t tag; + irq_handler_t handler; + L4_Word_t action; + L4_ThreadId_t recv_tid = { + .raw = TID_TO_GLOBALID(THREAD_INTERRUPT)}; + + tag = L4_Receive(recv_tid); + + L4_MsgStore(tag, &msg); + handler = (irq_handler_t)L4_MsgWord(&msg, IRQ_IPC_HANDLER); + action = L4_MsgWord(&msg, IRQ_IPC_ACTION); + + switch (action) { + case USER_IRQ_ENABLE: + handler(); + break; + case USER_IRQ_FREE: + return NULL; + } + } while(1); + +} + +__USER_TEXT +static void __irq_msg( + L4_Msg_t *out_msg, L4_ThreadId_t tid, + unsigned int irq, irq_handler_t handler, + L4_Word_t action, uint16_t priority) +{ + L4_Word_t irq_data[IRQ_IPC_MSG_NUM]; + + L4_MsgClear(out_msg); + + irq_data[IRQ_IPC_IRQN] = (L4_Word_t)irq; + irq_data[IRQ_IPC_TID] = (L4_Word_t)tid.raw; + irq_data[IRQ_IPC_HANDLER] = (L4_Word_t)handler; + irq_data[IRQ_IPC_ACTION] = (L4_Word_t)action; + irq_data[IRQ_IPC_PRIORITY] = (L4_Word_t)priority; + + /* Create msg for irq request */ + L4_MsgPut(out_msg, USER_INTERRUPT_LABEL, + IRQ_IPC_MSG_NUM, irq_data, 0, NULL); +} + +__USER_TEXT +static L4_Word_t __request_irq(L4_Msg_t *msg) +{ + L4_MsgTag_t ret; + L4_ThreadId_t send_tid = { + .raw = TID_TO_GLOBALID(THREAD_IRQ_REQUEST)}; + + /* Load msg to registers */ + L4_MsgLoad(msg); + + /* register irq in kernel */ + ret = L4_Send(send_tid); + + return ret.raw; +} + +__USER_TEXT +L4_Word_t request_irq(int irq, irq_handler_t handler, uint16_t priority) +{ + L4_Msg_t msg; + L4_ThreadId_t tid; + + /* Create thread for interrupt handler */ + tid = pager_create_thread(); + pager_start_thread(tid, __interrupt_handler_thread, NULL); + __irq_msg(&msg, tid, irq, handler, USER_IRQ_ENABLE, priority); + + return __request_irq(&msg); +} + +__USER_TEXT +L4_Word_t enable_irq(int irq) +{ + L4_Msg_t msg; + + __irq_msg(&msg, L4_nilthread, irq, NULL, USER_IRQ_ENABLE, -1); + + return __request_irq(&msg); +} + +__USER_TEXT +L4_Word_t disable_irq(int irq) +{ + L4_Msg_t msg; + + __irq_msg(&msg, L4_nilthread, irq, NULL, USER_IRQ_DISABLE, -1); + + return __request_irq(&msg); +} + +__USER_TEXT +L4_Word_t free_irq(int irq) +{ + L4_Msg_t msg; + + __irq_msg(&msg, L4_nilthread, irq, NULL, USER_IRQ_FREE, -1); + + return __request_irq(&msg); +} +