集成cmbacktrace && fatfs分离硬件接口

This commit is contained in:
zhangzheng
2025-03-17 00:35:42 +08:00
parent 137382205e
commit 3ecafaed24
73 changed files with 3024 additions and 204 deletions

View File

@@ -211,7 +211,12 @@
"u_rpc_1.h": "c",
"mk_sys.h": "c",
"environ.h": "c",
"lwipopts.h": "c"
"lwipopts.h": "c",
"pm_svr.h": "c",
"cm_backtrace.h": "c",
"xprintf.h": "c",
"cmb_def.h": "c",
"getopt.h": "c"
},
"cortex-debug.showRTOS": false,
"cortex-debug.variableUseNaturalFormat": true,

View File

@@ -1,20 +1,20 @@
message("========use armv7_8.cmake")
set(CMAKE_C_FLAGS "-mcpu=${CONFIG_ARCH} -Os -g3 -mfloat-abi=${CONFIG_FLOAT_TYPE} -mthumb -DMKRTOS \
set(CMAKE_C_FLAGS "-mcpu=${CONFIG_ARCH} -O0 -g3 -mfloat-abi=${CONFIG_FLOAT_TYPE} -mthumb -DMKRTOS \
-std=gnu11 -ffunction-sections -fdata-sections -fno-builtin -u=_printf_float \
-nostartfiles -nodefaultlibs -nostdlib -nostdinc \
-fno-stack-protector -Wl,--gc-section -D__ARM_ARCH_7M__ \
-include ${CMAKE_SOURCE_DIR}/build/autoconf.h \
" CACHE STRING "" FORCE)
set(CMAKE_CXX_FLAGS "-mcpu=${CONFIG_ARCH} -Os -g3 -mfloat-abi=${CONFIG_FLOAT_TYPE} -mthumb -DMKRTOS -std=c++11 \
set(CMAKE_CXX_FLAGS "-mcpu=${CONFIG_ARCH} -O0 -g3 -mfloat-abi=${CONFIG_FLOAT_TYPE} -mthumb -DMKRTOS -std=c++11 \
-fmessage-length=0 -Xlinker --print-map -Wall -W -fno-stack-protector \
-u=_printf_float -D__ARM_ARCH_7M__ \
-ffunction-sections -fdata-sections -fno-builtin -nostartfiles -nodefaultlibs -nostdlib -nostdinc -Xlinker \
-include ${CMAKE_SOURCE_DIR}/build/autoconf.h \
" CACHE STRING "" FORCE)
set(CMAKE_ASM_FLAGS "-mcpu=${CONFIG_ARCH} -Os -g3 -mfloat-abi=${CONFIG_FLOAT_TYPE} -mthumb -DMKRTOS \
set(CMAKE_ASM_FLAGS "-mcpu=${CONFIG_ARCH} -O0 -g3 -mfloat-abi=${CONFIG_FLOAT_TYPE} -mthumb -DMKRTOS \
-u=_printf_float -std=gnu11 -ffunction-sections -fdata-sections -fno-builtin \
-nostartfiles -nodefaultlibs -nostdlib -nostdinc -Xlinker -fno-stack-protector -D__ARM_ARCH_7M__ \
-include ${CMAKE_SOURCE_DIR}/build/autoconf.h \

View File

@@ -1,18 +1,17 @@
cmake_minimum_required(VERSION 3.13)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D__MPU_PRESENT=1 -DUSE_STDPERIPH_DRIVER=1 ")
file(GLOB deps *.c *.S)
file(GLOB deps
CmBacktrace/cm_backtrace/cm_backtrace.c
*.c
*.S
)
list(REMOVE_ITEM deps ${CMAKE_SOURCE_DIR}/mkrtos_knl/arch/${CONFIG_ARCH}/link.lds.S)
add_library(arch STATIC ${deps})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D__MPU_PRESENT=1 -DUSE_STDPERIPH_DRIVER=1 ")
message(=======${CONFIG_CPU_TYPE})
target_include_directories(
arch
PUBLIC
${CMAKE_SOURCE_DIR}/mkrtos_knl/arch/${CONFIG_ARCH}/${CONFIG_CPU_TYPE}
${CMAKE_SOURCE_DIR}/mkrtos_knl/arch/${CONFIG_ARCH}/
)
if (${CONFIG_CPU_TYPE} STREQUAL "stm32f1")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSTM32F10X_XL ")
target_include_directories(
@@ -69,10 +68,18 @@ target_link_libraries(
PUBLIC
knl_bsp
)
add_dependencies(
arch
knl_bsp
)
target_include_directories(
arch
PUBLIC
${CMAKE_SOURCE_DIR}/mkrtos_knl/arch/inc
${CMAKE_SOURCE_DIR}/mkrtos_knl/inc/lib
${CMAKE_SOURCE_DIR}/mkrtos_knl/inc/knl
${CMAKE_SOURCE_DIR}/mkrtos_knl/arch/${CONFIG_ARCH}/${CONFIG_CPU_TYPE}
${CMAKE_SOURCE_DIR}/mkrtos_knl/arch/${CONFIG_ARCH}/
${CMAKE_SOURCE_DIR}/mkrtos_knl/arch/cortex-m/CmBacktrace/cm_backtrace
${CMAKE_SOURCE_DIR}/mkrtos_knl/arch/cortex-m/CmBacktrace/cm_backtrace/Languages/en-US
)

View File

@@ -0,0 +1,40 @@
* text=auto
*.S text
*.asm text
*.c text
*.cc text
*.cpp text
*.cxx text
*.h text
*.htm text
*.html text
*.in text
*.ld text
*.m4 text
*.mak text
*.mk text
*.py text
*.rb text
*.s text
*.sct text
*.sh text
*.txt text
*.xml text
Makefile text
AUTHORS text
COPYING text
*.LZO -text
*.Opt -text
*.Uv2 -text
*.ewp -text
*.eww -text
*.vcproj -text
*.bat -text
*.dos -text
*.icf -text
*.inf -text
*.ini -text
*.sct -text
*.xsd -text

View File

@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2016-2019 Armink (armink.ztl@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,221 @@
# CmBacktrace: ARM Cortex-M series MCU error tracking library
[中文页](README_ZH.md) | English
[![GitHub release](https://img.shields.io/github/release/armink/CmBacktrace.svg)](https://github.com/armink/CmBacktrace/releases/latest) [![GitHub commits](https://img.shields.io/github/commits-since/armink/CmBacktrace/1.4.0.svg)](https://github.com/armink/CmBacktrace/compare/1.0.0...master) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/armink/CmBacktrace/master/LICENSE)
## 0、What is CmBacktrace
[CmBacktrace](https://github.com/armink/CmBacktrace) (Cortex Microcontroller Backtrace) is an open source library that automatically tracks and locates error codes for ARM Cortex-M series MCUs, and automatically analyzes the causes of errors. The main features are as follows:
- Supported errors include:
- Assert
- Fault (Hard Fault, Memory Management Fault, Bus Fault, Usage Fault, Debug Fault)
- Failure reason **Automatic diagnosis**: When a failure occurs, the cause of the failure can be automatically analyzed, and the code location of the failure can be located, without the need to manually analyze the complicated fault registers;
-Output the **function call stack** of the error site (need to cooperate with the addr2line tool for precise positioning), restore the field information when the error occurred, and locate the problem code location and logic more quickly and accurately. You can also use the library under normal conditions to get the current function call stack;
- Support bare metal and the following operating system platforms:
- [RT-Thread](http://www.rt-thread.org/)
- UCOS
- FreeRTOS (source code needs to be modified)
- According to the error scene status, output the corresponding thread stack or C main stack;
- The fault diagnosis information supports multiple languages (currently: Simplified Chinese, English);
- Adapt to Cortex-M0/M3/M4/M7 MCU;
- Support IAR, KEIL, GCC compiler;
## 1. Why choose CmBacktrace
**Beginner Newcomer**: For newcomers who switch from simple microcontrollers such as C51 and MSP430 to more complex ARM, the chance of "hard falut" death from time to time makes newcomers instantly stunned. The method of locating errors is often to connect to the emulator, step by step F10/F11, locate the specific error code, and then guess, eliminate, and deliberate on the cause of the error. This process is very painful.
**Skilled veteran**: Slowly everyone knows that the fault cause and fault code address can be located through the fault register information. Although this can solve a small part of the problem, the repeated and tedious analysis process will also delay a lot of time. Moreover, for some complex problems, it is impossible to solve only by the code address, and the function call logic relationship of the wrong scene must be restored. Although the function call stack can be viewed by connecting to the emulator, it cannot be displayed in the fault state, so it is necessary to step by step F10/F11 to locate the error code. In addition, there are two scenarios,
1. The emulator must be disconnected when debugging many products
2. The problem does exist, but it is extremely difficult to reproduce
So locating such problems is even more difficult.
**Use this library**: All the above problems can be solved easily. The error message can be output to the console, and the error message can also be saved using the Log function of [EasyFlash](https://github.com/armink/EasyFlash) In Flash, the last error message can still be read after the device crashes and restarts. The information output by CmBacktrace includes function call stack, fault diagnosis result, stack, fault register and product firmware information, which greatly improves the efficiency and accuracy of error location.
As the saying goes, a worker must first sharpen his tools if he wants to do his job well. So sometimes the reason for the low efficiency may be that you will use too few types of tools.
**Cooperation, Contribution**: The development of open source software is inseparable from everyone's support. You are welcome to make more suggestions and hope that more people will join in and improve together. If you think this open source project is great, you can click [Project Homepage](https://github.com/armink/CmBacktrace) **([Github](https://github.com/armink/CmBacktrace)|[OSChina](http://git.oschina.net/armink/CmBacktrace)|[Coding](https://coding.net/u/armink/p/CmBacktrace/git))** Star** in the upper right corner, At the same time recommend it to more friends in need.
## 2. How to use CmBacktrace
### 2.1 Demo
The demonstration is divided into the following steps:
1. Manufacturing division by zero exception ([IAR project, click to view source code](https://github.com/armink/CmBacktrace/tree/master/demos/non_os/stm32f10x/app/src))
2. View error diagnosis information
3. View the basic information of the function call stack
4. Enter the path where the executable file is stored in the project project through the command line tool
5. Use the addr2line command to view the function call stack details and locate the error code
[![cm_backtrace_demo](https://raw.githubusercontent.com/armink/CmBacktrace/master/docs/zh/images/cm_backtrace_demo.gif)](https://github.com/armink/CmBacktrace)
### 2.2 Demo
|Catalog|Platform|Link|
|:--|:--:|:--:|
| `\demos\non_os\stm32f10x` |bare metal STM32 Cortex-M3|[click to view](https://github.com/armink/CmBacktrace/tree/master/demos/non_os/stm32f10x)|
| `\demos\os\rtthread\stm32f4xx`|RT-Thread STM32 Cortex-M4|[Click to view](https://github.com/armink/CmBacktrace/tree/master/demos/os/rtthread/stm32f4xx)|
| `\demos\os\ucosii\stm32f10x` |UCOSII STM32 Cortex-M3|[Click to view](https://github.com/armink/CmBacktrace/tree/master/demos/os/ucosii/stm32f10x)|
| `\demos\os\freertos\stm32f10x` |FreeRTOS STM32 Cortex-M3|[Click to view](https://github.com/armink/CmBacktrace/tree/master/demos/os/freertos/stm32f10x)|
### 2.3 Porting instructions
#### 2.3.1 Preparation
1. Check whether there is a suitable Demo in the `\demos` directory, if there is a similar, it is recommended to modify it on the basis of it
2. Identify the operating system/bare metal platform and CPU platform
3. Add all source files under `\src` to the product project, and ensure that the source code directory is added to the header file path
4. The cmb_fault.s assembly file ([click to view](https://github.com/armink/CmBacktrace/tree/master/cm_backtrace/fault_handler)) can be optionally added to the project. After adding, you need to add the original project `HardFault_Handler` comment out
5. Put the `cm_backtrace_init` function in the project initialization place for execution
6. Put `cm_backtrace_assert` in the assertion function of the project for execution. For specific usage, please refer to the API description below
7. If the cmb_fault.s assembly file is not enabled in step 4, you need to put `cm_backtrace_fault` in the fault handling function (for example: `HardFault_Handler`) for execution. For details, refer to the API description below
#### 2.3.2 Configuration Instructions
Configuration file name: `cmb_cfg.h`, users need to manually configure themselves for different platforms and scenarios. Common configurations are as follows:
| Configuration name | Function | Remarks |
|:--|:--|:--|
|cmb_println(...)|Error and diagnostic information output|Must be configured|
|CMB_USING_BARE_METAL_PLATFORM|Whether it is used on a bare metal platform|Define this macro if it is used|
|CMB_USING_OS_PLATFORM|Whether it is used on the operating system platform|Operating system and bare metal must choose one of two|
|CMB_OS_PLATFORM_TYPE|Operating System Platform|RTT/UCOSII/UCOSIII/FREERTOS|
|CMB_CPU_PLATFORM_TYPE|CPU platform|M0/M3/M4/M7|
|CMB_USING_DUMP_STACK_INFO|Whether to use Dump stack function|Use to define this macro|
|CMB_PRINT_LANGUAGE|Language when outputting information|CHINESE/ENGLISH|
> Note: The content of the above configuration can be selected in `cmb_def.h`, please read the source code for more flexible configuration
### 2.4 API description
#### 2.4.1 Library initialization
```C
void cm_backtrace_init(const char *firmware_name, const char *hardware_ver, const char *software_ver)
```
|Parameter |Description|
|:----- |:----|
|firmware_name |firmware name, which must correspond to the firmware name generated by the compiler|
|hardware_ver |The hardware version number corresponding to the firmware|
|software_ver |Software version number of the firmware|
> **Note**: The above input parameters will be output in case of assertion or failure, mainly for retrospective purposes
#### 2.4.2 Get function call stack
```C
size_t cm_backtrace_call_stack(uint32_t *buffer, size_t size, uint32_t sp)
```
|Parameter |Description|
|:----- |:----|
|buffer |Buffer for storing function call stack|
|size |Buffer size|
|sp |Stack pointer to be obtained|
Example:
```C
/* Create a function call stack buffer with a depth of 16, and the depth should not exceed CMB_CALL_STACK_MAX_DEPTH (default 16) */
uint32_t call_stack[16] = {0};
size_t i, depth = 0;
/* Get the function call stack in the current environment, each element will be stored as a 32-bit address, and depth is the actual depth of the function call stack */
depth = cm_backtrace_call_stack(call_stack, sizeof(call_stack), cmb_get_sp());
/* Output current function call stack information
* Note: When viewing the function name and specific line number, you need to use the addr2line tool to convert
*/
for (i = 0; i <depth; i++) {
printf("%08x ", call_stack[i]);
}
```
#### 2.4.3 Tracking assertion error messages
```C
void cm_backtrace_assert(uint32_t sp)
```
|Parameter |Description|
|:----- |:----|
|sp |Stack pointer when asserting environment|
> **Note**: The input parameter SP should be obtained inside the assertion function as much as possible, and as close as possible to the beginning of the assertion function. When used in the sub-function of the assertion function (for example: in the assertion hook method of RT-Thread), due to the nesting of the function, there will be the operation of registering the stack, and the SP will be changed at this time, and manual adjustment is required ( Add and subtract a fixed deviation value) into the parameter value, so as a novice, it is not recommended to use this function in the sub-function of the assertion.
#### 2.4.4 Tracking fault information
```C
void cm_backtrace_fault(uint32_t fault_handler_lr, uint32_t fault_handler_sp)
```
|Parameter |Description|
|:----- |:----|
|fault_handler_lr |LR register value under fault handling function environment|
|fault_handler_sp |SP register value under fault handling function environment|
This function can be called in the fault handling function (for example: `HardFault_Handler`). In addition, the library itself provides assembly files processed by `HardFault` ([click to view](https://github.com/armink/CmBacktrace/tree/master/cm_backtrace/fault_handler), you need to choose according to your own compiler), The `cm_backtrace_fault` method is automatically called in the event of a fault. So when transplanting, the easiest way is to use the assembly file directly.
### 2.5 FAQ
#### 2.5.1 Compilation error, suggesting that C99 support is required
[Click to view the tutorial: Open Keil/IAR/GCC C99 support in one step](https://github.com/armink/CmBacktrace/blob/master/docs/zh/enable_c99_for_keil_iar_gcc.md)
#### 2.5.2 How to view the specific name and code line number of the function in the function call stack
[Click to view the tutorial: How to use the addr2line tool to get the function call stack details](https://github.com/armink/CmBacktrace/blob/master/docs/zh/how_to_use_addr2line_for_call_stack.md)
#### 2.5.3 Fault handling function: HardFault_Handler repeated definition
When the cmb_fault.s assembly file provided by this library is used, because HardFault_Handler is already defined in the assembly file, if this function is defined elsewhere in the project, an error that HardFault_Handler is repeatedly defined will be prompted. There are two solutions at this time:
1. Comment/delete the `HardFault_Handler` function defined in other files, and only keep the cmb_fault.s;
2. Remove cmb_fault.s from the project, and manually add the `cm_backtrace_fault` function to the existing fault handling function, but it should be noted that you must ** ensure the readiness of the function to enter the parameters**, otherwise it may cause The fault diagnosis function and stack printing function cannot operate normally. So if you are a novice, the second solution is not recommended.
#### 2.5.4 Prompt that the main stack information cannot be obtained during initialization
The default main stack configuration is defined in `cmd_def.h`, roughly as follows:
```c
#if defined(__CC_ARM)
/* C stack block name,default is STACK */
#ifndef CMB_CSTACK_BLOCK_NAME
#define CMB_CSTACK_BLOCK_NAME STACK
#endif
...
#elif defined(__ICCARM__)
/* C stack block name, default is'CSTACK' */
#ifndef CMB_CSTACK_BLOCK_NAME
#define CMB_CSTACK_BLOCK_NAME "CSTACK"
#endif
...
#elif defined(__GNUC__)
/* C stack block start address, defined on linker script file, default is _sstack */
#ifndef CMB_CSTACK_BLOCK_START
#define CMB_CSTACK_BLOCK_START _sstack
#endif
/* C stack block end address, defined on linker script file, default is _estack */
#ifndef CMB_CSTACK_BLOCK_END
#define CMB_CSTACK_BLOCK_END _estack
#endif
...
#else
```
For example, under the Keil-MDK compiler, `STACK` will be selected as the name of the main stack block by default, but under some special platforms, the name of the main stack block of the project may not be called `STACK`, causing CmBacktrace to fail to obtain the correct main stack Information, so there will be the above error message during initialization.
There are generally two ways to solve this problem
1. Redefine the main stack information in `cmb_cfg.h`. At this time, CmBacktrace will give priority to using the configuration information in `cmb_cfg.h`;
2. Modify the project configuration. If it is Keil-MDK, change the name of the main stack to the default `STACK` at the beginning of the startup file. This problem rarely occurs with other compilers.
### 2.6 License
The MIT open source agreement is adopted. For details, please read the contents of the LICENSE file in the project.

View File

@@ -0,0 +1,227 @@
# CmBacktrace: ARM Cortex-M 系列 MCU 错误追踪库
中文页 | [English](README.md)
[![GitHub release](https://img.shields.io/github/release/armink/CmBacktrace.svg)](https://github.com/armink/CmBacktrace/releases/latest) [![GitHub commits](https://img.shields.io/github/commits-since/armink/CmBacktrace/1.4.0.svg)](https://github.com/armink/CmBacktrace/compare/1.0.0...master) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/armink/CmBacktrace/master/LICENSE)
## 0、CmBacktrace 是什么
[CmBacktrace](https://github.com/armink/CmBacktrace) Cortex Microcontroller Backtrace是一款针对 ARM Cortex-M 系列 MCU 的错误代码自动追踪、定位,错误原因自动分析的开源库。主要特性如下:
- 支持的错误包括:
- 断言assert
- 故障Hard Fault, Memory Management Fault, Bus Fault, Usage Fault, Debug Fault
- 故障原因 **自动诊断** :可在故障发生时,自动分析出故障的原因,定位发生故障的代码位置,而无需再手动分析繁杂的故障寄存器;
- 输出错误现场的 **函数调用栈**(需配合 addr2line 工具进行精确定位),还原发生错误时的现场信息,定位问题代码位置、逻辑更加快捷、精准。也可以在正常状态下使用该库,获取当前的函数调用栈;
- 支持 裸机 及以下操作系统平台:
- [RT-Thread](http://www.rt-thread.org/)
- UCOS
- FreeRTOS需修改源码
- 根据错误现场状态,输出对应的 线程栈 或 C 主栈;
- 故障诊断信息支持多国语言(目前:简体中文、英文);
- 适配 Cortex-M0/M3/M4/M7 MCU
- 支持 IAR、KEIL、GCC 编译器;
## 1、为什么选择 CmBacktrace
**入门新人** :对于从 C51 、MSP430 等简单单片机转而使用更加复杂的 ARM 新人来说,时不时出现的 "hard falut" 死机会让新人瞬间懵掉。定位错误的方法也往往是连接上仿真器,一步步 F10/F11 单步,定位到具体的错误代码,再去猜测、排除、推敲错误原因,这种过程十分痛苦。
**熟练老手** :慢慢的大家知道可以通过故障寄存器信息来定位故障原因及故障代码地址,虽然这样能解决一小部分问题,但是重复的、繁琐的分析过程也会耽误很多时间。而且对于一些复杂问题,只依靠代码地址是无法解决的,必须得还原错误现场的函数调用逻辑关系。虽然连接仿真器可以查看到的函数调用栈,但故障状态下是无法显示的,所以还是得一步步 F10/F11 单步去定位错误代码的位置。另外,还有两种场景,
- 1、很多产品真机调试时必须断开仿真器
- 2、问题确实存在但是极难被重现
所以定位这类问题就显得难上加难。
**使用本库** :上述所有问题都迎刃而解,可以将错误信息输出到控制台上,还可以将错误信息使用 [EasyFlash](https://github.com/armink/EasyFlash) 的 Log 功能保存至 Flash 中设备死机后重启依然能够读取上次的错误信息。CmBacktrace 输出的信息包括函数调用栈、故障诊断结果、堆栈、故障寄存器及产品固件信息,极大的提升了错误定位的效率及准确性。
俗话说,工欲善其事,必先利其器。所以有时候做事效率低的原因也许是,你会用的工具种类太少。
**合作、贡献** :开源软件的发展离不开大家的支持,欢迎大家多提建议,也希望更多的人一起参与进来,共同提高 。如果觉得这个开源项目很赞,可以点击 [项目主页](https://github.com/armink/CmBacktrace) **([Github](https://github.com/armink/CmBacktrace)|[OSChina](http://git.oschina.net/armink/CmBacktrace)|[Coding](https://coding.net/u/armink/p/CmBacktrace/git))** 右上角的 **Star** ,同时把它推荐给更多有需要的朋友。
## 2、CmBacktrace 如何使用
### 2.1 演示
该演示分如下几个步骤:
- 1、制造除零异常[IAR 工程,点击查看源码](https://github.com/armink/CmBacktrace/tree/master/demos/non_os/stm32f10x/app/src)
- 2、查看错误诊断信息
- 3、查看函数调用栈基本信息
- 4、通过命令行工具进入项目工程存放可执行文件的路径
- 5、使用 addr2line 命令,查看函数调用栈详细信息,并定位错误代码
[![cm_backtrace_demo](https://raw.githubusercontent.com/armink/CmBacktrace/master/docs/zh/images/cm_backtrace_demo.gif)](https://github.com/armink/CmBacktrace)
### 2.2 Demo
|目录|平台|链接|
|:--|:--:|:--:|
| `\demos\non_os\stm32f10x` |裸机 STM32 Cortex-M3|[点击查看](https://github.com/armink/CmBacktrace/tree/master/demos/non_os/stm32f10x)|
| `\demos\os\rtthread\stm32f4xx`|RT-Thread STM32 Cortex-M4|[点击查看](https://github.com/armink/CmBacktrace/tree/master/demos/os/rtthread/stm32f4xx)|
| `\demos\os\ucosii\stm32f10x` |UCOSII STM32 Cortex-M3|[点击查看](https://github.com/armink/CmBacktrace/tree/master/demos/os/ucosii/stm32f10x)|
| `\demos\os\freertos\stm32f10x` |FreeRTOS STM32 Cortex-M3|[点击查看](https://github.com/armink/CmBacktrace/tree/master/demos/os/freertos/stm32f10x)|
### 2.3 移植说明
#### 2.3.1 准备工作
- 1、查看 `\demos` 目录下有没有合适自己的 Demo ,如有类似,则建议在其基础上修改
- 2、明确操作系统/裸机平台及 CPU 平台
- 3、将 `\src` 下的全部源文件添加至产品工程中,并保证源码目录被添加至头文件路径
- 4、cmb_fault.s 汇编文件([点击查看](https://github.com/armink/CmBacktrace/tree/master/cm_backtrace/fault_handler))可以选择性添加至工程,添加后需要把项目原有的 `HardFault_Handler` 注释掉
- 5、把 `cm_backtrace_init` 函数放在项目初始化地方执行
- 6、将 `cm_backtrace_assert` 放在项目的断言函数中执行,具体使用方法参照下面的 API 说明
- 7、如果第 4 步骤没有将 cmb_fault.s 汇编文件启用,则需要将 `cm_backtrace_fault` 放到故障处理函数(例如: `HardFault_Handler` )中执行,具体使用方法参照下面的 API 说明
#### 2.3.2 配置说明
配置文件名: `cmb_cfg.h` ,针对不同的平台和场景,用户需要自自行手动配置,常用配置如下:
| 配置名称 |功能|备注|
|:--|:--|:--|
|cmb_println(...)|错误及诊断信息输出|必须配置|
|CMB_USING_BARE_METAL_PLATFORM|是否使用在裸机平台|使用则定义该宏|
|CMB_USING_OS_PLATFORM|是否使用在操作系统平台|操作系统与裸机必须二选一|
|CMB_OS_PLATFORM_TYPE|操作系统平台|RTT/UCOSII/UCOSIII/FREERTOS/MKRTOS|
|CMB_CPU_PLATFORM_TYPE|CPU平台|M0/M3/M4/M7|
|CMB_USING_DUMP_STACK_INFO|是否使用 Dump 堆栈的功能|使用则定义该宏|
|CMB_PRINT_LANGUAGE|输出信息时的语言|CHINESE/ENGLISH|
> 注意:以上部分配置的内容可以在 `cmb_def.h` 中选择,更多灵活的配置请阅读源码
### 2.4 API 说明
#### 2.4.1 库初始化
```C
void cm_backtrace_init(const char *firmware_name, const char *hardware_ver, const char *software_ver)
```
|参数 |描述|
|:----- |:----|
|firmware_name |固件名称,需与编译器生成的固件名称对应|
|hardware_ver |固件对应的硬件版本号|
|software_ver |固件的软件版本号|
> **注意** :以上入参将会在断言或故障时输出,主要起了追溯的作用
#### 2.4.2 获取函数调用栈
```C
size_t cm_backtrace_call_stack(uint32_t *buffer, size_t size, uint32_t sp)
```
|参数 |描述|
|:----- |:----|
|buffer |存储函数调用栈的缓冲区|
|size |缓冲区大小|
|sp |待获取的堆栈指针|
示例:
```C
/* 建立深度为 16 的函数调用栈缓冲区,深度大小不应该超过 CMB_CALL_STACK_MAX_DEPTH默认16 */
uint32_t call_stack[16] = {0};
size_t i, depth = 0;
/* 获取当前环境下的函数调用栈,每个元素将会以 32 位地址形式存储, depth 为函数调用栈实际深度 */
depth = cm_backtrace_call_stack(call_stack, sizeof(call_stack), cmb_get_sp());
/* 输出当前函数调用栈信息
* 注意:查看函数名称及具体行号时,需要使用 addr2line 工具转换
*/
for (i = 0; i < depth; i++) {
printf("%08x ", call_stack[i]);
}
```
#### 2.4.3 追踪断言错误信息
```C
void cm_backtrace_assert(uint32_t sp)
```
|参数 |描述|
|:----- |:----|
|sp |断言环境时的堆栈指针|
> **注意** :入参 SP 尽量在断言函数内部获取,而且尽可能靠近断言函数开始的位置。当在断言函数的子函数中(例如:在 RT-Thread 的断言钩子方法中)使用时,由于函数嵌套会存在寄存器入栈的操作,此时再获取 SP 将发生变化,就需要人为调整(加减固定的偏差值)入参值,所以作为新手 **不建议在断言的子函数** 中使用该函数。
#### 2.4.4 追踪故障错误信息
```C
void cm_backtrace_fault(uint32_t fault_handler_lr, uint32_t fault_handler_sp)
```
|参数 |描述|
|:----- |:----|
|fault_handler_lr |故障处理函数环境下的 LR 寄存器值|
|fault_handler_sp |故障处理函数环境下的 SP 寄存器值|
该函数可以在故障处理函数(例如: `HardFault_Handler`)中调用。另外,库本身提供了 `HardFault` 处理的汇编文件([点击查看](https://github.com/armink/CmBacktrace/tree/master/cm_backtrace/fault_handler),需根据自己编译器进行选择),会在故障时自动调用 `cm_backtrace_fault` 方法。所以移植时,最简单的方式就是直接使用该汇编文件。
### 2.5 常见问题
#### 2.5.1 编译出错,提示需要 C99 支持
[点击查看教程:一步开启 Keil/IAR/GCC 的 C99 支持](https://github.com/armink/CmBacktrace/blob/master/docs/zh/enable_c99_for_keil_iar_gcc.md)
#### 2.5.2 如何查看到函数调用栈中函数的具体名称及代码行号
[点击查看教程:如何使用 addr2line 工具获取函数调用栈详细信息](https://github.com/armink/CmBacktrace/blob/master/docs/zh/how_to_use_addr2line_for_call_stack.md)
#### 2.5.3 故障处理函数HardFault_Handler 重复定义
在使用了本库提供的 cmb_fault.s 汇编文件时,因为该汇编文件内部已经定义了 HardFault_Handler ,所以如果项目中还有其他地方定义了该函数,则会提示 HardFault_Handler 被重复定义的错误。此时有两种解决方法:
- 1、注释/删除其他文件中定义的 `HardFault_Handler` 函数,仅保留 cmb_fault.s 中的;
- 2、将 cmb_fault.s 移除工程,手动添加 `cm_backtrace_fault` 函数至现有的故障处理函数,但需要注意的是,务必 **保证该函数数入参的准备性** ,否则可能会导致故障诊断功能及堆栈打印功能无法正常运行。所以如果是新手,不推荐第二种解决方法。
#### 2.5.4 初始化时提示无法获取主栈main stack信息
`cmd_def.h` 中有定义默认的主栈配置,大致如下:
```c
#if defined(__CC_ARM)
/* C stack block name, default is STACK */
#ifndef CMB_CSTACK_BLOCK_NAME
#define CMB_CSTACK_BLOCK_NAME STACK
#endif
...
#elif defined(__ICCARM__)
/* C stack block name, default is 'CSTACK' */
#ifndef CMB_CSTACK_BLOCK_NAME
#define CMB_CSTACK_BLOCK_NAME "CSTACK"
#endif
...
#elif defined(__GNUC__)
/* C stack block start address, defined on linker script file, default is _sstack */
#ifndef CMB_CSTACK_BLOCK_START
#define CMB_CSTACK_BLOCK_START _sstack
#endif
/* C stack block end address, defined on linker script file, default is _estack */
#ifndef CMB_CSTACK_BLOCK_END
#define CMB_CSTACK_BLOCK_END _estack
#endif
...
#else
```
比如在 Keil-MDK 编译器下会默认选择 `STACK` 作为主栈 block 的名称,但在一些特殊平台下,项目的主栈 block 名称可能不叫 `STACK`,导致 CmBacktrace 无法获取到正确的主栈信息,所以在初始化时会有如上的错误提示信息。
解决这个问题一般有两个思路
- 1、在 `cmb_cfg.h` 中重新定义主栈的信息,此时 CmBacktrace 会优先使用 `cmb_cfg.h` 中的配置信息;
- 2、修改项目配置如果是 Keil-MDK ,则在启动文件的开头位置,将主栈的名称修改为默认的 `STACK` ,其他编译器一般很少出现该问题。
### 2.6 视频讲解
- https://www.bilibili.com/video/BV1LB4y1Q78a
- https://www.bilibili.com/video/BV1uF411i7Ka
- https://www.bilibili.com/video/BV1rb4y1474Y
### 2.7 许可
采用 MIT 开源协议,细节请阅读项目中的 LICENSE 文件内容。

View File

@@ -0,0 +1,8 @@
# CmBacktrace: ARM Cortex-M 系列 MCU 错误追踪库
## 多语言支持
| Language | Location (or type) | Language tag |
|----------------------|----------------------------|--------------|
| English | United States | en-US |
| Chinese (Simplified) | People's Republic of China | zh-CN |

View File

@@ -0,0 +1,71 @@
/*
* This file is part of the CmBacktrace Library.
*
* Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
* Chenxuan, <chenxuan.zhao@icloud.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* 'Software'), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* NOTE: DO NOT include this file on the header file.
* Encoding: UTF-8
* Created on: 2020-09-06
*/
[PRINT_MAIN_STACK_CFG_ERROR] = "ERROR: Unable to get the main stack information, please check the configuration of the main stack",
[PRINT_FIRMWARE_INFO] = "Firmware name: %s, hardware version: %s, software version: %s",
[PRINT_ASSERT_ON_THREAD] = "Assert on thread %s",
[PRINT_ASSERT_ON_HANDLER] = "Assert on interrupt or bare metal(no OS) environment",
[PRINT_THREAD_STACK_INFO] = "===== Thread stack information =====",
[PRINT_MAIN_STACK_INFO] = "====== Main stack information ======",
[PRINT_THREAD_STACK_OVERFLOW] = "Error: Thread stack(%08x) was overflow",
[PRINT_MAIN_STACK_OVERFLOW] = "Error: Main stack(%08x) was overflow",
[PRINT_CALL_STACK_INFO] = "Show more call stack info by run: addr2line -e %s%s -afpiC %.*s",
[PRINT_CALL_STACK_ERR] = "Dump call stack has an error",
[PRINT_FAULT_ON_THREAD] = "Fault on thread %s",
[PRINT_FAULT_ON_HANDLER] = "Fault on interrupt or bare metal(no OS) environment",
[PRINT_REGS_TITLE] = "=================== Registers information ====================",
[PRINT_HFSR_VECTBL] = "Hard fault is caused by failed vector fetch",
[PRINT_MFSR_IACCVIOL] = "Memory management fault is caused by instruction access violation",
[PRINT_MFSR_DACCVIOL] = "Memory management fault is caused by data access violation",
[PRINT_MFSR_MUNSTKERR] = "Memory management fault is caused by unstacking error",
[PRINT_MFSR_MSTKERR] = "Memory management fault is caused by stacking error",
[PRINT_MFSR_MLSPERR] = "Memory management fault is caused by floating-point lazy state preservation",
[PRINT_BFSR_IBUSERR] = "Bus fault is caused by instruction access violation",
[PRINT_BFSR_PRECISERR] = "Bus fault is caused by precise data access violation",
[PRINT_BFSR_IMPREISERR] = "Bus fault is caused by imprecise data access violation",
[PRINT_BFSR_UNSTKERR] = "Bus fault is caused by unstacking error",
[PRINT_BFSR_STKERR] = "Bus fault is caused by stacking error",
[PRINT_BFSR_LSPERR] = "Bus fault is caused by floating-point lazy state preservation",
[PRINT_UFSR_UNDEFINSTR] = "Usage fault is caused by attempts to execute an undefined instruction",
[PRINT_UFSR_INVSTATE] = "Usage fault is caused by attempts to switch to an invalid state (e.g., ARM)",
[PRINT_UFSR_INVPC] = "Usage fault is caused by attempts to do an exception with a bad value in the EXC_RETURN number",
[PRINT_UFSR_NOCP] = "Usage fault is caused by attempts to execute a coprocessor instruction",
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
[PRINT_UFSR_STKOF] = "Usage fault is caused by indicates that a stack overflow (hardware check) has taken place",
#endif
[PRINT_UFSR_UNALIGNED] = "Usage fault is caused by indicates that an unaligned access fault has taken place",
[PRINT_UFSR_DIVBYZERO0] = "Usage fault is caused by Indicates a divide by zero has taken place (can be set only if DIV_0_TRP is set)",
[PRINT_DFSR_HALTED] = "Debug fault is caused by halt requested in NVIC",
[PRINT_DFSR_BKPT] = "Debug fault is caused by BKPT instruction executed",
[PRINT_DFSR_DWTTRAP] = "Debug fault is caused by DWT match occurred",
[PRINT_DFSR_VCATCH] = "Debug fault is caused by Vector fetch occurred",
[PRINT_DFSR_EXTERNAL] = "Debug fault is caused by EDBGRQ signal asserted",
[PRINT_MMAR] = "The memory management fault occurred address is %08x",
[PRINT_BFAR] = "The bus fault occurred address is %08x",

View File

@@ -0,0 +1,71 @@
/*
* This file is part of the CmBacktrace Library.
*
* Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
* Chenxuan, <chenxuan.zhao@icloud.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* 'Software'), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* NOTE: DO NOT include this file on the header file.
* Encoding: GB18030
* Created on: 2020-09-06
*/
[PRINT_MAIN_STACK_CFG_ERROR] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>޷<EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD>ջ<EFBFBD><EFBFBD>Ϣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
[PRINT_FIRMWARE_INFO] = "<EFBFBD>̼<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƣ<EFBFBD>%s<><73>Ӳ<EFBFBD><D3B2><EFBFBD><EFBFBD>ţ<EFBFBD>%s<><73><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ţ<EFBFBD>%s",
[PRINT_ASSERT_ON_THREAD] = "<EFBFBD><EFBFBD><EFBFBD>߳<EFBFBD>(%s)<29>з<EFBFBD><D0B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
[PRINT_ASSERT_ON_HANDLER] = "<EFBFBD><EFBFBD><EFBFBD>жϻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
[PRINT_THREAD_STACK_INFO] = "=========== <20>̶߳<DFB3>ջ<EFBFBD><D5BB>Ϣ ===========",
[PRINT_MAIN_STACK_INFO] = "============ <20><><EFBFBD><EFBFBD>ջ<EFBFBD><D5BB>Ϣ ============",
[PRINT_THREAD_STACK_OVERFLOW] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߳<EFBFBD>ջ(%08x)<29><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
[PRINT_MAIN_STACK_OVERFLOW] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ(%08x)<29><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
[PRINT_CALL_STACK_INFO] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><EFBFBD>Ϣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD>addr2line -e %s%s -afpiC %.*s",
[PRINT_CALL_STACK_ERR] = "<EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջʧ<EFBFBD><EFBFBD>",
[PRINT_FAULT_ON_THREAD] = "<EFBFBD><EFBFBD><EFBFBD>߳<EFBFBD>(%s)<29>з<EFBFBD><D0B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
[PRINT_FAULT_ON_HANDLER] = "<EFBFBD><EFBFBD><EFBFBD>жϻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
[PRINT_REGS_TITLE] = "========================= <20>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD>Ϣ =========================",
[PRINT_HFSR_VECTBL] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD>ж<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
[PRINT_MFSR_IACCVIOL] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ<EFBFBD>Ӳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡָ<EFBFBD><EFBFBD>",
[PRINT_MFSR_DACCVIOL] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ<EFBFBD>Ӳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
[PRINT_MFSR_MUNSTKERR] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD>򣺳<EFBFBD>ջʱ<EFBFBD><EFBFBD>ͼ<EFBFBD><EFBFBD><EFBFBD>ʲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
[PRINT_MFSR_MSTKERR] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջʱ<EFBFBD><EFBFBD>ͼ<EFBFBD><EFBFBD><EFBFBD>ʲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
[PRINT_MFSR_MLSPERR] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD>򣺶<EFBFBD><EFBFBD>Ա<EFBFBD><EFBFBD><EFBFBD><EFBFBD>״̬ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
[PRINT_BFSR_IBUSERR] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ߴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ߴ<EFBFBD><EFBFBD><EFBFBD>",
[PRINT_BFSR_PRECISERR] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ߴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD>򣺾<EFBFBD>ȷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ߴ<EFBFBD><EFBFBD><EFBFBD>",
[PRINT_BFSR_IMPREISERR] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ߴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD>򣺲<EFBFBD><EFBFBD><EFBFBD>ȷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ߴ<EFBFBD><EFBFBD><EFBFBD>",
[PRINT_BFSR_UNSTKERR] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ߴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD>򣺳<EFBFBD>ջʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
[PRINT_BFSR_STKERR] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ߴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
[PRINT_BFSR_LSPERR] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ߴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD>򣺶<EFBFBD><EFBFBD>Ա<EFBFBD><EFBFBD><EFBFBD><EFBFBD>״̬ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
[PRINT_UFSR_UNDEFINSTR] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>÷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼִ<EFBFBD><EFBFBD>δ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD>",
[PRINT_UFSR_INVSTATE] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>÷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ<EFBFBD>л<EFBFBD><EFBFBD><EFBFBD> ARM ״̬",
[PRINT_UFSR_INVPC] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>÷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
[PRINT_UFSR_NOCP] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>÷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼִ<EFBFBD><EFBFBD>Э<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD>",
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
[PRINT_UFSR_STKOF] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>÷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>⵽ջ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
#endif
[PRINT_UFSR_UNALIGNED] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>÷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼִ<EFBFBD>зǶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
[PRINT_UFSR_DIVBYZERO0] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>÷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼִ<EFBFBD>г<EFBFBD> 0 <20><><EFBFBD><EFBFBD>",
[PRINT_DFSR_HALTED] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>NVIC ͣ<><CDA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
[PRINT_DFSR_BKPT] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD><EFBFBD> BKPT ָ<><D6B8>",
[PRINT_DFSR_DWTTRAP] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƥ<EFBFBD><EFBFBD>",
[PRINT_DFSR_VCATCH] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD>򣺷<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
[PRINT_DFSR_EXTERNAL] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ⲿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
[PRINT_MMAR] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD>ַ<EFBFBD><EFBFBD>%08x",
[PRINT_BFAR] = "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ߴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD>ַ<EFBFBD><EFBFBD>%08x",

View File

@@ -0,0 +1,71 @@
/*
* This file is part of the CmBacktrace Library.
*
* Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
* Chenxuan, <chenxuan.zhao@icloud.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* 'Software'), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* NOTE: DO NOT include this file on the header file.
* Encoding: UTF-8
* Created on: 2020-09-06
*/
[PRINT_MAIN_STACK_CFG_ERROR] = "错误:无法获取主栈信息,请检查主栈的相关配置",
[PRINT_FIRMWARE_INFO] = "固件名称:%s硬件版本号%s软件版本号%s",
[PRINT_ASSERT_ON_THREAD] = "在线程(%s)中发生断言",
[PRINT_ASSERT_ON_HANDLER] = "在中断或裸机环境下发生断言",
[PRINT_THREAD_STACK_INFO] = "=========== 线程堆栈信息 ===========",
[PRINT_MAIN_STACK_INFO] = "============ 主堆栈信息 ============",
[PRINT_THREAD_STACK_OVERFLOW] = "错误:线程栈(%08x)发生溢出",
[PRINT_MAIN_STACK_OVERFLOW] = "错误:主栈(%08x)发生溢出",
[PRINT_CALL_STACK_INFO] = "查看更多函数调用栈信息请运行addr2line -e %s%s -afpiC %.*s",
[PRINT_CALL_STACK_ERR] = "获取函数调用栈失败",
[PRINT_FAULT_ON_THREAD] = "在线程(%s)中发生错误异常",
[PRINT_FAULT_ON_HANDLER] = "在中断或裸机环境下发生错误异常",
[PRINT_REGS_TITLE] = "========================= 寄存器信息 =========================",
[PRINT_HFSR_VECTBL] = "发生硬错误,原因:取中断向量时出错",
[PRINT_MFSR_IACCVIOL] = "发生存储器管理错误,原因:企图从不允许访问的区域取指令",
[PRINT_MFSR_DACCVIOL] = "发生存储器管理错误,原因:企图从不允许访问的区域读、写数据",
[PRINT_MFSR_MUNSTKERR] = "发生存储器管理错误,原因:出栈时企图访问不被允许的区域",
[PRINT_MFSR_MSTKERR] = "发生存储器管理错误,原因:入栈时企图访问不被允许的区域",
[PRINT_MFSR_MLSPERR] = "发生存储器管理错误,原因:惰性保存浮点状态时发生错误",
[PRINT_BFSR_IBUSERR] = "发生总线错误,原因:指令总线错误",
[PRINT_BFSR_PRECISERR] = "发生总线错误,原因:精确的数据总线错误",
[PRINT_BFSR_IMPREISERR] = "发生总线错误,原因:不精确的数据总线错误",
[PRINT_BFSR_UNSTKERR] = "发生总线错误,原因:出栈时发生错误",
[PRINT_BFSR_STKERR] = "发生总线错误,原因:入栈时发生错误",
[PRINT_BFSR_LSPERR] = "发生总线错误,原因:惰性保存浮点状态时发生错误",
[PRINT_UFSR_UNDEFINSTR] = "发生用法错误,原因:企图执行未定义指令",
[PRINT_UFSR_INVSTATE] = "发生用法错误,原因:试图切换到 ARM 状态",
[PRINT_UFSR_INVPC] = "发生用法错误,原因:无效的异常返回码",
[PRINT_UFSR_NOCP] = "发生用法错误,原因:企图执行协处理器指令",
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
[PRINT_UFSR_STKOF] = "发生用法错误,原因:硬件检测到栈溢出",
#endif
[PRINT_UFSR_UNALIGNED] = "发生用法错误,原因:企图执行非对齐访问",
[PRINT_UFSR_DIVBYZERO0] = "发生用法错误,原因:企图执行除 0 操作",
[PRINT_DFSR_HALTED] = "发生调试错误原因NVIC 停机请求",
[PRINT_DFSR_BKPT] = "发生调试错误,原因:执行 BKPT 指令",
[PRINT_DFSR_DWTTRAP] = "发生调试错误,原因:数据监测点匹配",
[PRINT_DFSR_VCATCH] = "发生调试错误,原因:发生向量捕获",
[PRINT_DFSR_EXTERNAL] = "发生调试错误,原因:外部调试请求",
[PRINT_MMAR] = "发生存储器管理错误的地址:%08x",
[PRINT_BFAR] = "发生总线错误的地址:%08x",

View File

@@ -0,0 +1,816 @@
/*
* This file is part of the CmBacktrace Library.
*
* Copyright (c) 2016-2019, Armink, <armink.ztl@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* 'Software'), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Function: Initialize function and other general function.
* Created on: 2016-12-15
*/
#include <cm_backtrace.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#if __STDC_VERSION__ < 199901L
#error "must be C99 or higher. try to add '-std=c99' to compile parameters"
#endif
#if defined(__ARMCC_VERSION)
#define SECTION_START(_name_) _name_##$$Base
#define SECTION_END(_name_) _name_##$$Limit
#define IMAGE_SECTION_START(_name_) Image$$##_name_##$$Base
#define IMAGE_SECTION_END(_name_) Image$$##_name_##$$Limit
#define CSTACK_BLOCK_START(_name_) SECTION_START(_name_)
#define CSTACK_BLOCK_END(_name_) SECTION_END(_name_)
#define CODE_SECTION_START(_name_) IMAGE_SECTION_START(_name_)
#define CODE_SECTION_END(_name_) IMAGE_SECTION_END(_name_)
extern const int CSTACK_BLOCK_START(CMB_CSTACK_BLOCK_NAME);
extern const int CSTACK_BLOCK_END(CMB_CSTACK_BLOCK_NAME);
extern const int CODE_SECTION_START(CMB_CODE_SECTION_NAME);
extern const int CODE_SECTION_END(CMB_CODE_SECTION_NAME);
#elif defined(__ICCARM__)
#pragma section = CMB_CSTACK_BLOCK_NAME
#pragma section = CMB_CODE_SECTION_NAME
#elif defined(__GNUC__)
extern const int CMB_CSTACK_BLOCK_START;
extern const int CMB_CSTACK_BLOCK_END;
extern const int CMB_CODE_SECTION_START;
extern const int CMB_CODE_SECTION_END;
#else
#error "not supported compiler"
#endif
enum
{
PRINT_MAIN_STACK_CFG_ERROR,
PRINT_FIRMWARE_INFO,
PRINT_ASSERT_ON_THREAD,
PRINT_ASSERT_ON_HANDLER,
PRINT_THREAD_STACK_INFO,
PRINT_MAIN_STACK_INFO,
PRINT_THREAD_STACK_OVERFLOW,
PRINT_MAIN_STACK_OVERFLOW,
PRINT_CALL_STACK_INFO,
PRINT_CALL_STACK_ERR,
PRINT_FAULT_ON_THREAD,
PRINT_FAULT_ON_HANDLER,
PRINT_REGS_TITLE,
PRINT_HFSR_VECTBL,
PRINT_MFSR_IACCVIOL,
PRINT_MFSR_DACCVIOL,
PRINT_MFSR_MUNSTKERR,
PRINT_MFSR_MSTKERR,
PRINT_MFSR_MLSPERR,
PRINT_BFSR_IBUSERR,
PRINT_BFSR_PRECISERR,
PRINT_BFSR_IMPREISERR,
PRINT_BFSR_UNSTKERR,
PRINT_BFSR_STKERR,
PRINT_BFSR_LSPERR,
PRINT_UFSR_UNDEFINSTR,
PRINT_UFSR_INVSTATE,
PRINT_UFSR_INVPC,
PRINT_UFSR_NOCP,
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
PRINT_UFSR_STKOF,
#endif
PRINT_UFSR_UNALIGNED,
PRINT_UFSR_DIVBYZERO0,
PRINT_DFSR_HALTED,
PRINT_DFSR_BKPT,
PRINT_DFSR_DWTTRAP,
PRINT_DFSR_VCATCH,
PRINT_DFSR_EXTERNAL,
PRINT_MMAR,
PRINT_BFAR,
};
static const char *const print_info[] = {
#if (CMB_PRINT_LANGUAGE == CMB_PRINT_LANGUAGE_ENGLISH)
#include "Languages/en-US/cmb_en_US.h"
#elif (CMB_PRINT_LANGUAGE == CMB_PRINT_LANGUAGE_CHINESE)
#include "Languages/zh-CN/cmb_zh_CN.h"
#elif (CMB_PRINT_LANGUAGE == CMB_PRINT_LANGUAGE_CHINESE_UTF8)
#include "Languages/zh-CN/cmb_zh_CN_UTF8.h"
#elif (CMB_PRINT_LANGUAGE == CMB_PRINT_LANGUAGE_CUSTOM)
#include "cmb_language_custom.h"
#else
#error "CMB_PRINT_LANGUAGE defined error in 'cmb_cfg.h'"
#endif
};
static char fw_name[CMB_NAME_MAX + 1] = {0};
static char hw_ver[CMB_NAME_MAX + 1] = {0};
static char sw_ver[CMB_NAME_MAX + 1] = {0};
static uint32_t main_stack_start_addr = 0;
static size_t main_stack_size = 0;
static uint32_t code_start_addr = 0;
static size_t code_size = 0;
static bool init_ok = false;
static char call_stack_info[CMB_CALL_STACK_MAX_DEPTH * (8 + 1)] = {0};
static bool on_fault = false;
static bool stack_is_overflow = false;
static struct cmb_hard_fault_regs regs;
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M4) || (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M7) || \
(CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
static bool statck_has_fpu_regs = false;
#endif
static bool on_thread_before_fault = false;
/**
* library initialize
*/
void cm_backtrace_init(const char *firmware_name, const char *hardware_ver, const char *software_ver)
{
strncpy(fw_name, firmware_name, CMB_NAME_MAX);
strncpy(hw_ver, hardware_ver, CMB_NAME_MAX);
strncpy(sw_ver, software_ver, CMB_NAME_MAX);
#if defined(__ARMCC_VERSION)
main_stack_start_addr = (uint32_t)&CSTACK_BLOCK_START(CMB_CSTACK_BLOCK_NAME);
main_stack_size = (uint32_t)&CSTACK_BLOCK_END(CMB_CSTACK_BLOCK_NAME) - main_stack_start_addr;
code_start_addr = (uint32_t)&CODE_SECTION_START(CMB_CODE_SECTION_NAME);
code_size = (uint32_t)&CODE_SECTION_END(CMB_CODE_SECTION_NAME) - code_start_addr;
#elif defined(__ICCARM__)
main_stack_start_addr = (uint32_t)__section_begin(CMB_CSTACK_BLOCK_NAME);
main_stack_size = (uint32_t)__section_end(CMB_CSTACK_BLOCK_NAME) - main_stack_start_addr;
code_start_addr = (uint32_t)__section_begin(CMB_CODE_SECTION_NAME);
code_size = (uint32_t)__section_end(CMB_CODE_SECTION_NAME) - code_start_addr;
#elif defined(__GNUC__)
// main_stack_start_addr = (uint32_t)(&CMB_CSTACK_BLOCK_START);
// main_stack_size = (uint32_t)(&CMB_CSTACK_BLOCK_END) - main_stack_start_addr;
// code_start_addr = (uint32_t)(&CMB_CODE_SECTION_START);
// code_size = (uint32_t)(&CMB_CODE_SECTION_END) - code_start_addr;
code_start_addr = (uint32_t)(CONFIG_SYS_TEXT_ADDR);
code_size = (uint32_t)(CONFIG_SYS_TEXT_SIZE);
#else
#error "not supported compiler"
#endif
#if 0
if (main_stack_size == 0) {
cmb_println(print_info[PRINT_MAIN_STACK_CFG_ERROR]);
return;
}
#endif
init_ok = true;
}
/**
* print firmware information, such as: firmware name, hardware version, software version
*/
void cm_backtrace_firmware_info(void)
{
cmb_println(print_info[PRINT_FIRMWARE_INFO], fw_name, hw_ver, sw_ver);
}
#ifdef CMB_USING_OS_PLATFORM
/**
* Get current thread stack information
*
* @param sp stack current pointer
* @param start_addr stack start address
* @param size stack size
*/
static void get_cur_thread_stack_info(uint32_t *sp, uint32_t *start_addr, size_t *size)
{
CMB_ASSERT(start_addr);
CMB_ASSERT(size);
#if (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_RTT)
*start_addr = (uint32_t)rt_thread_self()->stack_addr;
*size = rt_thread_self()->stack_size;
*sp = (uint32_t)rt_thread_self()->sp;
#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_UCOSII)
extern OS_TCB *OSTCBCur;
*start_addr = (uint32_t)OSTCBCur->OSTCBStkBottom;
*size = OSTCBCur->OSTCBStkSize * sizeof(OS_STK);
#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_UCOSIII)
extern OS_TCB *OSTCBCurPtr;
*start_addr = (uint32_t)OSTCBCurPtr->StkBasePtr;
*size = OSTCBCurPtr->StkSize * sizeof(CPU_STK_SIZE);
#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_FREERTOS)
*start_addr = (uint32_t)vTaskStackAddr();
*size = vTaskStackSize() * sizeof(StackType_t);
#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_RTX5)
osRtxThread_t *thread = osRtxInfo.thread.run.curr;
*start_addr = (uint32_t)thread->stack_mem;
*size = thread->stack_size;
#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_THREADX)
TX_THREAD *ptThread = NULL;
TX_THREAD_GET_CURRENT(ptThread);
*start_addr = (uint32_t)ptThread->tx_thread_stack_start;
*size = ptThread->tx_thread_stack_size;
#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_MKRTOS)
// thread_t *cur_th = NULL;
// cur_th = thread_get_current();
// *start_addr = (uint32_t)cur_th->sp.knl_sp;
// *size = CONFIG_THREAD_BLOCK_SIZE;
void *mem;
mm_space_get_ram_block(&(thread_get_current_task()->mm_space), &mem, size);
*start_addr = (uint32_t)mem;
#endif
}
/**
* Get current thread name
*/
static const char *get_cur_thread_name(void)
{
#if (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_RTT)
#if (RT_VER_NUM < 0x50001)
return rt_thread_self()->name;
#else
return rt_thread_self()->parent.name;
#endif
#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_UCOSII)
extern OS_TCB *OSTCBCur;
#if OS_TASK_NAME_SIZE > 0 || OS_TASK_NAME_EN > 0
return (const char *)OSTCBCur->OSTCBTaskName;
#else
return NULL;
#endif /* OS_TASK_NAME_SIZE > 0 || OS_TASK_NAME_EN > 0 */
#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_UCOSIII)
extern OS_TCB *OSTCBCurPtr;
return (const char *)OSTCBCurPtr->NamePtr;
#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_FREERTOS)
return vTaskName();
#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_RTX5)
return osRtxInfo.thread.run.curr->name;
#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_THREADX)
TX_THREAD *ptThread = NULL;
TX_THREAD_GET_CURRENT(ptThread);
return ptThread->tx_thread_name;
#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_MKRTOS)
return kobject_get_name(&(thread_get_current()->kobj));
#endif
}
#endif /* CMB_USING_OS_PLATFORM */
#ifdef CMB_USING_DUMP_STACK_INFO
/**
* dump current stack information
*/
static void dump_stack(uint32_t stack_start_addr, size_t stack_size, uint32_t *stack_pointer)
{
uint32_t deep = CMB_DUMP_STACK_DEPTH_SIZE;
if (stack_is_overflow)
{
if (on_thread_before_fault)
{
cmb_println(print_info[PRINT_THREAD_STACK_OVERFLOW], stack_pointer);
}
else
{
cmb_println(print_info[PRINT_MAIN_STACK_OVERFLOW], stack_pointer);
}
if ((uint32_t)stack_pointer < stack_start_addr)
{
stack_pointer = (uint32_t *)stack_start_addr;
}
else if ((uint32_t)stack_pointer > stack_start_addr + stack_size)
{
stack_pointer = (uint32_t *)(stack_start_addr + stack_size);
}
}
cmb_println(print_info[PRINT_THREAD_STACK_INFO]);
for (; (uint32_t)stack_pointer < stack_start_addr + stack_size && deep; stack_pointer++, deep--)
{
cmb_println(" addr: %08x data: %08x", stack_pointer, *stack_pointer);
}
cmb_println("====================================");
}
#endif /* CMB_USING_DUMP_STACK_INFO */
/* check the disassembly instruction is 'BL' or 'BLX' */
static bool disassembly_ins_is_bl_blx(uint32_t addr)
{
uint16_t ins1 = *((uint16_t *)addr);
uint16_t ins2 = *((uint16_t *)(addr + 2));
#define BL_INS_MASK 0xF800
#define BL_INS_HIGH 0xF800
#define BL_INS_LOW 0xF000
#define BLX_INX_MASK 0xFF00
#define BLX_INX 0x4700
if ((ins2 & BL_INS_MASK) == BL_INS_HIGH && (ins1 & BL_INS_MASK) == BL_INS_LOW)
{
return true;
}
else if ((ins2 & BLX_INX_MASK) == BLX_INX)
{
return true;
}
else
{
return false;
}
}
size_t cm_backtrace_call_stack_any(uint32_t *buffer, size_t size, uint32_t sp, uint32_t stack_start_addr, uint32_t stack_size)
{
uint32_t pc;
size_t depth = 0;
/* copy called function address */
for (; sp < stack_start_addr + stack_size; sp += sizeof(size_t))
{
/* the *sp value may be LR, so need decrease a word to PC */
pc = *((uint32_t *)sp) - sizeof(size_t);
/* the Cortex-M using thumb instruction, so the pc must be an odd number */
if (pc % 2 == 0)
{
continue;
}
/* fix the PC address in thumb mode */
pc = *((uint32_t *)sp) - 1;
if ((pc >= code_start_addr + sizeof(size_t)) && (pc <= code_start_addr + code_size) && (depth < CMB_CALL_STACK_MAX_DEPTH)
/* check the the instruction before PC address is 'BL' or 'BLX' */
&& disassembly_ins_is_bl_blx(pc - sizeof(size_t)) && (depth < size))
{
/* the second depth function may be already saved, so need ignore repeat */
buffer[depth++] = pc;
}
}
return depth;
}
/**
* backtrace function call stack
*
* @param buffer call stack buffer
* @param size buffer size
* @param sp stack pointer
*
* @return depth
*/
size_t cm_backtrace_call_stack(uint32_t *buffer, size_t size, uint32_t sp)
{
uint32_t stack_start_addr = main_stack_start_addr, pc;
#ifdef CMB_USING_OS_PLATFORM
uint32_t tcb_sp;
#endif
size_t depth = 0, stack_size = main_stack_size;
bool regs_saved_lr_is_valid = false;
if (on_fault)
{
if (!stack_is_overflow)
{
/* first depth is PC */
buffer[depth++] = regs.saved.pc;
/* fix the LR address in thumb mode */
pc = regs.saved.lr - 1;
if ((pc >= code_start_addr) && (pc <= code_start_addr + code_size) && (depth < CMB_CALL_STACK_MAX_DEPTH) && (depth < size))
{
buffer[depth++] = pc;
regs_saved_lr_is_valid = true;
}
}
#ifdef CMB_USING_OS_PLATFORM
/* program is running on thread before fault */
if (on_thread_before_fault)
{
get_cur_thread_stack_info(&tcb_sp, &stack_start_addr, &stack_size);
}
}
else
{
/* OS environment */
if (cmb_get_sp() == cmb_get_psp())
{
get_cur_thread_stack_info(&tcb_sp, &stack_start_addr, &stack_size);
}
#endif /* CMB_USING_OS_PLATFORM */
}
if (stack_is_overflow)
{
sp = stack_start_addr;
}
/* copy called function address */
for (; sp < stack_start_addr + stack_size; sp += sizeof(size_t))
{
/* the *sp value may be LR, so need decrease a word to PC */
pc = *((uint32_t *)sp) - sizeof(size_t);
/* the Cortex-M using thumb instruction, so the pc must be an odd number */
if (pc % 2 == 0)
{
continue;
}
/* fix the PC address in thumb mode */
pc = *((uint32_t *)sp) - 1;
if ((pc >= code_start_addr + sizeof(size_t)) && (pc <= code_start_addr + code_size) && (depth < CMB_CALL_STACK_MAX_DEPTH)
/* check the the instruction before PC address is 'BL' or 'BLX' */
&& disassembly_ins_is_bl_blx(pc - sizeof(size_t)) && (depth < size))
{
/* the second depth function may be already saved, so need ignore repeat */
if ((depth == 2) && regs_saved_lr_is_valid && (pc == buffer[1]))
{
continue;
}
buffer[depth++] = pc;
}
}
return depth;
}
/**
* dump function call stack
*
* @param sp stack pointer
*/
static void print_call_stack(uint32_t sp)
{
size_t i, cur_depth = 0;
uint32_t call_stack_buf[CMB_CALL_STACK_MAX_DEPTH] = {0};
cur_depth = cm_backtrace_call_stack(call_stack_buf, CMB_CALL_STACK_MAX_DEPTH, sp);
for (i = 0; i < cur_depth; i++)
{
sprintf(call_stack_info + i * (8 + 1), "%08lx", (unsigned long)call_stack_buf[i] - (umword_t)(thread_get_current_task()->text_addr));
call_stack_info[i * (8 + 1) + 8] = ' ';
}
if (cur_depth)
{
cmb_println(print_info[PRINT_CALL_STACK_INFO], fw_name, CMB_ELF_FILE_EXTENSION_NAME, cur_depth * (8 + 1),
call_stack_info);
}
else
{
cmb_println(print_info[PRINT_CALL_STACK_ERR]);
}
}
/**
* backtrace for assert
*
* @param sp the stack pointer when on assert occurred
*/
void cm_backtrace_assert(uint32_t sp)
{
#ifdef CMB_USING_OS_PLATFORM
uint32_t tcb_sp;
uint32_t cur_stack_pointer = cmb_get_sp();
#endif
CMB_ASSERT(init_ok);
cmb_println("");
cm_backtrace_firmware_info();
#ifdef CMB_USING_OS_PLATFORM
/* OS environment */
if (cur_stack_pointer == cmb_get_msp())
{
cmb_println(print_info[PRINT_ASSERT_ON_HANDLER]);
#ifdef CMB_USING_DUMP_STACK_INFO
dump_stack(main_stack_start_addr, main_stack_size, (uint32_t *)sp);
#endif /* CMB_USING_DUMP_STACK_INFO */
}
else if (cur_stack_pointer == cmb_get_psp())
{
cmb_println(print_info[PRINT_ASSERT_ON_THREAD], get_cur_thread_name());
#ifdef CMB_USING_DUMP_STACK_INFO
uint32_t stack_start_addr;
size_t stack_size;
get_cur_thread_stack_info(&tcb_sp, &stack_start_addr, &stack_size);
dump_stack(stack_start_addr, stack_size, (uint32_t *)sp);
#endif /* CMB_USING_DUMP_STACK_INFO */
}
#else
/* bare metal(no OS) environment */
#ifdef CMB_USING_DUMP_STACK_INFO
dump_stack(main_stack_start_addr, main_stack_size, (uint32_t *)sp);
#endif /* CMB_USING_DUMP_STACK_INFO */
#endif /* CMB_USING_OS_PLATFORM */
print_call_stack(sp);
}
#if (CMB_CPU_PLATFORM_TYPE != CMB_CPU_ARM_CORTEX_M0)
/**
* fault diagnosis then print cause of fault
*/
static void fault_diagnosis(void)
{
if (regs.hfsr.bits.VECTBL)
{
cmb_println(print_info[PRINT_HFSR_VECTBL]);
}
if (regs.hfsr.bits.FORCED)
{
/* Memory Management Fault */
if (regs.mfsr.value)
{
if (regs.mfsr.bits.IACCVIOL)
{
cmb_println(print_info[PRINT_MFSR_IACCVIOL]);
}
if (regs.mfsr.bits.DACCVIOL)
{
cmb_println(print_info[PRINT_MFSR_DACCVIOL]);
}
if (regs.mfsr.bits.MUNSTKERR)
{
cmb_println(print_info[PRINT_MFSR_MUNSTKERR]);
}
if (regs.mfsr.bits.MSTKERR)
{
cmb_println(print_info[PRINT_MFSR_MSTKERR]);
}
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M4) || (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M7) || \
(CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
if (regs.mfsr.bits.MLSPERR)
{
cmb_println(print_info[PRINT_MFSR_MLSPERR]);
}
#endif
if (regs.mfsr.bits.MMARVALID)
{
if (regs.mfsr.bits.IACCVIOL || regs.mfsr.bits.DACCVIOL)
{
cmb_println(print_info[PRINT_MMAR], regs.mmar);
}
}
}
/* Bus Fault */
if (regs.bfsr.value)
{
if (regs.bfsr.bits.IBUSERR)
{
cmb_println(print_info[PRINT_BFSR_IBUSERR]);
}
if (regs.bfsr.bits.PRECISERR)
{
cmb_println(print_info[PRINT_BFSR_PRECISERR]);
}
if (regs.bfsr.bits.IMPREISERR)
{
cmb_println(print_info[PRINT_BFSR_IMPREISERR]);
}
if (regs.bfsr.bits.UNSTKERR)
{
cmb_println(print_info[PRINT_BFSR_UNSTKERR]);
}
if (regs.bfsr.bits.STKERR)
{
cmb_println(print_info[PRINT_BFSR_STKERR]);
}
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M4) || (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M7) || \
(CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
if (regs.bfsr.bits.LSPERR)
{
cmb_println(print_info[PRINT_BFSR_LSPERR]);
}
#endif
if (regs.bfsr.bits.BFARVALID)
{
if (regs.bfsr.bits.PRECISERR)
{
cmb_println(print_info[PRINT_BFAR], regs.bfar);
}
}
}
/* Usage Fault */
if (regs.ufsr.value)
{
if (regs.ufsr.bits.UNDEFINSTR)
{
cmb_println(print_info[PRINT_UFSR_UNDEFINSTR]);
}
if (regs.ufsr.bits.INVSTATE)
{
cmb_println(print_info[PRINT_UFSR_INVSTATE]);
}
if (regs.ufsr.bits.INVPC)
{
cmb_println(print_info[PRINT_UFSR_INVPC]);
}
if (regs.ufsr.bits.NOCP)
{
cmb_println(print_info[PRINT_UFSR_NOCP]);
}
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
if (regs.ufsr.bits.STKOF)
{
cmb_println(print_info[PRINT_UFSR_STKOF]);
}
#endif
if (regs.ufsr.bits.UNALIGNED)
{
cmb_println(print_info[PRINT_UFSR_UNALIGNED]);
}
if (regs.ufsr.bits.DIVBYZERO0)
{
cmb_println(print_info[PRINT_UFSR_DIVBYZERO0]);
}
}
}
/* Debug Fault */
if (regs.hfsr.bits.DEBUGEVT)
{
if (regs.dfsr.value)
{
if (regs.dfsr.bits.HALTED)
{
cmb_println(print_info[PRINT_DFSR_HALTED]);
}
if (regs.dfsr.bits.BKPT)
{
cmb_println(print_info[PRINT_DFSR_BKPT]);
}
if (regs.dfsr.bits.DWTTRAP)
{
cmb_println(print_info[PRINT_DFSR_DWTTRAP]);
}
if (regs.dfsr.bits.VCATCH)
{
cmb_println(print_info[PRINT_DFSR_VCATCH]);
}
if (regs.dfsr.bits.EXTERNAL)
{
cmb_println(print_info[PRINT_DFSR_EXTERNAL]);
}
}
}
}
#endif /* (CMB_CPU_PLATFORM_TYPE != CMB_CPU_ARM_CORTEX_M0) */
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M4) || (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M7) || \
(CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
static uint32_t statck_del_fpu_regs(uint32_t fault_handler_lr, uint32_t sp)
{
statck_has_fpu_regs = (fault_handler_lr & (1UL << 4)) == 0 ? true : false;
/* the stack has S0~S15 and FPSCR registers when statck_has_fpu_regs is true, double word align */
return statck_has_fpu_regs == true ? sp + sizeof(size_t) * 18 : sp;
}
#endif
/**
* backtrace for fault
* @note only call once
*
* @param fault_handler_lr the LR register value on fault handler
* @param fault_handler_sp the stack pointer on fault handler
*/
void cm_backtrace_fault(uint32_t fault_handler_lr, uint32_t fault_handler_sp)
{
uint32_t stack_pointer = fault_handler_sp, saved_regs_addr = stack_pointer, tcb_stack_pointer = 0;
const char *regs_name[] = {"R0 ", "R1 ", "R2 ", "R3 ", "R12", "LR ", "PC ", "PSR"};
#ifdef CMB_USING_DUMP_STACK_INFO
uint32_t stack_start_addr = main_stack_start_addr;
size_t stack_size = main_stack_size;
#endif
CMB_ASSERT(init_ok);
/* only call once */
CMB_ASSERT(!on_fault);
#ifdef MKRTOS
code_start_addr = ((umword_t)(thread_get_current_task()->text_addr));
code_size = ((umword_t)(thread_get_current_task()->text_size));
#endif
on_fault = true;
cmb_println("");
cm_backtrace_firmware_info();
#ifdef CMB_USING_OS_PLATFORM
on_thread_before_fault = fault_handler_lr & (1UL << 2);
/* check which stack was used before (MSP or PSP) */
if (on_thread_before_fault)
{
cmb_println(print_info[PRINT_FAULT_ON_THREAD], get_cur_thread_name() != NULL ? get_cur_thread_name() : "NO_NAME");
saved_regs_addr = stack_pointer = cmb_get_psp();
#ifdef CMB_USING_DUMP_STACK_INFO
get_cur_thread_stack_info(&tcb_stack_pointer, &stack_start_addr, &stack_size);
#endif /* CMB_USING_DUMP_STACK_INFO */
}
else
{
cmb_println(print_info[PRINT_FAULT_ON_HANDLER]);
}
#else
/* bare metal(no OS) environment */
cmb_println(print_info[PRINT_FAULT_ON_HANDLER]);
#endif /* CMB_USING_OS_PLATFORM */
/* delete saved R0~R3, R12, LR,PC,xPSR registers space */
stack_pointer += sizeof(size_t) * 8;
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M4) || (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M7) || \
(CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
stack_pointer = statck_del_fpu_regs(fault_handler_lr, stack_pointer);
#endif /* (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M4) || (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M7) */
#ifdef CMB_USING_DUMP_STACK_INFO
/* check stack overflow */
if (stack_pointer < stack_start_addr || stack_pointer > stack_start_addr + stack_size)
{
cmb_println("stack_pointer: 0x%08x, stack_start_addr: 0x%08x, stack_end_addr: 0x%08x", stack_pointer, stack_start_addr,
stack_start_addr + stack_size);
stack_is_overflow = true;
#if (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_RTT)
if (on_thread_before_fault)
{
/* change the stack start adder to TCB->sp when stack is overflow */
stack_pointer = tcb_stack_pointer;
}
#endif
}
/* dump stack information */
dump_stack(stack_start_addr, stack_size, (uint32_t *)stack_pointer);
#endif /* CMB_USING_DUMP_STACK_INFO */
{
/* dump register */
cmb_println(print_info[PRINT_REGS_TITLE]);
regs.saved.r0 = ((uint32_t *)saved_regs_addr)[0]; // Register R0
regs.saved.r1 = ((uint32_t *)saved_regs_addr)[1]; // Register R1
regs.saved.r2 = ((uint32_t *)saved_regs_addr)[2]; // Register R2
regs.saved.r3 = ((uint32_t *)saved_regs_addr)[3]; // Register R3
regs.saved.r12 = ((uint32_t *)saved_regs_addr)[4]; // Register R12
regs.saved.lr = ((uint32_t *)saved_regs_addr)[5]; // Link register LR
regs.saved.pc = ((uint32_t *)saved_regs_addr)[6]; // Program counter PC
regs.saved.psr.value = ((uint32_t *)saved_regs_addr)[7]; // Program status word PSR
cmb_println(" %s: %08x %s: %08x %s: %08x %s: %08x", regs_name[0], regs.saved.r0,
regs_name[1], regs.saved.r1,
regs_name[2], regs.saved.r2,
regs_name[3], regs.saved.r3);
cmb_println(" %s: %08x %s: %08x %s: %08x %s: %08x", regs_name[4], regs.saved.r12,
regs_name[5], regs.saved.lr,
regs_name[6], regs.saved.pc,
regs_name[7], regs.saved.psr.value);
cmb_println("==============================================================");
}
/* the Cortex-M0 is not support fault diagnosis */
#if (CMB_CPU_PLATFORM_TYPE != CMB_CPU_ARM_CORTEX_M0)
regs.syshndctrl.value = CMB_SYSHND_CTRL; // System Handler Control and State Register
regs.mfsr.value = CMB_NVIC_MFSR; // Memory Fault Status Register
regs.mmar = CMB_NVIC_MMAR; // Memory Management Fault Address Register
regs.bfsr.value = CMB_NVIC_BFSR; // Bus Fault Status Register
regs.bfar = CMB_NVIC_BFAR; // Bus Fault Manage Address Register
regs.ufsr.value = CMB_NVIC_UFSR; // Usage Fault Status Register
regs.hfsr.value = CMB_NVIC_HFSR; // Hard Fault Status Register
regs.dfsr.value = CMB_NVIC_DFSR; // Debug Fault Status Register
regs.afsr = CMB_NVIC_AFSR; // Auxiliary Fault Status Register
fault_diagnosis();
#endif
print_call_stack(stack_pointer);
}

View File

@@ -0,0 +1,48 @@
/*
* This file is part of the CmBacktrace Library.
*
* Copyright (c) 2016, Armink, <armink.ztl@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* 'Software'), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Function: It is an head file for this library. You can see all be called functions.
* Created on: 2016-12-15
*/
#ifndef _CORTEXM_BACKTRACE_H_
#define _CORTEXM_BACKTRACE_H_
#include "cmb_def.h"
#ifdef __cplusplus
extern "C" {
#endif
void cm_backtrace_init(const char *firmware_name, const char *hardware_ver, const char *software_ver);
void cm_backtrace_firmware_info(void);
size_t cm_backtrace_call_stack(uint32_t *buffer, size_t size, uint32_t sp);
void cm_backtrace_assert(uint32_t sp);
void cm_backtrace_fault(uint32_t fault_handler_lr, uint32_t fault_handler_sp);
#ifdef __cplusplus
}
#endif
#endif /* _CORTEXM_BACKTRACE_H_ */

View File

@@ -0,0 +1,48 @@
/*
* This file is part of the CmBacktrace Library.
*
* Copyright (c) 2016, Armink, <armink.ztl@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* 'Software'), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Function: It is the configure head file for this library.
* Created on: 2016-12-15
*/
#ifndef _CMB_CFG_H_
#define _CMB_CFG_H_
#include <printk.h>
#include <thread.h>
/* print line, must config by user */
#define cmb_println(...) printkln(__VA_ARGS__);
/* enable OS platform */
#define CMB_USING_OS_PLATFORM
/* OS platform type, must config when CMB_USING_OS_PLATFORM is enable */
#define CMB_OS_PLATFORM_TYPE CMB_OS_PLATFORM_MKRTOS
/* cpu platform type, must config by user */
#define CMB_CPU_PLATFORM_TYPE CMB_CPU_ARM_CORTEX_M3/*FIXME:*/
/* enable dump stack information */
#define CMB_USING_DUMP_STACK_INFO
/* language of print information */
#define CMB_PRINT_LANGUAGE CMB_PRINT_LANGUAGE_ENGLISH
#endif /* _CMB_CFG_H_ */

View File

@@ -0,0 +1,434 @@
/*
* This file is part of the CmBacktrace Library.
*
* Copyright (c) 2016-2020, Armink, <armink.ztl@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* 'Software'), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Function: It is the macro definition head file for this library.
* Created on: 2016-12-15
*/
#ifndef _CMB_DEF_H_
#define _CMB_DEF_H_
#include <cmb_cfg.h>
#include <stdint.h>
#include <stdlib.h>
/* library software version number */
#define CMB_SW_VERSION "1.4.2"
#define CMB_CPU_ARM_CORTEX_M0 0
#define CMB_CPU_ARM_CORTEX_M3 1
#define CMB_CPU_ARM_CORTEX_M4 2
#define CMB_CPU_ARM_CORTEX_M7 3
#define CMB_CPU_ARM_CORTEX_M33 4
#define CMB_OS_PLATFORM_RTT 0
#define CMB_OS_PLATFORM_UCOSII 1
#define CMB_OS_PLATFORM_UCOSIII 2
#define CMB_OS_PLATFORM_FREERTOS 3
#define CMB_OS_PLATFORM_RTX5 4
#define CMB_OS_PLATFORM_THREADX 5
#define CMB_OS_PLATFORM_MKRTOS 6
#define CMB_PRINT_LANGUAGE_ENGLISH 0
#define CMB_PRINT_LANGUAGE_CHINESE 1
#define CMB_PRINT_LANGUAGE_CHINESE_UTF8 2
#define CMB_PRINT_LANGUAGE_CUSTOM 0xFF
/* name max length, default size: 32 */
#ifndef CMB_NAME_MAX
#define CMB_NAME_MAX 32
#endif
/* print information language, default is English */
#ifndef CMB_PRINT_LANGUAGE
#define CMB_PRINT_LANGUAGE CMB_PRINT_LANGUAGE_ENGLISH
#endif
#if defined(__ARMCC_VERSION)
/* C stack block name, default is STACK */
#ifndef CMB_CSTACK_BLOCK_NAME
#define CMB_CSTACK_BLOCK_NAME STACK
#endif
/* code section name, default is ER_IROM1 */
#ifndef CMB_CODE_SECTION_NAME
#define CMB_CODE_SECTION_NAME ER_IROM1
#endif
#elif defined(__ICCARM__)
/* C stack block name, default is 'CSTACK' */
#ifndef CMB_CSTACK_BLOCK_NAME
#define CMB_CSTACK_BLOCK_NAME "CSTACK"
#endif
/* code section name, default is '.text' */
#ifndef CMB_CODE_SECTION_NAME
#define CMB_CODE_SECTION_NAME ".text"
#endif
#elif defined(__GNUC__)
/* C stack block start address, defined on linker script file, default is _sstack */
#ifndef CMB_CSTACK_BLOCK_START
#define CMB_CSTACK_BLOCK_START _sstack
#endif
/* C stack block end address, defined on linker script file, default is _estack */
#ifndef CMB_CSTACK_BLOCK_END
#define CMB_CSTACK_BLOCK_END _estack
#endif
/* code section start address, defined on linker script file, default is _stext */
#ifndef CMB_CODE_SECTION_START
#define CMB_CODE_SECTION_START _stext
#endif
/* code section end address, defined on linker script file, default is _etext */
#ifndef CMB_CODE_SECTION_END
#define CMB_CODE_SECTION_END _etext
#endif
#else
#error "not supported compiler"
#endif
/* supported function call stack max depth, default is 32 */
#ifndef CMB_CALL_STACK_MAX_DEPTH
#define CMB_CALL_STACK_MAX_DEPTH 8
#endif
/*
* The maximum print depth in case of exception prevents
* too much stack information from printing and insufficient log space
*/
#ifndef CMB_DUMP_STACK_DEPTH_SIZE
#define CMB_DUMP_STACK_DEPTH_SIZE (16)
#endif
/* system handler control and state register */
#ifndef CMB_SYSHND_CTRL
#define CMB_SYSHND_CTRL (*(volatile unsigned int*) (0xE000ED24u))
#endif
/* memory management fault status register */
#ifndef CMB_NVIC_MFSR
#define CMB_NVIC_MFSR (*(volatile unsigned char*) (0xE000ED28u))
#endif
/* bus fault status register */
#ifndef CMB_NVIC_BFSR
#define CMB_NVIC_BFSR (*(volatile unsigned char*) (0xE000ED29u))
#endif
/* usage fault status register */
#ifndef CMB_NVIC_UFSR
#define CMB_NVIC_UFSR (*(volatile unsigned short*)(0xE000ED2Au))
#endif
/* hard fault status register */
#ifndef CMB_NVIC_HFSR
#define CMB_NVIC_HFSR (*(volatile unsigned int*) (0xE000ED2Cu))
#endif
/* debug fault status register */
#ifndef CMB_NVIC_DFSR
#define CMB_NVIC_DFSR (*(volatile unsigned short*)(0xE000ED30u))
#endif
/* memory management fault address register */
#ifndef CMB_NVIC_MMAR
#define CMB_NVIC_MMAR (*(volatile unsigned int*) (0xE000ED34u))
#endif
/* bus fault manage address register */
#ifndef CMB_NVIC_BFAR
#define CMB_NVIC_BFAR (*(volatile unsigned int*) (0xE000ED38u))
#endif
/* auxiliary fault status register */
#ifndef CMB_NVIC_AFSR
#define CMB_NVIC_AFSR (*(volatile unsigned short*)(0xE000ED3Cu))
#endif
/**
* Cortex-M fault registers
*/
struct cmb_hard_fault_regs{
struct {
unsigned int r0; // Register R0
unsigned int r1; // Register R1
unsigned int r2; // Register R2
unsigned int r3; // Register R3
unsigned int r12; // Register R12
unsigned int lr; // Link register
unsigned int pc; // Program counter
union {
unsigned int value;
struct {
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
unsigned int IPSR : 9; // Interrupt Program Status register (IPSR)
unsigned int EPSR : 18; // Execution Program Status register (EPSR)
unsigned int APSR : 5; // Application Program Status register (APSR)
#else
unsigned int IPSR : 8; // Interrupt Program Status register (IPSR)
unsigned int EPSR : 19; // Execution Program Status register (EPSR)
unsigned int APSR : 5; // Application Program Status register (APSR)
#endif
} bits;
} psr; // Program status register.
} saved;
union {
unsigned int value;
struct {
unsigned int MEMFAULTACT : 1; // Read as 1 if memory management fault is active
unsigned int BUSFAULTACT : 1; // Read as 1 if bus fault exception is active
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
unsigned int HARDFAULTACT : 1; // Read as 1 if hardfault is active
#else
unsigned int UnusedBits1 : 1;
#endif
unsigned int USGFAULTACT : 1; // Read as 1 if usage fault exception is active
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
unsigned int SECUREFAULTACT : 1; // Read as 1 if secure fault exception is active
unsigned int NMIACT : 1; // Read as 1 if NMI exception is active
unsigned int UnusedBits2 : 1;
#else
unsigned int UnusedBits2 : 3;
#endif
unsigned int SVCALLACT : 1; // Read as 1 if SVC exception is active
unsigned int MONITORACT : 1; // Read as 1 if debug monitor exception is active
unsigned int UnusedBits3 : 1;
unsigned int PENDSVACT : 1; // Read as 1 if PendSV exception is active
unsigned int SYSTICKACT : 1; // Read as 1 if SYSTICK exception is active
unsigned int USGFAULTPENDED : 1; // Usage fault pended; usage fault started but was replaced by a higher-priority exception
unsigned int MEMFAULTPENDED : 1; // Memory management fault pended; memory management fault started but was replaced by a higher-priority exception
unsigned int BUSFAULTPENDED : 1; // Bus fault pended; bus fault handler was started but was replaced by a higher-priority exception
unsigned int SVCALLPENDED : 1; // SVC pended; SVC was started but was replaced by a higher-priority exception
unsigned int MEMFAULTENA : 1; // Memory management fault handler enable
unsigned int BUSFAULTENA : 1; // Bus fault handler enable
unsigned int USGFAULTENA : 1; // Usage fault handler enable
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
unsigned int SECUREFAULTENA : 1; // Secure fault handler enable
unsigned int SECUREFAULTPENDED : 1; // Secure fault pended; Secure fault handler was started but was replaced by a higher-priority exception
unsigned int HARDFAULTPENDED : 1; // Hard fault pended; Hard fault handler was started but was replaced by a higher-priority exception
#else
// None
#endif
} bits;
} syshndctrl; // System Handler Control and State Register (0xE000ED24)
union {
unsigned char value;
struct {
unsigned char IACCVIOL : 1; // Instruction access violation
unsigned char DACCVIOL : 1; // Data access violation
unsigned char UnusedBits : 1;
unsigned char MUNSTKERR : 1; // Unstacking error
unsigned char MSTKERR : 1; // Stacking error
unsigned char MLSPERR : 1; // Floating-point lazy state preservation (M4/M7)
unsigned char UnusedBits2 : 1;
unsigned char MMARVALID : 1; // Indicates the MMAR is valid
} bits;
} mfsr; // Memory Management Fault Status Register (0xE000ED28)
unsigned int mmar; // Memory Management Fault Address Register (0xE000ED34)
union {
unsigned char value;
struct {
unsigned char IBUSERR : 1; // Instruction access violation
unsigned char PRECISERR : 1; // Precise data access violation
unsigned char IMPREISERR : 1; // Imprecise data access violation
unsigned char UNSTKERR : 1; // Unstacking error
unsigned char STKERR : 1; // Stacking error
unsigned char LSPERR : 1; // Floating-point lazy state preservation (M4/M7)
unsigned char UnusedBits : 1;
unsigned char BFARVALID : 1; // Indicates BFAR is valid
} bits;
} bfsr; // Bus Fault Status Register (0xE000ED29)
unsigned int bfar; // Bus Fault Manage Address Register (0xE000ED38)
union {
unsigned short value;
struct {
unsigned short UNDEFINSTR : 1; // Attempts to execute an undefined instruction
unsigned short INVSTATE : 1; // Attempts to switch to an invalid state (e.g., ARM)
unsigned short INVPC : 1; // Attempts to do an exception with a bad value in the EXC_RETURN number
unsigned short NOCP : 1; // Attempts to execute a coprocessor instruction
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
unsigned short STKOF : 1; // Indicates a stack overflow error has occured
unsigned short UnusedBits : 3;
#else
unsigned short UnusedBits : 4;
#endif
unsigned short UNALIGNED : 1; // Indicates that an unaligned access fault has taken place
unsigned short DIVBYZERO0 : 1; // Indicates a divide by zero has taken place (can be set only if DIV_0_TRP is set)
} bits;
} ufsr; // Usage Fault Status Register (0xE000ED2A)
union {
unsigned int value;
struct {
unsigned int UnusedBits : 1;
unsigned int VECTBL : 1; // Indicates hard fault is caused by failed vector fetch
unsigned int UnusedBits2 : 28;
unsigned int FORCED : 1; // Indicates hard fault is taken because of bus fault/memory management fault/usage fault
unsigned int DEBUGEVT : 1; // Indicates hard fault is triggered by debug event
} bits;
} hfsr; // Hard Fault Status Register (0xE000ED2C)
union {
unsigned int value;
struct {
unsigned int HALTED : 1; // Halt requested in NVIC
unsigned int BKPT : 1; // BKPT instruction executed
unsigned int DWTTRAP : 1; // DWT match occurred
unsigned int VCATCH : 1; // Vector fetch occurred
unsigned int EXTERNAL : 1; // EDBGRQ signal asserted
} bits;
} dfsr; // Debug Fault Status Register (0xE000ED30)
unsigned int afsr; // Auxiliary Fault Status Register (0xE000ED3C), Vendor controlled (optional)
};
/* assert for developer. */
#define CMB_ASSERT(EXPR) \
if (!(EXPR)) \
{ \
cmb_println("(%s) has assert failed at %s.", #EXPR, __FUNCTION__); \
while (1); \
}
/* ELF(Executable and Linking Format) file extension name for each compiler */
#if defined(__CC_ARM) || defined(__CLANG_ARM) || defined(__ARMCC_VERSION)
#define CMB_ELF_FILE_EXTENSION_NAME ".axf"
#elif defined(__ICCARM__)
#define CMB_ELF_FILE_EXTENSION_NAME ".out"
#elif defined(__GNUC__)
#define CMB_ELF_FILE_EXTENSION_NAME ".elf"
#else
#error "not supported compiler"
#endif
#ifndef cmb_println
#error "cmb_println isn't defined in 'cmb_cfg.h'"
#endif
#ifndef CMB_CPU_PLATFORM_TYPE
#error "CMB_CPU_PLATFORM_TYPE isn't defined in 'cmb_cfg.h'"
#endif
#if (defined(CMB_USING_BARE_METAL_PLATFORM) && defined(CMB_USING_OS_PLATFORM))
#error "CMB_USING_BARE_METAL_PLATFORM and CMB_USING_OS_PLATFORM only one of them can be used"
#elif defined(CMB_USING_OS_PLATFORM)
#if !defined(CMB_OS_PLATFORM_TYPE)
#error "CMB_OS_PLATFORM_TYPE isn't defined in 'cmb_cfg.h'"
#endif /* !defined(CMB_OS_PLATFORM_TYPE) */
#if (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_RTT)
#include <rtthread.h>
#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_UCOSII)
#include <ucos_ii.h>
#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_UCOSIII)
#include <os.h>
#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_FREERTOS)
#include <FreeRTOS.h>
extern uint32_t *vTaskStackAddr(void);/* need to modify the FreeRTOS/tasks source code */
extern uint32_t vTaskStackSize(void);
extern char * vTaskName(void);
#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_RTX5)
#include "rtx_os.h"
#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_THREADX)
#include "tx_api.h"
#include "tx_thread.h"
#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_MKRTOS)
#include "printk.h"
#include "thread.h"
#else
#error "not supported OS type"
#endif /* (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_RTT) */
#endif /* (defined(CMB_USING_BARE_METAL_PLATFORM) && defined(CMB_USING_OS_PLATFORM)) */
/* include or export for supported cmb_get_msp, cmb_get_psp and cmb_get_sp function */
#if defined(__CC_ARM)
static __inline __asm uint32_t cmb_get_msp(void) {
mrs r0, msp
bx lr
}
static __inline __asm uint32_t cmb_get_psp(void) {
mrs r0, psp
bx lr
}
static __inline __asm uint32_t cmb_get_sp(void) {
mov r0, sp
bx lr
}
#elif defined(__CLANG_ARM)
__attribute__( (always_inline) ) static __inline uint32_t cmb_get_msp(void) {
uint32_t result;
__asm volatile ("mrs %0, msp" : "=r" (result) );
return (result);
}
__attribute__( (always_inline) ) static __inline uint32_t cmb_get_psp(void) {
uint32_t result;
__asm volatile ("mrs %0, psp" : "=r" (result) );
return (result);
}
__attribute__( (always_inline) ) static __inline uint32_t cmb_get_sp(void) {
uint32_t result;
__asm volatile ("mov %0, sp" : "=r" (result) );
return (result);
}
#elif defined(__ICCARM__)
/* IAR iccarm specific functions */
/* Close Raw Asm Code Warning */
#pragma diag_suppress=Pe940
static uint32_t cmb_get_msp(void)
{
__asm("mrs r0, msp");
__asm("bx lr");
}
static uint32_t cmb_get_psp(void)
{
__asm("mrs r0, psp");
__asm("bx lr");
}
static uint32_t cmb_get_sp(void)
{
__asm("mov r0, sp");
__asm("bx lr");
}
#pragma diag_default=Pe940
#elif defined(__GNUC__)
__attribute__( ( always_inline ) ) static inline uint32_t cmb_get_msp(void) {
register uint32_t result;
__asm volatile ("MRS %0, msp\n" : "=r" (result) );
return(result);
}
__attribute__( ( always_inline ) ) static inline uint32_t cmb_get_psp(void) {
register uint32_t result;
__asm volatile ("MRS %0, psp\n" : "=r" (result) );
return(result);
}
__attribute__( ( always_inline ) ) static inline uint32_t cmb_get_sp(void) {
register uint32_t result;
__asm volatile ("MOV %0, sp\n" : "=r" (result) );
return(result);
}
#else
#error "not supported compiler"
#endif
#endif /* _CMB_DEF_H_ */

View File

@@ -0,0 +1,43 @@
/*
* This file is part of the CmBacktrace Library.
*
* Copyright (c) 2016, Armink, <armink.ztl@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* 'Software'), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Function: Fault handler by GCC assembly code
* Created on: 2016-12-16
*/
.syntax unified
.thumb
.text
/* NOTE: If use this file's HardFault_Handler, please comments the HardFault_Handler code on other file. */
.global HardFault_Handler
.type HardFault_Handler, %function
HardFault_Handler:
MOV r0, lr /* get lr */
MOV r1, sp /* get stack pointer (current is MSP) */
BL cm_backtrace_fault
Fault_Loop:
BL Fault_Loop /* while(1) */

View File

@@ -0,0 +1,41 @@
/*
* This file is part of the CmBacktrace Library.
*
* Copyright (c) 2016, Armink, <armink.ztl@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* 'Software'), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Function: Fault handler by GCC assembly code
* Created on: 2016-12-16
*/
.thumb
.text
/* NOTE: If use this file's HardFault_Handler, please comments the HardFault_Handler code on other file. */
.global HardFault_Handler
HardFault_Handler:
MOV r0, lr /* get lr */
MOV r1, sp /* get stack pointer (current is MSP) */
BL cm_backtrace_fault
Fault_Loop:
BL Fault_Loop /* while(1) */

View File

@@ -0,0 +1,46 @@
;/*
; * This file is part of the CmBacktrace Library.
; *
; * Copyright (c) 2016, Armink, <armink.ztl@gmail.com>
; *
; * Permission is hereby granted, free of charge, to any person obtaining
; * a copy of this software and associated documentation files (the
; * 'Software'), to deal in the Software without restriction, including
; * without limitation the rights to use, copy, modify, merge, publish,
; * distribute, sublicense, and/or sell copies of the Software, and to
; * permit persons to whom the Software is furnished to do so, subject to
; * the following conditions:
; *
; * The above copyright notice and this permission notice shall be
; * included in all copies or substantial portions of the Software.
; *
; * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
; * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
; * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
; * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
; * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
; * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
; * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
; *
; * Function: Fault handler by EWARM assembly code
; * Created on: 2016-12-16
; */
SECTION .text:CODE(2)
THUMB
REQUIRE8
PRESERVE8
; NOTE: If use this file's HardFault_Handler, please comments the HardFault_Handler code on other file.
IMPORT cm_backtrace_fault
EXPORT HardFault_Handler
HardFault_Handler:
MOV r0, lr ; get lr
MOV r1, sp ; get stack pointer (current is MSP)
BL cm_backtrace_fault
Fault_Loop
BL Fault_Loop ;while(1)
END

View File

@@ -0,0 +1,47 @@
;/*
; * This file is part of the CmBacktrace Library.
; *
; * Copyright (c) 2016, Armink, <armink.ztl@gmail.com>
; *
; * Permission is hereby granted, free of charge, to any person obtaining
; * a copy of this software and associated documentation files (the
; * 'Software'), to deal in the Software without restriction, including
; * without limitation the rights to use, copy, modify, merge, publish,
; * distribute, sublicense, and/or sell copies of the Software, and to
; * permit persons to whom the Software is furnished to do so, subject to
; * the following conditions:
; *
; * The above copyright notice and this permission notice shall be
; * included in all copies or substantial portions of the Software.
; *
; * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
; * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
; * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
; * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
; * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
; * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
; * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
; *
; * Function: Fault handler by MDK-ARM assembly code
; * Created on: 2016-12-16
; */
AREA |.text|, CODE, READONLY, ALIGN=2
THUMB
REQUIRE8
PRESERVE8
; NOTE: If use this file's HardFault_Handler, please comments the HardFault_Handler code on other file.
IMPORT cm_backtrace_fault
EXPORT HardFault_Handler
HardFault_Handler PROC
MOV r0, lr ; get lr
MOV r1, sp ; get stack pointer (current is MSP)
BL cm_backtrace_fault
Fault_Loop
BL Fault_Loop ;while(1)
ENDP
END

View File

@@ -0,0 +1,4 @@
|File or folder name |Description|
|:----- |:----|
|en |English documents|
|zh |中文文档(简体)|

View File

@@ -0,0 +1,51 @@
# 一步开启 Keil/IAR/GCC 的 C99 支持
## 背景
C99 标准于 1999 年发布至今2016-12-28将近 20 年的时间,相比早期的 C89 C99 有如下新特性(摘自 [维基百科](https://zh.wikipedia.org/wiki/C%E8%AF%AD%E8%A8%80#C99)
- 增加了对编译器的限制,比如源程序每行要求至少支持到 4095 字节,变量名函数名的要求支持到 63 字节extern 要求支持到 31
- 增强了预处理功能。例如:
- 宏支持取可变参数 #define Macro(...) `__VA_ARGS__`
- 使用宏的时候,允许省略参数,被省略的参数会被扩展成空串。
- 支持 // 开头的单行注释这个特性实际上在C89的很多编译器上已经被支持了
- 增加了新关键字 restrict, inline, _Complex, _Imaginary, _Bool
- 支持 long long, long double _Complex, float _Complex 等类型
- 支持不定长的数组,即数组长度可以在运行时决定,比如利用变量作为数组长度。声明时使用 int a[var] 的形式。不过考虑到效率和实现,不定长数组不能用在全局,或 struct 与 union 里。
- 变量声明不必放在语句块的开头for 语句提倡写成 for(int i=0;i<100;++i) 的形式即i 只在 for 语句块内部有效
- 允许采用type_name{xx,xx,xx} 类似于 C++ 的构造函数的形式构造匿名的结构体
- 初始化结构的时候允许对特定的元素赋值形式为
- `struct test{int a[3]b;} foo[] = { [0].a = {1}, [1].a = 2 };`
- `struct test{int a, b, c, d;} foo = { .a = 1, .c = 3, 4, .b = 5 }; // 3,4 是对 .c,.d 赋值的`
- 格式化字符串中利用 \u 支持 unicode 的字符
- 支持 16 进制的浮点数的描述
- printf scanf 的格式化串增加了对 long long int 类型的支持
- 浮点数的内部数据描述支持了新标准可以使用 #pragma 编译器指令指定
- 除了已有的 `__line__` `__file__` 以外增加了 `__func__` 得到当前的函数名
- 允许编译器化简非常数的表达式
- 修改了 / % 处理负数时的定义这样可以给出明确的结果例如在C89中-22 / 7 = -3, -22 % 7 = -1也可以-22 / 7= -4, -22 % 7 = 6。 而C99中明确为 -22 / 7 = -3, -22 % 7 = -1只有一种结果。
- 取消了函数返回类型默认为 int 的规定
- 允许在 struct 的最后定义的数组不指定其长度写做 [](flexible array member)。
- const const int i 将被当作 const int i 处理
- 增加和修改了一些标准头文件比如定义 bool <stdbool.h> ,定义一些标准长度的 int 的 <inttypes.h> ,定义复数的 <complex.h> ,定义宽字符的 <wctype.h> ,类似于泛型的数学函数 <tgmath.h> 浮点数相关的 <fenv.h>。 在<stdarg.h> 增加了 va_copy 用于复制 ... 的参数。<time.h> 里增加了 struct tmx ,对 struct tm 做了扩展。
- 输入输出对宽字符以及长整数等做了相应的支持。
> C99 提供了众多的便利,也提高了程序开发的效率,但是一些嵌入式工具链并不是默认开启 C99接下来将会针对不同的工具链介绍如何开启 C99 模式。
## Keil 4
![keil4_enable_c99](https://raw.githubusercontent.com/armink/CmBacktrace/master/docs/zh/images/keil4_enable_c99.jpg)
## Keil 5
![keil5_enable_c99](https://raw.githubusercontent.com/armink/CmBacktrace/master/docs/zh/images/keil5_enable_c99.jpg)
## IAR
IAR 新建完的工程,默认开启 C99 ,如果工程没有开启,请使用下面的方法
![iar_enable_c99](https://raw.githubusercontent.com/armink/CmBacktrace/master/docs/zh/images/iar_enable_c99.png)
## GCC
在编译配置中增加 `-std=c99` 即可

View File

@@ -0,0 +1,59 @@
# 如何使用 addr2line 工具获取函数调用栈详细信息
## addr2line 是什么
addr2line (它是标准的 [GNU Binutils](https://www.gnu.org/software/binutils/) 中的一部分)是一个可以将指令的地址和可执行映像转换成文件名、函数名和源代码行数的工具。
## 如何获得 addr2line
Linux 系统一般会集成这个工具,本文重点介绍 Windows 系统下如何获取该工具。方法很多,我这里仅介绍两种方式
- 第一种:安装 MinGW网上教程很多自行搜索安装后在其安装目录的 `bin` 文件夹里会包含 `addr2line.exe` ,此时只用保证环境变量 `path` 中包含该路径即可;
- 第二种XP 平台除外):在本项目的 `tools` 文件夹中已存放 `addr2line.exe` ,可以将其直接拷贝至 `C:\Windows` 下,或者将 CmBacktrace 仓库的 `tools` 文件夹路径添加至到环境变量 `path` 中,这样都能保证命令行工具能正常使用 `addr2line` 命令。
## addr2line 如何使用
使用 `addr2line --help` 可以看到如下介绍:
```
$addr2line --help
Usage: addr2line [option(s)] [addr(s)]
Convert addresses into line number/file name pairs.
If no addresses are specified on the command line, they will be read from stdin
The options are:
@<file> Read options from <file>
-a --addresses Show addresses
-b --target=<bfdname> Set the binary file format
-e --exe=<executable> Set the input file name (default is a.out)
-i --inlines Unwind inlined functions
-j --section=<name> Read section-relative offsets instead of addresses
-p --pretty-print Make the output easier to read for humans
-s --basenames Strip directory names
-f --functions Show function names
-C --demangle[=style] Demangle function names
-h --help Display this information
-v --version Display the program's version
addr2line: supported targets: pe-x86-64 pei-x86-64 pe-bigobj-x86-64 elf64-x86-64 elf64-l1om elf64-k1om pe-i386 pei-i386 elf32-i386 elf64-little elf64-big elf32-little elf32-big plugin srec symbolsrec verilog tekhex binary ihex
Report bugs to <http://www.sourceware.org/bugzilla/>
```
这里常用的是以下参数
- `-e` :指定可执行映像名称
- `-a` :显示函数地址
- `-f` :显示函数名称
例如命令 `addr2line -e CmBacktrace.out -f 08000a60 08000141 0800313f` 将会显示名称为 `CmBacktrace.out` 的可执行映像,在地址为 `08000a60` `08000141` `0800313f` 对应的函数名称及源代码信息。执行结果如下:
```
$addr2line -e CmBacktrace.out -a -f 08000a60 08000141 0800313f
fault_test_by_div0
D:\Program\STM32\CmBacktrace\demo\non_os\stm32f10x\app\src/fault_test.c:38
main
D:\Program\STM32\CmBacktrace\demo\non_os\stm32f10x\app\src/app.c:20
_call_main
??:?
```
> 更多使用指南,请 [参考官方说明文档](https://sourceware.org/binutils/docs-2.27/binutils/addr2line.html#addr2line) 。

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

View File

@@ -1,33 +1,4 @@
/**
******************************************************************************
* @file Project/STM32F2xx_StdPeriph_Template/stm32f2xx_it.c
* @author MCD Application Team
* @version V1.1.0
* @date 13-April-2012
* @brief Main Interrupt Service Routines.
* This file provides template for all exceptions handler and
* peripherals interrupt service routine.
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2012 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "mk_sys.h"
#include "printk.h"
#include "mm_man.h"
@@ -36,21 +7,7 @@
#include "map.h"
#include "thread_knl.h"
#include "vma.h"
/** @addtogroup Template_Project
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/******************************************************************************/
/* Cortex-M3 Processor Exceptions Handlers */
/******************************************************************************/
#include <cm_backtrace.h>
/**
* @brief This function handles NMI exception.
* @param None
@@ -68,13 +25,25 @@ void NMI_Handler(void)
*/
void HardFault_Handler(void)
{
uint32_t lr_val = cmb_get_lr();
bool_t is_knl = is_run_knl();
addr_t fault_addr = (addr_t)(SCB->MMFAR);
printk("data 0x%x access is error.\n", fault_addr);
bool_t reset_r9 = FALSE;
printk("%s\n", __FUNCTION__);
task_knl_kill(thread_get_current(), is_knl);
cm_backtrace_fault(lr_val, cmb_get_psp() + sizeof(uint32_t) * 9);
reset_r9 = task_knl_kill(thread_get_current(), is_knl);
if (reset_r9)
{
do
{
__asm__ __volatile__(
"mov r9, %0\n\t"
: /* 无输出操作数 */
: "r"(thread_get_current_task()->mm_space.mm_block) // 输入操作数将value的值传递给R0寄存器
: // 告诉编译器R9寄存器将被修改
);
} while (0);
}
}
/**
@@ -84,6 +53,7 @@ void HardFault_Handler(void)
*/
void MemManage_Handler(void)
{
uint32_t lr_val = cmb_get_lr();
bool_t is_knl = is_run_knl();
addr_t fault_addr = (addr_t)(SCB->MMFAR);
addr_t bus_addr = (addr_t)(SCB->BFAR);
@@ -129,6 +99,7 @@ void MemManage_Handler(void)
printk("Floating point lazy stack error.\n");
}
end:
cm_backtrace_fault(lr_val, cmb_get_psp() + sizeof(uint32_t) * 9);
reset_r9 = task_knl_kill(thread_get_current(), is_knl);
if (reset_r9)
{
@@ -151,10 +122,26 @@ end:
*/
void BusFault_Handler(void)
{
uint32_t lr_val = cmb_get_lr();
bool_t is_knl = is_run_knl();
bool_t reset_r9 = FALSE;
printk("%s\n", __FUNCTION__);
task_knl_kill(thread_get_current(), is_knl);
cm_backtrace_fault(lr_val, cmb_get_psp() + sizeof(uint32_t) * 9);
reset_r9 = task_knl_kill(thread_get_current(), is_knl);
if (reset_r9)
{
do
{
__asm__ __volatile__(
"mov r9, %0\n\t"
: /* 无输出操作数 */
: "r"(thread_get_current_task()->mm_space.mm_block) // 输入操作数将value的值传递给R0寄存器
: // 告诉编译器R9寄存器将被修改
);
} while (0);
}
}
/**
@@ -164,6 +151,7 @@ void BusFault_Handler(void)
*/
void UsageFault_Handler(void)
{
uint32_t lr_val = cmb_get_lr();
bool_t is_knl = is_run_knl();
printk("%s\n", __FUNCTION__);
if (SCB->CFSR & (1 << 16))
@@ -190,7 +178,23 @@ void UsageFault_Handler(void)
{
printk("Division by zero error\n");
}
task_knl_kill(thread_get_current(), is_knl);
bool_t reset_r9 = FALSE;
printk("%s\n", __FUNCTION__);
cm_backtrace_fault(lr_val, cmb_get_psp() + sizeof(uint32_t) * 9);
reset_r9 = task_knl_kill(thread_get_current(), is_knl);
if (reset_r9)
{
do
{
__asm__ __volatile__(
"mov r9, %0\n\t"
: /* 无输出操作数 */
: "r"(thread_get_current_task()->mm_space.mm_block) // 输入操作数将value的值传递给R0寄存器
: // 告诉编译器R9寄存器将被修改
);
} while (0);
}
}
/**
@@ -202,25 +206,3 @@ void DebugMon_Handler(void)
{
printk("%s\n", __FUNCTION__);
}
/******************************************************************************/
/* STM32F2xx Peripherals Interrupt Handlers */
/* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */
/* available peripheral interrupt handler's name please refer to the startup */
/* file (startup_stm32f2xx.s). */
/******************************************************************************/
/**
* @brief This function handles PPP interrupt request.
* @param None
* @retval None
*/
/*void PPP_IRQHandler(void)
{
}*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@@ -18,4 +18,5 @@ target_include_directories(
${CMAKE_SOURCE_DIR}/mkrtos_knl/inc/drv
${CMAKE_SOURCE_DIR}/mkrtos_knl/inc/knl
${CMAKE_SOURCE_DIR}/mkrtos_knl/arch/inc
${CMAKE_CURRENT_SOURCE_DIR}/../CmBacktrace/cm_backtrace
)

View File

@@ -17,6 +17,10 @@
#include "mk_sys.h"
#include "mpu.h"
#include "boot_info.h"
#include <cm_backtrace.h>
#define HARDWARE_VERSION "V1.0.0"
#define SOFTWARE_VERSION "V0.1.0"
__ALIGN__(CONFIG_THREAD_BLOCK_SIZE)
static uint8_t thread_knl_stack[CONFIG_THREAD_BLOCK_SIZE] = {0};
void *_estack = thread_knl_stack + CONFIG_THREAD_BLOCK_SIZE;
@@ -112,6 +116,9 @@ void arch_init(void)
SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk;
SCB->SHCSR |= SCB_SHCSR_BUSFAULTENA_Msk;
((uint8_t *)(0xE000E008))[0] |= 0x6;
cm_backtrace_init("CmBacktrace", HARDWARE_VERSION, SOFTWARE_VERSION);
// RCC_ClocksTypeDef RCC_ClocksStatus;
// RCC_GetClocksFreq(&RCC_ClocksStatus);
}

View File

@@ -98,6 +98,11 @@ static inline umword_t arch_get_isr_no(void)
:);
return num;
}
__attribute__( (always_inline) ) static __inline uint32_t cmb_get_lr(void) {
uint32_t result;
__asm volatile ("mov %0, lr" : "=r" (result) );
return (result);
}
static inline void arch_set_knl_sp(umword_t sp)
{
write_sysreg(sp, msp);

View File

@@ -32,6 +32,7 @@ int getc(void);
* @param ...
*/
void printk(const char *fmt, ...);
void printkln(const char *fmt, ...);
void dumpstack(void);

View File

@@ -3,12 +3,14 @@
#include <spinlock.h>
#include <slist.h>
#include <kobject.h>
#include <ref.h>
typedef struct sema
{
kobject_t kobj; //!< 内核对象节点
spinlock_t lock; //!<
int cnt; //!< 计数
ref_counter_t ref;
int max_cnt; //!< 最大计数
kobject_t *hold_th; //!< 那个线程获取到了信号量只有当max_cnt为1时才能有效因为>1时可能有多个消费者
int hold_th_prio; //!< 获取mutex线程的优先级.

View File

@@ -29,8 +29,8 @@ typedef struct task
ref_counter_t ref_cn; //!< ref count.
slist_head_t del_node; //!< delect list node.
void *nofity_point; //!< commint point func.
addr_t nofity_stack; //!< nofity_point_stack.
void *notify_point; //!< commint point func.
addr_t nofity_stack; //!< notify_point_stack.
mutex_t nofity_lock;
sema_t notify_sema; //!< sema
addr_t nofity_msg_buf; //!<
@@ -39,6 +39,8 @@ typedef struct task
int nofity_bitmap_len; //!< max is WORD_BITS
slist_head_t nofity_theads_head;
void *text_addr; //!< text start addr for cmbacktrace.
size_t text_size;
pid_t pid; //!< task pid.
} task_t;

View File

@@ -93,11 +93,12 @@ enum thread_state
enum thread_ipc_state
{
THREAD_NONE = 0,
THREAD_SEND = 1,
THREAD_RECV = 2,
THREAD_WAIT = 4,
THREAD_TIMEOUT = 8,
THREAD_IPC_ABORT = 16,
// THREAD_SEND = 1,
// THREAD_RECV = 2,
// THREAD_WAIT = 4,
THREAD_TIMEOUT = 1,
THREAD_IPC_ABORT = 2,
// THREAD_IPC_KILL = 4,
};
typedef struct msg_buf
@@ -122,7 +123,7 @@ typedef struct thread_fast_ipc_com
thread_fast_ipc_item_t fast_ipc_stack_data[THREAD_FAST_IPC_ITEM_NUM]; //!< 栈数据,用于通信栈备份
stack_t fast_ipc_stack; //!< fast ipc stack
slist_head_t fast_ipc_node; //!< 用于加入到task中去。
thread_t *th;
thread_t *th; //!< 存储当前ipc_com属于那个线程
} thread_fast_ipc_com_t;
#define THREAD_MAGIC 0xdeadead //!< 用于栈溢出检测

View File

@@ -0,0 +1,6 @@
#pragma once
#include <xprintf.h>
#define sprintf xsprintf

View File

@@ -679,7 +679,7 @@ static void futex_unmap(obj_space_t *obj_space, kobject_t *kobj)
{
assert(pos->status == THREAD_SUSPEND);
slist_del(&pos->futex_node);
pos->status == THREAD_IPC_ABORT;
pos->status = THREAD_IPC_ABORT;
thread_ready_remote(pos, TRUE);
}
pos = next;

View File

@@ -194,7 +194,7 @@ static void ipc_release_stage1(kobject_t *kobj)
slist_foreach(pos, &ipc->wait_bind, node)
{
assert(pos->th->status == THREAD_SUSPEND);
pos->th->ipc_status == THREAD_IPC_ABORT;
pos->th->ipc_status = THREAD_IPC_ABORT;
thread_ready_remote(pos->th, TRUE);
}
if (ipc->svr_tk)

View File

@@ -66,3 +66,21 @@ void printk(const char *fmt, ...)
print_raw(print_cache);
spinlock_set(&lock, state);
}
void printkln(const char *fmt, ...)
{
va_list args;
umword_t state = 0;
thread_t *cut_th = thread_get_current();
state = spinlock_lock(&lock);
xsprintf(print_cache, "[%8d]%s:",
pre_cpu_is_init() ? sys_tick_cnt_get() : 0,
kobject_get_name(&cut_th->kobj));
print_raw(print_cache);
va_start(args, fmt);
xvsprintf(print_cache, fmt, args);
va_end(args);
print_raw(print_cache);
print_raw("\r\n");
spinlock_set(&lock, state);
}

View File

@@ -47,6 +47,7 @@ void sema_up(sema_t *obj)
umword_t status;
thread_t *th = thread_get_current();
ref_counter_inc(&obj->ref);
again:
status = spinlock_lock(&obj->lock);
if (slist_is_empty(&obj->suspend_head))
@@ -67,10 +68,8 @@ again:
if (thread_get_status(first_wait->thread) == THREAD_SUSPEND)
{
slist_del(first_wait_node);
if (ref_counter_dec_and_release(&first_wait->thread->ref, &first_wait->thread->kobj) != 1)
{
thread_sleep_del_and_wakeup(first_wait->thread);
}
ref_counter_dec_and_release(&first_wait->thread->ref, &first_wait->thread->kobj);
if (obj->cnt < obj->max_cnt)
{
obj->cnt++;
@@ -85,8 +84,10 @@ again:
else
{
// 超时退出,但是切出来的时候没有切到休眠线程,切到了这里。
spinlock_set(&obj->lock, status);
goto again;
if (obj->cnt < obj->max_cnt)
{
obj->cnt++;
}
}
}
spinlock_set(&obj->lock, status);
@@ -94,6 +95,7 @@ again:
{
preemption();
}
ref_counter_dec_and_release(&obj->ref, &obj->kobj);
}
umword_t sema_down(sema_t *obj, umword_t ticks)
{
@@ -103,6 +105,7 @@ umword_t sema_down(sema_t *obj, umword_t ticks)
umword_t remain_sleep = 0;
sema_wait_item_t wait_item;
ref_counter_inc(&obj->ref);
again:
status = spinlock_lock(&obj->lock);
if (obj->cnt == 0)
@@ -118,7 +121,7 @@ again:
thread_set_prio(((thread_t*)(obj->hold_th)), thread_get_prio(th));
}
}
remain_sleep = thread_sleep(ticks); //注意这里可能不是up环保型
remain_sleep = thread_sleep(ticks);
if (remain_sleep == 0 && ticks != 0)
{
// 超时退出的,直接从列表中删除
@@ -147,6 +150,7 @@ again:
}
}
spinlock_set(&obj->lock, status);
ref_counter_dec_and_release(&obj->ref, &obj->kobj);
return remain_sleep;
}
@@ -206,25 +210,31 @@ static void sema_release_stage1(kobject_t *kobj)
{
sema_t *obj = container_of(kobj, sema_t, kobj);
kobject_invalidate(kobj);
#if 1
umword_t status;
status = spinlock_lock(&obj->lock);
sema_wait_item_t *wait_item;
slist_foreach(wait_item, &obj->suspend_head, node)
slist_foreach_not_next(wait_item, &obj->suspend_head, node)
{
slist_head_t *first_wait_node;
sema_wait_item_t *first_wait;
sema_wait_item_t *next = slist_next_entry(wait_item, &obj->suspend_head, node);
first_wait_node = slist_first(&obj->suspend_head);
first_wait = container_of(first_wait_node, sema_wait_item_t, node);
slist_del(first_wait_node);
if (ref_counter_dec_and_release(&first_wait->thread->ref, &first_wait->thread->kobj) != 1)
{
thread_ready_remote(first_wait->thread, FALSE);
}
slist_del(&wait_item->node);
thread_sleep_del_and_wakeup(wait_item->thread);
if (obj->cnt < obj->max_cnt)
{
obj->cnt++;
}
wait_item = next;
}
spinlock_set(&obj->lock, status);
#endif
}
static bool_t sema_put(kobject_t *kobj)
{
sema_t *th = container_of(kobj, sema_t, kobj);
return ref_counter_dec(&th->ref) == 1;
}
static void sema_release_stage2(kobject_t *kobj)
{
@@ -256,11 +266,14 @@ void sema_init(sema_t *obj, int cnt, int max)
kobject_init(&obj->kobj, SEMA_TYPE);
spinlock_init(&obj->lock);
slist_init(&obj->suspend_head);
ref_counter_init(&obj->ref);
ref_counter_inc(&obj->ref);
obj->max_cnt = max <= 0 ? 1 : max;
obj->kobj.invoke_func = sema_syscall;
// obj->kobj.put_func = thread_put;
obj->kobj.stage_1_func = sema_release_stage1;
obj->kobj.stage_2_func = sema_release_stage2;
obj->kobj.put_func = sema_put;
printk("sema init cnt:%d max:%d.\n", cnt, max);
}

View File

@@ -93,11 +93,11 @@ thread_wait_entry_t *thread_sleep_del(thread_t *th)
if (pos->th == th)
{
slist_del(&pos->node);
break;
return pos;
}
pos = next;
}
return pos;
return NULL;
}
void thread_sleep_del_and_wakeup(thread_t *th)
{

View File

@@ -309,6 +309,8 @@ static void task_syscall_func(kobject_t *kobj, syscall_prot_t sys_p, msg_tag_t i
}
int ret = task_alloc_base_ram(tag_task, tag_task->lim, f->regs[1], f->regs[2]);
tag = msg_tag_init4(0, 0, 0, ret);
tag_task->text_addr = (void *)(f->regs[3]);
tag_task->text_size = (size_t)(f->regs[4]);
f->regs[1] = (umword_t)(tag_task->mm_space.mm_block);
spinlock_set(&tag_task->kobj.lock, status);
}
@@ -426,7 +428,7 @@ static void task_syscall_func(kobject_t *kobj, syscall_prot_t sys_p, msg_tag_t i
}
int stack_size = f->regs[2];
tag_task->nofity_point = (void *)(f->regs[0]);
tag_task->notify_point = (void *)(f->regs[0]);
tag_task->nofity_stack = (addr_t)(f->regs[1] + stack_size);
tag_task->nofity_bitmap = (void *)(f->regs[3]);
tag_task->nofity_bitmap_len = (f->regs[4]);

View File

@@ -158,12 +158,33 @@ static bool_t thread_put(kobject_t *kobj)
}
static void thread_release_stage1_impl(thread_t *th)
{
// int is_wait_suspend = 0;
// while(stack_len(&th->com->fast_ipc_stack)!=0)
// {
// thread_sleep(1);
// is_wait_suspend = 1;
// }
// if (is_wait_suspend)
// {
// while (th->status != THREAD_SUSPEND) {
// thread_sleep(1);
// }
// }
if (stack_len(&th->com->fast_ipc_stack)==0){
//处于ipc通信中不能直接删除否者会立刻中断ipc中的执行
if (th->status == THREAD_READY)
{
thread_suspend(th);
}
th->ipc_status = THREAD_IPC_ABORT;
thread_sleep_del(th); //!< 从休眠中删除
thread_unbind(th);
th->ipc_status = THREAD_IPC_ABORT;
} else {
th->ipc_status = THREAD_IPC_ABORT;
}
#if 0
thread_wait_entry_t *pos;
@@ -209,7 +230,7 @@ static void thread_release_stage1_impl(thread_t *th)
pos2 = next;
}
#endif
thread_unbind(th);
}
#if IS_ENABLED(CONFIG_SMP)
static int thread_remote_release_stage1_handler(ipi_msg_t *msg, bool_t *is_sched)
@@ -1197,8 +1218,12 @@ msg_tag_t thread_fast_ipc_call(task_t *to_task, entry_frame_t *f, umword_t user_
// 3.多线程访问时,服务端提供一个小的用户线程栈,然后内核到用户部分为临界区域,在服务端重新分配用户栈用,使用新的用户栈。
// 4.fastipc嵌套访问会有问题内核必须要提供一个软件上的调用栈。
// 在嵌套调用时,如果在其它进程中挂掉,如果是当前线程则需要还原
// 回收ipc线程注意事项
// 1.ipc的线程在与其它进程通信时在其它进程中死亡这个最常见
// 2.ipc的线程在其它进程通信时其它进程死亡需要吧其它进程的ipc线程给还原回去
// 3.ipc的线程在与其他的进程通信时ipc线程的原进程死亡需要推迟ipc线程的删除到ipc操作完成否者可能发生未知的错误
if (to_task->nofity_point == NULL)
if (to_task->notify_point == NULL)
{
printk("task:0x%x, notify point is not set.\n", to_task);
return msg_tag_init4(0, 0, 0, -EIO);
@@ -1208,7 +1233,6 @@ msg_tag_t thread_fast_ipc_call(task_t *to_task, entry_frame_t *f, umword_t user_
umword_t cpu_status = cpulock_lock();
assert(cur_th->magic == THREAD_MAGIC);
// to_task = thread_get_bind_task(to_th);FIXME:
ref_counter_inc((&to_task->ref_cn));
//!< 执行目标线程时用的是当前线程的资源,这里还需要备份当前线程的上下文。
ret = thread_fast_ipc_save(cur_th, to_task, (void *)(to_task->nofity_stack - 4 * 8 /*FIXME:改成宏*/)); //!< 备份栈和usp
@@ -1227,7 +1251,7 @@ msg_tag_t thread_fast_ipc_call(task_t *to_task, entry_frame_t *f, umword_t user_
if (thread_is_knl(cur_th))
{
// 如果是内核线程则全部重新设置
thread_set_user_pf_noset_knl_sp(cur_th, to_task->nofity_point,
thread_set_user_pf_noset_knl_sp(cur_th, to_task->notify_point,
(void *)to_task->nofity_stack, (void *)to_task->mm_space.mm_block);
usr_stask_point->rg0[0] = in_tag.raw;
usr_stask_point->rg0[1] = user_id;
@@ -1241,7 +1265,7 @@ msg_tag_t thread_fast_ipc_call(task_t *to_task, entry_frame_t *f, umword_t user_
usr_stask_point->r12 = 0x12121212;
usr_stask_point->xpsr = 0x01000000L;
usr_stask_point->lr = (umword_t)NULL; //!< 线程退出时调用的函数
usr_stask_point->pc = (umword_t)(to_task->nofity_point) | 0x1;
usr_stask_point->pc = (umword_t)(to_task->notify_point) | 0x1;
//! 获得内核栈栈顶
pf_t *cur_pf = ((pf_t *)((char *)cur_th + CONFIG_THREAD_BLOCK_SIZE + 8)) - 1;
@@ -1256,6 +1280,7 @@ msg_tag_t thread_fast_ipc_call(task_t *to_task, entry_frame_t *f, umword_t user_
f->regs[3] = f->regs[3];
}
// 切换mpu
ref_counter_inc(&cur_th->ref);
mpu_switch_to_task(to_task);
cpulock_set(cpu_status);
if (thread_is_knl(cur_th))
@@ -1269,6 +1294,7 @@ msg_tag_t thread_fast_ipc_call(task_t *to_task, entry_frame_t *f, umword_t user_
else
{
ref_counter_dec_and_release(&to_task->ref_cn, &to_task->kobj);
cpulock_set(cpu_status);
mutex_unlock(&to_task->nofity_lock);
sema_up(&to_task->notify_sema);
}
@@ -1276,10 +1302,10 @@ msg_tag_t thread_fast_ipc_call(task_t *to_task, entry_frame_t *f, umword_t user_
else
{
ref_counter_dec_and_release(&to_task->ref_cn, &to_task->kobj);
cpulock_set(cpu_status);
mutex_unlock(&to_task->nofity_lock);
sema_up(&to_task->notify_sema);
}
cpulock_set(cpu_status);
return msg_tag_init4(0, 0, 0, ret);
}
@@ -1299,7 +1325,8 @@ msg_tag_t thread_fast_ipc_replay(entry_frame_t *f)
if (ret < 0)
{
mutex_unlock(&old_task->nofity_lock);
return msg_tag_init4(0, 0, 0, ret);
in_tag = msg_tag_init4(0, 0, 0, ret);
goto end;
}
umword_t cpu_status = cpulock_lock();
@@ -1326,9 +1353,6 @@ msg_tag_t thread_fast_ipc_replay(entry_frame_t *f)
if (thread_is_knl(cur_th))
{
//! 吧r4-r11留出来
// memcpy((char *)cur_th->sp.knl_sp - 4 * 8 /*FIXME:*/, (char *)cur_th->sp.knl_sp, 4 * 8);
// memset(cur_th->sp.knl_sp, 0, 4 * 8);
// cur_th->sp.knl_sp = (char *)cur_th->sp.knl_sp - 4 * 8;
cur_th->sp.user_sp = 0x0;
cur_th->sp.sp_type = 0xfffffff9;
scheduler_get_current()->sched_reset = 3;
@@ -1352,6 +1376,17 @@ msg_tag_t thread_fast_ipc_replay(entry_frame_t *f)
arch_to_sche();
preemption();
}
end:
if (thread_get_ipc_state(cur_th) == THREAD_IPC_ABORT && stack_len(&cur_th->com->fast_ipc_stack)==0)
{
/*FIXME:这里面没有释放线程的内存*/
cpu_status = cpulock_lock();
thread_unbind(cur_th);
thread_suspend(cur_th);
cpulock_set(cpu_status);
} else {
ref_counter_dec_and_release(&cur_th->ref, &cur_th->kobj);
}
return in_tag;
}
/**

View File

@@ -1,6 +1,10 @@
cmake_minimum_required(VERSION 3.13)
file(GLOB deps *.c libfdt/lib/contrib/*.c)
file(GLOB
deps
*.c
libfdt/lib/contrib/*.c
)
add_library(lib STATIC ${deps})
target_include_directories(
@@ -14,5 +18,6 @@ target_include_directories(
${CMAKE_SOURCE_DIR}/mkrtos_knl/inc/knl
${CMAKE_SOURCE_DIR}/mkrtos_knl/inc/drv
${CMAKE_SOURCE_DIR}/mkrtos_knl/arch/inc
)

View File

@@ -46,4 +46,13 @@ int shell_float_test(int argc, char *argv[])
return 0;
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), ftest, shell_float_test, ftest command);
int shell_div0(int argc, char *argv[])
{
int a=1,b=0;
*((char *)(0)) = 0;
printf("%d\n", a/b);
return 0;
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), div0, shell_div0, div0 command);
#endif

View File

@@ -37,9 +37,9 @@
#define MEM_ALIGNMENT 4 // 使用4字节对齐模式
#define MEM_SIZE (8 * 1024) // 内存堆heap大小
#define MEMP_NUM_PBUF 16 // MEMP_NUM_PBUF:memp结构的pbuf数量,如果应用从ROM或者静态存储区发送大量数据时,这个值应该设置大一点
#define MEMP_NUM_UDP_PCB 4 // MEMP_NUM_UDP_PCB:UDP协议控制块(PCB)数量.每个活动的UDP"连接"需要一个PCB.
#define MEMP_NUM_TCP_PCB 4 // MEMP_NUM_TCP_PCB:同时建立激活的TCP数量
#define MEMP_NUM_TCP_PCB_LISTEN 4 // MEMP_NUM_TCP_PCB_LISTEN:能够监听的TCP连接数量
#define MEMP_NUM_UDP_PCB 16 // MEMP_NUM_UDP_PCB:UDP协议控制块(PCB)数量.每个活动的UDP"连接"需要一个PCB.
#define MEMP_NUM_TCP_PCB 16 // MEMP_NUM_TCP_PCB:同时建立激活的TCP数量
#define MEMP_NUM_TCP_PCB_LISTEN 16 // MEMP_NUM_TCP_PCB_LISTEN:能够监听的TCP连接数量
#define MEMP_NUM_TCP_SEG 64 // MEMP_NUM_TCP_SEG:最多同时在队列中的TCP段数量
#define MEMP_NUM_SYS_TIMEOUT 4 // MEMP_NUM_SYS_TIMEOUT:能够同时激活的timeout个数
#define LWIP_NETCONN_SEM_PER_THREAD 0

View File

@@ -484,6 +484,11 @@ u32_t sys_arch_mbox_fetch(struct sys_mbox **mb, void **msg, u32_t timeout)
must be prepared to timeout. */
if (timeout != 0)
{
if (mbox->not_empty == NULL)
{
return SYS_ARCH_TIMEOUT;
}
time_needed = sys_arch_sem_wait(&mbox->not_empty, timeout);
if (time_needed == SYS_ARCH_TIMEOUT)
@@ -493,9 +498,17 @@ u32_t sys_arch_mbox_fetch(struct sys_mbox **mb, void **msg, u32_t timeout)
}
else
{
if (mbox->not_empty == NULL)
{
return SYS_ARCH_TIMEOUT;
}
sys_arch_sem_wait(&mbox->not_empty, 0);
}
if (mbox->mutex == NULL)
{
return SYS_ARCH_TIMEOUT;
}
sys_arch_sem_wait(&mbox->mutex, 0);
}

View File

@@ -62,7 +62,7 @@ typedef struct lwip_mbox sys_mbox_t;
#define SYS_MBOX_NULL NULL
#define sys_mbox_valid_val(mbox) (((mbox).sem != NULL) && ((mbox).sem != (void*)-1))
#define sys_mbox_valid(mbox) ((mbox != NULL) && sys_mbox_valid_val(*(mbox)))
#define sys_mbox_set_invalid(mbox) ((mbox)->sem = NULL)
#define = NULL)
/* DWORD (thread id) is used for sys_thread_t but we won't include windows.h */
typedef u32_t sys_thread_t;

View File

@@ -13,7 +13,8 @@ msg_tag_t task_get_pid(obj_handler_t dst_task, umword_t *data);
msg_tag_t task_obj_valid(obj_handler_t dst_task, obj_handler_t obj_inx, int *obj_type);
msg_tag_t task_map(obj_handler_t dst_task, obj_handler_t src_obj, obj_handler_t dst_obj, uint8_t attrs);
msg_tag_t task_unmap(obj_handler_t task_han, vpage_t vpage);
msg_tag_t task_alloc_ram_base(obj_handler_t task_han, umword_t size, addr_t *alloc_addr, int mem_block);
msg_tag_t task_alloc_ram_base(obj_handler_t task_han, umword_t size, addr_t *alloc_addr,
int mem_block, addr_t text_addr, size_t text_size);
msg_tag_t task_copy_data(obj_handler_t task_obj, void *st_addr, umword_t size);
msg_tag_t task_copy_data_to(obj_handler_t task_obj, obj_handler_t dst_task_obj, void *st_addr, void *dst_addr, umword_t size);
msg_tag_t task_set_com_point(obj_handler_t task_obj, void *com_point_func,

View File

@@ -144,7 +144,7 @@ msg_tag_t task_unmap(obj_handler_t task_han, vpage_t vpage)
return tag;
}
MK_SYSCALL
msg_tag_t task_alloc_ram_base(obj_handler_t task_han, umword_t size, addr_t *alloc_addr,int mem_block)
msg_tag_t task_alloc_ram_base(obj_handler_t task_han, umword_t size, addr_t *alloc_addr,int mem_block, addr_t text_addr, size_t text_size)
{
register volatile umword_t r0 asm(ARCH_REG_0);
register volatile umword_t r1 asm(ARCH_REG_1);
@@ -153,8 +153,8 @@ msg_tag_t task_alloc_ram_base(obj_handler_t task_han, umword_t size, addr_t *all
0,
size,
mem_block,
0,
0,
text_addr,
text_size,
0);
asm __volatile__(""
:

View File

@@ -3,7 +3,7 @@
#include "u_rpc_svr.h"
#include "u_slist.h"
#include "blk_drv_types.h"
int blk_drv_cli_write(obj_handler_t dm9000_obj, obj_handler_t shm_obj, int len, int inx);
int blk_drv_cli_read(obj_handler_t dm9000_obj, obj_handler_t shm_obj, int len, int inx);
int blk_drv_cli_write(obj_handler_t svr_boj, obj_handler_t shm_obj, int len, int inx);
int blk_drv_cli_read(obj_handler_t svr_boj, obj_handler_t shm_obj, int len, int inx);
int blk_drv_cli_map(obj_handler_t svr_boj, obj_handler_t *sem_obj);
int blk_drv_cli_info(obj_handler_t obj, blk_drv_info_t *info);
int blk_drv_cli_info(obj_handler_t svr_boj, blk_drv_info_t *info);

View File

@@ -17,7 +17,7 @@
typedef struct watch_entry
{
pid_t watch_pid;//!<被监控的pid
pid_t src_pid; //!<发起监控的pid
pid_t src_pid; //!<观察者
obj_handler_t sig_hd; //!<用于通信用的ipc对象
#if 0
obj_handler_t notify_sem_hd;//!<通知用的信号量

View File

@@ -130,21 +130,16 @@ int app_load(const char *name, uenv_t *cur_env, pid_t *pid,
{
return -ENOENT;
}
#if 0
for (int i = 0; i < arg_cn; i++)
{
printf("argv[%d]:%s\n", i, argv[i]);
}
#endif
int type;
umword_t addr;
int ret = 0;
unsigned long size;
#if IS_ENABLED(CONFIG_CPIO_SUPPORT)
ret = cpio_find_file((umword_t)sys_info.bootfs_start_addr, (umword_t)(-1), name, NULL, &type, &addr);
#else
type = 0;
addr = (umword_t)appfs_tiny_find_file_addr_by_name(appfs_tiny_get_form_addr((void *)sys_info.bootfs_start_addr), name, NULL);
addr = (umword_t)appfs_tiny_find_file_addr_by_name(appfs_tiny_get_form_addr((void *)sys_info.bootfs_start_addr), name, &size);
if (addr == 0)
{
ret = -ENOENT;
@@ -205,7 +200,7 @@ int app_load(const char *name, uenv_t *cur_env, pid_t *pid,
goto end_del_obj;
}
tag = task_alloc_ram_base(hd_task, app ? app->i.ram_size : 100 * 1024 /*TODO:*/,
&ram_base, mem_block);
&ram_base, mem_block, (addr_t)addr, size);
if (msg_tag_get_prot(tag) < 0)
{
goto end_del_obj;

View File

@@ -18,6 +18,7 @@
#include <rpc_prot.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include "u_fast_ipc.h"
#include "u_hd_man.h"
#include "u_rpc_svr.h"
@@ -71,6 +72,7 @@ static int kill(int flags, int pid)
{
int ret = -EINVAL;
printf("kill pid:%d, flags:0x%x\n", pid ,flags);
if (wait_pid == pid || wait_pid == -1)
{
u_sema_up(sema_wait_hd);

View File

@@ -11,16 +11,17 @@
#include <ff.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "u_hd_man.h"
#include <u_fast_ipc.h>
#include <getopt.h>
#define STACK_COM_ITME_SIZE (2048)
ATTR_ALIGN(8)
uint8_t stack_coms[STACK_COM_ITME_SIZE];
uint8_t msg_buf_coms[MSG_BUG_LEN];
static uint8_t stack_coms[STACK_COM_ITME_SIZE];
static uint8_t msg_buf_coms[MSG_BUG_LEN];
static obj_handler_t com_th_obj;
void fast_ipc_init(void)
static void fast_ipc_init(void)
{
com_th_obj = handler_alloc();
assert(com_th_obj != HANDLER_INVALID);
@@ -30,36 +31,70 @@ void fast_ipc_init(void)
static FATFS fs;
static MKFS_PARM defopt = {FM_ANY, 0, 0, 0};
int main(int args, char *argv[])
extern int disk_set_dev_path(int pdrv, const char *dev);
int main(int argc, char *argv[])
{
obj_handler_t hd;
int ret;
char *dev_path = NULL;
char *mount_path = NULL;
int opt;
fast_ipc_init();
while ((opt = getopt(argc, argv, "m:d:")) != -1)
{
switch (opt)
{
case 'm':
mount_path = optarg;
break;
case 'd':
dev_path = optarg;
break;
}
}
if (mount_path == NULL || dev_path == NULL)
{
printf("example:fatfs -m /mnt -d /dev/ram_block\n");
return -1;
}
if (disk_set_dev_path(0, dev_path) < 0)
{
printf("dev open failed.\n");
return -1;
}
ret = rpc_meta_init_def(TASK_THIS, &hd);
assert(ret >= 0);
fs_svr_init();
ns_register("/mnt", hd, 0);
FRESULT res = f_mount(&fs, "0:/", 1);
if (res != FR_OK) {
if (res != FR_OK)
{
assert(sizeof(fs.win) >= FF_MAX_SS);
res = f_mkfs("0:/", &defopt, (void *)(fs.win), FF_MAX_SS); // 第三个参数可以设置成NULL默认使用heap memory
if (res != FR_OK) {
cons_write_str("f_mkfs err.\n");
if (res != FR_OK)
{
printf("f_mkfs err.\n");
exit(-1);
} else {
}
else
{
res = f_mount(&fs, "0:/", 1);
if (res != FR_OK) {
cons_write_str("f_mount err.\n");
if (res != FR_OK)
{
printf("f_mount err.\n");
exit(-1);
}
}
}
cons_write_str("fatfs mount success\n");
ns_register(mount_path, hd, 0);
printf("fatfs mount success\n");
while(1) {
while (1)
{
u_sleep_ms(U_SLEEP_ALWAYS);
}
return 0;

View File

@@ -0,0 +1,156 @@
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module SKELETON for FatFs (C)ChaN, 2019 */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be */
/* attached to the FatFs via a glue function rather than modifying it. */
/* This is an example of glue functions to attach various exsisting */
/* storage control modules to the FatFs module with a defined API. */
/*-----------------------------------------------------------------------*/
#include "ff.h" /* Obtains integer types */
#include "diskio.h" /* Declarations of disk functions */
#include "ram_disk.h"
#include <stdio.h>
/* Definitions of physical drive number for each drive */
#define DEV_RAM 0 /* Example: Map Ramdisk to physical drive 0 */
#define DEV_MMC 1 /* Example: Map MMC/SD card to physical drive 1 */
#define DEV_USB 2 /* Example: Map USB MSD to physical drive 2 */
/*-----------------------------------------------------------------------*/
/* Get Drive Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status(
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat;
int result;
switch (pdrv)
{
case DEV_RAM:
result = 0;
// translate the reslut code here
stat = RES_OK;
return stat;
}
return STA_NOINIT;
}
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize(
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat;
int result;
switch (pdrv)
{
case DEV_RAM:
result = 0;
stat = RES_OK;
// translate the reslut code here
return stat;
}
return STA_NOINIT;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_read(
BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */
LBA_t sector, /* Start sector in LBA */
UINT count /* Number of sectors to read */
)
{
DRESULT res;
switch (pdrv)
{
case DEV_RAM:
// translate the reslut code here
if (ram_disk_read(buff, sector, count) < 0) {
return RES_ERROR;
}
return 0;
}
return RES_PARERR;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
#if FF_FS_READONLY == 0
DRESULT disk_write(
BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */
LBA_t sector, /* Start sector in LBA */
UINT count /* Number of sectors to write */
)
{
int result;
switch (pdrv)
{
case DEV_RAM:
// translate the arguments here
if (ram_disk_write((uint8_t *)buff, sector, count) < 0) {
return RES_ERROR;
}
return 0;
}
return RES_PARERR;
}
#endif
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl(
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res;
int result;
switch (pdrv)
{
case DEV_RAM:
switch (cmd)
{ // fatfs内核使用cmd调用
case GET_SECTOR_COUNT: // sector count, 传入sect_cnt
*(DWORD *)buff = ram_disk_sector_nr();
return RES_OK;
case GET_SECTOR_SIZE: // sector size, 传入block size(SD),单位bytes
*(DWORD *)buff = 512;
return RES_OK;
case GET_BLOCK_SIZE: // block size, 由上文可得对于SD2.0卡最大8192最小 1
*(DWORD *)buff = 1; // 单位为 sector(FatFs)
return RES_OK;
case CTRL_SYNC: // 同步命令貌似FatFs内核用来判断写操作是否完成
return RES_OK;
}
default:
printf("No device %d.\n", pdrv);
break;
}
return RES_PARERR; // 默认返回参数错误
}

View File

@@ -0,0 +1,77 @@
/*-----------------------------------------------------------------------/
/ Low level disk interface modlue include file (C)ChaN, 2019 /
/-----------------------------------------------------------------------*/
#ifndef _DISKIO_DEFINED
#define _DISKIO_DEFINED
#ifdef __cplusplus
extern "C" {
#endif
/* Status of Disk Functions */
typedef BYTE DSTATUS;
/* Results of Disk Functions */
typedef enum {
RES_OK = 0, /* 0: Successful */
RES_ERROR, /* 1: R/W Error */
RES_WRPRT, /* 2: Write Protected */
RES_NOTRDY, /* 3: Not Ready */
RES_PARERR /* 4: Invalid Parameter */
} DRESULT;
/*---------------------------------------*/
/* Prototypes for disk control functions */
DSTATUS disk_initialize (BYTE pdrv);
DSTATUS disk_status (BYTE pdrv);
DRESULT disk_read (BYTE pdrv, BYTE* buff, LBA_t sector, UINT count);
DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count);
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
/* Disk Status Bits (DSTATUS) */
#define STA_NOINIT 0x01 /* Drive not initialized */
#define STA_NODISK 0x02 /* No medium in the drive */
#define STA_PROTECT 0x04 /* Write protected */
/* Command code for disk_ioctrl fucntion */
/* Generic command (Used by FatFs) */
#define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */
#define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */
/* Generic command (Not used by FatFs) */
#define CTRL_POWER 5 /* Get/Set power status */
#define CTRL_LOCK 6 /* Lock/Unlock media removal */
#define CTRL_EJECT 7 /* Eject media */
#define CTRL_FORMAT 8 /* Create physical format on the media */
/* MMC/SDC specific ioctl command */
#define MMC_GET_TYPE 10 /* Get card type */
#define MMC_GET_CSD 11 /* Get CSD */
#define MMC_GET_CID 12 /* Get CID */
#define MMC_GET_OCR 13 /* Get OCR */
#define MMC_GET_SDSTAT 14 /* Get SD status */
#define ISDIO_READ 55 /* Read data form SD iSDIO register */
#define ISDIO_WRITE 56 /* Write data to SD iSDIO register */
#define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */
/* ATA/CF specific ioctl command */
#define ATA_GET_REV 20 /* Get F/W revision */
#define ATA_GET_MODEL 21 /* Get model name */
#define ATA_GET_SN 22 /* Get serial number */
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -11,11 +11,54 @@
#include "diskio.h" /* Declarations of disk functions */
#include "ram_disk.h"
#include <stdio.h>
#include "blk_drv_cli.h"
#include "ns_cli.h"
#include "u_factory.h"
#include "u_vmam.h"
#include "u_hd_man.h"
#include "u_sleep.h"
#include <string.h>
#include "u_share_mem.h"
/* Definitions of physical drive number for each drive */
#define DEV_RAM 0 /* Example: Map Ramdisk to physical drive 0 */
#define DEV_MMC 1 /* Example: Map MMC/SD card to physical drive 1 */
#define DEV_USB 2 /* Example: Map USB MSD to physical drive 2 */
static obj_handler_t dev_hd;
static obj_handler_t shm_hd;
static addr_t dev_shm_mem;
static addr_t dev_shm_size;
static blk_drv_info_t blk_info;
int disk_set_dev_path(int pdrv, const char *dev)
{
int ret;
switch (DEV_RAM)
{
case DEV_RAM:
{
int try_cn = 0;
again:
ret = ns_query_svr(dev, &dev_hd, 1);
if (ret < 0)
{
try_cn++;
if (try_cn > 10)
{
return ret;
}
u_sleep_ms(20);
goto again;
}
ret = blk_drv_cli_info(dev_hd, &blk_info);
if (ret < 0)
{
return ret;
}
}
break;
default:
return -1;
}
return 0;
}
/*-----------------------------------------------------------------------*/
/* Get Drive Status */
/*-----------------------------------------------------------------------*/
@@ -53,11 +96,35 @@ DSTATUS disk_initialize(
switch (pdrv)
{
case DEV_RAM:
result = 0;
{
msg_tag_t tag;
shm_hd = handler_alloc();
if (shm_hd == HANDLER_INVALID)
{
printf("handler alloc failed.\n");
return RES_ERROR;
}
tag = facotry_create_share_mem(FACTORY_PROT, vpage_create_raw3(KOBJ_ALL_RIGHTS, 0, shm_hd),
SHARE_MEM_CNT_BUDDY_CNT, blk_info.blk_size);
if (msg_tag_get_val(tag) < 0)
{
handler_free(shm_hd);
printf("share mem create failed.\n");
return RES_ERROR;
}
tag = share_mem_map(shm_hd, vma_addr_create(VPAGE_PROT_RW, VMA_ADDR_RESV, 0), &dev_shm_mem, &dev_shm_size);
if (msg_tag_get_val(tag) < 0)
{
handler_del_umap(shm_hd);
printf("share mem map failed.\n");
return RES_ERROR;
}
stat = RES_OK;
// translate the reslut code here
return stat;
}
}
return STA_NOINIT;
}
@@ -78,9 +145,14 @@ DRESULT disk_read(
{
case DEV_RAM:
// translate the reslut code here
if (ram_disk_read(buff, sector, count) < 0) {
for (umword_t i = sector; i < sector + count; i++)
{
if (blk_drv_cli_read(dev_hd, shm_hd, blk_info.blk_size, i) < 0)
{
return RES_ERROR;
}
memcpy(buff + (i - sector) * blk_info.blk_size, (void *)dev_shm_mem, blk_info.blk_size);
}
return 0;
}
@@ -106,10 +178,15 @@ DRESULT disk_write(
{
case DEV_RAM:
// translate the arguments here
for (umword_t i = sector; i < sector + count; i++)
{
memcpy((void *)dev_shm_mem, buff + (i - sector) * blk_info.blk_size, blk_info.blk_size);
if (ram_disk_write((uint8_t *)buff, sector, count) < 0) {
if (blk_drv_cli_write(dev_hd, shm_hd, blk_info.blk_size, i) < 0)
{
return RES_ERROR;
}
}
return 0;
}
@@ -121,7 +198,6 @@ DRESULT disk_write(
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl(
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
@@ -134,13 +210,14 @@ DRESULT disk_ioctl(
switch (pdrv)
{
case DEV_RAM:
{
switch (cmd)
{ // fatfs内核使用cmd调用
case GET_SECTOR_COUNT: // sector count, 传入sect_cnt
*(DWORD *)buff = ram_disk_sector_nr();
*(DWORD *)buff = blk_info.blk_nr;
return RES_OK;
case GET_SECTOR_SIZE: // sector size, 传入block size(SD),单位bytes
*(DWORD *)buff = 512;
*(DWORD *)buff = blk_info.blk_size;
return RES_OK;
case GET_BLOCK_SIZE: // block size, 由上文可得对于SD2.0卡最大8192最小 1
*(DWORD *)buff = 1; // 单位为 sector(FatFs)
@@ -148,6 +225,7 @@ DRESULT disk_ioctl(
case CTRL_SYNC: // 同步命令貌似FatFs内核用来判断写操作是否完成
return RES_OK;
}
}
default:
printf("No device %d.\n", pdrv);
break;

View File

@@ -50,8 +50,6 @@ set_target_properties(init.elf PROPERTIES LINK_FLAGS
add_custom_target(
init_dump ALL
COMMAND
${CMAKE_OBJDUMP} -s -S init.elf > ${CMAKE_SOURCE_DIR}/build/output/init.S
COMMAND
${CMAKE_OBJCOPY} -O binary -S init.elf init.bin
COMMAND
${CMAKE_SIZE} init.elf

View File

@@ -1,14 +1,14 @@
#一次读取一行,每行代表启动的应用程序
block /dev/block
ram_block -p /dev/rblk -s 512 -n 2048
appfs -m /bin -d /dev/block
# cpiofs -m /bin
# fatfs
fatfs -m /mnt -d /dev/rblk
# pin
# i2c
# pca9555
# display
# eth
# snd
# net
a_net
# nes
sh

View File

@@ -67,14 +67,14 @@ bool_t pm_pid_is_task(pid_t pid)
* @param pid
* @return watch_entry_t*
*/
watch_entry_t *pm_watch_lookup(pm_t *pm, pid_t pid)
watch_entry_t *pm_watch_lookup(pm_t *pm, pid_t src_pid, pid_t listen_pid)
{
watch_entry_t *pos;
slist_foreach_not_next(pos, &pm->watch_head, node)
{
watch_entry_t *next = slist_next_entry(pos, &pm->watch_head, node);
if (pos->src_pid == pid)
if (pos->src_pid == src_pid && pos->watch_pid == listen_pid)
{
return pos;
}
@@ -105,7 +105,7 @@ void pm_del_watch_by_pid(pm_t *pm, pid_t pid)
}
}
/**
* @brief 源pid监听某个pid的状态
* @brief 某个task去另一个task的状态
*
* @param pid 被监听的状态
* @param flags 监听的flags
@@ -119,7 +119,7 @@ int pm_rpc_watch_pid(pm_t *pm, obj_handler_t sig_rcv_hd, pid_t pid, int flags)
{
return -EINVAL;
}
if (pm_watch_lookup(pm, src_pid))
if (pm_watch_lookup(pm, src_pid, pid))
{
handler_free_umap(sig_rcv_hd);
return -EEXIST;
@@ -135,8 +135,8 @@ int pm_rpc_watch_pid(pm_t *pm, obj_handler_t sig_rcv_hd, pid_t pid, int flags)
entry->notify_sem_hd = HANDLER_INVALID;
#endif
entry->sig_hd = sig_rcv_hd;
entry->src_pid = src_pid;
entry->watch_pid = pid;
entry->src_pid = src_pid; // 监控的pid
entry->watch_pid = pid; //被监控的pid
entry->flags = flags;
slist_init(&entry->node);
slist_add_append(&pm->watch_head, &entry->node);
@@ -163,7 +163,7 @@ static bool_t pm_send_sig_to_task(pm_t *pm, pid_t pid, umword_t sig_val)
{
watch_entry_t *next = slist_next_entry(pos, &pm->watch_head, node);
printf("watch_pid:%d pid:%d\n", pos->watch_pid, pid);
// printf("watch_pid:%d pid:%d\n", pos->watch_pid, pid);
if (pos->watch_pid == pid)
{
if (sig_val == KILL_SIG)
@@ -174,7 +174,7 @@ static bool_t pm_send_sig_to_task(pm_t *pm, pid_t pid, umword_t sig_val)
}
slist_del(&pos->node);
handler_free_umap(pos->sig_hd); //!< 删除信号通知的ipc
handler_free_umap(pos->watch_pid); //!< 删除被watch的进程
// handler_free_umap(pos->watch_pid); //!< 删除被watch的进程
u_free(pos);
}
pos = next;
@@ -200,7 +200,6 @@ int pm_rpc_kill_task(int src_pid, int pid, int flags, int exit_code)
printf("pid is error.\n");
return -EINVAL;
}
// ns_node_del_by_pid(pid, flags); TODO: //!< 从ns中删除
#if IS_ENABLED(CONFIG_USING_SIG)
if (src_pid != pid)

View File

@@ -23,11 +23,8 @@
#include "u_task.h"
#include "pm.h"
#include "pm_svr.h"
#if IS_ENABLED(CONFIG_MMU)
#include "u_sig.h"
#define CONS_STACK_SIZE 1024
#else
#define CONS_STACK_SIZE 1024
#endif
static ATTR_ALIGN(8) uint8_t cons_stack[CONS_STACK_SIZE];
static uint8_t cons_ipc_msg[MSG_BUG_LEN];
static tty_struct_t sys_tty;
@@ -346,12 +343,11 @@ static int tty_def_line_handler(tty_struct_t *tty, uint8_t r)
{
// 发送给前台进程组的所有进程
// inner_set_sig(SIGINT);TODO:
pm_rpc_kill_task(-1, tty->fg_pid, 0, 0);
// ulog_write_str(LOG_PROT, "ctrl c");
pm_rpc_kill_task(-1, tty->fg_pid, KILL_SIG, 0);
if (!L_NOFLSH(tty))
{
q_queue_clear(&tty->w_queue);
// q_queue_clear(&tty->r_queue);
q_queue_clear(&tty->pre_queue);
ret = 1;
}
tty->is_nl = 1;
@@ -360,11 +356,11 @@ static int tty_def_line_handler(tty_struct_t *tty, uint8_t r)
else if (r == QUIT_C(tty))
{
// inner_set_sig(SIGQUIT);TODO:
ulog_write_str(LOG_PROT, "Ctrl+C");
// ulog_write_str(LOG_PROT, "Ctrl+C");
if (!L_NOFLSH(tty))
{
q_queue_clear(&tty->w_queue);
// q_queue_clear(&tty->r_queue);
q_queue_clear(&tty->pre_queue);
ret = 1;
}
tty->is_nl = 1;

View File

@@ -1,7 +1,7 @@
#include <u_types.h>
#if !IS_ENABLED(CONFIG_MMU)
#define HEAP_SIZE (10 * 1024)
#define HEAP_SIZE (16 * 1024)
#define STACK_SIZE (2048)
#if defined(__CC_ARM)

View File

@@ -59,6 +59,7 @@ void fd_man_close_without_pid(pid_t pid)
if (fd_man_list[i].used == 1 && fd_man_list[i].pid == pid)
{
printf("net close fd:%d\n", fd_man_list[i].fd);
// lwip_shutdown(fd_man_list[i].fd, SHUT_RzDWR);
lwip_close(fd_man_list[i].fd);
fd_man_list[i].used = 0;
}

View File

@@ -136,7 +136,7 @@ int main(int argc, char *argv[])
if (dev_path == NULL)
{
printf("please set dev path.\n");
printf("example:ram_block -p /block -s 512 -n 2048");
printf("example:ram_block -p /dev/block -s 512 -n 2048");
return -1;
}
blk_data = mmap(0, blk_nr * blk_size, PROT_PFS | PROT_READ | PROT_WRITE, MAP_PRIVATE, -1, 0);