From 6b023fada4e7927798956c85a3b9c5b412cafbb8 Mon Sep 17 00:00:00 2001 From: Wxqwu Date: Sun, 29 Sep 2024 09:18:51 +0800 Subject: [PATCH] uniproton: interrupt stack overflow docs update, add interrupt stack protection and testcase Signed-off-by: wuxiaoqing --- .../config_armv8_ascend310b/defconfig | 2 + demos/ascend310b/CMakeLists.txt | 4 ++ demos/ascend310b/bsp/print.c | 7 +- doc/Uniproton_interrupt.md | 26 +++++++ src/arch/cpu/armv8/common/hwi/prt_hwi.c | 12 ++++ src/arch/cpu/armv8/common/prt_port.c | 18 +++++ src/core/kernel/include/prt_sys_external.h | 2 + testsuites/kern-test/CMakeLists.txt | 12 +++- testsuites/kern-test/interrupt_test.c | 70 +++++++++++++++++++ 9 files changed, 149 insertions(+), 4 deletions(-) create mode 100644 doc/Uniproton_interrupt.md create mode 100644 testsuites/kern-test/interrupt_test.c diff --git a/build/uniproton_config/config_armv8_ascend310b/defconfig b/build/uniproton_config/config_armv8_ascend310b/defconfig index 1a4d5d35..e190af37 100644 --- a/build/uniproton_config/config_armv8_ascend310b/defconfig +++ b/build/uniproton_config/config_armv8_ascend310b/defconfig @@ -35,6 +35,8 @@ CONFIG_OS_BYTE_ORDER="OS_LITTLE_ENDIAN" # CONFIG_OS_OPTION_SMP is not set # CONFIG_OS_OPTION_DCACHE is not set CONFIG_OS_CACHE_LINE_SIZE=64 +# CONFIG_OS_OPTION_INTERRUPT_PRO is not set +# CONFIG_OS_OPTION_INTERRUPT_PRO=y # # Openamp Modules Configuration, mutually exclusive with Guest diff --git a/demos/ascend310b/CMakeLists.txt b/demos/ascend310b/CMakeLists.txt index 5eb30689..6044049f 100644 --- a/demos/ascend310b/CMakeLists.txt +++ b/demos/ascend310b/CMakeLists.txt @@ -124,6 +124,10 @@ if (${CONFIG_OS_OPTION_OPENAMP}) target_compile_options(rpmsg PUBLIC -DPOSIX_TESTCASE -DLOG_TESTCASE) target_compile_options(config PUBLIC -DPOSIX_TESTCASE -DLOG_TESTCASE) list(APPEND OBJS $ $ $ $) + elseif(${APP} STREQUAL "UniPorton_test_ir") + add_subdirectory(${HOME_PATH}/testsuites/kern-test tmp) + target_compile_options(rpmsg PUBLIC -DPOSIX_TESTCASE) + list(APPEND OBJS $ $ $ $) else() list(APPEND OBJS $ $ $) endif() diff --git a/demos/ascend310b/bsp/print.c b/demos/ascend310b/bsp/print.c index 99404501..e183837d 100644 --- a/demos/ascend310b/bsp/print.c +++ b/demos/ascend310b/bsp/print.c @@ -33,9 +33,10 @@ static void TestPutc(unsigned char ch) #else void uart_poll_send(unsigned char ch) { - volatile int time = 100; - *(unsigned long long int *)(UART_BASE_ADDR + UART_DR) = ch; - while(time--); + while (UART_REG(UART_FR) & UART_TXFF) { + asm volatile("yield" ::: "memory"); + } + UART_REG(UART_DR) = ch; } void TestPutc(unsigned char ch) diff --git a/doc/Uniproton_interrupt.md b/doc/Uniproton_interrupt.md new file mode 100644 index 00000000..58ac05e3 --- /dev/null +++ b/doc/Uniproton_interrupt.md @@ -0,0 +1,26 @@ +# Uniproton 中断栈溢出保护使用指南 + +## 1 整体方案: +目前使用软件保护方案。在分配系统栈(中断栈)时,初始化系统栈时写入魔鬼数字,每次发送中断时,检查本核的系统栈栈顶魔鬼数字是否被改变,若栈顶魔鬼数字被改变,则说明栈溢出,则进入中断栈溢出处理程序。 + +中断栈溢出时,进入异常,并打印出本核系统栈溢出的提示信息。 + +## 2 编译时使能中断栈保护功能: +使用中断栈溢出保护功能,需要在defconfig设置 +``` +CONFIG_OS_OPTION_INTERRUPT_PRO=y +``` +## 3 中断栈保护功能适配: +中断栈保护功能接口参考OsSysStackCheck, 系统栈初始化参考InitSystemStack(); + +**测试套参考:** + +testsuites/kern-test/interrupt_test.c + +测试套中发送中断,通过中断函数中创建大数组触发中断栈溢出。 +``` +volatile U32 list[6000] = {0}; // 创建大于系统栈大小的数组,中断栈溢出。 +list[100] = 1; +TEST_LOG("[SUCCESS] reccceived test interrupt handler.\n"); +``` +目前已经在demos/ascend310b/CMakeLists.txt适配测试套UniPorton_test_ir。 \ No newline at end of file diff --git a/src/arch/cpu/armv8/common/hwi/prt_hwi.c b/src/arch/cpu/armv8/common/hwi/prt_hwi.c index 69292c65..9e87325d 100644 --- a/src/arch/cpu/armv8/common/hwi/prt_hwi.c +++ b/src/arch/cpu/armv8/common/hwi/prt_hwi.c @@ -17,6 +17,7 @@ #include "prt_irq_external.h" #include "prt_hwi_internal.h" +extern U32 PRT_Printf(const char *format, ...); OS_SEC_DATA OsVoidFunc g_hwiSplLockHook = NULL; OS_SEC_DATA OsVoidFunc g_hwiSplUnLockHook = NULL; /* @@ -114,6 +115,14 @@ OS_SEC_TEXT void OsHwiReportHwiNumErr(void) return; } +void OsSysStackCheck(void) +{ + if (*((U32 *)(OsGetSysStackStart(OsGetHwThreadId()))) != OS_SYS_STACK_TOP_MAGIC) { + PRT_Printf("Core: %u system stack overflow, magic word changed to 0x%x\n", + OsGetHwThreadId(), *((U32 *)(OsGetSysStackStart(OsGetHwThreadId())))); + OsAsmIll(); + } +} /* * 描述: 中断处理, 调用处外部已关中断 */ @@ -143,6 +152,9 @@ OS_SEC_L0_TEXT void OsHwiDispatchHandle(U32 arg1) OsHwiNestedIntEnable(); OsHwiHookDispatcher(hwiNum); OsHwiNestedIntDisable(); +#if defined(OS_OPTION_INTERRUPT_PRO) + OsSysStackCheck(); +#endif OS_HWI_CONTINUE: // 清除中断位 diff --git a/src/arch/cpu/armv8/common/prt_port.c b/src/arch/cpu/armv8/common/prt_port.c index da9b7821..65707aa6 100644 --- a/src/arch/cpu/armv8/common/prt_port.c +++ b/src/arch/cpu/armv8/common/prt_port.c @@ -46,6 +46,7 @@ #define ARMV8_X29_INIT_VALUE 0x29292929UL #define ARMV8_SPSR_INIT_VALUE 0x305U // EL1_SP1 | D | A | I | F +extern U32 PRT_Printf(const char *format, ...); /* Tick中断对应的硬件定时器ID */ OS_SEC_DATA U32 g_tickTimerID = U32_INVALID; @@ -53,6 +54,21 @@ OS_SEC_DATA U32 g_tickTimerID = U32_INVALID; // 系统栈配置 OS_SEC_DATA uintptr_t g_sysStackHigh[OS_VAR_ARRAY_NUM] = {(uintptr_t)&__os_sys_sp_end}; OS_SEC_DATA uintptr_t g_sysStackLow[OS_VAR_ARRAY_NUM] = {(uintptr_t)&__os_sys_sp_start}; + +/* + * 描述: 将系统栈初始化为魔术字 + */ +INIT_SEC_L4_TEXT void InitSystemStack(void) +{ + U32 loop; + U32 stackSize = (U32)((uintptr_t)(&__os_sys_sp_end) - (uintptr_t)(&__os_sys_sp_start)); + + /* 初始化系统栈,并写入栈魔术字 */ + for (loop = 1; loop < (stackSize / sizeof(U32)); loop++) { + *((U32 *)((uintptr_t)&__os_sys_sp_end) - loop) = OS_SYS_STACK_TOP_MAGIC; + } + *((U32 *)((uintptr_t)&__os_sys_sp_start)) = OS_SYS_STACK_TOP_MAGIC; +} /* * 描述: 分配各核的系统栈空间 */ @@ -70,11 +86,13 @@ INIT_SEC_L4_TEXT void InitSystemSp(void) g_sysStackLow[loop] = g_sysStackHigh[loop] - stackStep; } + InitSystemStack(); return; } #else INIT_SEC_L4_TEXT void InitSystemSp(void) { + InitSystemStack(); return; } #endif diff --git a/src/core/kernel/include/prt_sys_external.h b/src/core/kernel/include/prt_sys_external.h index 3831454a..d4ff5fab 100644 --- a/src/core/kernel/include/prt_sys_external.h +++ b/src/core/kernel/include/prt_sys_external.h @@ -28,6 +28,8 @@ #define OS_VAR_ARRAY_NUM OS_MAX_CORE_NUM #endif +#define OS_SYS_STACK_TOP_MAGIC 0xC5A2C1C6 + #define ARRAY_COUNT(arr) (sizeof(arr) / sizeof((arr)[0])) #if defined(OS_OPTION_SMP) diff --git a/testsuites/kern-test/CMakeLists.txt b/testsuites/kern-test/CMakeLists.txt index 201605dd..f4cf3f27 100644 --- a/testsuites/kern-test/CMakeLists.txt +++ b/testsuites/kern-test/CMakeLists.txt @@ -1,6 +1,7 @@ if ((NOT ${APP} STREQUAL "UniPorton_test_sem") AND (NOT ${APP} STREQUAL "UniPorton_test_rr_sched") AND - (NOT ${APP} STREQUAL "UniPorton_test_mmu")) + (NOT ${APP} STREQUAL "UniPorton_test_mmu") AND + (NOT ${APP} STREQUAL "UniPorton_test_ir")) return() endif() @@ -28,4 +29,13 @@ if (${APP} STREQUAL "UniPorton_test_mmu") endif() endif() +if (${APP} STREQUAL "UniPorton_test_ir") + if(${CONFIG_OS_ARCH_ARMV8}) + set(BUILD_APP "UniPorton_test_ir") + set(ALL_SRC interrupt_test.c kern_test_public.c) + else() + return() + endif() +endif() + add_library(kernTest OBJECT ${ALL_SRC}) diff --git a/testsuites/kern-test/interrupt_test.c b/testsuites/kern-test/interrupt_test.c new file mode 100644 index 00000000..0d1a0aed --- /dev/null +++ b/testsuites/kern-test/interrupt_test.c @@ -0,0 +1,70 @@ +#include "prt_config.h" +#include "prt_task.h" +#include "prt_mem.h" +#include "prt_sem.h" +#include "prt_log.h" +#include "prt_clk.h" +#include "prt_sys_external.h" +#include "prt_task_external.h" +#include "securec.h" +#include "time.h" +#include "kern_test_public.h" +#include "prt_proxy_ext.h" +#define dprintf(format, ...) PRT_ProxyPrintf(format, ##__VA_ARGS__) + +#if !defined(OS_OPTION_SMP) +extern void OsHwiMcTrigger(U32 coreMask, U32 hwiNum); +#else +extern void OsHwiMcTrigger(enum OsHwiIpiType type, U32 coreMask, U32 hwiNum); +#endif + +static void test_interrupt_handler(void) +{ + volatile U32 list[17000] = {0}; // 创建大于系统栈大小的数组,中断栈溢出。 + list[100] = 1; + TEST_LOG("[SUCCESS] reccceived test interrupt handler.\n"); +} + +static int test_interrupt_create(U32 hwirq, void *handler_function) +{ + U32 ret = PRT_HwiSetAttr(hwirq, 10, OS_HWI_MODE_ENGROSS); + if (ret != OS_OK) { + return ret; + } + ret = PRT_HwiCreate(hwirq, (HwiProcFunc)handler_function, 0); + if (ret != OS_OK) { + return ret; + } + ret = PRT_HwiEnable(hwirq); + if (ret != OS_OK) { + return ret; + } + dprintf("[SUCCESS] test_interrupt_create.\n"); + return OS_OK; +} + + +static int test_interrupt_protection(void) +{ + U32 loop; + test_interrupt_create(OS_HWI_IPI_NO_015, test_interrupt_handler); + +#if !defined(OS_OPTION_SMP) + OsHwiMcTrigger(0xf, OS_HWI_IPI_NO_015); +#else + OsHwiMcTrigger(OS_TYPE_TRIGGER_TO_SELF, 0, OS_HWI_IPI_NO_015); +#endif + + return 0; +} + +test_case_t g_cases[] = { + TEST_CASE_Y(test_interrupt_protection), +}; + +int g_test_case_size = sizeof(g_cases); + +void prt_kern_test_end() +{ + TEST_LOG("interrupt protection check test finished\n"); +} \ No newline at end of file -- Gitee