集成cmbacktrace && fatfs分离硬件接口
7
.vscode/settings.json
vendored
@@ -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,
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
40
mkrtos_knl/arch/cortex-m/CmBacktrace/.gitattributes
vendored
Normal 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
|
||||
22
mkrtos_knl/arch/cortex-m/CmBacktrace/LICENSE
Normal 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.
|
||||
221
mkrtos_knl/arch/cortex-m/CmBacktrace/README.md
Normal file
@@ -0,0 +1,221 @@
|
||||
# CmBacktrace: ARM Cortex-M series MCU error tracking library
|
||||
|
||||
[中文页](README_ZH.md) | English
|
||||
|
||||
[](https://github.com/armink/CmBacktrace/releases/latest) [](https://github.com/armink/CmBacktrace/compare/1.0.0...master) [](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
|
||||
|
||||
[](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.
|
||||
227
mkrtos_knl/arch/cortex-m/CmBacktrace/README_ZH.md
Normal file
@@ -0,0 +1,227 @@
|
||||
# CmBacktrace: ARM Cortex-M 系列 MCU 错误追踪库
|
||||
|
||||
中文页 | [English](README.md)
|
||||
|
||||
[](https://github.com/armink/CmBacktrace/releases/latest) [](https://github.com/armink/CmBacktrace/compare/1.0.0...master) [](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 命令,查看函数调用栈详细信息,并定位错误代码
|
||||
|
||||
[](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 文件内容。
|
||||
@@ -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 |
|
||||
@@ -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",
|
||||
@@ -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",
|
||||
@@ -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",
|
||||
816
mkrtos_knl/arch/cortex-m/CmBacktrace/cm_backtrace/cm_backtrace.c
Normal 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);
|
||||
}
|
||||
@@ -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_ */
|
||||
48
mkrtos_knl/arch/cortex-m/CmBacktrace/cm_backtrace/cmb_cfg.h
Normal 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_ */
|
||||
|
||||
434
mkrtos_knl/arch/cortex-m/CmBacktrace/cm_backtrace/cmb_def.h
Normal 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_ */
|
||||
@@ -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) */
|
||||
@@ -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) */
|
||||
@@ -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
|
||||
@@ -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
|
||||
4
mkrtos_knl/arch/cortex-m/CmBacktrace/docs/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
|File or folder name |Description|
|
||||
|:----- |:----|
|
||||
|en |English documents|
|
||||
|zh |中文文档(简体)|
|
||||
@@ -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
|
||||
|
||||

|
||||
|
||||
## Keil 5
|
||||
|
||||

|
||||
|
||||
## IAR
|
||||
|
||||
IAR 新建完的工程,默认开启 C99 ,如果工程没有开启,请使用下面的方法
|
||||
|
||||

|
||||
|
||||
## GCC
|
||||
|
||||
在编译配置中增加 `-std=c99` 即可
|
||||
@@ -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) 。
|
||||
|
After Width: | Height: | Size: 134 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 99 KiB |
@@ -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>© 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****/
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -32,6 +32,7 @@ int getc(void);
|
||||
* @param ...
|
||||
*/
|
||||
void printk(const char *fmt, ...);
|
||||
void printkln(const char *fmt, ...);
|
||||
|
||||
void dumpstack(void);
|
||||
|
||||
|
||||
@@ -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线程的优先级.
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 //!< 用于栈溢出检测
|
||||
|
||||
6
mkrtos_knl/inc/lib/stdio.h
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <xprintf.h>
|
||||
|
||||
#define sprintf xsprintf
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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__(""
|
||||
:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;//!<通知用的信号量
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
156
mkrtos_user/server/fs/fatfs/mk_ram_disk_drv/diskio.c
Normal 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; // 默认返回参数错误
|
||||
}
|
||||
77
mkrtos_user/server/fs/fatfs/mk_ram_disk_drv/diskio.h
Normal 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
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||