forked from espressif/esp-idf
Compare commits
52 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
27574a31e7 | ||
|
|
8134140acd | ||
|
|
efdbc63b5f | ||
|
|
1891382db6 | ||
|
|
16cd517410 | ||
|
|
8fc78a958a | ||
|
|
3cbaf98d29 | ||
|
|
b2d41a3506 | ||
|
|
5d1ec0da02 | ||
|
|
6a9e9759ea | ||
|
|
0de622e4f6 | ||
|
|
fc67a8b1b9 | ||
|
|
41f43164e2 | ||
|
|
2236ab7bd4 | ||
|
|
a281359db0 | ||
|
|
1fb777cc49 | ||
|
|
92facb6884 | ||
|
|
eb38883217 | ||
|
|
5d736f7eca | ||
|
|
bdc499aea7 | ||
|
|
99dbfb3539 | ||
|
|
8d3e1a2a79 | ||
|
|
f33b0fd4c9 | ||
|
|
b99551b48f | ||
|
|
6c04e3ee6a | ||
|
|
6878c4e329 | ||
|
|
f54a656932 | ||
|
|
305564cd59 | ||
|
|
6bceb41bf7 | ||
|
|
2e9db99921 | ||
|
|
fa7d3f38fc | ||
|
|
602e223c9c | ||
|
|
baa743c7b9 | ||
|
|
6db29f0766 | ||
|
|
abec2392c7 | ||
|
|
8a54ebe02e | ||
|
|
0a1c68d7b6 | ||
|
|
494641c481 | ||
|
|
3ab2436b11 | ||
|
|
ee86c15ab8 | ||
|
|
9deaa6ab60 | ||
|
|
8a5c1e9209 | ||
|
|
3d3994632b | ||
|
|
17dd3e9ca0 | ||
|
|
c40bbc5c42 | ||
|
|
1b3120615b | ||
|
|
3365b9322b | ||
|
|
852e94d73a | ||
|
|
09bb7a7650 | ||
|
|
4f4fb7b453 | ||
|
|
663129abce | ||
|
|
9cf81f754b |
@@ -1,39 +0,0 @@
|
||||
# EditorConfig helps developers define and maintain consistent
|
||||
# coding styles between different editors and IDEs
|
||||
# http://editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[{*.md,*.rst}]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[{Makefile,*.mk,*.bat}]
|
||||
indent_style = tab
|
||||
indent_size = 2
|
||||
|
||||
[*/freertos/**]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
[{*/freertos/**.S,**/FreeRTOSConfig.h}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.pem]
|
||||
insert_final_newline = false
|
||||
|
||||
[*.py]
|
||||
max_line_length = 119
|
||||
|
||||
[{*.cmake,CMakeLists.txt}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
max_line_length = 120
|
||||
165
.flake8
165
.flake8
@@ -1,165 +0,0 @@
|
||||
[flake8]
|
||||
|
||||
select =
|
||||
# Full lists are given in order to suppress all errors from other plugins
|
||||
# Full list of pyflakes error codes:
|
||||
F401, # module imported but unused
|
||||
F402, # import module from line N shadowed by loop variable
|
||||
F403, # 'from module import *' used; unable to detect undefined names
|
||||
F404, # future import(s) name after other statements
|
||||
F405, # name may be undefined, or defined from star imports: module
|
||||
F406, # 'from module import *' only allowed at module level
|
||||
F407, # an undefined __future__ feature name was imported
|
||||
F601, # dictionary key name repeated with different values
|
||||
F602, # dictionary key variable name repeated with different values
|
||||
F621, # too many expressions in an assignment with star-unpacking
|
||||
F622, # two or more starred expressions in an assignment (a, *b, *c = d)
|
||||
F631, # assertion test is a tuple, which are always True
|
||||
F701, # a break statement outside of a while or for loop
|
||||
F702, # a continue statement outside of a while or for loop
|
||||
F703, # a continue statement in a finally block in a loop
|
||||
F704, # a yield or yield from statement outside of a function
|
||||
F705, # a return statement with arguments inside a generator
|
||||
F706, # a return statement outside of a function/method
|
||||
F707, # an except: block as not the last exception handler
|
||||
F721, F722, # doctest syntax error syntax error in forward type annotation
|
||||
F811, # redefinition of unused name from line N
|
||||
F812, # list comprehension redefines name from line N
|
||||
F821, # undefined name name
|
||||
F822, # undefined name name in __all__
|
||||
F823, # local variable name referenced before assignment
|
||||
F831, # duplicate argument name in function definition
|
||||
F841, # local variable name is assigned to but never used
|
||||
F901, # raise NotImplemented should be raise NotImplementedError
|
||||
|
||||
# Full list of pycodestyle violations:
|
||||
E101, # indentation contains mixed spaces and tabs
|
||||
E111, # indentation is not a multiple of four
|
||||
E112, # expected an indented block
|
||||
E113, # unexpected indentation
|
||||
E114, # indentation is not a multiple of four (comment)
|
||||
E115, # expected an indented block (comment)
|
||||
E116, # unexpected indentation (comment)
|
||||
E121, # continuation line under-indented for hanging indent
|
||||
E122, # continuation line missing indentation or outdented
|
||||
E123, # closing bracket does not match indentation of opening bracket's line
|
||||
E124, # closing bracket does not match visual indentation
|
||||
E125, # continuation line with same indent as next logical line
|
||||
E126, # continuation line over-indented for hanging indent
|
||||
E127, # continuation line over-indented for visual indent
|
||||
E128, # continuation line under-indented for visual indent
|
||||
E129, # visually indented line with same indent as next logical line
|
||||
E131, # continuation line unaligned for hanging indent
|
||||
E133, # closing bracket is missing indentation
|
||||
E201, # whitespace after '('
|
||||
E202, # whitespace before ')'
|
||||
E203, # whitespace before ':'
|
||||
E211, # whitespace before '('
|
||||
E221, # multiple spaces before operator
|
||||
E222, # multiple spaces after operator
|
||||
E223, # tab before operator
|
||||
E224, # tab after operator
|
||||
E225, # missing whitespace around operator
|
||||
E226, # missing whitespace around arithmetic operator
|
||||
E227, # missing whitespace around bitwise or shift operator
|
||||
E228, # missing whitespace around modulo operator
|
||||
E231, # missing whitespace after ',', ';', or ':'
|
||||
E241, # multiple spaces after ','
|
||||
E242, # tab after ','
|
||||
E251, # unexpected spaces around keyword / parameter equals
|
||||
E261, # at least two spaces before inline comment
|
||||
E262, # inline comment should start with '# '
|
||||
E265, # block comment should start with '# '
|
||||
E266, # too many leading '#' for block comment
|
||||
E271, # multiple spaces after keyword
|
||||
E272, # multiple spaces before keyword
|
||||
E273, # tab after keyword
|
||||
E274, # tab before keyword
|
||||
E275, # missing whitespace after keyword
|
||||
E301, # expected 1 blank line, found 0
|
||||
E302, # expected 2 blank lines, found 0
|
||||
E303, # too many blank lines
|
||||
E304, # blank lines found after function decorator
|
||||
E305, # expected 2 blank lines after end of function or class
|
||||
E306, # expected 1 blank line before a nested definition
|
||||
E401, # multiple imports on one line
|
||||
E402, # module level import not at top of file
|
||||
E501, # line too long (82 > 79 characters)
|
||||
E502, # the backslash is redundant between brackets
|
||||
E701, # multiple statements on one line (colon)
|
||||
E702, # multiple statements on one line (semicolon)
|
||||
E703, # statement ends with a semicolon
|
||||
E704, # multiple statements on one line (def)
|
||||
E711, # comparison to None should be 'if cond is None:'
|
||||
E712, # comparison to True should be 'if cond is True:' or 'if cond:'
|
||||
E713, # test for membership should be 'not in'
|
||||
E714, # test for object identity should be 'is not'
|
||||
E721, # do not compare types, use 'isinstance()'
|
||||
E722, # do not use bare except, specify exception instead
|
||||
E731, # do not assign a lambda expression, use a def
|
||||
E741, # do not use variables named 'l', 'O', or 'I'
|
||||
E742, # do not define classes named 'l', 'O', or 'I'
|
||||
E743, # do not define functions named 'l', 'O', or 'I'
|
||||
E901, # SyntaxError or IndentationError
|
||||
E902, # IOError
|
||||
W191, # indentation contains tabs
|
||||
W291, # trailing whitespace
|
||||
W292, # no newline at end of file
|
||||
W293, # blank line contains whitespace
|
||||
W391, # blank line at end of file
|
||||
W503, # line break before binary operator
|
||||
W504, # line break after binary operator
|
||||
W505, # doc line too long (82 > 79 characters)
|
||||
W601, # .has_key() is deprecated, use 'in'
|
||||
W602, # deprecated form of raising exception
|
||||
W603, # '<>' is deprecated, use '!='
|
||||
W604, # backticks are deprecated, use 'repr()'
|
||||
W605, # invalid escape sequence 'x'
|
||||
W606, # 'async' and 'await' are reserved keywords starting with Python 3.7
|
||||
|
||||
# Full list of flake8 violations
|
||||
E999, # failed to compile a file into an Abstract Syntax Tree for the plugins that require it
|
||||
|
||||
# Full list of mccabe violations
|
||||
C901 # complexity value provided by the user
|
||||
|
||||
ignore =
|
||||
E221, # multiple spaces before operator
|
||||
E231, # missing whitespace after ',', ';', or ':'
|
||||
E241, # multiple spaces after ','
|
||||
W503, # line break before binary operator
|
||||
W504 # line break after binary operator
|
||||
|
||||
max-line-length = 160
|
||||
|
||||
show_source = True
|
||||
|
||||
statistics = True
|
||||
|
||||
exclude =
|
||||
.git,
|
||||
__pycache__,
|
||||
# submodules
|
||||
components/esptool_py/esptool,
|
||||
components/micro-ecc/micro-ecc,
|
||||
components/nghttp/nghttp2,
|
||||
components/libsodium/libsodium,
|
||||
components/json/cJSON,
|
||||
components/mbedtls/mbedtls,
|
||||
components/expat/expat,
|
||||
components/unity/unity,
|
||||
examples/build_system/cmake/import_lib/main/lib/tinyxml2
|
||||
# other third-party libraries
|
||||
tools/kconfig_new/kconfiglib.py,
|
||||
# autogenerated scripts
|
||||
components/protocomm/python/constants_pb2.py,
|
||||
components/protocomm/python/sec0_pb2.py,
|
||||
components/protocomm/python/sec1_pb2.py,
|
||||
components/protocomm/python/session_pb2.py,
|
||||
components/wifi_provisioning/python/wifi_scan_pb2.py,
|
||||
components/wifi_provisioning/python/wifi_config_pb2.py,
|
||||
components/wifi_provisioning/python/wifi_constants_pb2.py,
|
||||
examples/provisioning/custom_config/components/custom_provisioning/python/custom_config_pb2.py,
|
||||
# temporary list (should be empty)
|
||||
tools/esp_app_trace/pylibelf,
|
||||
tools/mass_mfg/mfg_gen.py,
|
||||
17
.github/main.workflow
vendored
17
.github/main.workflow
vendored
@@ -1,17 +0,0 @@
|
||||
workflow "Sync issues to JIRA" {
|
||||
on = "issues"
|
||||
resolves = ["Sync to JIRA"]
|
||||
}
|
||||
|
||||
workflow "Sync issue comments to JIRA" {
|
||||
on = "issue_comment"
|
||||
resolves = ["Sync to JIRA"]
|
||||
}
|
||||
|
||||
action "Sync to JIRA" {
|
||||
uses = "espressif/github-actions/sync_issues_to_jira@master"
|
||||
secrets = ["GITHUB_TOKEN", "JIRA_URL", "JIRA_USER", "JIRA_PASS"]
|
||||
env = {
|
||||
JIRA_PROJECT = "IDFGH"
|
||||
}
|
||||
}
|
||||
48
.gitignore
vendored
48
.gitignore
vendored
@@ -18,59 +18,23 @@ GPATH
|
||||
# eclipse setting
|
||||
.settings
|
||||
|
||||
# MacOS directory files
|
||||
.DS_Store
|
||||
|
||||
# Example project files
|
||||
examples/**/sdkconfig
|
||||
examples/**/sdkconfig.old
|
||||
examples/**/build
|
||||
|
||||
# Doc build artifacts
|
||||
docs/*/_build/
|
||||
docs/*/doxygen-warning-log.txt
|
||||
docs/*/sphinx-warning-log.txt
|
||||
docs/*/sphinx-warning-log-sanitized.txt
|
||||
docs/*/xml/
|
||||
docs/*/xml_in/
|
||||
docs/*/man/
|
||||
docs/doxygen_sqlite3.db
|
||||
#Doc build artifacts
|
||||
docs/_build/
|
||||
docs/doxygen-warning-log.txt
|
||||
docs/sphinx-warning-log.txt
|
||||
docs/xml/
|
||||
docs/man/
|
||||
|
||||
# Unit test app files
|
||||
tools/unit-test-app/sdkconfig
|
||||
tools/unit-test-app/sdkconfig.old
|
||||
tools/unit-test-app/build
|
||||
tools/unit-test-app/builds
|
||||
tools/unit-test-app/output
|
||||
|
||||
# IDF monitor test
|
||||
tools/test_idf_monitor/outputs
|
||||
|
||||
TEST_LOGS
|
||||
|
||||
# AWS IoT Examples require device-specific certs/keys
|
||||
examples/protocols/aws_iot/*/main/certs/*.pem.*
|
||||
|
||||
# gcov coverage reports
|
||||
*.gcda
|
||||
*.gcno
|
||||
coverage.info
|
||||
coverage_report/
|
||||
|
||||
# Windows tools installer build
|
||||
tools/windows/tool_setup/.*
|
||||
tools/windows/tool_setup/input
|
||||
tools/windows/tool_setup/dl
|
||||
tools/windows/tool_setup/keys
|
||||
tools/windows/tool_setup/Output
|
||||
|
||||
test_multi_heap_host
|
||||
|
||||
# VS Code Settings
|
||||
.vscode/
|
||||
|
||||
# Results for the checking of the Python coding style
|
||||
flake8_output.txt
|
||||
|
||||
# ESP-IDF library
|
||||
build
|
||||
|
||||
1499
.gitlab-ci.yml
1499
.gitlab-ci.yml
File diff suppressed because it is too large
Load Diff
65
.gitmodules
vendored
65
.gitmodules
vendored
@@ -1,80 +1,31 @@
|
||||
#
|
||||
# All the relative URL paths are intended to be GitHub ones
|
||||
# For Espressif's public projects please use '../../espressif/proj', not a '../proj'
|
||||
#
|
||||
|
||||
[submodule "components/esp32/lib"]
|
||||
path = components/esp32/lib
|
||||
url = ../../espressif/esp32-wifi-lib.git
|
||||
url = https://github.com/espressif/esp32-wifi-lib.git
|
||||
|
||||
[submodule "components/esptool_py/esptool"]
|
||||
path = components/esptool_py/esptool
|
||||
url = ../../espressif/esptool.git
|
||||
url = https://github.com/espressif/esptool.git
|
||||
|
||||
[submodule "components/bt/lib"]
|
||||
path = components/bt/lib
|
||||
url = ../../espressif/esp32-bt-lib.git
|
||||
url = https://github.com/espressif/esp32-bt-lib.git
|
||||
|
||||
[submodule "components/micro-ecc/micro-ecc"]
|
||||
path = components/micro-ecc/micro-ecc
|
||||
url = ../../kmackay/micro-ecc.git
|
||||
url = https://github.com/kmackay/micro-ecc.git
|
||||
|
||||
[submodule "components/coap/libcoap"]
|
||||
path = components/coap/libcoap
|
||||
url = ../../obgm/libcoap.git
|
||||
url = https://github.com/obgm/libcoap.git
|
||||
|
||||
[submodule "components/aws_iot/aws-iot-device-sdk-embedded-C"]
|
||||
path = components/aws_iot/aws-iot-device-sdk-embedded-C
|
||||
url = ../../espressif/aws-iot-device-sdk-embedded-C.git
|
||||
url = https://github.com/espressif/aws-iot-device-sdk-embedded-C.git
|
||||
|
||||
[submodule "components/nghttp/nghttp2"]
|
||||
path = components/nghttp/nghttp2
|
||||
url = ../../nghttp2/nghttp2.git
|
||||
url = https://github.com/nghttp2/nghttp2.git
|
||||
|
||||
[submodule "components/libsodium/libsodium"]
|
||||
path = components/libsodium/libsodium
|
||||
url = ../../jedisct1/libsodium.git
|
||||
|
||||
[submodule "components/spiffs/spiffs"]
|
||||
path = components/spiffs/spiffs
|
||||
url = ../../pellepl/spiffs.git
|
||||
|
||||
[submodule "components/json/cJSON"]
|
||||
path = components/json/cJSON
|
||||
url = ../../DaveGamble/cJSON.git
|
||||
|
||||
[submodule "components/mbedtls/mbedtls"]
|
||||
path = components/mbedtls/mbedtls
|
||||
url = ../../espressif/mbedtls.git
|
||||
|
||||
[submodule "components/asio/asio"]
|
||||
path = components/asio/asio
|
||||
url = ../../espressif/asio.git
|
||||
|
||||
[submodule "components/expat/expat"]
|
||||
path = components/expat/expat
|
||||
url = ../../libexpat/libexpat.git
|
||||
|
||||
[submodule "components/lwip/lwip"]
|
||||
path = components/lwip/lwip
|
||||
url = ../../espressif/esp-lwip.git
|
||||
|
||||
[submodule "components/mqtt/esp-mqtt"]
|
||||
path = components/mqtt/esp-mqtt
|
||||
url = ../../espressif/esp-mqtt.git
|
||||
|
||||
[submodule "components/protobuf-c/protobuf-c"]
|
||||
path = components/protobuf-c/protobuf-c
|
||||
url = ../../protobuf-c/protobuf-c.git
|
||||
|
||||
[submodule "components/unity/unity"]
|
||||
path = components/unity/unity
|
||||
url = ../../ThrowTheSwitch/Unity.git
|
||||
|
||||
[submodule "examples/build_system/cmake/import_lib/main/lib/tinyxml2"]
|
||||
path = examples/build_system/cmake/import_lib/main/lib/tinyxml2
|
||||
url = ../../leethomason/tinyxml2.git
|
||||
|
||||
[submodule "components/nimble/nimble"]
|
||||
path = components/nimble/nimble
|
||||
url = ../../espressif/esp-nimble.git
|
||||
url = https://github.com/jedisct1/libsodium.git
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
# .readthedocs.yml
|
||||
# Read the Docs configuration file
|
||||
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||
|
||||
# Required
|
||||
version: 2
|
||||
|
||||
# Optionally build your docs in additional formats such as PDF and ePub
|
||||
formats:
|
||||
- pdf
|
||||
|
||||
# Optionally set the version of Python and requirements required to build your docs
|
||||
python:
|
||||
version: 2.7
|
||||
install:
|
||||
- requirements: docs/requirements.txt
|
||||
|
||||
# We need to list all the submodules included in documentation build by Doxygen
|
||||
submodules:
|
||||
include:
|
||||
- components/mqtt/esp-mqtt
|
||||
@@ -1,7 +0,0 @@
|
||||
language: python
|
||||
sudo: false
|
||||
python:
|
||||
- "3.4"
|
||||
script:
|
||||
- pip install flake8
|
||||
- travis_wait 20 python -m flake8 --config=.flake8 .
|
||||
@@ -1,45 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(esp-idf C CXX ASM)
|
||||
|
||||
#
|
||||
# Add each component to the build as a library
|
||||
#
|
||||
foreach(COMPONENT_PATH ${BUILD_COMPONENT_PATHS})
|
||||
get_filename_component(COMPONENT_NAME ${COMPONENT_PATH} NAME)
|
||||
|
||||
list(FIND BUILD_TEST_COMPONENT_PATHS ${COMPONENT_PATH} idx)
|
||||
|
||||
if(NOT idx EQUAL -1)
|
||||
list(GET BUILD_TEST_COMPONENTS ${idx} test_component)
|
||||
set(COMPONENT_NAME ${test_component})
|
||||
endif()
|
||||
|
||||
component_get_target(COMPONENT_TARGET ${COMPONENT_NAME})
|
||||
|
||||
add_subdirectory(${COMPONENT_PATH} ${COMPONENT_NAME})
|
||||
endforeach()
|
||||
unset(COMPONENT_NAME)
|
||||
unset(COMPONENT_PATH)
|
||||
|
||||
# each component should see the include directories of its requirements
|
||||
#
|
||||
# (we can't do this until all components are registered and targets exist in cmake, as we have
|
||||
# a circular requirements graph...)
|
||||
foreach(component ${BUILD_COMPONENTS})
|
||||
component_get_target(component_target ${component})
|
||||
if(TARGET ${component_target})
|
||||
get_component_requirements(${component} deps priv_deps)
|
||||
|
||||
list(APPEND priv_deps ${IDF_COMPONENT_REQUIRES_COMMON})
|
||||
|
||||
foreach(dep ${deps})
|
||||
component_get_target(dep_target ${dep})
|
||||
add_component_dependencies(${component_target} ${dep_target} PUBLIC)
|
||||
endforeach()
|
||||
|
||||
foreach(dep ${priv_deps})
|
||||
component_get_target(dep_target ${dep})
|
||||
add_component_dependencies(${component_target} ${dep_target} PRIVATE)
|
||||
endforeach()
|
||||
endif()
|
||||
endforeach()
|
||||
@@ -25,8 +25,6 @@ Before sending us a Pull Request, please consider this list of points:
|
||||
|
||||
* Are comments and documentation written in clear English, with no spelling or grammar errors?
|
||||
|
||||
* Example contributions are also welcome. Please check the :doc:`creating-examples` guide for these.
|
||||
|
||||
* If the contribution contains multiple commits, are they grouped together into logical changes (one major change per pull request)? Are any commits with names like "fixed typo" `squashed into previous commits <http://eli.thegreenplace.net/2014/02/19/squashing-github-pull-requests-into-a-single-commit/>`_?
|
||||
|
||||
* If you're unsure about any of these points, please open the Pull Request anyhow and then ask us for feedback.
|
||||
@@ -53,7 +51,5 @@ Related Documents
|
||||
|
||||
style-guide
|
||||
documenting-code
|
||||
add-ons-reference
|
||||
creating-examples
|
||||
../api-reference/template
|
||||
contributor-agreement
|
||||
contributor-agreement
|
||||
244
Kconfig
244
Kconfig
@@ -4,208 +4,48 @@
|
||||
#
|
||||
mainmenu "Espressif IoT Development Framework Configuration"
|
||||
|
||||
config IDF_CMAKE
|
||||
bool
|
||||
option env="IDF_CMAKE"
|
||||
|
||||
menu "SDK tool configuration"
|
||||
config TOOLPREFIX
|
||||
string "Compiler toolchain path/prefix"
|
||||
default "xtensa-esp32-elf-"
|
||||
help
|
||||
The prefix/path that is used to call the toolchain. The default setting assumes
|
||||
a crosstool-ng gcc setup that is in your PATH.
|
||||
|
||||
config PYTHON
|
||||
string "Python 2 interpreter"
|
||||
default "python"
|
||||
help
|
||||
The executable name/path that is used to run python. On some systems Python 2.x
|
||||
may need to be invoked as python2.
|
||||
endmenu
|
||||
|
||||
source "$COMPONENT_KCONFIGS_PROJBUILD"
|
||||
|
||||
choice OPTIMIZATION_LEVEL
|
||||
prompt "Optimization level"
|
||||
default OPTIMIZATION_LEVEL_DEBUG
|
||||
help
|
||||
This option sets optimization level.
|
||||
|
||||
- for "Release" setting, -Os flag is added to CFLAGS,
|
||||
and -DNDEBUG flag is added to CPPFLAGS.
|
||||
|
||||
- for "Debug" setting, -Og flag is added to CFLAGS.
|
||||
|
||||
To override any of these settings, set CFLAGS and/or CPPFLAGS
|
||||
in project makefile, before including $(IDF_PATH)/make/project.mk.
|
||||
|
||||
config OPTIMIZATION_LEVEL_DEBUG
|
||||
bool "Debug"
|
||||
config OPTIMIZATION_LEVEL_RELEASE
|
||||
bool "Release"
|
||||
endchoice
|
||||
|
||||
menu "Component config"
|
||||
source "$COMPONENT_KCONFIGS"
|
||||
endmenu
|
||||
|
||||
|
||||
config IDF_TARGET_ENV
|
||||
# A proxy to get environment variable $IDF_TARGET
|
||||
string
|
||||
option env="IDF_TARGET"
|
||||
|
||||
config IDF_TARGET
|
||||
# This option records the IDF target when sdkconfig is generated the first time.
|
||||
# It is not updated if environment variable $IDF_TARGET changes later, and
|
||||
# the build system is responsible for detecting the mismatch between
|
||||
# CONFIG_IDF_TARGET and $IDF_TARGET.
|
||||
string
|
||||
default "IDF_TARGET_NOT_SET" if IDF_TARGET_ENV=""
|
||||
default IDF_TARGET_ENV
|
||||
|
||||
config IDF_FIRMWARE_CHIP_ID
|
||||
hex
|
||||
default 0x0000 if IDF_TARGET="esp32"
|
||||
default 0xFFFF
|
||||
|
||||
menu "SDK tool configuration"
|
||||
config TOOLPREFIX
|
||||
string "Compiler toolchain path/prefix"
|
||||
default "xtensa-esp32-elf-"
|
||||
help
|
||||
The prefix/path that is used to call the toolchain. The default setting assumes
|
||||
a crosstool-ng gcc setup that is in your PATH.
|
||||
|
||||
config PYTHON
|
||||
string "Python 2 interpreter"
|
||||
depends on !IDF_CMAKE
|
||||
default "python"
|
||||
help
|
||||
The executable name/path that is used to run python. On some systems Python 2.x
|
||||
may need to be invoked as python2.
|
||||
|
||||
(Note: This option is used with the GNU Make build system only, not idf.py
|
||||
or CMake-based builds.)
|
||||
|
||||
config MAKE_WARN_UNDEFINED_VARIABLES
|
||||
bool "'make' warns on undefined variables"
|
||||
default "y"
|
||||
help
|
||||
Adds --warn-undefined-variables to MAKEFLAGS. This causes make to
|
||||
print a warning any time an undefined variable is referenced.
|
||||
|
||||
This option helps find places where a variable reference is misspelled
|
||||
or otherwise missing, but it can be unwanted if you have Makefiles which
|
||||
depend on undefined variables expanding to an empty string.
|
||||
|
||||
endmenu # SDK tool configuration
|
||||
|
||||
source "$COMPONENT_KCONFIGS_PROJBUILD"
|
||||
|
||||
menu "Compiler options"
|
||||
|
||||
choice OPTIMIZATION_COMPILER
|
||||
prompt "Optimization Level"
|
||||
default OPTIMIZATION_LEVEL_DEBUG
|
||||
help
|
||||
This option sets compiler optimization level (gcc -O argument).
|
||||
|
||||
- for "Release" setting, -Os flag is added to CFLAGS.
|
||||
- for "Debug" setting, -Og flag is added to CFLAGS.
|
||||
|
||||
"Release" with -Os produces smaller & faster compiled code but it
|
||||
may be harder to correlated code addresses to source files when debugging.
|
||||
|
||||
To add custom optimization settings, set CFLAGS and/or CPPFLAGS
|
||||
in project makefile, before including $(IDF_PATH)/make/project.mk. Note that
|
||||
custom optimization levels may be unsupported.
|
||||
|
||||
config OPTIMIZATION_LEVEL_DEBUG
|
||||
bool "Debug (-Og)"
|
||||
config OPTIMIZATION_LEVEL_RELEASE
|
||||
bool "Release (-Os)"
|
||||
endchoice
|
||||
|
||||
choice OPTIMIZATION_ASSERTION_LEVEL
|
||||
prompt "Assertion level"
|
||||
default OPTIMIZATION_ASSERTIONS_ENABLED
|
||||
help
|
||||
Assertions can be:
|
||||
|
||||
- Enabled. Failure will print verbose assertion details. This is the default.
|
||||
|
||||
- Set to "silent" to save code size (failed assertions will abort() but user
|
||||
needs to use the aborting address to find the line number with the failed assertion.)
|
||||
|
||||
- Disabled entirely (not recommended for most configurations.) -DNDEBUG is added
|
||||
to CPPFLAGS in this case.
|
||||
|
||||
config OPTIMIZATION_ASSERTIONS_ENABLED
|
||||
prompt "Enabled"
|
||||
bool
|
||||
help
|
||||
Enable assertions. Assertion content and line number will be printed on failure.
|
||||
|
||||
config OPTIMIZATION_ASSERTIONS_SILENT
|
||||
prompt "Silent (saves code size)"
|
||||
bool
|
||||
help
|
||||
Enable silent assertions. Failed assertions will abort(), user needs to
|
||||
use the aborting address to find the line number with the failed assertion.
|
||||
|
||||
config OPTIMIZATION_ASSERTIONS_DISABLED
|
||||
prompt "Disabled (sets -DNDEBUG)"
|
||||
bool
|
||||
help
|
||||
If assertions are disabled, -DNDEBUG is added to CPPFLAGS.
|
||||
|
||||
endchoice # assertions
|
||||
|
||||
menuconfig CXX_EXCEPTIONS
|
||||
bool "Enable C++ exceptions"
|
||||
default n
|
||||
help
|
||||
Enabling this option compiles all IDF C++ files with exception support enabled.
|
||||
|
||||
Disabling this option disables C++ exception support in all compiled files, and any libstdc++ code
|
||||
which throws an exception will abort instead.
|
||||
|
||||
Enabling this option currently adds an additional ~500 bytes of heap overhead
|
||||
when an exception is thrown in user code for the first time.
|
||||
|
||||
config CXX_EXCEPTIONS_EMG_POOL_SIZE
|
||||
int "Emergency Pool Size"
|
||||
default 0
|
||||
depends on CXX_EXCEPTIONS
|
||||
help
|
||||
Size (in bytes) of the emergency memory pool for C++ exceptions. This pool will be used to allocate
|
||||
memory for thrown exceptions when there is not enough memory on the heap.
|
||||
|
||||
choice STACK_CHECK_MODE
|
||||
prompt "Stack smashing protection mode"
|
||||
default STACK_CHECK_NONE
|
||||
help
|
||||
Stack smashing protection mode. Emit extra code to check for buffer overflows, such as stack
|
||||
smashing attacks. This is done by adding a guard variable to functions with vulnerable objects.
|
||||
The guards are initialized when a function is entered and then checked when the function exits.
|
||||
If a guard check fails, program is halted. Protection has the following modes:
|
||||
|
||||
- In NORMAL mode (GCC flag: -fstack-protector) only functions that call alloca, and functions with
|
||||
buffers larger than 8 bytes are protected.
|
||||
|
||||
- STRONG mode (GCC flag: -fstack-protector-strong) is like NORMAL, but includes additional functions
|
||||
to be protected -- those that have local array definitions, or have references to local frame
|
||||
addresses.
|
||||
|
||||
- In OVERALL mode (GCC flag: -fstack-protector-all) all functions are protected.
|
||||
|
||||
Modes have the following impact on code performance and coverage:
|
||||
|
||||
- performance: NORMAL > STRONG > OVERALL
|
||||
|
||||
- coverage: NORMAL < STRONG < OVERALL
|
||||
|
||||
|
||||
config STACK_CHECK_NONE
|
||||
bool "None"
|
||||
config STACK_CHECK_NORM
|
||||
bool "Normal"
|
||||
config STACK_CHECK_STRONG
|
||||
bool "Strong"
|
||||
config STACK_CHECK_ALL
|
||||
bool "Overall"
|
||||
endchoice
|
||||
|
||||
config STACK_CHECK
|
||||
bool
|
||||
default !STACK_CHECK_NONE
|
||||
help
|
||||
Stack smashing protection.
|
||||
|
||||
config WARN_WRITE_STRINGS
|
||||
bool "Enable -Wwrite-strings warning flag"
|
||||
default "n"
|
||||
help
|
||||
Adds -Wwrite-strings flag for the C/C++ compilers.
|
||||
|
||||
For C, this gives string constants the type ``const char[]`` so that
|
||||
copying the address of one into a non-const ``char *`` pointer
|
||||
produces a warning. This warning helps to find at compile time code
|
||||
that tries to write into a string constant.
|
||||
|
||||
For C++, this warns about the deprecated conversion from string
|
||||
literals to ``char *``.
|
||||
|
||||
config DISABLE_GCC8_WARNINGS
|
||||
bool "Disable new warnings introduced in GCC 6 - 8"
|
||||
default "n"
|
||||
help
|
||||
Enable this option if using GCC 6 or newer, and wanting to disable warnings which don't appear with
|
||||
GCC 5.
|
||||
|
||||
|
||||
endmenu # Compiler Options
|
||||
|
||||
menu "Component config"
|
||||
source "$COMPONENT_KCONFIGS"
|
||||
endmenu
|
||||
|
||||
55
README.md
55
README.md
@@ -1,38 +1,25 @@
|
||||
# Espressif IoT Development Framework
|
||||
|
||||
[](https://docs.espressif.com/projects/esp-idf/en/latest/?badge=latest)
|
||||
[](http://esp-idf.readthedocs.io/en/latest/?badge=latest)
|
||||
|
||||
ESP-IDF is the official development framework for the [ESP32](https://espressif.com/en/products/hardware/esp32/overview) chip.
|
||||
|
||||
# Developing With ESP-IDF
|
||||
# Developing With the ESP-IDF
|
||||
|
||||
## Setting Up ESP-IDF
|
||||
|
||||
See setup guides for detailed instructions to set up the ESP-IDF:
|
||||
|
||||
* [Getting Started Guide for the stable ESP-IDF version](https://docs.espressif.com/projects/esp-idf/en/stable/get-started/)
|
||||
* [Getting Started Guide for the latest (master branch) ESP-IDF version](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/)
|
||||
|
||||
### Non-GitHub forks
|
||||
|
||||
ESP-IDF uses relative locations as its submodules URLs ([.gitmodules](.gitmodules)). So they link to GitHub.
|
||||
If ESP-IDF is forked to a Git repository which is not on GitHub, you will need to run the script
|
||||
[tools/set-submodules-to-github.sh](tools/set-submodules-to-github.sh) after git clone.
|
||||
The script sets absolute URLs for all submodules, allowing `git submodule update --init --recursive` to complete.
|
||||
If cloning ESP-IDF from GitHub, this step is not needed.
|
||||
* [Windows Setup Guide](http://esp-idf.readthedocs.io/en/latest/get-started/windows-setup.html)
|
||||
* [Mac OS Setup Guide](http://esp-idf.readthedocs.io/en/latest/get-started/macos-setup.html)
|
||||
* [Linux Setup Guide](http://esp-idf.readthedocs.io/en/latest/get-started/linux-setup.html)
|
||||
|
||||
## Finding a Project
|
||||
|
||||
As well as the [esp-idf-template](https://github.com/espressif/esp-idf-template) project mentioned in Getting Started, ESP-IDF comes with some example projects in the [examples](examples) directory.
|
||||
As well as the [esp-idf-template](https://github.com/espressif/esp-idf-template) project mentioned in the setup guide, ESP-IDF comes with some example projects in the [examples](examples) directory.
|
||||
|
||||
Once you've found the project you want to work with, change to its directory and you can configure and build it.
|
||||
|
||||
To start your own project based on an example, copy the example project directory outside of the ESP-IDF directory.
|
||||
|
||||
# Quick Reference
|
||||
|
||||
See the Getting Started guide links above for a detailed setup guide. This is a quick reference for common commands when working with ESP-IDF projects:
|
||||
|
||||
## Configuring the Project
|
||||
|
||||
`make menuconfig`
|
||||
@@ -49,17 +36,15 @@ Once done configuring, press Escape multiple times to exit and say "Yes" to save
|
||||
|
||||
## Compiling the Project
|
||||
|
||||
`make -j4 all`
|
||||
`make all`
|
||||
|
||||
... will compile app, bootloader and generate a partition table based on the config.
|
||||
|
||||
NOTE: The `-j4` option causes `make` to run 4 parallel jobs. This is much faster than the default single job. The recommended number to pass to this option is `-j(number of CPUs + 1)`.
|
||||
|
||||
## Flashing the Project
|
||||
|
||||
When the build finishes, it will print a command line to use esptool.py to flash the chip. However you can also do this automatically by running:
|
||||
When `make all` finishes, it will print a command line to use esptool.py to flash the chip. However you can also do this from make by running:
|
||||
|
||||
`make -j4 flash`
|
||||
`make flash`
|
||||
|
||||
This will flash the entire project (app, bootloader and partition table) to a new chip. The settings for serial port flashing can be configured with `make menuconfig`.
|
||||
|
||||
@@ -67,28 +52,28 @@ You don't need to run `make all` before running `make flash`, `make flash` will
|
||||
|
||||
## Viewing Serial Output
|
||||
|
||||
The `make monitor` target uses the [idf_monitor tool](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/idf-monitor.html) to display serial output from the ESP32. idf_monitor also has a range of features to decode crash output and interact with the device. [Check the documentation page for details](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/idf-monitor.html).
|
||||
The `make monitor` target uses the [idf_monitor tool](http://esp-idf.readthedocs.io/en/latest/get-started/idf-monitor.html) to display serial output from the ESP32. idf_monitor also has a range of features to decode crash output and interact with the device. [Check the documentation page for details](http://esp-idf.readthedocs.io/en/latest/get-started/idf-monitor.html).
|
||||
|
||||
Exit the monitor by typing Ctrl-].
|
||||
|
||||
To build, flash and monitor output in one pass, you can run:
|
||||
To flash and monitor output in one pass, you can run:
|
||||
|
||||
`make -j4 flash monitor`
|
||||
`make flash monitor`
|
||||
|
||||
## Compiling & Flashing Only the App
|
||||
## Compiling & Flashing Just the App
|
||||
|
||||
After the initial flash, you may just want to build and flash just your app, not the bootloader and partition table:
|
||||
|
||||
* `make app` - build just the app.
|
||||
* `make app-flash` - flash just the app.
|
||||
|
||||
`make app-flash` will automatically rebuild the app if any source files have changed.
|
||||
`make app-flash` will automatically rebuild the app if it needs it.
|
||||
|
||||
(In normal development there's no downside to reflashing the bootloader and partition table each time, if they haven't changed.)
|
||||
|
||||
## Parallel Builds
|
||||
|
||||
ESP-IDF supports compiling multiple files in parallel, so all of the above commands can be run as `make -jN` where `N` is the number of parallel make processes to run (generally N should be equal to the number of CPU cores in your system, plus one.)
|
||||
ESP-IDF supports compiling multiple files in parallel, so all of the above commands can be run as `make -jN` where `N` is the number of parallel make processes to run (generally N should be equal to or one more than the number of CPU cores in your system.)
|
||||
|
||||
Multiple make functions can be combined into one. For example: to build the app & bootloader using 5 jobs in parallel, then flash everything, and then display serial output from the ESP32 run:
|
||||
|
||||
@@ -96,7 +81,6 @@ Multiple make functions can be combined into one. For example: to build the app
|
||||
make -j5 flash monitor
|
||||
```
|
||||
|
||||
|
||||
## The Partition Table
|
||||
|
||||
Once you've compiled your project, the "build" directory will contain a binary file with a name like "my_app.bin". This is an ESP32 image binary that can be loaded by the bootloader.
|
||||
@@ -112,7 +96,7 @@ The simplest way to use the partition table is to `make menuconfig` and choose o
|
||||
|
||||
In both cases the factory app is flashed at offset 0x10000. If you `make partition_table` then it will print a summary of the partition table.
|
||||
|
||||
For more details about partition tables and how to create custom variations, view the [`docs/en/api-guides/partition-tables.rst`](docs/en/api-guides/partition-tables.rst) file.
|
||||
For more details about partition tables and how to create custom variations, view the `docs/partition-tables.rst` file.
|
||||
|
||||
## Erasing Flash
|
||||
|
||||
@@ -122,12 +106,11 @@ This can be combined with other targets, ie `make erase_flash flash` will erase
|
||||
|
||||
# Resources
|
||||
|
||||
* Documentation for the latest version: https://docs.espressif.com/projects/esp-idf/. This documentation is built from the [docs directory](docs) of this repository.
|
||||
* Documentation for the latest version: http://esp-idf.readthedocs.io/. This documentation is built from the [docs directory](docs) of this repository.
|
||||
|
||||
* The [esp32.com forum](https://esp32.com/) is a place to ask questions and find community resources.
|
||||
* The [esp32.com forum](http://esp32.com/) is a place to ask questions and find community resources.
|
||||
|
||||
* [Check the Issues section on github](https://github.com/espressif/esp-idf/issues) if you find a bug or have a feature request. Please check existing Issues before opening a new one.
|
||||
|
||||
* If you're interested in contributing to ESP-IDF, please check the [Contributions Guide](https://docs.espressif.com/projects/esp-idf/en/latest/contribute/index.html).
|
||||
|
||||
* If you're interested in contributing to ESP-IDF, please check the [Contributions Guide](http://esp-idf.readthedocs.io/en/latest/contribute/index.html).
|
||||
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
The latest support policy for ESP-IDF can be found at [https://github.com/espressif/esp-idf/blob/master/SUPPORT_POLICY.md](https://github.com/espressif/esp-idf/blob/master/SUPPORT_POLICY.md)
|
||||
|
||||
Support Period Policy
|
||||
=====================
|
||||
|
||||
Each ESP-IDF major and minor release (V4.0, V4.1, etc) is supported for
|
||||
18 months after the initial stable release date.
|
||||
|
||||
Supported means that the ESP-IDF team will continue to apply bug fixes,
|
||||
security fixes, etc to the release branch on GitHub, and periodically
|
||||
make new bugfix releases as needed.
|
||||
|
||||
Users are encouraged to upgrade to a newer ESP-IDF release before the
|
||||
support period finishes and the release becomes End of Life (EOL). It is
|
||||
our policy to not continue fixing bugs in End of Life releases.
|
||||
|
||||
Pre-release versions (betas, previews, `-rc` and `-dev` versions, etc)
|
||||
are not covered by any support period. Sometimes a particular feature is
|
||||
marked as \"Preview\" in a release, which means it is also not covered
|
||||
by the support period.
|
||||
|
||||
The ESP-IDF Programming Guide has information about the
|
||||
[different versions of ESP-IDF](https://docs.espressif.com/projects/esp-idf/en/latest/versions.html)
|
||||
(major, minor, bugfix, etc).
|
||||
|
||||
Long Term Support releases
|
||||
--------------------------
|
||||
|
||||
Some releases (starting with ESP-IDF V3.3) are designated Long Term
|
||||
Support (LTS). LTS releases are supported for 30 months (2.5 years)
|
||||
after the initial stable release date.
|
||||
|
||||
A new LTS release will be made at least every 18 months. This means
|
||||
there will always be a period of at least 12 months to upgrade from the
|
||||
previous LTS release to the following LTS release.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
ESP-IDF V3.3 was released in September 2019 and is a Long Term Support
|
||||
(LTS) release, meaning it will be supported for 30 months until February
|
||||
2022.
|
||||
|
||||
- The first V3.3 release was `v3.3` in September 2019.
|
||||
- The ESP-IDF team continues to backport bug fixes, security fixes,
|
||||
etc to the release branch `release/v3.3`.
|
||||
- Periodically stable bugfix releases are created from the release
|
||||
branch. For example `v3.3.1`, `v3.3.2`, etc. Users are encouraged to
|
||||
always update to the latest bugfix release.
|
||||
- V3.3 bugfix releases continue until February 2022, when all V3.3.x
|
||||
releases become End of Life.
|
||||
|
||||
Existing Releases
|
||||
-----------------
|
||||
|
||||
ESP-IDF release V3.3 and all newer releases will follow this support
|
||||
period policy. The support period for each release will be announced
|
||||
when the release is made.
|
||||
|
||||
For releases made before the support period policy was announced,
|
||||
the following support periods apply:
|
||||
|
||||
- ESP-IDF V3.1.x and V3.2.x will both be supported until October 2020.
|
||||
- ESP-IDF V3.0.9 (planned for October 2019) will be the last V3.0
|
||||
bugfix release. ESP-IDF V3.0.x is End of Life from October 2019.
|
||||
- ESP-IDF versions before V3.0 are already End of Life.
|
||||
@@ -9,12 +9,8 @@
|
||||
if [ -z ${IDF_PATH} ]; then
|
||||
echo "IDF_PATH must be set before including this script."
|
||||
else
|
||||
IDF_ADD_PATHS_EXTRAS=
|
||||
IDF_ADD_PATHS_EXTRAS="${IDF_ADD_PATHS_EXTRAS}:${IDF_PATH}/components/esptool_py/esptool"
|
||||
IDF_ADD_PATHS_EXTRAS="${IDF_ADD_PATHS_EXTRAS}:${IDF_PATH}/components/espcoredump"
|
||||
IDF_ADD_PATHS_EXTRAS="${IDF_ADD_PATHS_EXTRAS}:${IDF_PATH}/components/partition_table/"
|
||||
IDF_ADD_PATHS_EXTRAS="${IDF_ADD_PATHS_EXTRAS}:${IDF_PATH}/tools/"
|
||||
export PATH="${IDF_ADD_PATHS_EXTRAS}:${PATH}"
|
||||
IDF_ADD_PATHS_EXTRAS="${IDF_PATH}/components/esptool_py/esptool:${IDF_PATH}/components/espcoredump:${IDF_PATH}/components/partition_table/"
|
||||
export PATH="${PATH}:${IDF_ADD_PATHS_EXTRAS}"
|
||||
echo "Added to PATH: ${IDF_ADD_PATHS_EXTRAS}"
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
set(COMPONENT_SRCS "app_trace.c"
|
||||
"app_trace_util.c"
|
||||
"host_file_io.c"
|
||||
"gcov/gcov_rtio.c")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS "include")
|
||||
|
||||
if(CONFIG_SYSVIEW_ENABLE)
|
||||
list(APPEND COMPONENT_ADD_INCLUDEDIRS
|
||||
sys_view/Config
|
||||
sys_view/SEGGER
|
||||
sys_view/Sample/OS)
|
||||
|
||||
list(APPEND COMPONENT_SRCS "sys_view/SEGGER/SEGGER_SYSVIEW.c"
|
||||
"sys_view/Sample/Config/SEGGER_SYSVIEW_Config_FreeRTOS.c"
|
||||
"sys_view/Sample/OS/SEGGER_SYSVIEW_FreeRTOS.c"
|
||||
"sys_view/esp32/SEGGER_RTT_esp32.c")
|
||||
endif()
|
||||
|
||||
set(COMPONENT_REQUIRES)
|
||||
set(COMPONENT_PRIV_REQUIRES xtensa-debug-module)
|
||||
set(COMPONENT_ADD_LDFRAGMENTS linker.lf)
|
||||
|
||||
register_component()
|
||||
|
||||
# disable --coverage for this component, as it is used as transport
|
||||
# for gcov
|
||||
component_compile_options("-fno-profile-arcs" "-fno-test-coverage")
|
||||
|
||||
target_link_libraries(${COMPONENT_TARGET} gcov)
|
||||
@@ -1,210 +0,0 @@
|
||||
menu "Application Level Tracing"
|
||||
|
||||
choice ESP32_APPTRACE_DESTINATION
|
||||
prompt "Data Destination"
|
||||
default ESP32_APPTRACE_DEST_NONE
|
||||
help
|
||||
Select destination for application trace: trace memory or none (to disable).
|
||||
|
||||
config ESP32_APPTRACE_DEST_TRAX
|
||||
bool "Trace memory"
|
||||
select ESP32_APPTRACE_ENABLE
|
||||
config ESP32_APPTRACE_DEST_NONE
|
||||
bool "None"
|
||||
endchoice
|
||||
|
||||
config ESP32_APPTRACE_ENABLE
|
||||
bool
|
||||
depends on !ESP32_TRAX
|
||||
select MEMMAP_TRACEMEM
|
||||
select MEMMAP_TRACEMEM_TWOBANKS
|
||||
default n
|
||||
help
|
||||
Enables/disable application tracing module.
|
||||
|
||||
config ESP32_APPTRACE_LOCK_ENABLE
|
||||
bool
|
||||
default !SYSVIEW_ENABLE
|
||||
help
|
||||
Enables/disable application tracing module internal sync lock.
|
||||
|
||||
config ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TMO
|
||||
int "Timeout for flushing last trace data to host on panic"
|
||||
depends on ESP32_APPTRACE_ENABLE
|
||||
range -1 5000
|
||||
default -1
|
||||
help
|
||||
Timeout for flushing last trace data to host in case of panic. In ms.
|
||||
Use -1 to disable timeout and wait forever.
|
||||
|
||||
config ESP32_APPTRACE_POSTMORTEM_FLUSH_TRAX_THRESH
|
||||
int "Threshold for flushing last trace data to host on panic"
|
||||
depends on ESP32_APPTRACE_DEST_TRAX
|
||||
range 0 16384
|
||||
default 0
|
||||
help
|
||||
Threshold for flushing last trace data to host on panic in post-mortem mode.
|
||||
This is minimal amount of data needed to perform flush. In bytes.
|
||||
|
||||
config ESP32_APPTRACE_PENDING_DATA_SIZE_MAX
|
||||
int "Size of the pending data buffer"
|
||||
depends on ESP32_APPTRACE_DEST_TRAX
|
||||
default 0
|
||||
help
|
||||
Size of the buffer for events in bytes. It is useful for buffering events from
|
||||
the time critical code (scheduler, ISRs etc). If this parameter is 0 then
|
||||
events will be discarded when main HW buffer is full.
|
||||
|
||||
menu "FreeRTOS SystemView Tracing"
|
||||
depends on ESP32_APPTRACE_ENABLE
|
||||
config SYSVIEW_ENABLE
|
||||
bool "SystemView Tracing Enable"
|
||||
depends on ESP32_APPTRACE_ENABLE
|
||||
default n
|
||||
help
|
||||
Enables supporrt for SEGGER SystemView tracing functionality.
|
||||
|
||||
choice SYSVIEW_TS_SOURCE
|
||||
prompt "Timer to use as timestamp source"
|
||||
depends on SYSVIEW_ENABLE
|
||||
default SYSVIEW_TS_SOURCE_CCOUNT if FREERTOS_UNICORE && !PM_ENABLE
|
||||
default SYSVIEW_TS_SOURCE_TIMER_00 if !FREERTOS_UNICORE && !PM_ENABLE
|
||||
default SYSVIEW_TS_SOURCE_ESP_TIMER if PM_ENABLE
|
||||
help
|
||||
SystemView needs to use a hardware timer as the source of timestamps
|
||||
when tracing. This option selects the timer for it.
|
||||
|
||||
config SYSVIEW_TS_SOURCE_CCOUNT
|
||||
bool "CPU cycle counter (CCOUNT)"
|
||||
depends on FREERTOS_UNICORE && !PM_ENABLE
|
||||
|
||||
config SYSVIEW_TS_SOURCE_TIMER_00
|
||||
bool "Timer 0, Group 0"
|
||||
depends on !PM_ENABLE
|
||||
|
||||
config SYSVIEW_TS_SOURCE_TIMER_01
|
||||
bool "Timer 1, Group 0"
|
||||
depends on !PM_ENABLE
|
||||
|
||||
config SYSVIEW_TS_SOURCE_TIMER_10
|
||||
bool "Timer 0, Group 1"
|
||||
depends on !PM_ENABLE
|
||||
|
||||
config SYSVIEW_TS_SOURCE_TIMER_11
|
||||
bool "Timer 1, Group 1"
|
||||
depends on !PM_ENABLE
|
||||
|
||||
config SYSVIEW_TS_SOURCE_ESP_TIMER
|
||||
bool "esp_timer high resolution timer"
|
||||
|
||||
endchoice
|
||||
|
||||
config SYSVIEW_MAX_TASKS
|
||||
int "Maximum supported tasks"
|
||||
depends on SYSVIEW_ENABLE
|
||||
range 1 64
|
||||
default 16
|
||||
help
|
||||
Configures maximum supported tasks in sysview debug
|
||||
|
||||
config SYSVIEW_EVT_OVERFLOW_ENABLE
|
||||
bool "Trace Buffer Overflow Event"
|
||||
depends on SYSVIEW_ENABLE
|
||||
default y
|
||||
help
|
||||
Enables "Trace Buffer Overflow" event.
|
||||
|
||||
config SYSVIEW_EVT_ISR_ENTER_ENABLE
|
||||
bool "ISR Enter Event"
|
||||
depends on SYSVIEW_ENABLE
|
||||
default y
|
||||
help
|
||||
Enables "ISR Enter" event.
|
||||
|
||||
config SYSVIEW_EVT_ISR_EXIT_ENABLE
|
||||
bool "ISR Exit Event"
|
||||
depends on SYSVIEW_ENABLE
|
||||
default y
|
||||
help
|
||||
Enables "ISR Exit" event.
|
||||
|
||||
config SYSVIEW_EVT_ISR_TO_SCHEDULER_ENABLE
|
||||
bool "ISR Exit to Scheduler Event"
|
||||
depends on SYSVIEW_ENABLE
|
||||
default y
|
||||
help
|
||||
Enables "ISR to Scheduler" event.
|
||||
|
||||
config SYSVIEW_EVT_TASK_START_EXEC_ENABLE
|
||||
bool "Task Start Execution Event"
|
||||
depends on SYSVIEW_ENABLE
|
||||
default y
|
||||
help
|
||||
Enables "Task Start Execution" event.
|
||||
|
||||
config SYSVIEW_EVT_TASK_STOP_EXEC_ENABLE
|
||||
bool "Task Stop Execution Event"
|
||||
depends on SYSVIEW_ENABLE
|
||||
default y
|
||||
help
|
||||
Enables "Task Stop Execution" event.
|
||||
|
||||
config SYSVIEW_EVT_TASK_START_READY_ENABLE
|
||||
bool "Task Start Ready State Event"
|
||||
depends on SYSVIEW_ENABLE
|
||||
default y
|
||||
help
|
||||
Enables "Task Start Ready State" event.
|
||||
|
||||
config SYSVIEW_EVT_TASK_STOP_READY_ENABLE
|
||||
bool "Task Stop Ready State Event"
|
||||
depends on SYSVIEW_ENABLE
|
||||
default y
|
||||
help
|
||||
Enables "Task Stop Ready State" event.
|
||||
|
||||
config SYSVIEW_EVT_TASK_CREATE_ENABLE
|
||||
bool "Task Create Event"
|
||||
depends on SYSVIEW_ENABLE
|
||||
default y
|
||||
help
|
||||
Enables "Task Create" event.
|
||||
|
||||
config SYSVIEW_EVT_TASK_TERMINATE_ENABLE
|
||||
bool "Task Terminate Event"
|
||||
depends on SYSVIEW_ENABLE
|
||||
default y
|
||||
help
|
||||
Enables "Task Terminate" event.
|
||||
|
||||
config SYSVIEW_EVT_IDLE_ENABLE
|
||||
bool "System Idle Event"
|
||||
depends on SYSVIEW_ENABLE
|
||||
default y
|
||||
help
|
||||
Enables "System Idle" event.
|
||||
|
||||
config SYSVIEW_EVT_TIMER_ENTER_ENABLE
|
||||
bool "Timer Enter Event"
|
||||
depends on SYSVIEW_ENABLE
|
||||
default y
|
||||
help
|
||||
Enables "Timer Enter" event.
|
||||
|
||||
config SYSVIEW_EVT_TIMER_EXIT_ENABLE
|
||||
bool "Timer Exit Event"
|
||||
depends on SYSVIEW_ENABLE
|
||||
default y
|
||||
help
|
||||
Enables "Timer Exit" event.
|
||||
|
||||
endmenu
|
||||
|
||||
config ESP32_GCOV_ENABLE
|
||||
bool "GCOV to Host Enable"
|
||||
depends on ESP32_DEBUG_STUBS_ENABLE && ESP32_APPTRACE_ENABLE && !SYSVIEW_ENABLE
|
||||
default y
|
||||
help
|
||||
Enables support for GCOV data transfer to host.
|
||||
|
||||
endmenu
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,191 +0,0 @@
|
||||
// Copyright 2017 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_app_trace_util.h"
|
||||
#include "esp_clk.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////// TIMEOUT /////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define ESP_APPTRACE_CPUTICKS2US(_t_, _cpu_freq_) ((_t_)/(_cpu_freq_/1000000))
|
||||
#define ESP_APPTRACE_US2CPUTICKS(_t_, _cpu_freq_) ((_t_)*(_cpu_freq_/1000000))
|
||||
|
||||
esp_err_t esp_apptrace_tmo_check(esp_apptrace_tmo_t *tmo)
|
||||
{
|
||||
int cpu_freq = esp_clk_cpu_freq();
|
||||
if (tmo->tmo != ESP_APPTRACE_TMO_INFINITE) {
|
||||
unsigned cur = portGET_RUN_TIME_COUNTER_VALUE();
|
||||
if (tmo->start <= cur) {
|
||||
tmo->elapsed = ESP_APPTRACE_CPUTICKS2US(cur - tmo->start, cpu_freq);
|
||||
} else {
|
||||
tmo->elapsed = ESP_APPTRACE_CPUTICKS2US(0xFFFFFFFF - tmo->start + cur, cpu_freq);
|
||||
}
|
||||
if (tmo->elapsed >= tmo->tmo) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////// LOCK ////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
esp_err_t esp_apptrace_lock_take(esp_apptrace_lock_t *lock, esp_apptrace_tmo_t *tmo)
|
||||
{
|
||||
int res;
|
||||
|
||||
while (1) {
|
||||
// do not overwrite lock->int_state before we actually acquired the mux
|
||||
unsigned int_state = portENTER_CRITICAL_NESTED();
|
||||
// FIXME: if mux is busy it is not good idea to loop during the whole tmo with disabled IRQs.
|
||||
// So we check mux state using zero tmo, restore IRQs and let others tasks/IRQs to run on this CPU
|
||||
// while we are doing our own tmo check.
|
||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||
bool success = vPortCPUAcquireMutexTimeout(&lock->mux, 0, __FUNCTION__, __LINE__);
|
||||
#else
|
||||
bool success = vPortCPUAcquireMutexTimeout(&lock->mux, 0);
|
||||
#endif
|
||||
if (success) {
|
||||
lock->int_state = int_state;
|
||||
return ESP_OK;
|
||||
}
|
||||
portEXIT_CRITICAL_NESTED(int_state);
|
||||
// we can be preempted from this place till the next call (above) to portENTER_CRITICAL_NESTED()
|
||||
res = esp_apptrace_tmo_check(tmo);
|
||||
if (res != ESP_OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
esp_err_t esp_apptrace_lock_give(esp_apptrace_lock_t *lock)
|
||||
{
|
||||
// save lock's irq state value for this CPU
|
||||
unsigned int_state = lock->int_state;
|
||||
// after call to the following func we can not be sure that lock->int_state
|
||||
// is not overwritten by other CPU who has acquired the mux just after we released it. See esp_apptrace_lock_take().
|
||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||
vPortCPUReleaseMutex(&lock->mux, __FUNCTION__, __LINE__);
|
||||
#else
|
||||
vPortCPUReleaseMutex(&lock->mux);
|
||||
#endif
|
||||
portEXIT_CRITICAL_NESTED(int_state);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////// RING BUFFER ////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint8_t *esp_apptrace_rb_produce(esp_apptrace_rb_t *rb, uint32_t size)
|
||||
{
|
||||
uint8_t *ptr = rb->data + rb->wr;
|
||||
// check for avalable space
|
||||
if (rb->rd <= rb->wr) {
|
||||
// |?R......W??|
|
||||
if (rb->wr + size >= rb->size) {
|
||||
if (rb->rd == 0) {
|
||||
return NULL; // cannot wrap wr
|
||||
}
|
||||
if (rb->wr + size == rb->size) {
|
||||
rb->wr = 0;
|
||||
} else {
|
||||
// check if we can wrap wr earlier to get space for requested size
|
||||
if (size > rb->rd - 1) {
|
||||
return NULL; // cannot wrap wr
|
||||
}
|
||||
// shrink buffer a bit, full size will be restored at rd wrapping
|
||||
rb->cur_size = rb->wr;
|
||||
rb->wr = 0;
|
||||
ptr = rb->data;
|
||||
if (rb->rd == rb->cur_size) {
|
||||
rb->rd = 0;
|
||||
if (rb->cur_size < rb->size) {
|
||||
rb->cur_size = rb->size;
|
||||
}
|
||||
}
|
||||
rb->wr += size;
|
||||
}
|
||||
} else {
|
||||
rb->wr += size;
|
||||
}
|
||||
} else {
|
||||
// |?W......R??|
|
||||
if (size > rb->rd - rb->wr - 1) {
|
||||
return NULL;
|
||||
}
|
||||
rb->wr += size;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
uint8_t *esp_apptrace_rb_consume(esp_apptrace_rb_t *rb, uint32_t size)
|
||||
{
|
||||
uint8_t *ptr = rb->data + rb->rd;
|
||||
if (rb->rd <= rb->wr) {
|
||||
// |?R......W??|
|
||||
if (rb->rd + size > rb->wr) {
|
||||
return NULL;
|
||||
}
|
||||
rb->rd += size;
|
||||
} else {
|
||||
// |?W......R??|
|
||||
if (rb->rd + size > rb->cur_size) {
|
||||
return NULL;
|
||||
} else if (rb->rd + size == rb->cur_size) {
|
||||
// restore full size usage
|
||||
if (rb->cur_size < rb->size) {
|
||||
rb->cur_size = rb->size;
|
||||
}
|
||||
rb->rd = 0;
|
||||
} else {
|
||||
rb->rd += size;
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
uint32_t esp_apptrace_rb_read_size_get(esp_apptrace_rb_t *rb)
|
||||
{
|
||||
uint32_t size = 0;
|
||||
if (rb->rd <= rb->wr) {
|
||||
// |?R......W??|
|
||||
size = rb->wr - rb->rd;
|
||||
} else {
|
||||
// |?W......R??|
|
||||
size = rb->cur_size - rb->rd;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
uint32_t esp_apptrace_rb_write_size_get(esp_apptrace_rb_t *rb)
|
||||
{
|
||||
uint32_t size = 0;
|
||||
if (rb->rd <= rb->wr) {
|
||||
// |?R......W??|
|
||||
size = rb->size - rb->wr;
|
||||
if (size && rb->rd == 0) {
|
||||
size--;
|
||||
}
|
||||
} else {
|
||||
// |?W......R??|
|
||||
size = rb->rd - rb->wr - 1;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
#
|
||||
# Component Makefile
|
||||
#
|
||||
|
||||
COMPONENT_SRCDIRS := .
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS = include
|
||||
|
||||
COMPONENT_ADD_LDFLAGS = -lapp_trace
|
||||
|
||||
# do not produce gcov info for this module, it is used as transport for gcov
|
||||
CFLAGS := $(subst --coverage,,$(CFLAGS))
|
||||
|
||||
ifdef CONFIG_SYSVIEW_ENABLE
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS += \
|
||||
sys_view/Config \
|
||||
sys_view/SEGGER \
|
||||
sys_view/Sample/OS
|
||||
|
||||
COMPONENT_SRCDIRS += \
|
||||
gcov \
|
||||
sys_view/SEGGER \
|
||||
sys_view/Sample/OS \
|
||||
sys_view/Sample/Config \
|
||||
sys_view/esp32
|
||||
else
|
||||
COMPONENT_SRCDIRS += gcov
|
||||
endif
|
||||
|
||||
COMPONENT_ADD_LDFRAGMENTS += linker.lf
|
||||
@@ -1,195 +0,0 @@
|
||||
// Copyright 2017 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// 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.
|
||||
|
||||
// This module implements runtime file I/O API for GCOV.
|
||||
|
||||
#include "esp_task_wdt.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "soc/cpu.h"
|
||||
#include "soc/timer_group_struct.h"
|
||||
#include "soc/timer_group_reg.h"
|
||||
#include "esp_app_trace.h"
|
||||
#include "esp_dbg_stubs.h"
|
||||
|
||||
#if CONFIG_ESP32_GCOV_ENABLE
|
||||
|
||||
#define ESP_GCOV_DOWN_BUF_SIZE 4200
|
||||
|
||||
#define LOG_LOCAL_LEVEL CONFIG_LOG_DEFAULT_LEVEL
|
||||
#include "esp_log.h"
|
||||
const static char *TAG = "esp_gcov_rtio";
|
||||
|
||||
#if GCC_NOT_5_2_0
|
||||
void __gcov_dump(void);
|
||||
void __gcov_reset(void);
|
||||
#else
|
||||
/* The next code for old GCC */
|
||||
|
||||
static void (*s_gcov_exit)(void);
|
||||
/* Root of a program/shared-object state */
|
||||
struct gcov_root
|
||||
{
|
||||
void *list;
|
||||
unsigned dumped : 1; /* counts have been dumped. */
|
||||
unsigned run_counted : 1; /* run has been accounted for. */
|
||||
struct gcov_root *next;
|
||||
struct gcov_root *prev;
|
||||
};
|
||||
|
||||
/* Per-dynamic-object gcov state. */
|
||||
extern struct gcov_root __gcov_root;
|
||||
|
||||
static void esp_gcov_reset_status(void)
|
||||
{
|
||||
__gcov_root.dumped = 0;
|
||||
__gcov_root.run_counted = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static int esp_dbg_stub_gcov_dump_do(void)
|
||||
{
|
||||
int ret = ESP_OK;
|
||||
|
||||
ESP_EARLY_LOGV(TAG, "Alloc apptrace down buf %d bytes", ESP_GCOV_DOWN_BUF_SIZE);
|
||||
void *down_buf = malloc(ESP_GCOV_DOWN_BUF_SIZE);
|
||||
if (down_buf == NULL) {
|
||||
ESP_EARLY_LOGE(TAG, "Could not allocate memory for the buffer");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
ESP_EARLY_LOGV(TAG, "Config apptrace down buf");
|
||||
esp_apptrace_down_buffer_config(down_buf, ESP_GCOV_DOWN_BUF_SIZE);
|
||||
ESP_EARLY_LOGV(TAG, "Dump data...");
|
||||
#if GCC_NOT_5_2_0
|
||||
__gcov_dump();
|
||||
// reset dump status to allow incremental data accumulation
|
||||
__gcov_reset();
|
||||
#else
|
||||
ESP_EARLY_LOGV(TAG, "Check for dump handler %p", s_gcov_exit);
|
||||
if (s_gcov_exit) {
|
||||
s_gcov_exit();
|
||||
// reset dump status to allow incremental data accumulation
|
||||
esp_gcov_reset_status();
|
||||
}
|
||||
#endif
|
||||
ESP_EARLY_LOGV(TAG, "Free apptrace down buf");
|
||||
free(down_buf);
|
||||
ESP_EARLY_LOGV(TAG, "Finish file transfer session");
|
||||
ret = esp_apptrace_fstop(ESP_APPTRACE_DEST_TRAX);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_EARLY_LOGE(TAG, "Failed to send files transfer stop cmd (%d)!", ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Triggers gcov info dump.
|
||||
* This function is to be called by OpenOCD, not by normal user code.
|
||||
* TODO: what about interrupted flash access (when cache disabled)???
|
||||
*
|
||||
* @return ESP_OK on success, otherwise see esp_err_t
|
||||
*/
|
||||
static int esp_dbg_stub_gcov_entry(void)
|
||||
{
|
||||
#if GCC_NOT_5_2_0
|
||||
return esp_dbg_stub_gcov_dump_do();
|
||||
#else
|
||||
int ret = ESP_OK;
|
||||
// disable IRQs on this CPU, other CPU is halted by OpenOCD
|
||||
unsigned irq_state = portENTER_CRITICAL_NESTED();
|
||||
ret = esp_dbg_stub_gcov_dump_do();
|
||||
portEXIT_CRITICAL_NESTED(irq_state);
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
void esp_gcov_dump()
|
||||
{
|
||||
// disable IRQs on this CPU, other CPU is halted by OpenOCD
|
||||
unsigned irq_state = portENTER_CRITICAL_NESTED();
|
||||
#if !CONFIG_FREERTOS_UNICORE
|
||||
int other_core = xPortGetCoreID() ? 0 : 1;
|
||||
esp_cpu_stall(other_core);
|
||||
#endif
|
||||
while (!esp_apptrace_host_is_connected(ESP_APPTRACE_DEST_TRAX)) {
|
||||
// to avoid complains that task watchdog got triggered for other tasks
|
||||
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||
TIMERG0.wdt_feed=1;
|
||||
TIMERG0.wdt_wprotect=0;
|
||||
// to avoid reboot on INT_WDT
|
||||
TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||
TIMERG1.wdt_feed=1;
|
||||
TIMERG1.wdt_wprotect=0;
|
||||
}
|
||||
|
||||
esp_dbg_stub_gcov_dump_do();
|
||||
#if !CONFIG_FREERTOS_UNICORE
|
||||
esp_cpu_unstall(other_core);
|
||||
#endif
|
||||
portEXIT_CRITICAL_NESTED(irq_state);
|
||||
}
|
||||
|
||||
int gcov_rtio_atexit(void (*function)(void) __attribute__ ((unused)))
|
||||
{
|
||||
#if GCC_NOT_5_2_0
|
||||
ESP_EARLY_LOGV(TAG, "%s", __FUNCTION__);
|
||||
#else
|
||||
ESP_EARLY_LOGV(TAG, "%s %p", __FUNCTION__, function);
|
||||
s_gcov_exit = function;
|
||||
#endif
|
||||
esp_dbg_stub_entry_set(ESP_DBG_STUB_ENTRY_GCOV, (uint32_t)&esp_dbg_stub_gcov_entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *gcov_rtio_fopen(const char *path, const char *mode)
|
||||
{
|
||||
ESP_EARLY_LOGV(TAG, "%s '%s' '%s'", __FUNCTION__, path, mode);
|
||||
return esp_apptrace_fopen(ESP_APPTRACE_DEST_TRAX, path, mode);
|
||||
}
|
||||
|
||||
int gcov_rtio_fclose(void *stream)
|
||||
{
|
||||
ESP_EARLY_LOGV(TAG, "%s", __FUNCTION__);
|
||||
return esp_apptrace_fclose(ESP_APPTRACE_DEST_TRAX, stream);
|
||||
}
|
||||
|
||||
size_t gcov_rtio_fread(void *ptr, size_t size, size_t nmemb, void *stream)
|
||||
{
|
||||
ESP_EARLY_LOGV(TAG, "%s read %u", __FUNCTION__, size*nmemb);
|
||||
size_t sz = esp_apptrace_fread(ESP_APPTRACE_DEST_TRAX, ptr, size, nmemb, stream);
|
||||
ESP_EARLY_LOGV(TAG, "%s actually read %u", __FUNCTION__, sz);
|
||||
return sz;
|
||||
}
|
||||
|
||||
size_t gcov_rtio_fwrite(const void *ptr, size_t size, size_t nmemb, void *stream)
|
||||
{
|
||||
ESP_EARLY_LOGV(TAG, "%s", __FUNCTION__);
|
||||
return esp_apptrace_fwrite(ESP_APPTRACE_DEST_TRAX, ptr, size, nmemb, stream);
|
||||
}
|
||||
|
||||
int gcov_rtio_fseek(void *stream, long offset, int whence)
|
||||
{
|
||||
int ret = esp_apptrace_fseek(ESP_APPTRACE_DEST_TRAX, stream, offset, whence);
|
||||
ESP_EARLY_LOGV(TAG, "%s(%p %ld %d) = %d", __FUNCTION__, stream, offset, whence, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
long gcov_rtio_ftell(void *stream)
|
||||
{
|
||||
long ret = esp_apptrace_ftell(ESP_APPTRACE_DEST_TRAX, stream);
|
||||
ESP_EARLY_LOGV(TAG, "%s(%p) = %ld", __FUNCTION__, stream, ret);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
@@ -1,353 +0,0 @@
|
||||
// Copyright 2017 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Hot It Works
|
||||
// ************
|
||||
//
|
||||
// This module implements host file I/O protocol on top of apptrace module.
|
||||
// The protocol is enough simple. It sends command with arguments to the host and receives response from it.
|
||||
// Responses contains return values of respective file I/O API. This value is returned to the caller.
|
||||
// Commands has the following format:
|
||||
// * Header. See esp_apptrace_fcmd_hdr_t.
|
||||
// * Operation arguments. See file operation helper structures below.
|
||||
|
||||
#include <string.h>
|
||||
#include "esp_app_trace.h"
|
||||
|
||||
#if CONFIG_ESP32_APPTRACE_ENABLE
|
||||
|
||||
#define LOG_LOCAL_LEVEL CONFIG_LOG_DEFAULT_LEVEL
|
||||
#include "esp_log.h"
|
||||
const static char *TAG = "esp_host_file_io";
|
||||
|
||||
#define ESP_APPTRACE_FILE_CMD_FOPEN 0x0
|
||||
#define ESP_APPTRACE_FILE_CMD_FCLOSE 0x1
|
||||
#define ESP_APPTRACE_FILE_CMD_FWRITE 0x2
|
||||
#define ESP_APPTRACE_FILE_CMD_FREAD 0x3
|
||||
#define ESP_APPTRACE_FILE_CMD_FSEEK 0x4
|
||||
#define ESP_APPTRACE_FILE_CMD_FTELL 0x5
|
||||
#define ESP_APPTRACE_FILE_CMD_STOP 0x6 // indicates that there is no files to transfer
|
||||
|
||||
/** File operation header */
|
||||
typedef struct {
|
||||
uint8_t cmd; ///< Command ID
|
||||
} esp_apptrace_fcmd_hdr_t;
|
||||
|
||||
/** Helper structure for fopen */
|
||||
typedef struct {
|
||||
const char *path;
|
||||
uint16_t path_len;
|
||||
const char *mode;
|
||||
uint16_t mode_len;
|
||||
} esp_apptrace_fopen_args_t;
|
||||
|
||||
/** Helper structure for fclose */
|
||||
typedef struct {
|
||||
void *file;
|
||||
} esp_apptrace_fclose_args_t;
|
||||
|
||||
/** Helper structure for fwrite */
|
||||
typedef struct {
|
||||
void * buf;
|
||||
size_t size;
|
||||
void * file;
|
||||
} esp_apptrace_fwrite_args_t;
|
||||
|
||||
/** Helper structure for fread */
|
||||
typedef struct {
|
||||
size_t size;
|
||||
void * file;
|
||||
} esp_apptrace_fread_args_t;
|
||||
|
||||
/** Helper structure for fseek */
|
||||
typedef struct {
|
||||
long offset;
|
||||
int whence;
|
||||
void * file;
|
||||
} esp_apptrace_fseek_args_t;
|
||||
|
||||
/** Helper structure for ftell */
|
||||
typedef struct {
|
||||
void *file;
|
||||
} esp_apptrace_ftell_args_t;
|
||||
|
||||
static esp_err_t esp_apptrace_file_cmd_send(esp_apptrace_dest_t dest, uint8_t cmd, void (*prep_args)(uint8_t *, void *), void *args, uint32_t args_len)
|
||||
{
|
||||
esp_err_t ret;
|
||||
esp_apptrace_fcmd_hdr_t *hdr;
|
||||
|
||||
ESP_EARLY_LOGV(TAG, "%s %d", __func__, cmd);
|
||||
uint8_t *ptr = esp_apptrace_buffer_get(dest, sizeof(*hdr) + args_len, ESP_APPTRACE_TMO_INFINITE); //TODO: finite tmo
|
||||
if (ptr == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
hdr = (esp_apptrace_fcmd_hdr_t *)ptr;
|
||||
hdr->cmd = cmd;
|
||||
if (prep_args) {
|
||||
prep_args(ptr + sizeof(hdr->cmd), args);
|
||||
}
|
||||
|
||||
// now indicate that this buffer is ready to be sent off to host
|
||||
ret = esp_apptrace_buffer_put(dest, ptr, ESP_APPTRACE_TMO_INFINITE);//TODO: finite tmo
|
||||
if (ret != ESP_OK) {
|
||||
ESP_EARLY_LOGE(TAG, "Failed to put apptrace buffer (%d)!", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = esp_apptrace_flush(dest, ESP_APPTRACE_TMO_INFINITE);//TODO: finite tmo
|
||||
if (ret != ESP_OK) {
|
||||
ESP_EARLY_LOGE(TAG, "Failed to flush apptrace buffer (%d)!", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t esp_apptrace_file_rsp_recv(esp_apptrace_dest_t dest, uint8_t *buf, uint32_t buf_len)
|
||||
{
|
||||
uint32_t tot_rd = 0;
|
||||
while (tot_rd < buf_len) {
|
||||
uint32_t rd_size = buf_len - tot_rd;
|
||||
esp_err_t ret = esp_apptrace_read(dest, buf + tot_rd, &rd_size, ESP_APPTRACE_TMO_INFINITE); //TODO: finite tmo
|
||||
if (ret != ESP_OK) {
|
||||
ESP_EARLY_LOGE(TAG, "Failed to read (%d)!", ret);
|
||||
return ret;
|
||||
}
|
||||
ESP_EARLY_LOGV(TAG, "%s read %d bytes", __FUNCTION__, rd_size);
|
||||
tot_rd += rd_size;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void esp_apptrace_fopen_args_prepare(uint8_t *buf, void *priv)
|
||||
{
|
||||
esp_apptrace_fopen_args_t *args = priv;
|
||||
|
||||
memcpy(buf, args->path, args->path_len);
|
||||
memcpy(buf + args->path_len, args->mode, args->mode_len);
|
||||
}
|
||||
|
||||
void *esp_apptrace_fopen(esp_apptrace_dest_t dest, const char *path, const char *mode)
|
||||
{
|
||||
esp_apptrace_fopen_args_t cmd_args;
|
||||
|
||||
ESP_EARLY_LOGV(TAG, "esp_apptrace_fopen '%s' '%s'", path, mode);
|
||||
|
||||
cmd_args.path = path;
|
||||
cmd_args.path_len = strlen(path) + 1;
|
||||
cmd_args.mode = mode;
|
||||
cmd_args.mode_len = strlen(mode) + 1;
|
||||
|
||||
esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_FOPEN, esp_apptrace_fopen_args_prepare,
|
||||
&cmd_args, cmd_args.path_len+cmd_args.mode_len);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_EARLY_LOGE(TAG, "Failed to send file cmd (%d)!", ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// now read the answer
|
||||
void *resp;
|
||||
ret = esp_apptrace_file_rsp_recv(dest, (uint8_t *)&resp, sizeof(resp));
|
||||
if (ret != ESP_OK) {
|
||||
ESP_EARLY_LOGE(TAG, "Failed to read response (%d)!", ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
static void esp_apptrace_fclose_args_prepare(uint8_t *buf, void *priv)
|
||||
{
|
||||
esp_apptrace_fclose_args_t *args = priv;
|
||||
|
||||
memcpy(buf, &args->file, sizeof(args->file));
|
||||
}
|
||||
|
||||
int esp_apptrace_fclose(esp_apptrace_dest_t dest, void *stream)
|
||||
{
|
||||
esp_apptrace_fclose_args_t cmd_args;
|
||||
|
||||
cmd_args.file = stream;
|
||||
esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_FCLOSE, esp_apptrace_fclose_args_prepare,
|
||||
&cmd_args, sizeof(cmd_args));
|
||||
if (ret != ESP_OK) {
|
||||
ESP_EARLY_LOGE(TAG, "Failed to send file cmd (%d)!", ret);
|
||||
return EOF;
|
||||
}
|
||||
|
||||
// now read the answer
|
||||
int resp;
|
||||
ret = esp_apptrace_file_rsp_recv(dest, (uint8_t *)&resp, sizeof(resp));
|
||||
if (ret != ESP_OK) {
|
||||
ESP_EARLY_LOGE(TAG, "Failed to read response (%d)!", ret);
|
||||
return EOF;
|
||||
}
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
static void esp_apptrace_fwrite_args_prepare(uint8_t *buf, void *priv)
|
||||
{
|
||||
esp_apptrace_fwrite_args_t *args = priv;
|
||||
|
||||
memcpy(buf, &args->file, sizeof(args->file));
|
||||
memcpy(buf + sizeof(args->file), args->buf, args->size);
|
||||
}
|
||||
|
||||
size_t esp_apptrace_fwrite(esp_apptrace_dest_t dest, const void *ptr, size_t size, size_t nmemb, void *stream)
|
||||
{
|
||||
esp_apptrace_fwrite_args_t cmd_args;
|
||||
|
||||
ESP_EARLY_LOGV(TAG, "esp_apptrace_fwrite f %p l %d", stream, size*nmemb);
|
||||
|
||||
cmd_args.buf = (void *)ptr;
|
||||
cmd_args.size = size * nmemb;
|
||||
cmd_args.file = stream;
|
||||
esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_FWRITE, esp_apptrace_fwrite_args_prepare,
|
||||
&cmd_args, sizeof(cmd_args.file)+cmd_args.size);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_EARLY_LOGE(TAG, "Failed to send file cmd (%d)!", ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// now read the answer
|
||||
size_t resp;
|
||||
ret = esp_apptrace_file_rsp_recv(dest, (uint8_t *)&resp, sizeof(resp));
|
||||
if (ret != ESP_OK) {
|
||||
ESP_EARLY_LOGE(TAG, "Failed to read response (%d)!", ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
static void esp_apptrace_fread_args_prepare(uint8_t *buf, void *priv)
|
||||
{
|
||||
esp_apptrace_fread_args_t *args = priv;
|
||||
|
||||
memcpy(buf, &args->file, sizeof(args->file));
|
||||
memcpy(buf + sizeof(args->file), &args->size, sizeof(args->size));
|
||||
}
|
||||
|
||||
size_t esp_apptrace_fread(esp_apptrace_dest_t dest, void *ptr, size_t size, size_t nmemb, void *stream)
|
||||
{
|
||||
esp_apptrace_fread_args_t cmd_args;
|
||||
|
||||
ESP_EARLY_LOGV(TAG, "esp_apptrace_fread f %p l %d", stream, size*nmemb);
|
||||
|
||||
cmd_args.size = size * nmemb;
|
||||
cmd_args.file = stream;
|
||||
esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_FREAD, esp_apptrace_fread_args_prepare,
|
||||
&cmd_args, sizeof(cmd_args));
|
||||
if (ret != ESP_OK) {
|
||||
ESP_EARLY_LOGE(TAG, "Failed to send file cmd (%d)!", ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// now read the answer
|
||||
size_t resp;
|
||||
ret = esp_apptrace_file_rsp_recv(dest, (uint8_t *)&resp, sizeof(resp));
|
||||
if (ret != ESP_OK) {
|
||||
ESP_EARLY_LOGE(TAG, "Failed to read response (%d)!", ret);
|
||||
return 0;
|
||||
}
|
||||
if (resp > 0) {
|
||||
ret = esp_apptrace_file_rsp_recv(dest, ptr, resp);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_EARLY_LOGE(TAG, "Failed to read file data (%d)!", ret);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
|
||||
static void esp_apptrace_fseek_args_prepare(uint8_t *buf, void *priv)
|
||||
{
|
||||
esp_apptrace_fseek_args_t *args = priv;
|
||||
|
||||
memcpy(buf, &args->file, sizeof(args->file));
|
||||
memcpy(buf + sizeof(args->file), &args->offset, sizeof(args->offset));
|
||||
memcpy(buf + sizeof(args->file) + sizeof(args->offset), &args->whence, sizeof(args->whence));
|
||||
}
|
||||
|
||||
int esp_apptrace_fseek(esp_apptrace_dest_t dest, void *stream, long offset, int whence)
|
||||
{
|
||||
esp_apptrace_fseek_args_t cmd_args;
|
||||
|
||||
ESP_EARLY_LOGV(TAG, "esp_apptrace_fseek f %p o 0x%lx w %d", stream, offset, whence);
|
||||
|
||||
cmd_args.file = stream;
|
||||
cmd_args.offset = offset;
|
||||
cmd_args.whence = whence;
|
||||
esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_FSEEK, esp_apptrace_fseek_args_prepare,
|
||||
&cmd_args, sizeof(cmd_args));
|
||||
if (ret != ESP_OK) {
|
||||
ESP_EARLY_LOGE(TAG, "Failed to send file cmd (%d)!", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// now read the answer
|
||||
int resp;
|
||||
ret = esp_apptrace_file_rsp_recv(dest, (uint8_t *)&resp, sizeof(resp));
|
||||
if (ret != ESP_OK) {
|
||||
ESP_EARLY_LOGE(TAG, "Failed to read response (%d)!", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
static void esp_apptrace_ftell_args_prepare(uint8_t *buf, void *priv)
|
||||
{
|
||||
esp_apptrace_ftell_args_t *args = priv;
|
||||
|
||||
memcpy(buf, &args->file, sizeof(args->file));
|
||||
}
|
||||
|
||||
int esp_apptrace_ftell(esp_apptrace_dest_t dest, void *stream)
|
||||
{
|
||||
esp_apptrace_ftell_args_t cmd_args;
|
||||
|
||||
cmd_args.file = stream;
|
||||
esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_FTELL, esp_apptrace_ftell_args_prepare,
|
||||
&cmd_args, sizeof(cmd_args));
|
||||
if (ret != ESP_OK) {
|
||||
ESP_EARLY_LOGE(TAG, "Failed to send file cmd (%d)!", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// now read the answer
|
||||
int resp;
|
||||
ret = esp_apptrace_file_rsp_recv(dest, (uint8_t *)&resp, sizeof(resp));
|
||||
if (ret != ESP_OK) {
|
||||
ESP_EARLY_LOGE(TAG, "Failed to read response (%d)!", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
int esp_apptrace_fstop(esp_apptrace_dest_t dest)
|
||||
{
|
||||
ESP_EARLY_LOGV(TAG, "%s", __func__);
|
||||
esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_STOP, NULL, NULL, 0);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_EARLY_LOGE(TAG, "Failed to send files transfer stop cmd (%d)!", ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,265 +0,0 @@
|
||||
// Copyright 2017 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// 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.
|
||||
#ifndef ESP_APP_TRACE_H_
|
||||
#define ESP_APP_TRACE_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "esp_err.h"
|
||||
#include "esp_app_trace_util.h" // ESP_APPTRACE_TMO_INFINITE
|
||||
|
||||
/**
|
||||
* Application trace data destinations bits.
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_APPTRACE_DEST_TRAX = 0x1, ///< JTAG destination
|
||||
ESP_APPTRACE_DEST_UART0 = 0x2, ///< UART destination
|
||||
} esp_apptrace_dest_t;
|
||||
|
||||
/**
|
||||
* @brief Initializes application tracing module.
|
||||
*
|
||||
* @note Should be called before any esp_apptrace_xxx call.
|
||||
*
|
||||
* @return ESP_OK on success, otherwise see esp_err_t
|
||||
*/
|
||||
esp_err_t esp_apptrace_init();
|
||||
|
||||
/**
|
||||
* @brief Configures down buffer.
|
||||
* @note Needs to be called before initiating any data transfer using esp_apptrace_buffer_get and esp_apptrace_write.
|
||||
* This function does not protect internal data by lock.
|
||||
*
|
||||
* @param buf Address of buffer to use for down channel (host to target) data.
|
||||
* @param size Size of the buffer.
|
||||
*/
|
||||
void esp_apptrace_down_buffer_config(uint8_t *buf, uint32_t size);
|
||||
|
||||
/**
|
||||
* @brief Allocates buffer for trace data.
|
||||
* After data in buffer are ready to be sent off esp_apptrace_buffer_put must be called to indicate it.
|
||||
*
|
||||
* @param dest Indicates HW interface to send data.
|
||||
* @param size Size of data to write to trace buffer.
|
||||
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely.
|
||||
*
|
||||
* @return non-NULL on success, otherwise NULL.
|
||||
*/
|
||||
uint8_t *esp_apptrace_buffer_get(esp_apptrace_dest_t dest, uint32_t size, uint32_t tmo);
|
||||
|
||||
/**
|
||||
* @brief Indicates that the data in buffer are ready to be sent off.
|
||||
* This function is a counterpart of and must be preceeded by esp_apptrace_buffer_get.
|
||||
*
|
||||
* @param dest Indicates HW interface to send data. Should be identical to the same parameter in call to esp_apptrace_buffer_get.
|
||||
* @param ptr Address of trace buffer to release. Should be the value returned by call to esp_apptrace_buffer_get.
|
||||
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely.
|
||||
*
|
||||
* @return ESP_OK on success, otherwise see esp_err_t
|
||||
*/
|
||||
esp_err_t esp_apptrace_buffer_put(esp_apptrace_dest_t dest, uint8_t *ptr, uint32_t tmo);
|
||||
|
||||
/**
|
||||
* @brief Writes data to trace buffer.
|
||||
*
|
||||
* @param dest Indicates HW interface to send data.
|
||||
* @param data Address of data to write to trace buffer.
|
||||
* @param size Size of data to write to trace buffer.
|
||||
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely.
|
||||
*
|
||||
* @return ESP_OK on success, otherwise see esp_err_t
|
||||
*/
|
||||
esp_err_t esp_apptrace_write(esp_apptrace_dest_t dest, const void *data, uint32_t size, uint32_t tmo);
|
||||
|
||||
/**
|
||||
* @brief vprintf-like function to sent log messages to host via specified HW interface.
|
||||
*
|
||||
* @param dest Indicates HW interface to send data.
|
||||
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely.
|
||||
* @param fmt Address of format string.
|
||||
* @param ap List of arguments.
|
||||
*
|
||||
* @return Number of bytes written.
|
||||
*/
|
||||
int esp_apptrace_vprintf_to(esp_apptrace_dest_t dest, uint32_t tmo, const char *fmt, va_list ap);
|
||||
|
||||
/**
|
||||
* @brief vprintf-like function to sent log messages to host.
|
||||
*
|
||||
* @param fmt Address of format string.
|
||||
* @param ap List of arguments.
|
||||
*
|
||||
* @return Number of bytes written.
|
||||
*/
|
||||
int esp_apptrace_vprintf(const char *fmt, va_list ap);
|
||||
|
||||
/**
|
||||
* @brief Flushes remaining data in trace buffer to host.
|
||||
*
|
||||
* @param dest Indicates HW interface to flush data on.
|
||||
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely.
|
||||
*
|
||||
* @return ESP_OK on success, otherwise see esp_err_t
|
||||
*/
|
||||
esp_err_t esp_apptrace_flush(esp_apptrace_dest_t dest, uint32_t tmo);
|
||||
|
||||
/**
|
||||
* @brief Flushes remaining data in trace buffer to host without locking internal data.
|
||||
* This is special version of esp_apptrace_flush which should be called from panic handler.
|
||||
*
|
||||
* @param dest Indicates HW interface to flush data on.
|
||||
* @param min_sz Threshold for flushing data. If current filling level is above this value, data will be flushed. TRAX destinations only.
|
||||
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely.
|
||||
*
|
||||
* @return ESP_OK on success, otherwise see esp_err_t
|
||||
*/
|
||||
esp_err_t esp_apptrace_flush_nolock(esp_apptrace_dest_t dest, uint32_t min_sz, uint32_t tmo);
|
||||
|
||||
/**
|
||||
* @brief Reads host data from trace buffer.
|
||||
*
|
||||
* @param dest Indicates HW interface to read the data on.
|
||||
* @param data Address of buffer to put data from trace buffer.
|
||||
* @param size Pointer to store size of read data. Before call to this function pointed memory must hold requested size of data
|
||||
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely.
|
||||
*
|
||||
* @return ESP_OK on success, otherwise see esp_err_t
|
||||
*/
|
||||
esp_err_t esp_apptrace_read(esp_apptrace_dest_t dest, void *data, uint32_t *size, uint32_t tmo);
|
||||
|
||||
/**
|
||||
* @brief Retrieves incoming data buffer if any.
|
||||
* After data in buffer are processed esp_apptrace_down_buffer_put must be called to indicate it.
|
||||
*
|
||||
* @param dest Indicates HW interface to receive data.
|
||||
* @param size Address to store size of available data in down buffer. Must be initialized with requested value.
|
||||
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely.
|
||||
*
|
||||
* @return non-NULL on success, otherwise NULL.
|
||||
*/
|
||||
uint8_t *esp_apptrace_down_buffer_get(esp_apptrace_dest_t dest, uint32_t *size, uint32_t tmo);
|
||||
|
||||
/**
|
||||
* @brief Indicates that the data in down buffer are processed.
|
||||
* This function is a counterpart of and must be preceeded by esp_apptrace_down_buffer_get.
|
||||
*
|
||||
* @param dest Indicates HW interface to receive data. Should be identical to the same parameter in call to esp_apptrace_down_buffer_get.
|
||||
* @param ptr Address of trace buffer to release. Should be the value returned by call to esp_apptrace_down_buffer_get.
|
||||
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinitely.
|
||||
*
|
||||
* @return ESP_OK on success, otherwise see esp_err_t
|
||||
*/
|
||||
esp_err_t esp_apptrace_down_buffer_put(esp_apptrace_dest_t dest, uint8_t *ptr, uint32_t tmo);
|
||||
|
||||
/**
|
||||
* @brief Checks whether host is connected.
|
||||
*
|
||||
* @param dest Indicates HW interface to use.
|
||||
*
|
||||
* @return true if host is connected, otherwise false
|
||||
*/
|
||||
bool esp_apptrace_host_is_connected(esp_apptrace_dest_t dest);
|
||||
|
||||
/**
|
||||
* @brief Opens file on host.
|
||||
* This function has the same semantic as 'fopen' except for the first argument.
|
||||
*
|
||||
* @param dest Indicates HW interface to use.
|
||||
* @param path Path to file.
|
||||
* @param mode Mode string. See fopen for details.
|
||||
*
|
||||
* @return non zero file handle on success, otherwise 0
|
||||
*/
|
||||
void *esp_apptrace_fopen(esp_apptrace_dest_t dest, const char *path, const char *mode);
|
||||
|
||||
/**
|
||||
* @brief Closes file on host.
|
||||
* This function has the same semantic as 'fclose' except for the first argument.
|
||||
*
|
||||
* @param dest Indicates HW interface to use.
|
||||
* @param stream File handle returned by esp_apptrace_fopen.
|
||||
*
|
||||
* @return Zero on success, otherwise non-zero. See fclose for details.
|
||||
*/
|
||||
int esp_apptrace_fclose(esp_apptrace_dest_t dest, void *stream);
|
||||
|
||||
/**
|
||||
* @brief Writes to file on host.
|
||||
* This function has the same semantic as 'fwrite' except for the first argument.
|
||||
*
|
||||
* @param dest Indicates HW interface to use.
|
||||
* @param ptr Address of data to write.
|
||||
* @param size Size of an item.
|
||||
* @param nmemb Number of items to write.
|
||||
* @param stream File handle returned by esp_apptrace_fopen.
|
||||
*
|
||||
* @return Number of written items. See fwrite for details.
|
||||
*/
|
||||
size_t esp_apptrace_fwrite(esp_apptrace_dest_t dest, const void *ptr, size_t size, size_t nmemb, void *stream);
|
||||
|
||||
/**
|
||||
* @brief Read file on host.
|
||||
* This function has the same semantic as 'fread' except for the first argument.
|
||||
*
|
||||
* @param dest Indicates HW interface to use.
|
||||
* @param ptr Address to store read data.
|
||||
* @param size Size of an item.
|
||||
* @param nmemb Number of items to read.
|
||||
* @param stream File handle returned by esp_apptrace_fopen.
|
||||
*
|
||||
* @return Number of read items. See fread for details.
|
||||
*/
|
||||
size_t esp_apptrace_fread(esp_apptrace_dest_t dest, void *ptr, size_t size, size_t nmemb, void *stream);
|
||||
|
||||
/**
|
||||
* @brief Set position indicator in file on host.
|
||||
* This function has the same semantic as 'fseek' except for the first argument.
|
||||
*
|
||||
* @param dest Indicates HW interface to use.
|
||||
* @param stream File handle returned by esp_apptrace_fopen.
|
||||
* @param offset Offset. See fseek for details.
|
||||
* @param whence Position in file. See fseek for details.
|
||||
*
|
||||
* @return Zero on success, otherwise non-zero. See fseek for details.
|
||||
*/
|
||||
int esp_apptrace_fseek(esp_apptrace_dest_t dest, void *stream, long offset, int whence);
|
||||
|
||||
/**
|
||||
* @brief Get current position indicator for file on host.
|
||||
* This function has the same semantic as 'ftell' except for the first argument.
|
||||
*
|
||||
* @param dest Indicates HW interface to use.
|
||||
* @param stream File handle returned by esp_apptrace_fopen.
|
||||
*
|
||||
* @return Current position in file. See ftell for details.
|
||||
*/
|
||||
int esp_apptrace_ftell(esp_apptrace_dest_t dest, void *stream);
|
||||
|
||||
/**
|
||||
* @brief Indicates to the host that all file operations are completed.
|
||||
* This function should be called after all file operations are finished and
|
||||
* indicate to the host that it can perform cleanup operations (close open files etc.).
|
||||
*
|
||||
* @param dest Indicates HW interface to use.
|
||||
*
|
||||
* @return ESP_OK on success, otherwise see esp_err_t
|
||||
*/
|
||||
int esp_apptrace_fstop(esp_apptrace_dest_t dest);
|
||||
|
||||
/**
|
||||
* @brief Triggers gcov info dump.
|
||||
* This function waits for the host to connect to target before dumping data.
|
||||
*/
|
||||
void esp_gcov_dump(void);
|
||||
|
||||
#endif
|
||||
@@ -1,167 +0,0 @@
|
||||
// Copyright 2017 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// 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.
|
||||
#ifndef ESP_APP_TRACE_UTIL_H_
|
||||
#define ESP_APP_TRACE_UTIL_H_
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
/** Infinite waiting timeout */
|
||||
#define ESP_APPTRACE_TMO_INFINITE ((uint32_t)-1)
|
||||
|
||||
/** Structure which holds data necessary for measuring time intervals.
|
||||
*
|
||||
* After initialization via esp_apptrace_tmo_init() user needs to call esp_apptrace_tmo_check()
|
||||
* periodically to check timeout for expiration.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t start; ///< time interval start (in CPU ticks)
|
||||
uint32_t tmo; ///< timeout value (in us)
|
||||
uint32_t elapsed; ///< elapsed time (in us)
|
||||
} esp_apptrace_tmo_t;
|
||||
|
||||
/**
|
||||
* @brief Initializes timeout structure.
|
||||
*
|
||||
* @param tmo Pointer to timeout structure to be initialized.
|
||||
* @param user_tmo Timeout value (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly.
|
||||
*/
|
||||
static inline void esp_apptrace_tmo_init(esp_apptrace_tmo_t *tmo, uint32_t user_tmo)
|
||||
{
|
||||
tmo->start = portGET_RUN_TIME_COUNTER_VALUE();
|
||||
tmo->tmo = user_tmo;
|
||||
tmo->elapsed = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks timeout for expiration.
|
||||
*
|
||||
* @param tmo Pointer to timeout structure to be initialized.
|
||||
*
|
||||
* @return ESP_OK on success, otherwise \see esp_err_t
|
||||
*/
|
||||
esp_err_t esp_apptrace_tmo_check(esp_apptrace_tmo_t *tmo);
|
||||
|
||||
static inline uint32_t esp_apptrace_tmo_remaining_us(esp_apptrace_tmo_t *tmo)
|
||||
{
|
||||
return tmo->tmo != ESP_APPTRACE_TMO_INFINITE ? (tmo->elapsed - tmo->tmo) : ESP_APPTRACE_TMO_INFINITE;
|
||||
}
|
||||
|
||||
/** Tracing module synchronization lock */
|
||||
typedef struct {
|
||||
portMUX_TYPE mux;
|
||||
unsigned int_state;
|
||||
} esp_apptrace_lock_t;
|
||||
|
||||
/**
|
||||
* @brief Initializes lock structure.
|
||||
*
|
||||
* @param lock Pointer to lock structure to be initialized.
|
||||
*/
|
||||
static inline void esp_apptrace_lock_init(esp_apptrace_lock_t *lock)
|
||||
{
|
||||
vPortCPUInitializeMutex(&lock->mux);
|
||||
lock->int_state = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tries to acquire lock in specified time period.
|
||||
*
|
||||
* @param lock Pointer to lock structure.
|
||||
* @param tmo Pointer to timeout struct.
|
||||
*
|
||||
* @return ESP_OK on success, otherwise \see esp_err_t
|
||||
*/
|
||||
esp_err_t esp_apptrace_lock_take(esp_apptrace_lock_t *lock, esp_apptrace_tmo_t *tmo);
|
||||
|
||||
/**
|
||||
* @brief Releases lock.
|
||||
*
|
||||
* @param lock Pointer to lock structure.
|
||||
*
|
||||
* @return ESP_OK on success, otherwise \see esp_err_t
|
||||
*/
|
||||
esp_err_t esp_apptrace_lock_give(esp_apptrace_lock_t *lock);
|
||||
|
||||
/** Ring buffer control structure.
|
||||
*
|
||||
* @note For purposes of application tracing module if there is no enough space for user data and write pointer can be wrapped
|
||||
* current ring buffer size can be temporarily shrinked in order to provide buffer with requested size.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t *data; ///< pointer to data storage
|
||||
volatile uint32_t size; ///< size of data storage
|
||||
volatile uint32_t cur_size; ///< current size of data storage
|
||||
volatile uint32_t rd; ///< read pointer
|
||||
volatile uint32_t wr; ///< write pointer
|
||||
} esp_apptrace_rb_t;
|
||||
|
||||
/**
|
||||
* @brief Initializes ring buffer control structure.
|
||||
*
|
||||
* @param rb Pointer to ring buffer structure to be initialized.
|
||||
* @param data Pointer to buffer to be used as ring buffer's data storage.
|
||||
* @param size Size of buffer to be used as ring buffer's data storage.
|
||||
*/
|
||||
static inline void esp_apptrace_rb_init(esp_apptrace_rb_t *rb, uint8_t *data, uint32_t size)
|
||||
{
|
||||
rb->data = data;
|
||||
rb->size = rb->cur_size = size;
|
||||
rb->rd = 0;
|
||||
rb->wr = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocates memory chunk in ring buffer.
|
||||
*
|
||||
* @param rb Pointer to ring buffer structure.
|
||||
* @param size Size of the memory to allocate.
|
||||
*
|
||||
* @return Pointer to the allocated memory or NULL in case of failure.
|
||||
*/
|
||||
uint8_t *esp_apptrace_rb_produce(esp_apptrace_rb_t *rb, uint32_t size);
|
||||
|
||||
/**
|
||||
* @brief Consumes memory chunk in ring buffer.
|
||||
*
|
||||
* @param rb Pointer to ring buffer structure.
|
||||
* @param size Size of the memory to consume.
|
||||
*
|
||||
* @return Pointer to consumed memory chunk or NULL in case of failure.
|
||||
*/
|
||||
uint8_t *esp_apptrace_rb_consume(esp_apptrace_rb_t *rb, uint32_t size);
|
||||
|
||||
/**
|
||||
* @brief Gets size of memory which can consumed with single call to esp_apptrace_rb_consume().
|
||||
*
|
||||
* @param rb Pointer to ring buffer structure.
|
||||
*
|
||||
* @return Size of memory which can consumed.
|
||||
*
|
||||
* @note Due to read pointer wrapping returned size can be less then the total size of available data.
|
||||
*/
|
||||
uint32_t esp_apptrace_rb_read_size_get(esp_apptrace_rb_t *rb);
|
||||
|
||||
/**
|
||||
* @brief Gets size of memory which can produced with single call to esp_apptrace_rb_produce().
|
||||
*
|
||||
* @param rb Pointer to ring buffer structure.
|
||||
*
|
||||
* @return Size of memory which can produced.
|
||||
*
|
||||
* @note Due to write pointer wrapping returned size can be less then the total size of available data.
|
||||
*/
|
||||
uint32_t esp_apptrace_rb_write_size_get(esp_apptrace_rb_t *rb);
|
||||
|
||||
#endif //ESP_APP_TRACE_UTIL_H_
|
||||
@@ -1,12 +0,0 @@
|
||||
[mapping]
|
||||
archive: libapp_trace.a
|
||||
entries:
|
||||
* (noflash)
|
||||
|
||||
[mapping]
|
||||
archive: libdriver.a
|
||||
entries:
|
||||
: SYSVIEW_TS_SOURCE_TIMER_00 = y || SYSVIEW_TS_SOURCE_TIMER_01 = y
|
||||
|| SYSVIEW_TS_SOURCE_TIMER_10 = y || SYSVIEW_TS_SOURCE_TIMER_11 = y
|
||||
timer (noflash)
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
/*********************************************************************
|
||||
* SEGGER Microcontroller GmbH & Co. KG *
|
||||
* The Embedded Experts *
|
||||
**********************************************************************
|
||||
* *
|
||||
* (c) 2015 - 2017 SEGGER Microcontroller GmbH & Co. KG *
|
||||
* *
|
||||
* www.segger.com Support: support@segger.com *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* SEGGER SystemView * Real-time application analysis *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* SEGGER strongly recommends to not make any changes *
|
||||
* to or modify the source code of this software in order to stay *
|
||||
* compatible with the RTT protocol and J-Link. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or *
|
||||
* without modification, are permitted provided that the following *
|
||||
* conditions are met: *
|
||||
* *
|
||||
* o Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* o Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the following *
|
||||
* disclaimer in the documentation and/or other materials provided *
|
||||
* with the distribution. *
|
||||
* *
|
||||
* o Neither the name of SEGGER Microcontroller GmbH & Co. KG *
|
||||
* nor the names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without specific *
|
||||
* prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
|
||||
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
|
||||
* DAMAGE. *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* SystemView version: V2.42 *
|
||||
* *
|
||||
**********************************************************************
|
||||
----------------------------------------------------------------------
|
||||
File : Global.h
|
||||
Purpose : Global types
|
||||
In case your application already has a Global.h, you should
|
||||
merge the files. In order to use Segger code, the types
|
||||
U8, U16, U32, I8, I16, I32 need to be defined in Global.h;
|
||||
additional definitions do not hurt.
|
||||
---------------------------END-OF-HEADER------------------------------
|
||||
*/
|
||||
|
||||
#ifndef GLOBAL_H // Guard against multiple inclusion
|
||||
#define GLOBAL_H
|
||||
|
||||
#define U8 unsigned char
|
||||
#define U16 unsigned short
|
||||
#define U32 unsigned long
|
||||
#define I8 signed char
|
||||
#define I16 signed short
|
||||
#define I32 signed long
|
||||
|
||||
#ifdef _WIN32
|
||||
//
|
||||
// Microsoft VC6 compiler related
|
||||
//
|
||||
#define U64 unsigned __int64
|
||||
#define U128 unsigned __int128
|
||||
#define I64 __int64
|
||||
#define I128 __int128
|
||||
#if _MSC_VER <= 1200
|
||||
#define U64_C(x) x##UI64
|
||||
#else
|
||||
#define U64_C(x) x##ULL
|
||||
#endif
|
||||
#else
|
||||
//
|
||||
// C99 compliant compiler
|
||||
//
|
||||
#define U64 unsigned long long
|
||||
#define I64 signed long long
|
||||
#define U64_C(x) x##ULL
|
||||
#endif
|
||||
|
||||
#endif // Avoid multiple inclusion
|
||||
|
||||
/*************************** End of file ****************************/
|
||||
@@ -1,298 +0,0 @@
|
||||
/*********************************************************************
|
||||
* SEGGER Microcontroller GmbH & Co. KG *
|
||||
* The Embedded Experts *
|
||||
**********************************************************************
|
||||
* *
|
||||
* (c) 2015 - 2017 SEGGER Microcontroller GmbH & Co. KG *
|
||||
* *
|
||||
* www.segger.com Support: support@segger.com *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* SEGGER SystemView * Real-time application analysis *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* SEGGER strongly recommends to not make any changes *
|
||||
* to or modify the source code of this software in order to stay *
|
||||
* compatible with the RTT protocol and J-Link. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or *
|
||||
* without modification, are permitted provided that the following *
|
||||
* conditions are met: *
|
||||
* *
|
||||
* o Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* o Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the following *
|
||||
* disclaimer in the documentation and/or other materials provided *
|
||||
* with the distribution. *
|
||||
* *
|
||||
* o Neither the name of SEGGER Microcontroller GmbH & Co. KG *
|
||||
* nor the names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without specific *
|
||||
* prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
|
||||
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
|
||||
* DAMAGE. *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* SystemView version: V2.42 *
|
||||
* *
|
||||
**********************************************************************
|
||||
---------------------------END-OF-HEADER------------------------------
|
||||
File : SEGGER_RTT_Conf.h
|
||||
Purpose : Implementation of SEGGER real-time transfer (RTT) which
|
||||
allows real-time communication on targets which support
|
||||
debugger memory accesses while the CPU is running.
|
||||
Revision: $Rev: 5626 $
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SEGGER_RTT_CONF_H
|
||||
#define SEGGER_RTT_CONF_H
|
||||
|
||||
#ifdef __IAR_SYSTEMS_ICC__
|
||||
#include <intrinsics.h>
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Defines, configurable
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
#define SEGGER_RTT_MAX_NUM_UP_BUFFERS (3) // Max. number of up-buffers (T->H) available on this target (Default: 3)
|
||||
#define SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (3) // Max. number of down-buffers (H->T) available on this target (Default: 3)
|
||||
|
||||
#define BUFFER_SIZE_UP (1024) // Size of the buffer for terminal output of target, up to host (Default: 1k)
|
||||
#define BUFFER_SIZE_DOWN (16) // Size of the buffer for terminal input to target from host (Usually keyboard input) (Default: 16)
|
||||
|
||||
#define SEGGER_RTT_PRINTF_BUFFER_SIZE (64u) // Size of buffer for RTT printf to bulk-send chars via RTT (Default: 64)
|
||||
|
||||
#define SEGGER_RTT_MODE_DEFAULT SEGGER_RTT_MODE_NO_BLOCK_SKIP // Mode for pre-initialized terminal channel (buffer 0)
|
||||
|
||||
//
|
||||
// Target is not allowed to perform other RTT operations while string still has not been stored completely.
|
||||
// Otherwise we would probably end up with a mixed string in the buffer.
|
||||
// If using RTT from within interrupts, multiple tasks or multi processors, define the SEGGER_RTT_LOCK() and SEGGER_RTT_UNLOCK() function here.
|
||||
//
|
||||
// SEGGER_RTT_MAX_INTERRUPT_PRIORITY can be used in the sample lock routines on Cortex-M3/4.
|
||||
// Make sure to mask all interrupts which can send RTT data, i.e. generate SystemView events, or cause task switches.
|
||||
// When high-priority interrupts must not be masked while sending RTT data, SEGGER_RTT_MAX_INTERRUPT_PRIORITY needs to be adjusted accordingly.
|
||||
// (Higher priority = lower priority number)
|
||||
// Default value for embOS: 128u
|
||||
// Default configuration in FreeRTOS: configMAX_SYSCALL_INTERRUPT_PRIORITY: ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
|
||||
// In case of doubt mask all interrupts: 1 << (8 - BASEPRI_PRIO_BITS) i.e. 1 << 5 when 3 bits are implemented in NVIC
|
||||
// or define SEGGER_RTT_LOCK() to completely disable interrupts.
|
||||
//
|
||||
|
||||
#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) // Interrupt priority to lock on SEGGER_RTT_LOCK on Cortex-M3/4 (Default: 0x20)
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* RTT lock configuration for SEGGER Embedded Studio,
|
||||
* Rowley CrossStudio and GCC
|
||||
*/
|
||||
#if (defined __SES_ARM) || (defined __CROSSWORKS_ARM) || (defined __GNUC__)
|
||||
#ifdef __ARM_ARCH_6M__
|
||||
#define SEGGER_RTT_LOCK() { \
|
||||
unsigned int LockState; \
|
||||
__asm volatile ("mrs %0, primask \n\t" \
|
||||
"mov r1, $1 \n\t" \
|
||||
"msr primask, r1 \n\t" \
|
||||
: "=r" (LockState) \
|
||||
: \
|
||||
: "r1" \
|
||||
);
|
||||
|
||||
#define SEGGER_RTT_UNLOCK() __asm volatile ("msr primask, %0 \n\t" \
|
||||
: \
|
||||
: "r" (LockState) \
|
||||
: \
|
||||
); \
|
||||
}
|
||||
|
||||
#elif (defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__))
|
||||
#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
|
||||
#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20)
|
||||
#endif
|
||||
#define SEGGER_RTT_LOCK() { \
|
||||
unsigned int LockState; \
|
||||
__asm volatile ("mrs %0, basepri \n\t" \
|
||||
"mov r1, %1 \n\t" \
|
||||
"msr basepri, r1 \n\t" \
|
||||
: "=r" (LockState) \
|
||||
: "i"(SEGGER_RTT_MAX_INTERRUPT_PRIORITY) \
|
||||
: "r1" \
|
||||
);
|
||||
|
||||
#define SEGGER_RTT_UNLOCK() __asm volatile ("msr basepri, %0 \n\t" \
|
||||
: \
|
||||
: "r" (LockState) \
|
||||
: \
|
||||
); \
|
||||
}
|
||||
|
||||
#elif defined(__ARM_ARCH_7A__)
|
||||
#define SEGGER_RTT_LOCK() { \
|
||||
unsigned int LockState; \
|
||||
__asm volatile ("mrs r1, CPSR \n\t" \
|
||||
"mov %0, r1 \n\t" \
|
||||
"orr r1, r1, #0xC0 \n\t" \
|
||||
"msr CPSR_c, r1 \n\t" \
|
||||
: "=r" (LockState) \
|
||||
: \
|
||||
: "r1" \
|
||||
);
|
||||
|
||||
#define SEGGER_RTT_UNLOCK() __asm volatile ("mov r0, %0 \n\t" \
|
||||
"mrs r1, CPSR \n\t" \
|
||||
"bic r1, r1, #0xC0 \n\t" \
|
||||
"and r0, r0, #0xC0 \n\t" \
|
||||
"orr r1, r1, r0 \n\t" \
|
||||
"msr CPSR_c, r1 \n\t" \
|
||||
: \
|
||||
: "r" (LockState) \
|
||||
: "r0", "r1" \
|
||||
); \
|
||||
}
|
||||
#else
|
||||
#define SEGGER_RTT_LOCK()
|
||||
#define SEGGER_RTT_UNLOCK()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* RTT lock configuration for IAR EWARM
|
||||
*/
|
||||
#ifdef __ICCARM__
|
||||
#if (defined (__ARM6M__) && (__CORE__ == __ARM6M__))
|
||||
#define SEGGER_RTT_LOCK() { \
|
||||
unsigned int LockState; \
|
||||
LockState = __get_PRIMASK(); \
|
||||
__set_PRIMASK(1);
|
||||
|
||||
#define SEGGER_RTT_UNLOCK() __set_PRIMASK(LockState); \
|
||||
}
|
||||
#elif ((defined (__ARM7EM__) && (__CORE__ == __ARM7EM__)) || (defined (__ARM7M__) && (__CORE__ == __ARM7M__)))
|
||||
#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
|
||||
#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20)
|
||||
#endif
|
||||
#define SEGGER_RTT_LOCK() { \
|
||||
unsigned int LockState; \
|
||||
LockState = __get_BASEPRI(); \
|
||||
__set_BASEPRI(SEGGER_RTT_MAX_INTERRUPT_PRIORITY);
|
||||
|
||||
#define SEGGER_RTT_UNLOCK() __set_BASEPRI(LockState); \
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* RTT lock configuration for IAR RX
|
||||
*/
|
||||
#ifdef __ICCRX__
|
||||
#define SEGGER_RTT_LOCK() { \
|
||||
unsigned long LockState; \
|
||||
LockState = __get_interrupt_state(); \
|
||||
__disable_interrupt();
|
||||
|
||||
#define SEGGER_RTT_UNLOCK() __set_interrupt_state(LockState); \
|
||||
}
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* RTT lock configuration for KEIL ARM
|
||||
*/
|
||||
#ifdef __CC_ARM
|
||||
#if (defined __TARGET_ARCH_6S_M)
|
||||
#define SEGGER_RTT_LOCK() { \
|
||||
unsigned int LockState; \
|
||||
register unsigned char PRIMASK __asm( "primask"); \
|
||||
LockState = PRIMASK; \
|
||||
PRIMASK = 1u; \
|
||||
__schedule_barrier();
|
||||
|
||||
#define SEGGER_RTT_UNLOCK() PRIMASK = LockState; \
|
||||
__schedule_barrier(); \
|
||||
}
|
||||
#elif (defined(__TARGET_ARCH_7_M) || defined(__TARGET_ARCH_7E_M))
|
||||
#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
|
||||
#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20)
|
||||
#endif
|
||||
#define SEGGER_RTT_LOCK() { \
|
||||
unsigned int LockState; \
|
||||
register unsigned char BASEPRI __asm( "basepri"); \
|
||||
LockState = BASEPRI; \
|
||||
BASEPRI = SEGGER_RTT_MAX_INTERRUPT_PRIORITY; \
|
||||
__schedule_barrier();
|
||||
|
||||
#define SEGGER_RTT_UNLOCK() BASEPRI = LockState; \
|
||||
__schedule_barrier(); \
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* RTT lock configuration for TI ARM
|
||||
*/
|
||||
#ifdef __TI_ARM__
|
||||
#if defined (__TI_ARM_V6M0__)
|
||||
#define SEGGER_RTT_LOCK() { \
|
||||
unsigned int LockState; \
|
||||
LockState = __get_PRIMASK(); \
|
||||
__set_PRIMASK(1);
|
||||
|
||||
#define SEGGER_RTT_UNLOCK() __set_PRIMASK(LockState); \
|
||||
}
|
||||
#elif (defined (__TI_ARM_V7M3__) || defined (__TI_ARM_V7M4__))
|
||||
#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
|
||||
#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20)
|
||||
#endif
|
||||
#define SEGGER_RTT_LOCK() { \
|
||||
unsigned int LockState; \
|
||||
LockState = OS_GetBASEPRI(); \
|
||||
OS_SetBASEPRI(SEGGER_RTT_MAX_INTERRUPT_PRIORITY);
|
||||
|
||||
#define SEGGER_RTT_UNLOCK() OS_SetBASEPRI(LockState); \
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* RTT lock configuration fallback
|
||||
*/
|
||||
#ifndef SEGGER_RTT_LOCK
|
||||
void SEGGER_SYSVIEW_X_RTT_Lock();
|
||||
#define SEGGER_RTT_LOCK() SEGGER_SYSVIEW_X_RTT_Lock() // Lock RTT (nestable) (i.e. disable interrupts)
|
||||
#endif
|
||||
|
||||
#ifndef SEGGER_RTT_UNLOCK
|
||||
void SEGGER_SYSVIEW_X_RTT_Unlock();
|
||||
#define SEGGER_RTT_UNLOCK() SEGGER_SYSVIEW_X_RTT_Unlock() // Unlock RTT (nestable) (i.e. enable previous interrupt lock state)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/*************************** End of file ****************************/
|
||||
@@ -1,177 +0,0 @@
|
||||
/*********************************************************************
|
||||
* SEGGER Microcontroller GmbH & Co. KG *
|
||||
* The Embedded Experts *
|
||||
**********************************************************************
|
||||
* *
|
||||
* (c) 2015 - 2017 SEGGER Microcontroller GmbH & Co. KG *
|
||||
* *
|
||||
* www.segger.com Support: support@segger.com *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* SEGGER SystemView * Real-time application analysis *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* SEGGER strongly recommends to not make any changes *
|
||||
* to or modify the source code of this software in order to stay *
|
||||
* compatible with the RTT protocol and J-Link. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or *
|
||||
* without modification, are permitted provided that the following *
|
||||
* conditions are met: *
|
||||
* *
|
||||
* o Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* o Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the following *
|
||||
* disclaimer in the documentation and/or other materials provided *
|
||||
* with the distribution. *
|
||||
* *
|
||||
* o Neither the name of SEGGER Microcontroller GmbH & Co. KG *
|
||||
* nor the names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without specific *
|
||||
* prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
|
||||
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
|
||||
* DAMAGE. *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* SystemView version: V2.42 *
|
||||
* *
|
||||
**********************************************************************
|
||||
-------------------------- END-OF-HEADER -----------------------------
|
||||
|
||||
File : SEGGER_SYSVIEW_Conf.h
|
||||
Purpose : SEGGER SystemView configuration.
|
||||
Revision: $Rev: 5927 $
|
||||
*/
|
||||
|
||||
#ifndef SEGGER_SYSVIEW_CONF_H
|
||||
#define SEGGER_SYSVIEW_CONF_H
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Defines, fixed
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
//
|
||||
// Constants for known core configuration
|
||||
//
|
||||
#define SEGGER_SYSVIEW_CORE_OTHER 0
|
||||
#define SEGGER_SYSVIEW_CORE_CM0 1 // Cortex-M0/M0+/M1
|
||||
#define SEGGER_SYSVIEW_CORE_CM3 2 // Cortex-M3/M4/M7
|
||||
#define SEGGER_SYSVIEW_CORE_RX 3 // Renesas RX
|
||||
|
||||
#if (defined __SES_ARM) || (defined __CROSSWORKS_ARM) || (defined __GNUC__)
|
||||
#ifdef __ARM_ARCH_6M__
|
||||
#define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_CM0
|
||||
#elif (defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__))
|
||||
#define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_CM3
|
||||
#endif
|
||||
#elif defined(__ICCARM__)
|
||||
#if (defined (__ARM6M__) && (__CORE__ == __ARM6M__))
|
||||
#define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_CM0
|
||||
#elif ((defined (__ARM7M__) && (__CORE__ == __ARM7M__)) || (defined (__ARM7EM__) && (__CORE__ == __ARM7EM__)))
|
||||
#define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_CM3
|
||||
#endif
|
||||
#elif defined(__CC_ARM)
|
||||
#if (defined(__TARGET_ARCH_6S_M))
|
||||
#define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_CM0
|
||||
#elif (defined(__TARGET_ARCH_7_M) || defined(__TARGET_ARCH_7E_M))
|
||||
#define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_CM3
|
||||
#endif
|
||||
#elif defined(__TI_ARM__)
|
||||
#ifdef __TI_ARM_V6M0__
|
||||
#define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_CM0
|
||||
#elif (defined(__TI_ARM_V7M3__) || defined(__TI_ARM_V7M4__))
|
||||
#define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_CM3
|
||||
#endif
|
||||
#elif defined(__ICCRX__)
|
||||
#define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_RX
|
||||
#elif defined(__RX)
|
||||
#define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_RX
|
||||
#endif
|
||||
|
||||
#ifndef SEGGER_SYSVIEW_CORE
|
||||
#define SEGGER_SYSVIEW_CORE SEGGER_SYSVIEW_CORE_OTHER
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Defines, configurable
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
/*********************************************************************
|
||||
*
|
||||
* SystemView buffer configuration
|
||||
*/
|
||||
#define SEGGER_SYSVIEW_RTT_BUFFER_SIZE 1024 // Number of bytes that SystemView uses for the buffer.
|
||||
#define SEGGER_SYSVIEW_RTT_CHANNEL 1 // The RTT channel that SystemView will use. 0: Auto selection
|
||||
|
||||
#define SEGGER_SYSVIEW_USE_STATIC_BUFFER 1 // Use a static buffer to generate events instead of a buffer on the stack
|
||||
|
||||
#define SEGGER_SYSVIEW_POST_MORTEM_MODE 0 // 1: Enable post mortem analysis mode
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* SystemView timestamp configuration
|
||||
*/
|
||||
#if SEGGER_SYSVIEW_CORE == SEGGER_SYSVIEW_CORE_CM3
|
||||
#define SEGGER_SYSVIEW_GET_TIMESTAMP() (*(U32 *)(0xE0001004)) // Retrieve a system timestamp. Cortex-M cycle counter.
|
||||
#define SEGGER_SYSVIEW_TIMESTAMP_BITS 32 // Define number of valid bits low-order delivered by clock source
|
||||
#else
|
||||
#define SEGGER_SYSVIEW_GET_TIMESTAMP() SEGGER_SYSVIEW_X_GetTimestamp() // Retrieve a system timestamp via user-defined function
|
||||
#define SEGGER_SYSVIEW_TIMESTAMP_BITS 32 // Define number of valid bits low-order delivered by SEGGER_SYSVIEW_X_GetTimestamp()
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* SystemView Id configuration
|
||||
*/
|
||||
//TODO: optimise it
|
||||
#define SEGGER_SYSVIEW_ID_BASE 0x3F400000 // Default value for the lowest Id reported by the application. Can be overridden by the application via SEGGER_SYSVIEW_SetRAMBase(). (i.e. 0x20000000 when all Ids are an address in this RAM)
|
||||
#define SEGGER_SYSVIEW_ID_SHIFT 0 // Number of bits to shift the Id to save bandwidth. (i.e. 2 when Ids are 4 byte aligned)
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* SystemView interrupt configuration
|
||||
*/
|
||||
#if SEGGER_SYSVIEW_CORE == SEGGER_SYSVIEW_CORE_CM3
|
||||
#define SEGGER_SYSVIEW_GET_INTERRUPT_ID() ((*(U32 *)(0xE000ED04)) & 0x1FF) // Get the currently active interrupt Id. (i.e. read Cortex-M ICSR[8:0] = active vector)
|
||||
#elif SEGGER_SYSVIEW_CORE == SEGGER_SYSVIEW_CORE_CM0
|
||||
#if defined(__ICCARM__)
|
||||
#define SEGGER_SYSVIEW_GET_INTERRUPT_ID() (__get_IPSR()) // Workaround for IAR, which might do a byte-access to 0xE000ED04. Read IPSR instead.
|
||||
#else
|
||||
#define SEGGER_SYSVIEW_GET_INTERRUPT_ID() ((*(U32 *)(0xE000ED04)) & 0x3F) // Get the currently active interrupt Id. (i.e. read Cortex-M ICSR[5:0] = active vector)
|
||||
#endif
|
||||
#else
|
||||
#define SEGGER_SYSVIEW_GET_INTERRUPT_ID() SEGGER_SYSVIEW_X_GetInterruptId() // Get the currently active interrupt Id from the user-provided function.
|
||||
#endif
|
||||
|
||||
unsigned SEGGER_SYSVIEW_X_SysView_Lock();
|
||||
void SEGGER_SYSVIEW_X_SysView_Unlock(unsigned int_state);
|
||||
// to be recursive save IRQ status on the stack of the caller
|
||||
#define SEGGER_SYSVIEW_LOCK() unsigned _SYSVIEW_int_state = SEGGER_SYSVIEW_X_SysView_Lock()
|
||||
#define SEGGER_SYSVIEW_UNLOCK() SEGGER_SYSVIEW_X_SysView_Unlock(_SYSVIEW_int_state)
|
||||
|
||||
#endif // SEGGER_SYSVIEW_CONF_H
|
||||
|
||||
/*************************** End of file ****************************/
|
||||
@@ -1,155 +0,0 @@
|
||||
/*********************************************************************
|
||||
* SEGGER Microcontroller GmbH & Co. KG *
|
||||
* The Embedded Experts *
|
||||
**********************************************************************
|
||||
* *
|
||||
* (c) 2015 - 2017 SEGGER Microcontroller GmbH & Co. KG *
|
||||
* *
|
||||
* www.segger.com Support: support@segger.com *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* SEGGER SystemView * Real-time application analysis *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* SEGGER strongly recommends to not make any changes *
|
||||
* to or modify the source code of this software in order to stay *
|
||||
* compatible with the RTT protocol and J-Link. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or *
|
||||
* without modification, are permitted provided that the following *
|
||||
* conditions are met: *
|
||||
* *
|
||||
* o Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* o Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the following *
|
||||
* disclaimer in the documentation and/or other materials provided *
|
||||
* with the distribution. *
|
||||
* *
|
||||
* o Neither the name of SEGGER Microcontroller GmbH & Co. KG *
|
||||
* nor the names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without specific *
|
||||
* prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
|
||||
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
|
||||
* DAMAGE. *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* SystemView version: V2.42 *
|
||||
* *
|
||||
**********************************************************************
|
||||
----------------------------------------------------------------------
|
||||
File : SEGGER.h
|
||||
Purpose : Global types etc & general purpose utility functions
|
||||
---------------------------END-OF-HEADER------------------------------
|
||||
*/
|
||||
|
||||
#ifndef SEGGER_H // Guard against multiple inclusion
|
||||
#define SEGGER_H
|
||||
|
||||
#include "Global.h" // Type definitions: U8, U16, U32, I8, I16, I32
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" { /* Make sure we have C-declarations in C++ programs */
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Keywords/specifiers
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
#ifndef INLINE
|
||||
#ifdef _WIN32
|
||||
//
|
||||
// Microsoft VC6 and newer.
|
||||
// Force inlining without cost checking.
|
||||
//
|
||||
#define INLINE __forceinline
|
||||
#else
|
||||
#if (defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__) || defined(__RX) || defined(__ICCRX__))
|
||||
//
|
||||
// Other known compilers.
|
||||
//
|
||||
#define INLINE inline
|
||||
#else
|
||||
//
|
||||
// Unknown compilers.
|
||||
//
|
||||
#define INLINE
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Function-like macros
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
#define SEGGER_COUNTOF(a) (sizeof((a))/sizeof((a)[0]))
|
||||
#define SEGGER_MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#define SEGGER_MAX(a,b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Types
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
char *pBuffer;
|
||||
int BufferSize;
|
||||
int Cnt;
|
||||
} SEGGER_BUFFER_DESC;
|
||||
|
||||
typedef struct {
|
||||
int CacheLineSize; // 0: No Cache. Most Systems such as ARM9 use a 32 bytes cache line size.
|
||||
void (*pfDMB) (void); // Optional DMB function for Data Memory Barrier to make sure all memory operations are completed.
|
||||
void (*pfClean) (void *p, unsigned NumBytes); // Optional clean function for cached memory.
|
||||
void (*pfInvalidate)(void *p, unsigned NumBytes); // Optional invalidate function for cached memory.
|
||||
} SEGGER_CACHE_CONFIG;
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Utility functions
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
void SEGGER_ARM_memcpy (void *pDest, const void *pSrc, int NumBytes);
|
||||
void SEGGER_memcpy (void *pDest, const void *pSrc, int NumBytes);
|
||||
void SEGGER_memxor (void *pDest, const void *pSrc, unsigned NumBytes);
|
||||
void SEGGER_StoreChar (SEGGER_BUFFER_DESC *p, char c);
|
||||
void SEGGER_PrintUnsigned(SEGGER_BUFFER_DESC *pBufferDesc, U32 v, unsigned Base, int NumDigits);
|
||||
void SEGGER_PrintInt (SEGGER_BUFFER_DESC *pBufferDesc, I32 v, unsigned Base, unsigned NumDigits);
|
||||
int SEGGER_snprintf (char *pBuffer, int BufferSize, const char *sFormat, ...);
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} /* Make sure we have C-declarations in C++ programs */
|
||||
#endif
|
||||
|
||||
#endif // Avoid multiple inclusion
|
||||
|
||||
/*************************** End of file ****************************/
|
||||
@@ -1,251 +0,0 @@
|
||||
/*********************************************************************
|
||||
* SEGGER Microcontroller GmbH & Co. KG *
|
||||
* The Embedded Experts *
|
||||
**********************************************************************
|
||||
* *
|
||||
* (c) 2015 - 2017 SEGGER Microcontroller GmbH & Co. KG *
|
||||
* *
|
||||
* www.segger.com Support: support@segger.com *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* SEGGER SystemView * Real-time application analysis *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* SEGGER strongly recommends to not make any changes *
|
||||
* to or modify the source code of this software in order to stay *
|
||||
* compatible with the RTT protocol and J-Link. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or *
|
||||
* without modification, are permitted provided that the following *
|
||||
* conditions are met: *
|
||||
* *
|
||||
* o Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* o Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the following *
|
||||
* disclaimer in the documentation and/or other materials provided *
|
||||
* with the distribution. *
|
||||
* *
|
||||
* o Neither the name of SEGGER Microcontroller GmbH & Co. KG *
|
||||
* nor the names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without specific *
|
||||
* prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
|
||||
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
|
||||
* DAMAGE. *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* SystemView version: V2.42 *
|
||||
* *
|
||||
**********************************************************************
|
||||
---------------------------END-OF-HEADER------------------------------
|
||||
File : SEGGER_RTT.h
|
||||
Purpose : Implementation of SEGGER real-time transfer which allows
|
||||
real-time communication on targets which support debugger
|
||||
memory accesses while the CPU is running.
|
||||
Revision: $Rev: 5626 $
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef SEGGER_RTT_H
|
||||
#define SEGGER_RTT_H
|
||||
|
||||
#include "SEGGER_RTT_Conf.h"
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Defines, fixed
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Types
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
//
|
||||
// Description for a circular buffer (also called "ring buffer")
|
||||
// which is used as up-buffer (T->H)
|
||||
//
|
||||
typedef struct {
|
||||
const char* sName; // Optional name. Standard names so far are: "Terminal", "SysView", "J-Scope_t4i4"
|
||||
char* pBuffer; // Pointer to start of buffer
|
||||
unsigned SizeOfBuffer; // Buffer size in bytes. Note that one byte is lost, as this implementation does not fill up the buffer in order to avoid the problem of being unable to distinguish between full and empty.
|
||||
unsigned WrOff; // Position of next item to be written by either target.
|
||||
volatile unsigned RdOff; // Position of next item to be read by host. Must be volatile since it may be modified by host.
|
||||
unsigned Flags; // Contains configuration flags
|
||||
} SEGGER_RTT_BUFFER_UP;
|
||||
|
||||
//
|
||||
// Description for a circular buffer (also called "ring buffer")
|
||||
// which is used as down-buffer (H->T)
|
||||
//
|
||||
typedef struct {
|
||||
const char* sName; // Optional name. Standard names so far are: "Terminal", "SysView", "J-Scope_t4i4"
|
||||
char* pBuffer; // Pointer to start of buffer
|
||||
unsigned SizeOfBuffer; // Buffer size in bytes. Note that one byte is lost, as this implementation does not fill up the buffer in order to avoid the problem of being unable to distinguish between full and empty.
|
||||
volatile unsigned WrOff; // Position of next item to be written by host. Must be volatile since it may be modified by host.
|
||||
unsigned RdOff; // Position of next item to be read by target (down-buffer).
|
||||
unsigned Flags; // Contains configuration flags
|
||||
} SEGGER_RTT_BUFFER_DOWN;
|
||||
|
||||
//
|
||||
// RTT control block which describes the number of buffers available
|
||||
// as well as the configuration for each buffer
|
||||
//
|
||||
//
|
||||
typedef struct {
|
||||
char acID[16]; // Initialized to "SEGGER RTT"
|
||||
int MaxNumUpBuffers; // Initialized to SEGGER_RTT_MAX_NUM_UP_BUFFERS (type. 2)
|
||||
int MaxNumDownBuffers; // Initialized to SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (type. 2)
|
||||
SEGGER_RTT_BUFFER_UP aUp[SEGGER_RTT_MAX_NUM_UP_BUFFERS]; // Up buffers, transferring information up from target via debug probe to host
|
||||
SEGGER_RTT_BUFFER_DOWN aDown[SEGGER_RTT_MAX_NUM_DOWN_BUFFERS]; // Down buffers, transferring information down from host via debug probe to target
|
||||
} SEGGER_RTT_CB;
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Global data
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
extern SEGGER_RTT_CB _SEGGER_RTT;
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* RTT API functions
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
int SEGGER_RTT_AllocDownBuffer (const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags);
|
||||
int SEGGER_RTT_AllocUpBuffer (const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags);
|
||||
int SEGGER_RTT_ConfigUpBuffer (unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags);
|
||||
int SEGGER_RTT_ConfigDownBuffer (unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags);
|
||||
int SEGGER_RTT_GetKey (void);
|
||||
unsigned SEGGER_RTT_HasData (unsigned BufferIndex);
|
||||
int SEGGER_RTT_HasKey (void);
|
||||
void SEGGER_RTT_Init (void);
|
||||
unsigned SEGGER_RTT_Read (unsigned BufferIndex, void* pBuffer, unsigned BufferSize);
|
||||
unsigned SEGGER_RTT_ReadNoLock (unsigned BufferIndex, void* pData, unsigned BufferSize);
|
||||
int SEGGER_RTT_SetNameDownBuffer (unsigned BufferIndex, const char* sName);
|
||||
int SEGGER_RTT_SetNameUpBuffer (unsigned BufferIndex, const char* sName);
|
||||
int SEGGER_RTT_SetFlagsDownBuffer (unsigned BufferIndex, unsigned Flags);
|
||||
int SEGGER_RTT_SetFlagsUpBuffer (unsigned BufferIndex, unsigned Flags);
|
||||
int SEGGER_RTT_WaitKey (void);
|
||||
unsigned SEGGER_RTT_Write (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
|
||||
unsigned SEGGER_RTT_WriteNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
|
||||
unsigned SEGGER_RTT_WriteSkipNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
|
||||
unsigned SEGGER_RTT_WriteString (unsigned BufferIndex, const char* s);
|
||||
void SEGGER_RTT_WriteWithOverwriteNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
|
||||
void SEGGER_RTT_ESP32_FlushNoLock (unsigned long min_sz, unsigned long tmo);
|
||||
//
|
||||
// Function macro for performance optimization
|
||||
//
|
||||
// @AGv: This macro is used inside SEGGER SystemView code.
|
||||
// For ESP32 we use our own implementation of RTT, so this macro should not check SEGGER's RTT buffer state.
|
||||
#define SEGGER_RTT_HASDATA(n) (1)
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* RTT "Terminal" API functions
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
int SEGGER_RTT_SetTerminal (char TerminalId);
|
||||
int SEGGER_RTT_TerminalOut (char TerminalId, const char* s);
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* RTT printf functions (require SEGGER_RTT_printf.c)
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Defines
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
//
|
||||
// Operating modes. Define behavior if buffer is full (not enough space for entire message)
|
||||
//
|
||||
#define SEGGER_RTT_MODE_NO_BLOCK_SKIP (0U) // Skip. Do not block, output nothing. (Default)
|
||||
#define SEGGER_RTT_MODE_NO_BLOCK_TRIM (1U) // Trim: Do not block, output as much as fits.
|
||||
#define SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL (2U) // Block: Wait until there is space in the buffer.
|
||||
#define SEGGER_RTT_MODE_MASK (3U)
|
||||
|
||||
//
|
||||
// Control sequences, based on ANSI.
|
||||
// Can be used to control color, and clear the screen
|
||||
//
|
||||
#define RTT_CTRL_RESET "[0m" // Reset to default colors
|
||||
#define RTT_CTRL_CLEAR "[2J" // Clear screen, reposition cursor to top left
|
||||
|
||||
#define RTT_CTRL_TEXT_BLACK "[2;30m"
|
||||
#define RTT_CTRL_TEXT_RED "[2;31m"
|
||||
#define RTT_CTRL_TEXT_GREEN "[2;32m"
|
||||
#define RTT_CTRL_TEXT_YELLOW "[2;33m"
|
||||
#define RTT_CTRL_TEXT_BLUE "[2;34m"
|
||||
#define RTT_CTRL_TEXT_MAGENTA "[2;35m"
|
||||
#define RTT_CTRL_TEXT_CYAN "[2;36m"
|
||||
#define RTT_CTRL_TEXT_WHITE "[2;37m"
|
||||
|
||||
#define RTT_CTRL_TEXT_BRIGHT_BLACK "[1;30m"
|
||||
#define RTT_CTRL_TEXT_BRIGHT_RED "[1;31m"
|
||||
#define RTT_CTRL_TEXT_BRIGHT_GREEN "[1;32m"
|
||||
#define RTT_CTRL_TEXT_BRIGHT_YELLOW "[1;33m"
|
||||
#define RTT_CTRL_TEXT_BRIGHT_BLUE "[1;34m"
|
||||
#define RTT_CTRL_TEXT_BRIGHT_MAGENTA "[1;35m"
|
||||
#define RTT_CTRL_TEXT_BRIGHT_CYAN "[1;36m"
|
||||
#define RTT_CTRL_TEXT_BRIGHT_WHITE "[1;37m"
|
||||
|
||||
#define RTT_CTRL_BG_BLACK "[24;40m"
|
||||
#define RTT_CTRL_BG_RED "[24;41m"
|
||||
#define RTT_CTRL_BG_GREEN "[24;42m"
|
||||
#define RTT_CTRL_BG_YELLOW "[24;43m"
|
||||
#define RTT_CTRL_BG_BLUE "[24;44m"
|
||||
#define RTT_CTRL_BG_MAGENTA "[24;45m"
|
||||
#define RTT_CTRL_BG_CYAN "[24;46m"
|
||||
#define RTT_CTRL_BG_WHITE "[24;47m"
|
||||
|
||||
#define RTT_CTRL_BG_BRIGHT_BLACK "[4;40m"
|
||||
#define RTT_CTRL_BG_BRIGHT_RED "[4;41m"
|
||||
#define RTT_CTRL_BG_BRIGHT_GREEN "[4;42m"
|
||||
#define RTT_CTRL_BG_BRIGHT_YELLOW "[4;43m"
|
||||
#define RTT_CTRL_BG_BRIGHT_BLUE "[4;44m"
|
||||
#define RTT_CTRL_BG_BRIGHT_MAGENTA "[4;45m"
|
||||
#define RTT_CTRL_BG_BRIGHT_CYAN "[4;46m"
|
||||
#define RTT_CTRL_BG_BRIGHT_WHITE "[4;47m"
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*************************** End of file ****************************/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,334 +0,0 @@
|
||||
/*********************************************************************
|
||||
* SEGGER Microcontroller GmbH & Co. KG *
|
||||
* The Embedded Experts *
|
||||
**********************************************************************
|
||||
* *
|
||||
* (c) 2015 - 2017 SEGGER Microcontroller GmbH & Co. KG *
|
||||
* *
|
||||
* www.segger.com Support: support@segger.com *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* SEGGER SystemView * Real-time application analysis *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* SEGGER strongly recommends to not make any changes *
|
||||
* to or modify the source code of this software in order to stay *
|
||||
* compatible with the RTT protocol and J-Link. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or *
|
||||
* without modification, are permitted provided that the following *
|
||||
* conditions are met: *
|
||||
* *
|
||||
* o Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* o Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the following *
|
||||
* disclaimer in the documentation and/or other materials provided *
|
||||
* with the distribution. *
|
||||
* *
|
||||
* o Neither the name of SEGGER Microcontroller GmbH & Co. KG *
|
||||
* nor the names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without specific *
|
||||
* prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
|
||||
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
|
||||
* DAMAGE. *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* SystemView version: V2.42 *
|
||||
* *
|
||||
**********************************************************************
|
||||
-------------------------- END-OF-HEADER -----------------------------
|
||||
File : SEGGER_SYSVIEW.h
|
||||
Purpose : System visualization API.
|
||||
Revision: $Rev: 5626 $
|
||||
*/
|
||||
|
||||
#ifndef SEGGER_SYSVIEW_H
|
||||
#define SEGGER_SYSVIEW_H
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* #include Section
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
#include "SEGGER.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Defines, fixed
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
#define SEGGER_SYSVIEW_VERSION 21000
|
||||
|
||||
#define SEGGER_SYSVIEW_INFO_SIZE 9 // Minimum size, which has to be reserved for a packet. 1-2 byte of message type, 0-2 byte of payload length, 1-5 bytes of timestamp.
|
||||
#define SEGGER_SYSVIEW_QUANTA_U32 5 // Maximum number of bytes to encode a U32, should be reserved for each 32-bit value in a packet.
|
||||
|
||||
#define SEGGER_SYSVIEW_LOG (0u)
|
||||
#define SEGGER_SYSVIEW_WARNING (1u)
|
||||
#define SEGGER_SYSVIEW_ERROR (2u)
|
||||
#define SEGGER_SYSVIEW_FLAG_APPEND (1u << 6)
|
||||
|
||||
#define SEGGER_SYSVIEW_PREPARE_PACKET(p) (p) + 4
|
||||
//
|
||||
// SystemView events. First 32 IDs from 0 .. 31 are reserved for these
|
||||
//
|
||||
#define SYSVIEW_EVTID_NOP 0 // Dummy packet.
|
||||
#define SYSVIEW_EVTID_OVERFLOW 1
|
||||
#define SYSVIEW_EVTID_ISR_ENTER 2
|
||||
#define SYSVIEW_EVTID_ISR_EXIT 3
|
||||
#define SYSVIEW_EVTID_TASK_START_EXEC 4
|
||||
#define SYSVIEW_EVTID_TASK_STOP_EXEC 5
|
||||
#define SYSVIEW_EVTID_TASK_START_READY 6
|
||||
#define SYSVIEW_EVTID_TASK_STOP_READY 7
|
||||
#define SYSVIEW_EVTID_TASK_CREATE 8
|
||||
#define SYSVIEW_EVTID_TASK_INFO 9
|
||||
#define SYSVIEW_EVTID_TRACE_START 10
|
||||
#define SYSVIEW_EVTID_TRACE_STOP 11
|
||||
#define SYSVIEW_EVTID_SYSTIME_CYCLES 12
|
||||
#define SYSVIEW_EVTID_SYSTIME_US 13
|
||||
#define SYSVIEW_EVTID_SYSDESC 14
|
||||
#define SYSVIEW_EVTID_USER_START 15
|
||||
#define SYSVIEW_EVTID_USER_STOP 16
|
||||
#define SYSVIEW_EVTID_IDLE 17
|
||||
#define SYSVIEW_EVTID_ISR_TO_SCHEDULER 18
|
||||
#define SYSVIEW_EVTID_TIMER_ENTER 19
|
||||
#define SYSVIEW_EVTID_TIMER_EXIT 20
|
||||
#define SYSVIEW_EVTID_STACK_INFO 21
|
||||
#define SYSVIEW_EVTID_MODULEDESC 22
|
||||
|
||||
#define SYSVIEW_EVTID_INIT 24
|
||||
#define SYSVIEW_EVTID_NAME_RESOURCE 25
|
||||
#define SYSVIEW_EVTID_PRINT_FORMATTED 26
|
||||
#define SYSVIEW_EVTID_NUMMODULES 27
|
||||
#define SYSVIEW_EVTID_END_CALL 28
|
||||
#define SYSVIEW_EVTID_TASK_TERMINATE 29
|
||||
|
||||
#define SYSVIEW_EVTID_EX 31
|
||||
//
|
||||
// Event masks to disable/enable events
|
||||
//
|
||||
#define SYSVIEW_EVTMASK_NOP (1 << SYSVIEW_EVTID_NOP)
|
||||
#define SYSVIEW_EVTMASK_OVERFLOW (1 << SYSVIEW_EVTID_OVERFLOW)
|
||||
#define SYSVIEW_EVTMASK_ISR_ENTER (1 << SYSVIEW_EVTID_ISR_ENTER)
|
||||
#define SYSVIEW_EVTMASK_ISR_EXIT (1 << SYSVIEW_EVTID_ISR_EXIT)
|
||||
#define SYSVIEW_EVTMASK_TASK_START_EXEC (1 << SYSVIEW_EVTID_TASK_START_EXEC)
|
||||
#define SYSVIEW_EVTMASK_TASK_STOP_EXEC (1 << SYSVIEW_EVTID_TASK_STOP_EXEC)
|
||||
#define SYSVIEW_EVTMASK_TASK_START_READY (1 << SYSVIEW_EVTID_TASK_START_READY)
|
||||
#define SYSVIEW_EVTMASK_TASK_STOP_READY (1 << SYSVIEW_EVTID_TASK_STOP_READY)
|
||||
#define SYSVIEW_EVTMASK_TASK_CREATE (1 << SYSVIEW_EVTID_TASK_CREATE)
|
||||
#define SYSVIEW_EVTMASK_TASK_INFO (1 << SYSVIEW_EVTID_TASK_INFO)
|
||||
#define SYSVIEW_EVTMASK_TRACE_START (1 << SYSVIEW_EVTID_TRACE_START)
|
||||
#define SYSVIEW_EVTMASK_TRACE_STOP (1 << SYSVIEW_EVTID_TRACE_STOP)
|
||||
#define SYSVIEW_EVTMASK_SYSTIME_CYCLES (1 << SYSVIEW_EVTID_SYSTIME_CYCLES)
|
||||
#define SYSVIEW_EVTMASK_SYSTIME_US (1 << SYSVIEW_EVTID_SYSTIME_US)
|
||||
#define SYSVIEW_EVTMASK_SYSDESC (1 << SYSVIEW_EVTID_SYSDESC)
|
||||
#define SYSVIEW_EVTMASK_USER_START (1 << SYSVIEW_EVTID_USER_START)
|
||||
#define SYSVIEW_EVTMASK_USER_STOP (1 << SYSVIEW_EVTID_USER_STOP)
|
||||
#define SYSVIEW_EVTMASK_IDLE (1 << SYSVIEW_EVTID_IDLE)
|
||||
#define SYSVIEW_EVTMASK_ISR_TO_SCHEDULER (1 << SYSVIEW_EVTID_ISR_TO_SCHEDULER)
|
||||
#define SYSVIEW_EVTMASK_TIMER_ENTER (1 << SYSVIEW_EVTID_TIMER_ENTER)
|
||||
#define SYSVIEW_EVTMASK_TIMER_EXIT (1 << SYSVIEW_EVTID_TIMER_EXIT)
|
||||
#define SYSVIEW_EVTMASK_STACK_INFO (1 << SYSVIEW_EVTID_STACK_INFO)
|
||||
#define SYSVIEW_EVTMASK_MODULEDESC (1 << SYSVIEW_EVTID_MODULEDESC)
|
||||
|
||||
#define SYSVIEW_EVTMASK_INIT (1 << SYSVIEW_EVTID_INIT)
|
||||
#define SYSVIEW_EVTMASK_NAME_RESOURCE (1 << SYSVIEW_EVTID_NAME_RESOURCE)
|
||||
#define SYSVIEW_EVTMASK_PRINT_FORMATTED (1 << SYSVIEW_EVTID_PRINT_FORMATTED)
|
||||
#define SYSVIEW_EVTMASK_NUMMODULES (1 << SYSVIEW_EVTID_NUMMODULES)
|
||||
#define SYSVIEW_EVTMASK_END_CALL (1 << SYSVIEW_EVTID_END_CALL)
|
||||
#define SYSVIEW_EVTMASK_TASK_TERMINATE (1 << SYSVIEW_EVTID_TASK_TERMINATE)
|
||||
|
||||
#define SYSVIEW_EVTMASK_EX (1 << SYSVIEW_EVTID_EX)
|
||||
|
||||
#define SYSVIEW_EVTMASK_ALL_INTERRUPTS ( SYSVIEW_EVTMASK_ISR_ENTER \
|
||||
| SYSVIEW_EVTMASK_ISR_EXIT \
|
||||
| SYSVIEW_EVTMASK_ISR_TO_SCHEDULER)
|
||||
#define SYSVIEW_EVTMASK_ALL_TASKS ( SYSVIEW_EVTMASK_TASK_START_EXEC \
|
||||
| SYSVIEW_EVTMASK_TASK_STOP_EXEC \
|
||||
| SYSVIEW_EVTMASK_TASK_START_READY \
|
||||
| SYSVIEW_EVTMASK_TASK_STOP_READY \
|
||||
| SYSVIEW_EVTMASK_TASK_CREATE \
|
||||
| SYSVIEW_EVTMASK_TASK_INFO \
|
||||
| SYSVIEW_EVTMASK_STACK_INFO \
|
||||
| SYSVIEW_EVTMASK_TASK_TERMINATE)
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Structures
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
U32 TaskID;
|
||||
const char* sName;
|
||||
U32 Prio;
|
||||
U32 StackBase;
|
||||
U32 StackSize;
|
||||
} SEGGER_SYSVIEW_TASKINFO;
|
||||
|
||||
typedef struct SEGGER_SYSVIEW_MODULE_STRUCT SEGGER_SYSVIEW_MODULE;
|
||||
|
||||
struct SEGGER_SYSVIEW_MODULE_STRUCT {
|
||||
const char* sModule;
|
||||
U32 NumEvents;
|
||||
U32 EventOffset;
|
||||
void (*pfSendModuleDesc)(void);
|
||||
SEGGER_SYSVIEW_MODULE* pNext;
|
||||
};
|
||||
|
||||
typedef void (SEGGER_SYSVIEW_SEND_SYS_DESC_FUNC)(void);
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* API functions
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
U64 (*pfGetTime) (void);
|
||||
void (*pfSendTaskList) (void);
|
||||
} SEGGER_SYSVIEW_OS_API;
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Control and initialization functions
|
||||
*/
|
||||
void SEGGER_SYSVIEW_Init (U32 SysFreq, U32 CPUFreq, const SEGGER_SYSVIEW_OS_API *pOSAPI, SEGGER_SYSVIEW_SEND_SYS_DESC_FUNC pfSendSysDesc);
|
||||
void SEGGER_SYSVIEW_SetRAMBase (U32 RAMBaseAddress);
|
||||
void SEGGER_SYSVIEW_Start (void);
|
||||
void SEGGER_SYSVIEW_Stop (void);
|
||||
void SEGGER_SYSVIEW_GetSysDesc (void);
|
||||
void SEGGER_SYSVIEW_SendTaskList (void);
|
||||
void SEGGER_SYSVIEW_SendTaskInfo (const SEGGER_SYSVIEW_TASKINFO* pInfo);
|
||||
void SEGGER_SYSVIEW_SendSysDesc (const char* sSysDesc);
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Event recording functions
|
||||
*/
|
||||
void SEGGER_SYSVIEW_RecordVoid (unsigned int EventId);
|
||||
void SEGGER_SYSVIEW_RecordU32 (unsigned int EventId, U32 Para0);
|
||||
void SEGGER_SYSVIEW_RecordU32x2 (unsigned int EventId, U32 Para0, U32 Para1);
|
||||
void SEGGER_SYSVIEW_RecordU32x3 (unsigned int EventId, U32 Para0, U32 Para1, U32 Para2);
|
||||
void SEGGER_SYSVIEW_RecordU32x4 (unsigned int EventId, U32 Para0, U32 Para1, U32 Para2, U32 Para3);
|
||||
void SEGGER_SYSVIEW_RecordU32x5 (unsigned int EventId, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4);
|
||||
void SEGGER_SYSVIEW_RecordU32x6 (unsigned int EventId, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4, U32 Para5);
|
||||
void SEGGER_SYSVIEW_RecordU32x7 (unsigned int EventId, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4, U32 Para5, U32 Para6);
|
||||
void SEGGER_SYSVIEW_RecordU32x8 (unsigned int EventId, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4, U32 Para5, U32 Para6, U32 Para7);
|
||||
void SEGGER_SYSVIEW_RecordU32x9 (unsigned int EventId, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4, U32 Para5, U32 Para6, U32 Para7, U32 Para8);
|
||||
void SEGGER_SYSVIEW_RecordU32x10 (unsigned int EventId, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4, U32 Para5, U32 Para6, U32 Para7, U32 Para8, U32 Para9);
|
||||
void SEGGER_SYSVIEW_RecordString (unsigned int EventId, const char* pString);
|
||||
void SEGGER_SYSVIEW_RecordSystime (void);
|
||||
void SEGGER_SYSVIEW_RecordEnterISR (U32 IrqId);
|
||||
void SEGGER_SYSVIEW_RecordExitISR (void);
|
||||
void SEGGER_SYSVIEW_RecordExitISRToScheduler (void);
|
||||
void SEGGER_SYSVIEW_RecordEnterTimer (U32 TimerId);
|
||||
void SEGGER_SYSVIEW_RecordExitTimer (void);
|
||||
void SEGGER_SYSVIEW_RecordEndCall (unsigned int EventID);
|
||||
void SEGGER_SYSVIEW_RecordEndCallU32 (unsigned int EventID, U32 Para0);
|
||||
|
||||
void SEGGER_SYSVIEW_OnIdle (void);
|
||||
void SEGGER_SYSVIEW_OnTaskCreate (U32 TaskId);
|
||||
void SEGGER_SYSVIEW_OnTaskTerminate (U32 TaskId);
|
||||
void SEGGER_SYSVIEW_OnTaskStartExec (U32 TaskId);
|
||||
void SEGGER_SYSVIEW_OnTaskStopExec (void);
|
||||
void SEGGER_SYSVIEW_OnTaskStartReady (U32 TaskId);
|
||||
void SEGGER_SYSVIEW_OnTaskStopReady (U32 TaskId, unsigned int Cause);
|
||||
void SEGGER_SYSVIEW_OnUserStart (unsigned int UserId); // Start of user defined event (such as a subroutine to profile)
|
||||
void SEGGER_SYSVIEW_OnUserStop (unsigned int UserId); // Start of user defined event
|
||||
|
||||
void SEGGER_SYSVIEW_NameResource (U32 ResourceId, const char* sName);
|
||||
|
||||
int SEGGER_SYSVIEW_SendPacket (U8* pPacket, U8* pPayloadEnd, unsigned int EventId);
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Event parameter encoding functions
|
||||
*/
|
||||
U8* SEGGER_SYSVIEW_EncodeU32 (U8* pPayload, U32 Value);
|
||||
U8* SEGGER_SYSVIEW_EncodeData (U8* pPayload, const char* pSrc, unsigned int Len);
|
||||
U8* SEGGER_SYSVIEW_EncodeString (U8* pPayload, const char* s, unsigned int MaxLen);
|
||||
U8* SEGGER_SYSVIEW_EncodeId (U8* pPayload, U32 Id);
|
||||
U32 SEGGER_SYSVIEW_ShrinkId (U32 Id);
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Middleware module registration
|
||||
*/
|
||||
void SEGGER_SYSVIEW_RegisterModule (SEGGER_SYSVIEW_MODULE* pModule);
|
||||
void SEGGER_SYSVIEW_RecordModuleDescription (const SEGGER_SYSVIEW_MODULE* pModule, const char* sDescription);
|
||||
void SEGGER_SYSVIEW_SendModule (U8 ModuleId);
|
||||
void SEGGER_SYSVIEW_SendModuleDescription (void);
|
||||
void SEGGER_SYSVIEW_SendNumModules (void);
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* printf-Style functions
|
||||
*/
|
||||
#ifndef SEGGER_SYSVIEW_EXCLUDE_PRINTF // Define in project to avoid warnings about variable parameter list
|
||||
void SEGGER_SYSVIEW_PrintfHostEx (const char* s, U32 Options, ...);
|
||||
void SEGGER_SYSVIEW_PrintfTargetEx (const char* s, U32 Options, ...);
|
||||
void SEGGER_SYSVIEW_PrintfHost (const char* s, ...);
|
||||
void SEGGER_SYSVIEW_PrintfTarget (const char* s, ...);
|
||||
void SEGGER_SYSVIEW_WarnfHost (const char* s, ...);
|
||||
void SEGGER_SYSVIEW_WarnfTarget (const char* s, ...);
|
||||
void SEGGER_SYSVIEW_ErrorfHost (const char* s, ...);
|
||||
void SEGGER_SYSVIEW_ErrorfTarget (const char* s, ...);
|
||||
#endif
|
||||
|
||||
void SEGGER_SYSVIEW_Print (const char* s);
|
||||
void SEGGER_SYSVIEW_Warn (const char* s);
|
||||
void SEGGER_SYSVIEW_Error (const char* s);
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Run-time configuration functions
|
||||
*/
|
||||
void SEGGER_SYSVIEW_EnableEvents (U32 EnableMask);
|
||||
void SEGGER_SYSVIEW_DisableEvents (U32 DisableMask);
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Application-provided functions
|
||||
*/
|
||||
void SEGGER_SYSVIEW_Conf (void);
|
||||
U32 SEGGER_SYSVIEW_X_GetTimestamp (void);
|
||||
U32 SEGGER_SYSVIEW_X_GetInterruptId (void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/*************************** End of file ****************************/
|
||||
@@ -1,178 +0,0 @@
|
||||
/*********************************************************************
|
||||
* SEGGER Microcontroller GmbH & Co. KG *
|
||||
* The Embedded Experts *
|
||||
**********************************************************************
|
||||
* *
|
||||
* (c) 2015 - 2017 SEGGER Microcontroller GmbH & Co. KG *
|
||||
* *
|
||||
* www.segger.com Support: support@segger.com *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* SEGGER SystemView * Real-time application analysis *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* SEGGER strongly recommends to not make any changes *
|
||||
* to or modify the source code of this software in order to stay *
|
||||
* compatible with the RTT protocol and J-Link. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or *
|
||||
* without modification, are permitted provided that the following *
|
||||
* conditions are met: *
|
||||
* *
|
||||
* o Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* o Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the following *
|
||||
* disclaimer in the documentation and/or other materials provided *
|
||||
* with the distribution. *
|
||||
* *
|
||||
* o Neither the name of SEGGER Microcontroller GmbH & Co. KG *
|
||||
* nor the names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without specific *
|
||||
* prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
|
||||
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
|
||||
* DAMAGE. *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* SystemView version: V2.42 *
|
||||
* *
|
||||
**********************************************************************
|
||||
-------------------------- END-OF-HEADER -----------------------------
|
||||
File : SEGGER_SYSVIEW_ConfDefaults.h
|
||||
Purpose : Defines defaults for configurable defines used in
|
||||
SEGGER SystemView.
|
||||
Revision: $Rev: 3734 $
|
||||
*/
|
||||
|
||||
#ifndef SEGGER_SYSVIEW_CONFDEFAULTS_H
|
||||
#define SEGGER_SYSVIEW_CONFDEFAULTS_H
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* #include Section
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
#include "SEGGER_SYSVIEW_Conf.h"
|
||||
#include "SEGGER_RTT_Conf.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Configuration defaults
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
// Number of bytes that SystemView uses for a buffer.
|
||||
#ifndef SEGGER_SYSVIEW_RTT_BUFFER_SIZE
|
||||
#define SEGGER_SYSVIEW_RTT_BUFFER_SIZE 1024
|
||||
#endif
|
||||
|
||||
// The RTT channel that SystemView will use.
|
||||
#ifndef SEGGER_SYSVIEW_RTT_CHANNEL
|
||||
#define SEGGER_SYSVIEW_RTT_CHANNEL 0
|
||||
#endif
|
||||
// Sanity check of RTT channel
|
||||
#if (SEGGER_SYSVIEW_RTT_CHANNEL == 0) && (SEGGER_RTT_MAX_NUM_UP_BUFFERS < 2)
|
||||
#error "SEGGER_RTT_MAX_NUM_UP_BUFFERS in SEGGER_RTT_Conf.h has to be > 1!"
|
||||
#elif (SEGGER_SYSVIEW_RTT_CHANNEL >= SEGGER_RTT_MAX_NUM_UP_BUFFERS)
|
||||
#error "SEGGER_RTT_MAX_NUM_UP_BUFFERS in SEGGER_RTT_Conf.h has to be > SEGGER_SYSVIEW_RTT_CHANNEL!"
|
||||
#endif
|
||||
|
||||
// Place the SystemView buffer into its own/the RTT section
|
||||
#if !(defined SEGGER_SYSVIEW_BUFFER_SECTION) && (defined SEGGER_RTT_SECTION)
|
||||
#define SEGGER_SYSVIEW_BUFFER_SECTION SEGGER_RTT_SECTION
|
||||
#endif
|
||||
|
||||
// Retrieve a system timestamp. This gets the Cortex-M cycle counter.
|
||||
#ifndef SEGGER_SYSVIEW_GET_TIMESTAMP
|
||||
#error "SEGGER_SYSVIEW_GET_TIMESTAMP has to be defined in SEGGER_SYSVIEW_Conf.h!"
|
||||
#endif
|
||||
|
||||
// Define number of valid bits low-order delivered by clock source.
|
||||
#ifndef SEGGER_SYSVIEW_TIMESTAMP_BITS
|
||||
#define SEGGER_SYSVIEW_TIMESTAMP_BITS 32
|
||||
#endif
|
||||
|
||||
// Lowest Id reported by the Application.
|
||||
#ifndef SEGGER_SYSVIEW_ID_BASE
|
||||
#define SEGGER_SYSVIEW_ID_BASE 0
|
||||
#endif
|
||||
|
||||
// Number of bits to shift Ids to save bandwidth
|
||||
#ifndef SEGGER_SYSVIEW_ID_SHIFT
|
||||
#define SEGGER_SYSVIEW_ID_SHIFT 0
|
||||
#endif
|
||||
|
||||
#ifndef SEGGER_SYSVIEW_GET_INTERRUPT_ID
|
||||
#error "SEGGER_SYSVIEW_GET_INTERRUPT_ID has to be defined in SEGGER_SYSVIEW_Conf.h!"
|
||||
#endif
|
||||
|
||||
#ifndef SEGGER_SYSVIEW_MAX_ARGUMENTS
|
||||
#define SEGGER_SYSVIEW_MAX_ARGUMENTS 16
|
||||
#endif
|
||||
|
||||
#ifndef SEGGER_SYSVIEW_MAX_STRING_LEN
|
||||
#define SEGGER_SYSVIEW_MAX_STRING_LEN 128
|
||||
#endif
|
||||
|
||||
// Use a static buffer instead of a buffer on the stack for packets
|
||||
#ifndef SEGGER_SYSVIEW_USE_STATIC_BUFFER
|
||||
#define SEGGER_SYSVIEW_USE_STATIC_BUFFER 1
|
||||
#endif
|
||||
|
||||
// Maximum packet size used by SystemView for the static buffer
|
||||
#ifndef SEGGER_SYSVIEW_MAX_PACKET_SIZE
|
||||
#define SEGGER_SYSVIEW_MAX_PACKET_SIZE SEGGER_SYSVIEW_INFO_SIZE + SEGGER_SYSVIEW_MAX_STRING_LEN + 2 * SEGGER_SYSVIEW_QUANTA_U32 + SEGGER_SYSVIEW_MAX_ARGUMENTS * SEGGER_SYSVIEW_QUANTA_U32
|
||||
#endif
|
||||
|
||||
// Use post-mortem analysis instead of real-time analysis
|
||||
#ifndef SEGGER_SYSVIEW_POST_MORTEM_MODE
|
||||
#define SEGGER_SYSVIEW_POST_MORTEM_MODE 0
|
||||
#endif
|
||||
|
||||
// Configure how frequently syncronization is sent
|
||||
#ifndef SEGGER_SYSVIEW_SYNC_PERIOD_SHIFT
|
||||
#define SEGGER_SYSVIEW_SYNC_PERIOD_SHIFT 8
|
||||
#endif
|
||||
|
||||
// Lock SystemView (nestable)
|
||||
#ifndef SEGGER_SYSVIEW_LOCK
|
||||
#define SEGGER_SYSVIEW_LOCK() SEGGER_RTT_LOCK()
|
||||
#endif
|
||||
|
||||
// Unlock SystemView (nestable)
|
||||
#ifndef SEGGER_SYSVIEW_UNLOCK
|
||||
#define SEGGER_SYSVIEW_UNLOCK() SEGGER_RTT_UNLOCK()
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/*************************** End of file ****************************/
|
||||
@@ -1,110 +0,0 @@
|
||||
/*********************************************************************
|
||||
* SEGGER Microcontroller GmbH & Co. KG *
|
||||
* The Embedded Experts *
|
||||
**********************************************************************
|
||||
* *
|
||||
* (c) 2015 - 2017 SEGGER Microcontroller GmbH & Co. KG *
|
||||
* *
|
||||
* www.segger.com Support: support@segger.com *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* SEGGER SystemView * Real-time application analysis *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* SEGGER strongly recommends to not make any changes *
|
||||
* to or modify the source code of this software in order to stay *
|
||||
* compatible with the RTT protocol and J-Link. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or *
|
||||
* without modification, are permitted provided that the following *
|
||||
* conditions are met: *
|
||||
* *
|
||||
* o Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* o Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the following *
|
||||
* disclaimer in the documentation and/or other materials provided *
|
||||
* with the distribution. *
|
||||
* *
|
||||
* o Neither the name of SEGGER Microcontroller GmbH & Co. KG *
|
||||
* nor the names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without specific *
|
||||
* prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
|
||||
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
|
||||
* DAMAGE. *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* SystemView version: V2.42 *
|
||||
* *
|
||||
**********************************************************************
|
||||
-------------------------- END-OF-HEADER -----------------------------
|
||||
File : SEGGER_SYSVIEW_Int.h
|
||||
Purpose : SEGGER SystemView internal header.
|
||||
Revision: $Rev: 5626 $
|
||||
*/
|
||||
|
||||
#ifndef SEGGER_SYSVIEW_INT_H
|
||||
#define SEGGER_SYSVIEW_INT_H
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* #include Section
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
#include "SEGGER_SYSVIEW.h"
|
||||
#include "SEGGER_SYSVIEW_Conf.h"
|
||||
#include "SEGGER_SYSVIEW_ConfDefaults.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Private data types
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
//
|
||||
// Commands that Host can send to target
|
||||
//
|
||||
typedef enum {
|
||||
SEGGER_SYSVIEW_COMMAND_ID_START = 1,
|
||||
SEGGER_SYSVIEW_COMMAND_ID_STOP,
|
||||
SEGGER_SYSVIEW_COMMAND_ID_GET_SYSTIME,
|
||||
SEGGER_SYSVIEW_COMMAND_ID_GET_TASKLIST,
|
||||
SEGGER_SYSVIEW_COMMAND_ID_GET_SYSDESC,
|
||||
SEGGER_SYSVIEW_COMMAND_ID_GET_NUMMODULES,
|
||||
SEGGER_SYSVIEW_COMMAND_ID_GET_MODULEDESC,
|
||||
// Extended commands: Commands >= 128 have a second parameter
|
||||
SEGGER_SYSVIEW_COMMAND_ID_GET_MODULE = 128
|
||||
} SEGGER_SYSVIEW_COMMAND_ID;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/*************************** End of file ****************************/
|
||||
@@ -1,355 +0,0 @@
|
||||
/*********************************************************************
|
||||
* SEGGER Microcontroller GmbH & Co. KG *
|
||||
* The Embedded Experts *
|
||||
**********************************************************************
|
||||
* *
|
||||
* (c) 2015 - 2017 SEGGER Microcontroller GmbH & Co. KG *
|
||||
* *
|
||||
* www.segger.com Support: support@segger.com *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* SEGGER SystemView * Real-time application analysis *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* SEGGER strongly recommends to not make any changes *
|
||||
* to or modify the source code of this software in order to stay *
|
||||
* compatible with the RTT protocol and J-Link. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or *
|
||||
* without modification, are permitted provided that the following *
|
||||
* conditions are met: *
|
||||
* *
|
||||
* o Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* o Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the following *
|
||||
* disclaimer in the documentation and/or other materials provided *
|
||||
* with the distribution. *
|
||||
* *
|
||||
* o Neither the name of SEGGER Microcontroller GmbH & Co. KG *
|
||||
* nor the names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without specific *
|
||||
* prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
|
||||
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
|
||||
* DAMAGE. *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* SystemView version: V2.42 *
|
||||
* *
|
||||
**********************************************************************
|
||||
-------------------------- END-OF-HEADER -----------------------------
|
||||
|
||||
File : SEGGER_SYSVIEW_Config_FreeRTOS.c
|
||||
Purpose : Sample setup configuration of SystemView with FreeRTOS.
|
||||
Revision: $Rev: 3734 $
|
||||
*/
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "SEGGER_SYSVIEW.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_app_trace.h"
|
||||
#include "esp_app_trace_util.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_clk.h"
|
||||
|
||||
extern const SEGGER_SYSVIEW_OS_API SYSVIEW_X_OS_TraceAPI;
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Defines, configurable
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
// The application name to be displayed in SystemViewer
|
||||
#define SYSVIEW_APP_NAME "FreeRTOS Application"
|
||||
|
||||
// The target device name
|
||||
#define SYSVIEW_DEVICE_NAME "ESP32"
|
||||
|
||||
// Determine which timer to use as timestamp source
|
||||
#if CONFIG_SYSVIEW_TS_SOURCE_CCOUNT
|
||||
#define TS_USE_CCOUNT 1
|
||||
#elif CONFIG_SYSVIEW_TS_SOURCE_ESP_TIMER
|
||||
#define TS_USE_ESP_TIMER 1
|
||||
#else
|
||||
#define TS_USE_TIMERGROUP 1
|
||||
#endif
|
||||
|
||||
#if TS_USE_TIMERGROUP
|
||||
#include "driver/timer.h"
|
||||
|
||||
// Timer group timer divisor
|
||||
#define SYSVIEW_TIMER_DIV 2
|
||||
|
||||
// Frequency of the timestamp.
|
||||
#define SYSVIEW_TIMESTAMP_FREQ (esp_clk_apb_freq() / SYSVIEW_TIMER_DIV)
|
||||
|
||||
// Timer ID and group ID
|
||||
#if defined(CONFIG_SYSVIEW_TS_SOURCE_TIMER_00) || defined(CONFIG_SYSVIEW_TS_SOURCE_TIMER_01)
|
||||
#define TS_TIMER_ID 0
|
||||
#else
|
||||
#define TS_TIMER_ID 1
|
||||
#endif // TIMER_00 || TIMER_01
|
||||
|
||||
#if defined(CONFIG_SYSVIEW_TS_SOURCE_TIMER_00) || defined(CONFIG_SYSVIEW_TS_SOURCE_TIMER_10)
|
||||
#define TS_TIMER_GROUP 0
|
||||
#else
|
||||
#define TS_TIMER_GROUP 1
|
||||
#endif // TIMER_00 || TIMER_10
|
||||
|
||||
#endif // TS_USE_TIMERGROUP
|
||||
|
||||
#if TS_USE_ESP_TIMER
|
||||
// esp_timer provides 1us resolution
|
||||
#define SYSVIEW_TIMESTAMP_FREQ (1000000)
|
||||
#endif // TS_USE_ESP_TIMER
|
||||
|
||||
#if TS_USE_CCOUNT
|
||||
// CCOUNT is incremented at CPU frequency
|
||||
#define SYSVIEW_TIMESTAMP_FREQ (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ * 1000000)
|
||||
#endif // TS_USE_CCOUNT
|
||||
|
||||
// System Frequency.
|
||||
#define SYSVIEW_CPU_FREQ (esp_clk_cpu_freq())
|
||||
|
||||
// The lowest RAM address used for IDs (pointers)
|
||||
#define SYSVIEW_RAM_BASE (0x3F400000)
|
||||
|
||||
#if CONFIG_FREERTOS_CORETIMER_0
|
||||
#define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER0_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)
|
||||
#endif
|
||||
#if CONFIG_FREERTOS_CORETIMER_1
|
||||
#define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER1_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)
|
||||
#endif
|
||||
|
||||
// SystemView is single core specific: it implies that SEGGER_SYSVIEW_LOCK()
|
||||
// disables IRQs (disables rescheduling globally). So we can not use finite timeouts for locks and return error
|
||||
// in case of expiration, because error will not be handled and SEGGER's code will go further implying that
|
||||
// everything is fine, so for multi-core env we have to wait on underlying lock forever
|
||||
#define SEGGER_LOCK_WAIT_TMO ESP_APPTRACE_TMO_INFINITE
|
||||
|
||||
static esp_apptrace_lock_t s_sys_view_lock = {.mux = portMUX_INITIALIZER_UNLOCKED, .int_state = 0};
|
||||
|
||||
static const char * const s_isr_names[] = {
|
||||
[0] = "WIFI_MAC",
|
||||
[1] = "WIFI_NMI",
|
||||
[2] = "WIFI_BB",
|
||||
[3] = "BT_MAC",
|
||||
[4] = "BT_BB",
|
||||
[5] = "BT_BB_NMI",
|
||||
[6] = "RWBT",
|
||||
[7] = "RWBLE",
|
||||
[8] = "RWBT_NMI",
|
||||
[9] = "RWBLE_NMI",
|
||||
[10] = "SLC0",
|
||||
[11] = "SLC1",
|
||||
[12] = "UHCI0",
|
||||
[13] = "UHCI1",
|
||||
[14] = "TG0_T0_LEVEL",
|
||||
[15] = "TG0_T1_LEVEL",
|
||||
[16] = "TG0_WDT_LEVEL",
|
||||
[17] = "TG0_LACT_LEVEL",
|
||||
[18] = "TG1_T0_LEVEL",
|
||||
[19] = "TG1_T1_LEVEL",
|
||||
[20] = "TG1_WDT_LEVEL",
|
||||
[21] = "TG1_LACT_LEVEL",
|
||||
[22] = "GPIO",
|
||||
[23] = "GPIO_NMI",
|
||||
[24] = "FROM_CPU0",
|
||||
[25] = "FROM_CPU1",
|
||||
[26] = "FROM_CPU2",
|
||||
[27] = "FROM_CPU3",
|
||||
[28] = "SPI0",
|
||||
[29] = "SPI1",
|
||||
[30] = "SPI2",
|
||||
[31] = "SPI3",
|
||||
[32] = "I2S0",
|
||||
[33] = "I2S1",
|
||||
[34] = "UART0",
|
||||
[35] = "UART1",
|
||||
[36] = "UART2",
|
||||
[37] = "SDIO_HOST",
|
||||
[38] = "ETH_MAC",
|
||||
[39] = "PWM0",
|
||||
[40] = "PWM1",
|
||||
[41] = "PWM2",
|
||||
[42] = "PWM3",
|
||||
[43] = "LEDC",
|
||||
[44] = "EFUSE",
|
||||
[45] = "CAN",
|
||||
[46] = "RTC_CORE",
|
||||
[47] = "RMT",
|
||||
[48] = "PCNT",
|
||||
[49] = "I2C_EXT0",
|
||||
[50] = "I2C_EXT1",
|
||||
[51] = "RSA",
|
||||
[52] = "SPI1_DMA",
|
||||
[53] = "SPI2_DMA",
|
||||
[54] = "SPI3_DMA",
|
||||
[55] = "WDT",
|
||||
[56] = "TIMER1",
|
||||
[57] = "TIMER2",
|
||||
[58] = "TG0_T0_EDGE",
|
||||
[59] = "TG0_T1_EDGE",
|
||||
[60] = "TG0_WDT_EDGE",
|
||||
[61] = "TG0_LACT_EDGE",
|
||||
[62] = "TG1_T0_EDGE",
|
||||
[63] = "TG1_T1_EDGE",
|
||||
[64] = "TG1_WDT_EDGE",
|
||||
[65] = "TG1_LACT_EDGE",
|
||||
[66] = "MMU_IA",
|
||||
[67] = "MPU_IA",
|
||||
[68] = "CACHE_IA",
|
||||
};
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* _cbSendSystemDesc()
|
||||
*
|
||||
* Function description
|
||||
* Sends SystemView description strings.
|
||||
*/
|
||||
static void _cbSendSystemDesc(void) {
|
||||
char irq_str[32];
|
||||
SEGGER_SYSVIEW_SendSysDesc("N="SYSVIEW_APP_NAME",D="SYSVIEW_DEVICE_NAME",C=Xtensa,O=FreeRTOS");
|
||||
snprintf(irq_str, sizeof(irq_str), "I#%d=SysTick", SYSTICK_INTR_ID);
|
||||
SEGGER_SYSVIEW_SendSysDesc(irq_str);
|
||||
size_t isr_count = sizeof(s_isr_names)/sizeof(s_isr_names[0]);
|
||||
for (size_t i = 0; i < isr_count; ++i) {
|
||||
snprintf(irq_str, sizeof(irq_str), "I#%d=%s", ETS_INTERNAL_INTR_SOURCE_OFF + i, s_isr_names[i]);
|
||||
SEGGER_SYSVIEW_SendSysDesc(irq_str);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Global functions
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
static void SEGGER_SYSVIEW_TS_Init()
|
||||
{
|
||||
/* We only need to initialize something if we use Timer Group.
|
||||
* esp_timer and ccount can be used as is.
|
||||
*/
|
||||
#if TS_USE_TIMERGROUP
|
||||
timer_config_t config = {
|
||||
.alarm_en = 0,
|
||||
.auto_reload = 0,
|
||||
.counter_dir = TIMER_COUNT_UP,
|
||||
.divider = SYSVIEW_TIMER_DIV,
|
||||
.counter_en = 0
|
||||
};
|
||||
/* Configure timer */
|
||||
timer_init(TS_TIMER_GROUP, TS_TIMER_ID, &config);
|
||||
/* Load counter value */
|
||||
timer_set_counter_value(TS_TIMER_GROUP, TS_TIMER_ID, 0x00000000ULL);
|
||||
/* Start counting */
|
||||
timer_start(TS_TIMER_GROUP, TS_TIMER_ID);
|
||||
#endif // TS_USE_TIMERGROUP
|
||||
}
|
||||
|
||||
void SEGGER_SYSVIEW_Conf(void) {
|
||||
U32 disable_evts = 0;
|
||||
|
||||
SEGGER_SYSVIEW_TS_Init();
|
||||
SEGGER_SYSVIEW_Init(SYSVIEW_TIMESTAMP_FREQ, SYSVIEW_CPU_FREQ,
|
||||
&SYSVIEW_X_OS_TraceAPI, _cbSendSystemDesc);
|
||||
SEGGER_SYSVIEW_SetRAMBase(SYSVIEW_RAM_BASE);
|
||||
|
||||
#if !CONFIG_SYSVIEW_EVT_OVERFLOW_ENABLE
|
||||
disable_evts |= SYSVIEW_EVTMASK_OVERFLOW;
|
||||
#endif
|
||||
#if !CONFIG_SYSVIEW_EVT_ISR_ENTER_ENABLE
|
||||
disable_evts |= SYSVIEW_EVTMASK_ISR_ENTER;
|
||||
#endif
|
||||
#if !CONFIG_SYSVIEW_EVT_ISR_EXIT_ENABLE
|
||||
disable_evts |= SYSVIEW_EVTMASK_ISR_EXIT;
|
||||
#endif
|
||||
#if !CONFIG_SYSVIEW_EVT_TASK_START_EXEC_ENABLE
|
||||
disable_evts |= SYSVIEW_EVTMASK_TASK_START_EXEC;
|
||||
#endif
|
||||
#if !CONFIG_SYSVIEW_EVT_TASK_STOP_EXEC_ENABLE
|
||||
disable_evts |= SYSVIEW_EVTMASK_TASK_STOP_EXEC;
|
||||
#endif
|
||||
#if !CONFIG_SYSVIEW_EVT_TASK_START_READY_ENABLE
|
||||
disable_evts |= SYSVIEW_EVTMASK_TASK_START_READY;
|
||||
#endif
|
||||
#if !CONFIG_SYSVIEW_EVT_TASK_STOP_READY_ENABLE
|
||||
disable_evts |= SYSVIEW_EVTMASK_TASK_STOP_READY;
|
||||
#endif
|
||||
#if !CONFIG_SYSVIEW_EVT_TASK_CREATE_ENABLE
|
||||
disable_evts |= SYSVIEW_EVTMASK_TASK_CREATE;
|
||||
#endif
|
||||
#if !CONFIG_SYSVIEW_EVT_TASK_TERMINATE_ENABLE
|
||||
disable_evts |= SYSVIEW_EVTMASK_TASK_TERMINATE;
|
||||
#endif
|
||||
#if !CONFIG_SYSVIEW_EVT_IDLE_ENABLE
|
||||
disable_evts |= SYSVIEW_EVTMASK_IDLE;
|
||||
#endif
|
||||
#if !CONFIG_SYSVIEW_EVT_ISR_TO_SCHEDULER_ENABLE
|
||||
disable_evts |= SYSVIEW_EVTMASK_ISR_TO_SCHEDULER;
|
||||
#endif
|
||||
#if !CONFIG_SYSVIEW_EVT_TIMER_ENTER_ENABLE
|
||||
disable_evts |= SYSVIEW_EVTMASK_TIMER_ENTER;
|
||||
#endif
|
||||
#if !CONFIG_SYSVIEW_EVT_TIMER_EXIT_ENABLE
|
||||
disable_evts |= SYSVIEW_EVTMASK_TIMER_EXIT;
|
||||
#endif
|
||||
SEGGER_SYSVIEW_DisableEvents(disable_evts);
|
||||
}
|
||||
|
||||
U32 SEGGER_SYSVIEW_X_GetTimestamp()
|
||||
{
|
||||
#if TS_USE_TIMERGROUP
|
||||
uint64_t ts = 0;
|
||||
timer_get_counter_value(TS_TIMER_GROUP, TS_TIMER_ID, &ts);
|
||||
return (U32) ts; // return lower part of counter value
|
||||
#elif TS_USE_CCOUNT
|
||||
return portGET_RUN_TIME_COUNTER_VALUE();
|
||||
#elif TS_USE_ESP_TIMER
|
||||
return (U32) esp_timer_get_time(); // return lower part of counter value
|
||||
#endif
|
||||
}
|
||||
|
||||
void SEGGER_SYSVIEW_X_RTT_Lock()
|
||||
{
|
||||
}
|
||||
|
||||
void SEGGER_SYSVIEW_X_RTT_Unlock()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned SEGGER_SYSVIEW_X_SysView_Lock()
|
||||
{
|
||||
esp_apptrace_tmo_t tmo;
|
||||
esp_apptrace_tmo_init(&tmo, SEGGER_LOCK_WAIT_TMO);
|
||||
esp_apptrace_lock_take(&s_sys_view_lock, &tmo);
|
||||
// to be recursive save IRQ status on the stack of the caller to keep it from overwriting
|
||||
return s_sys_view_lock.int_state;
|
||||
}
|
||||
|
||||
void SEGGER_SYSVIEW_X_SysView_Unlock(unsigned int_state)
|
||||
{
|
||||
s_sys_view_lock.int_state = int_state;
|
||||
esp_apptrace_lock_give(&s_sys_view_lock);
|
||||
}
|
||||
|
||||
/*************************** End of file ****************************/
|
||||
@@ -1,290 +0,0 @@
|
||||
/*********************************************************************
|
||||
* SEGGER Microcontroller GmbH & Co. KG *
|
||||
* The Embedded Experts *
|
||||
**********************************************************************
|
||||
* *
|
||||
* (c) 2015 - 2017 SEGGER Microcontroller GmbH & Co. KG *
|
||||
* *
|
||||
* www.segger.com Support: support@segger.com *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* SEGGER SystemView * Real-time application analysis *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* SEGGER strongly recommends to not make any changes *
|
||||
* to or modify the source code of this software in order to stay *
|
||||
* compatible with the RTT protocol and J-Link. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or *
|
||||
* without modification, are permitted provided that the following *
|
||||
* conditions are met: *
|
||||
* *
|
||||
* o Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* o Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the following *
|
||||
* disclaimer in the documentation and/or other materials provided *
|
||||
* with the distribution. *
|
||||
* *
|
||||
* o Neither the name of SEGGER Microcontroller GmbH & Co. KG *
|
||||
* nor the names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without specific *
|
||||
* prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
|
||||
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
|
||||
* DAMAGE. *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* SystemView version: V2.42 *
|
||||
* *
|
||||
**********************************************************************
|
||||
-------------------------- END-OF-HEADER -----------------------------
|
||||
|
||||
File : SEGGER_SYSVIEW_FreeRTOS.c
|
||||
Purpose : Interface between FreeRTOS and SystemView.
|
||||
Revision: $Rev: 3734 $
|
||||
*/
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "SEGGER_SYSVIEW.h"
|
||||
#include "SEGGER_SYSVIEW_FreeRTOS.h"
|
||||
#include "string.h" // Required for memset
|
||||
|
||||
|
||||
|
||||
typedef struct SYSVIEW_FREERTOS_TASK_STATUS SYSVIEW_FREERTOS_TASK_STATUS;
|
||||
|
||||
struct SYSVIEW_FREERTOS_TASK_STATUS {
|
||||
U32 xHandle;
|
||||
const char* pcTaskName;
|
||||
unsigned uxCurrentPriority;
|
||||
U32 pxStack;
|
||||
unsigned uStackHighWaterMark;
|
||||
};
|
||||
|
||||
static SYSVIEW_FREERTOS_TASK_STATUS _aTasks[SYSVIEW_FREERTOS_MAX_NOF_TASKS];
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* _cbSendTaskList()
|
||||
*
|
||||
* Function description
|
||||
* This function is part of the link between FreeRTOS and SYSVIEW.
|
||||
* Called from SystemView when asked by the host, it uses SYSVIEW
|
||||
* functions to send the entire task list to the host.
|
||||
*/
|
||||
static void _cbSendTaskList(void) {
|
||||
unsigned n;
|
||||
|
||||
for (n = 0; n < SYSVIEW_FREERTOS_MAX_NOF_TASKS; n++) {
|
||||
if (_aTasks[n].xHandle) {
|
||||
#if INCLUDE_uxTaskGetStackHighWaterMark // Report Task Stack High Watermark
|
||||
_aTasks[n].uStackHighWaterMark = uxTaskGetStackHighWaterMark((TaskHandle_t)_aTasks[n].xHandle);
|
||||
#endif
|
||||
SYSVIEW_SendTaskInfo((U32)_aTasks[n].xHandle, _aTasks[n].pcTaskName, (unsigned)_aTasks[n].uxCurrentPriority, (U32)_aTasks[n].pxStack, (unsigned)_aTasks[n].uStackHighWaterMark);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* _cbGetTime()
|
||||
*
|
||||
* Function description
|
||||
* This function is part of the link between FreeRTOS and SYSVIEW.
|
||||
* Called from SystemView when asked by the host, returns the
|
||||
* current system time in micro seconds.
|
||||
*/
|
||||
static U64 _cbGetTime(void) {
|
||||
U64 Time;
|
||||
|
||||
Time = xTaskGetTickCountFromISR();
|
||||
Time *= portTICK_PERIOD_MS;
|
||||
Time *= 1000;
|
||||
return Time;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Global functions
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
/*********************************************************************
|
||||
*
|
||||
* SYSVIEW_AddTask()
|
||||
*
|
||||
* Function description
|
||||
* Add a task to the internal list and record its information.
|
||||
*/
|
||||
void SYSVIEW_AddTask(U32 xHandle, const char* pcTaskName, unsigned uxCurrentPriority, U32 pxStack, unsigned uStackHighWaterMark) {
|
||||
unsigned n;
|
||||
|
||||
if (memcmp(pcTaskName, "IDLE", 5) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (n = 0; n < SYSVIEW_FREERTOS_MAX_NOF_TASKS; n++) {
|
||||
if (_aTasks[n].xHandle == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (n == SYSVIEW_FREERTOS_MAX_NOF_TASKS) {
|
||||
SEGGER_SYSVIEW_Warn("SYSTEMVIEW: Could not record task information. Maximum number of tasks reached.");
|
||||
return;
|
||||
}
|
||||
|
||||
_aTasks[n].xHandle = xHandle;
|
||||
_aTasks[n].pcTaskName = pcTaskName;
|
||||
_aTasks[n].uxCurrentPriority = uxCurrentPriority;
|
||||
_aTasks[n].pxStack = pxStack;
|
||||
_aTasks[n].uStackHighWaterMark = uStackHighWaterMark;
|
||||
|
||||
SYSVIEW_SendTaskInfo(xHandle, pcTaskName,uxCurrentPriority, pxStack, uStackHighWaterMark);
|
||||
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* SYSVIEW_UpdateTask()
|
||||
*
|
||||
* Function description
|
||||
* Update a task in the internal list and record its information.
|
||||
*/
|
||||
void SYSVIEW_UpdateTask(U32 xHandle, const char* pcTaskName, unsigned uxCurrentPriority, U32 pxStack, unsigned uStackHighWaterMark) {
|
||||
unsigned n;
|
||||
|
||||
if (memcmp(pcTaskName, "IDLE", 5) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (n = 0; n < SYSVIEW_FREERTOS_MAX_NOF_TASKS; n++) {
|
||||
if (_aTasks[n].xHandle == xHandle) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (n < SYSVIEW_FREERTOS_MAX_NOF_TASKS) {
|
||||
_aTasks[n].pcTaskName = pcTaskName;
|
||||
_aTasks[n].uxCurrentPriority = uxCurrentPriority;
|
||||
_aTasks[n].pxStack = pxStack;
|
||||
_aTasks[n].uStackHighWaterMark = uStackHighWaterMark;
|
||||
|
||||
SYSVIEW_SendTaskInfo(xHandle, pcTaskName, uxCurrentPriority, pxStack, uStackHighWaterMark);
|
||||
} else {
|
||||
SYSVIEW_AddTask(xHandle, pcTaskName, uxCurrentPriority, pxStack, uStackHighWaterMark);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* SYSVIEW_DeleteTask()
|
||||
*
|
||||
* Function description
|
||||
* Delete a task from the internal list.
|
||||
*/
|
||||
void SYSVIEW_DeleteTask(U32 xHandle) {
|
||||
unsigned n;
|
||||
|
||||
for (n = 0; n < SYSVIEW_FREERTOS_MAX_NOF_TASKS; n++) {
|
||||
if (_aTasks[n].xHandle == xHandle) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (n == SYSVIEW_FREERTOS_MAX_NOF_TASKS) {
|
||||
SEGGER_SYSVIEW_Warn("SYSTEMVIEW: Could not find task information. Cannot delete task.");
|
||||
return;
|
||||
}
|
||||
|
||||
_aTasks[n].xHandle = 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* SYSVIEW_SendTaskInfo()
|
||||
*
|
||||
* Function description
|
||||
* Record task information.
|
||||
*/
|
||||
void SYSVIEW_SendTaskInfo(U32 TaskID, const char* sName, unsigned Prio, U32 StackBase, unsigned StackSize) {
|
||||
SEGGER_SYSVIEW_TASKINFO TaskInfo;
|
||||
|
||||
memset(&TaskInfo, 0, sizeof(TaskInfo)); // Fill all elements with 0 to allow extending the structure in future version without breaking the code
|
||||
TaskInfo.TaskID = TaskID;
|
||||
TaskInfo.sName = sName;
|
||||
TaskInfo.Prio = Prio;
|
||||
TaskInfo.StackBase = StackBase;
|
||||
TaskInfo.StackSize = StackSize;
|
||||
SEGGER_SYSVIEW_SendTaskInfo(&TaskInfo);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* SYSVIEW_RecordU32x4()
|
||||
*
|
||||
* Function description
|
||||
* Record an event with 4 parameters
|
||||
*/
|
||||
void SYSVIEW_RecordU32x4(unsigned Id, U32 Para0, U32 Para1, U32 Para2, U32 Para3) {
|
||||
U8 aPacket[SEGGER_SYSVIEW_INFO_SIZE + 4 * SEGGER_SYSVIEW_QUANTA_U32];
|
||||
U8* pPayload;
|
||||
//
|
||||
pPayload = SEGGER_SYSVIEW_PREPARE_PACKET(aPacket); // Prepare the packet for SystemView
|
||||
pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, Para0); // Add the first parameter to the packet
|
||||
pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, Para1); // Add the second parameter to the packet
|
||||
pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, Para2); // Add the third parameter to the packet
|
||||
pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, Para3); // Add the fourth parameter to the packet
|
||||
//
|
||||
SEGGER_SYSVIEW_SendPacket(&aPacket[0], pPayload, Id); // Send the packet
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* SYSVIEW_RecordU32x5()
|
||||
*
|
||||
* Function description
|
||||
* Record an event with 5 parameters
|
||||
*/
|
||||
void SYSVIEW_RecordU32x5(unsigned Id, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4) {
|
||||
U8 aPacket[SEGGER_SYSVIEW_INFO_SIZE + 5 * SEGGER_SYSVIEW_QUANTA_U32];
|
||||
U8* pPayload;
|
||||
//
|
||||
pPayload = SEGGER_SYSVIEW_PREPARE_PACKET(aPacket); // Prepare the packet for SystemView
|
||||
pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, Para0); // Add the first parameter to the packet
|
||||
pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, Para1); // Add the second parameter to the packet
|
||||
pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, Para2); // Add the third parameter to the packet
|
||||
pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, Para3); // Add the fourth parameter to the packet
|
||||
pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, Para4); // Add the fifth parameter to the packet
|
||||
//
|
||||
SEGGER_SYSVIEW_SendPacket(&aPacket[0], pPayload, Id); // Send the packet
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Public API structures
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
// Callbacks provided to SYSTEMVIEW by FreeRTOS
|
||||
const SEGGER_SYSVIEW_OS_API SYSVIEW_X_OS_TraceAPI = {
|
||||
_cbGetTime,
|
||||
_cbSendTaskList,
|
||||
};
|
||||
|
||||
/*************************** End of file ****************************/
|
||||
@@ -1,335 +0,0 @@
|
||||
/*********************************************************************
|
||||
* SEGGER Microcontroller GmbH & Co. KG *
|
||||
* The Embedded Experts *
|
||||
**********************************************************************
|
||||
* *
|
||||
* (c) 2015 - 2017 SEGGER Microcontroller GmbH & Co. KG *
|
||||
* *
|
||||
* www.segger.com Support: support@segger.com *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* SEGGER SystemView * Real-time application analysis *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* SEGGER strongly recommends to not make any changes *
|
||||
* to or modify the source code of this software in order to stay *
|
||||
* compatible with the RTT protocol and J-Link. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or *
|
||||
* without modification, are permitted provided that the following *
|
||||
* conditions are met: *
|
||||
* *
|
||||
* o Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* o Redistributions in binary form must reproduce the above *
|
||||
* copyright notice, this list of conditions and the following *
|
||||
* disclaimer in the documentation and/or other materials provided *
|
||||
* with the distribution. *
|
||||
* *
|
||||
* o Neither the name of SEGGER Microcontroller GmbH & Co. KG *
|
||||
* nor the names of its contributors may be used to endorse or *
|
||||
* promote products derived from this software without specific *
|
||||
* prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
|
||||
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
|
||||
* DAMAGE. *
|
||||
* *
|
||||
**********************************************************************
|
||||
* *
|
||||
* SystemView version: V2.42 *
|
||||
* *
|
||||
**********************************************************************
|
||||
-------------------------- END-OF-HEADER -----------------------------
|
||||
|
||||
File : SEGGER_SYSVIEW_FreeRTOS.h
|
||||
Purpose : Interface between FreeRTOS and SystemView.
|
||||
Revision: $Rev: 3734 $
|
||||
|
||||
Notes:
|
||||
(1) Include this file at the end of FreeRTOSConfig.h
|
||||
*/
|
||||
|
||||
#ifndef SYSVIEW_FREERTOS_H
|
||||
#define SYSVIEW_FREERTOS_H
|
||||
|
||||
#include "SEGGER_SYSVIEW.h"
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Defines, configurable
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
#ifndef portSTACK_GROWTH
|
||||
#define portSTACK_GROWTH ( -1 )
|
||||
#endif
|
||||
|
||||
#define SYSVIEW_FREERTOS_MAX_NOF_TASKS CONFIG_SYSVIEW_MAX_TASKS
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Defines, fixed
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
// for dual-core targets we use event ID to keep core ID bit (0 or 1)
|
||||
// use the highest - 1 bit of event ID to indicate core ID
|
||||
// the highest bit can not be used due to event ID encoding method
|
||||
// this reduces supported ID range to [0..63] (for 1 byte IDs) plus [128..16383] (for 2 bytes IDs)
|
||||
// so original continuous event IDs range is split into two sub-ranges for 1-bytes IDs and 2-bytes ones
|
||||
|
||||
// events which use apiFastID_OFFSET will have 1 byte ID,
|
||||
// so for the sake of bandwidth economy events which are generated more frequently should use this ID offset
|
||||
// currently all used events fall into this range
|
||||
#define apiFastID_OFFSET (32u)
|
||||
|
||||
#define apiID_VTASKDELETE (1u)
|
||||
#define apiID_VTASKDELAY (2u)
|
||||
#define apiID_VTASKDELAYUNTIL (3u)
|
||||
#define apiID_VTASKSUSPEND (4u)
|
||||
#define apiID_ULTASKNOTIFYTAKE (5u)
|
||||
#define apiID_VTASKNOTIFYGIVEFROMISR (6u)
|
||||
#define apiID_VTASKPRIORITYINHERIT (7u)
|
||||
#define apiID_VTASKRESUME (8u)
|
||||
#define apiID_VTASKSTEPTICK (9u)
|
||||
#define apiID_XTASKPRIORITYDISINHERIT (10u)
|
||||
#define apiID_XTASKRESUMEFROMISR (11u)
|
||||
#define apiID_XTASKGENERICNOTIFY (12u)
|
||||
#define apiID_XTASKGENERICNOTIFYFROMISR (13u)
|
||||
#define apiID_XTASKNOTIFYWAIT (14u)
|
||||
#define apiID_XQUEUEGENERICCREATE (15u)
|
||||
#define apiID_VQUEUEDELETE (16u)
|
||||
#define apiID_XQUEUEGENERICRECEIVE (17u)
|
||||
#define apiID_XQUEUEPEEKFROMISR (18u)
|
||||
#define apiID_XQUEUERECEIVEFROMISR (19u)
|
||||
#define apiID_VQUEUEADDTOREGISTRY (20u)
|
||||
#define apiID_XQUEUEGENERICSEND (21u)
|
||||
#define apiID_XQUEUEGENERICSENDFROMISR (22u)
|
||||
#define apiID_VTASKPRIORITYSET (23u)
|
||||
#define apiID_UXTASKPRIORITYGETFROMISR (24u)
|
||||
#define apiID_XTASKGETTICKCOUNTFROMISR (25u)
|
||||
#define apiID_XEVENTGROUPCLEARBITSFROMISR (26u)
|
||||
#define apiID_XEVENTGROUPSETBITSFROMISR (27u)
|
||||
#define apiID_XEVENTGROUPGETBITSFROMISR (28u)
|
||||
#define apiID_XQUEUEGIVEFROMISR (29u)
|
||||
#define apiID_XQUEUEISQUEUEEMPTYFROMISR (30u)
|
||||
#define apiID_XQUEUEISQUEUEFULLFROMISR (31u) // the maximum allowed apiID for the first ID range
|
||||
|
||||
// events which use apiSlowID_OFFSET will have 2-bytes ID
|
||||
#define apiSlowID_OFFSET (127u)
|
||||
|
||||
#define apiID_VTASKALLOCATEMPUREGIONS (1u)
|
||||
#define apiID_UXTASKPRIORITYGET (2u)
|
||||
#define apiID_ETASKGETSTATE (3u)
|
||||
#define apiID_VTASKSTARTSCHEDULER (4u)
|
||||
#define apiID_VTASKENDSCHEDULER (5u)
|
||||
#define apiID_VTASKSUSPENDALL (6u)
|
||||
#define apiID_XTASKRESUMEALL (7u)
|
||||
#define apiID_XTASKGETTICKCOUNT (8u)
|
||||
#define apiID_UXTASKGETNUMBEROFTASKS (9u)
|
||||
#define apiID_PCTASKGETTASKNAME (10u)
|
||||
#define apiID_UXTASKGETSTACKHIGHWATERMARK (11u)
|
||||
#define apiID_VTASKSETAPPLICATIONTASKTAG (12u)
|
||||
#define apiID_XTASKGETAPPLICATIONTASKTAG (13u)
|
||||
#define apiID_VTASKSETTHREADLOCALSTORAGEPOINTER (14u)
|
||||
#define apiID_PVTASKGETTHREADLOCALSTORAGEPOINTER (15u)
|
||||
#define apiID_XTASKCALLAPPLICATIONTASKHOOK (16u)
|
||||
#define apiID_XTASKGETIDLETASKHANDLE (17u)
|
||||
#define apiID_UXTASKGETSYSTEMSTATE (18u)
|
||||
#define apiID_VTASKLIST (19u)
|
||||
#define apiID_VTASKGETRUNTIMESTATS (20u)
|
||||
#define apiID_XTASKNOTIFYSTATECLEAR (21u)
|
||||
#define apiID_XTASKGETCURRENTTASKHANDLE (22u)
|
||||
#define apiID_VTASKSETTIMEOUTSTATE (23u)
|
||||
#define apiID_XTASKCHECKFORTIMEOUT (24u)
|
||||
#define apiID_VTASKMISSEDYIELD (25u)
|
||||
#define apiID_XTASKGETSCHEDULERSTATE (26u)
|
||||
#define apiID_XTASKGENERICCREATE (27u)
|
||||
#define apiID_UXTASKGETTASKNUMBER (28u)
|
||||
#define apiID_VTASKSETTASKNUMBER (29u)
|
||||
#define apiID_ETASKCONFIRMSLEEPMODESTATUS (30u)
|
||||
#define apiID_XTIMERCREATE (31u)
|
||||
#define apiID_PVTIMERGETTIMERID (32u)
|
||||
#define apiID_VTIMERSETTIMERID (33u)
|
||||
#define apiID_XTIMERISTIMERACTIVE (34u)
|
||||
#define apiID_XTIMERGETTIMERDAEMONTASKHANDLE (35u)
|
||||
#define apiID_XTIMERPENDFUNCTIONCALLFROMISR (36u)
|
||||
#define apiID_XTIMERPENDFUNCTIONCALL (37u)
|
||||
#define apiID_PCTIMERGETTIMERNAME (38u)
|
||||
#define apiID_XTIMERCREATETIMERTASK (39u)
|
||||
#define apiID_XTIMERGENERICCOMMAND (40u)
|
||||
#define apiID_UXQUEUEMESSAGESWAITING (41u)
|
||||
#define apiID_UXQUEUESPACESAVAILABLE (42u)
|
||||
#define apiID_UXQUEUEMESSAGESWAITINGFROMISR (43u)
|
||||
#define apiID_XQUEUEALTGENERICSEND (44u)
|
||||
#define apiID_XQUEUEALTGENERICRECEIVE (45u)
|
||||
#define apiID_XQUEUECRSENDFROMISR (46u)
|
||||
#define apiID_XQUEUECRRECEIVEFROMISR (47u)
|
||||
#define apiID_XQUEUECRSEND (48u)
|
||||
#define apiID_XQUEUECRRECEIVE (49u)
|
||||
#define apiID_XQUEUECREATEMUTEX (50u)
|
||||
#define apiID_XQUEUECREATECOUNTINGSEMAPHORE (51u)
|
||||
#define apiID_XQUEUEGETMUTEXHOLDER (52u)
|
||||
#define apiID_XQUEUETAKEMUTEXRECURSIVE (53u)
|
||||
#define apiID_XQUEUEGIVEMUTEXRECURSIVE (54u)
|
||||
#define apiID_VQUEUEUNREGISTERQUEUE (55u)
|
||||
#define apiID_XQUEUECREATESET (56u)
|
||||
#define apiID_XQUEUEADDTOSET (57u)
|
||||
#define apiID_XQUEUEREMOVEFROMSET (58u)
|
||||
#define apiID_XQUEUESELECTFROMSET (59u)
|
||||
#define apiID_XQUEUESELECTFROMSETFROMISR (60u)
|
||||
#define apiID_XQUEUEGENERICRESET (61u)
|
||||
#define apiID_VLISTINITIALISE (62u)
|
||||
#define apiID_VLISTINITIALISEITEM (63u)
|
||||
#define apiID_VLISTINSERT (64u)
|
||||
#define apiID_VLISTINSERTEND (65u)
|
||||
#define apiID_UXLISTREMOVE (66u)
|
||||
#define apiID_XEVENTGROUPCREATE (67u)
|
||||
#define apiID_XEVENTGROUPWAITBITS (68u)
|
||||
#define apiID_XEVENTGROUPCLEARBITS (69u)
|
||||
#define apiID_XEVENTGROUPSETBITS (70u)
|
||||
#define apiID_XEVENTGROUPSYNC (71u)
|
||||
#define apiID_VEVENTGROUPDELETE (72u)
|
||||
#define apiID_UXEVENTGROUPGETNUMBER (73u)
|
||||
|
||||
#define traceTASK_NOTIFY_TAKE() SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_ULTASKNOTIFYTAKE, xClearCountOnExit, xTicksToWait)
|
||||
#define traceTASK_DELAY() SEGGER_SYSVIEW_RecordU32(apiFastID_OFFSET + apiID_VTASKDELAY, xTicksToDelay)
|
||||
#define traceTASK_DELAY_UNTIL() SEGGER_SYSVIEW_RecordVoid(apiFastID_OFFSET + apiID_VTASKDELAYUNTIL)
|
||||
#define traceTASK_DELETE( pxTCB ) if (pxTCB != NULL) { \
|
||||
SEGGER_SYSVIEW_RecordU32(apiFastID_OFFSET + apiID_VTASKDELETE, \
|
||||
SEGGER_SYSVIEW_ShrinkId((U32)pxTCB)); \
|
||||
SYSVIEW_DeleteTask((U32)pxTCB); \
|
||||
}
|
||||
#define traceTASK_NOTIFY_GIVE_FROM_ISR() SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_VTASKNOTIFYGIVEFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB), (U32)pxHigherPriorityTaskWoken)
|
||||
#define traceTASK_PRIORITY_INHERIT( pxTCB, uxPriority ) SEGGER_SYSVIEW_RecordU32(apiFastID_OFFSET + apiID_VTASKPRIORITYINHERIT, (U32)pxMutexHolder)
|
||||
#define traceTASK_RESUME( pxTCB ) SEGGER_SYSVIEW_RecordU32(apiFastID_OFFSET + apiID_VTASKRESUME, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB))
|
||||
#define traceINCREASE_TICK_COUNT( xTicksToJump ) SEGGER_SYSVIEW_RecordU32(apiFastID_OFFSET + apiID_VTASKSTEPTICK, xTicksToJump)
|
||||
#define traceTASK_SUSPEND( pxTCB ) SEGGER_SYSVIEW_RecordU32(apiFastID_OFFSET + apiID_VTASKSUSPEND, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB))
|
||||
#define traceTASK_PRIORITY_DISINHERIT( pxTCB, uxBasePriority ) SEGGER_SYSVIEW_RecordU32(apiFastID_OFFSET + apiID_XTASKPRIORITYDISINHERIT, (U32)pxMutexHolder)
|
||||
#define traceTASK_RESUME_FROM_ISR( pxTCB ) SEGGER_SYSVIEW_RecordU32(apiFastID_OFFSET + apiID_XTASKRESUMEFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB))
|
||||
#define traceTASK_NOTIFY() SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XTASKGENERICNOTIFY, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB), ulValue, eAction, (U32)pulPreviousNotificationValue)
|
||||
#define traceTASK_NOTIFY_FROM_ISR() SYSVIEW_RecordU32x5(apiFastID_OFFSET + apiID_XTASKGENERICNOTIFYFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxTCB), ulValue, eAction, (U32)pulPreviousNotificationValue, (U32)pxHigherPriorityTaskWoken)
|
||||
#define traceTASK_NOTIFY_WAIT() SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XTASKNOTIFYWAIT, ulBitsToClearOnEntry, ulBitsToClearOnExit, (U32)pulNotificationValue, xTicksToWait)
|
||||
|
||||
#define traceQUEUE_CREATE( pxNewQueue ) SEGGER_SYSVIEW_RecordU32x3(apiFastID_OFFSET + apiID_XQUEUEGENERICCREATE, uxQueueLength, uxItemSize, ucQueueType)
|
||||
#define traceQUEUE_DELETE( pxQueue ) SEGGER_SYSVIEW_RecordU32(apiFastID_OFFSET + apiID_VQUEUEDELETE, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue))
|
||||
#define traceQUEUE_PEEK( pxQueue ) SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XQUEUEGENERICRECEIVE, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), SEGGER_SYSVIEW_ShrinkId((U32)pvBuffer), xTicksToWait, xJustPeeking)
|
||||
#define traceQUEUE_PEEK_FROM_ISR( pxQueue ) SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_XQUEUEPEEKFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), SEGGER_SYSVIEW_ShrinkId((U32)pvBuffer))
|
||||
#define traceQUEUE_PEEK_FROM_ISR_FAILED( pxQueue ) SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_XQUEUEPEEKFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), SEGGER_SYSVIEW_ShrinkId((U32)pvBuffer))
|
||||
#define traceQUEUE_RECEIVE( pxQueue ) SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XQUEUEGENERICRECEIVE, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), SEGGER_SYSVIEW_ShrinkId((U32)pvBuffer), xTicksToWait, xJustPeeking)
|
||||
#define traceQUEUE_RECEIVE_FAILED( pxQueue ) SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XQUEUEGENERICRECEIVE, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), SEGGER_SYSVIEW_ShrinkId((U32)pvBuffer), xTicksToWait, xJustPeeking)
|
||||
#define traceQUEUE_RECEIVE_FROM_ISR( pxQueue ) SEGGER_SYSVIEW_RecordU32x3(apiFastID_OFFSET + apiID_XQUEUERECEIVEFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), SEGGER_SYSVIEW_ShrinkId((U32)pvBuffer), (U32)pxHigherPriorityTaskWoken)
|
||||
#define traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue ) SEGGER_SYSVIEW_RecordU32x3(apiFastID_OFFSET + apiID_XQUEUERECEIVEFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), SEGGER_SYSVIEW_ShrinkId((U32)pvBuffer), (U32)pxHigherPriorityTaskWoken)
|
||||
#define traceQUEUE_REGISTRY_ADD( xQueue, pcQueueName ) SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_VQUEUEADDTOREGISTRY, SEGGER_SYSVIEW_ShrinkId((U32)xQueue), (U32)pcQueueName)
|
||||
#if ( configUSE_QUEUE_SETS != 1 )
|
||||
#define traceQUEUE_SEND( pxQueue ) SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XQUEUEGENERICSEND, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), (U32)pvItemToQueue, xTicksToWait, xCopyPosition)
|
||||
#else
|
||||
#define traceQUEUE_SEND( pxQueue ) SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XQUEUEGENERICSEND, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), 0, 0, xCopyPosition)
|
||||
#endif
|
||||
#define traceQUEUE_SEND_FAILED( pxQueue ) SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XQUEUEGENERICSEND, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), (U32)pvItemToQueue, xTicksToWait, xCopyPosition)
|
||||
#define traceQUEUE_SEND_FROM_ISR( pxQueue ) SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_XQUEUEGENERICSENDFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), (U32)pxHigherPriorityTaskWoken)
|
||||
#define traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue ) SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_XQUEUEGENERICSENDFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), (U32)pxHigherPriorityTaskWoken)
|
||||
|
||||
#if( portSTACK_GROWTH < 0 )
|
||||
#define traceTASK_CREATE(pxNewTCB) if (pxNewTCB != NULL) { \
|
||||
SEGGER_SYSVIEW_OnTaskCreate((U32)pxNewTCB); \
|
||||
SYSVIEW_AddTask((U32)pxNewTCB, \
|
||||
&(pxNewTCB->pcTaskName[0]), \
|
||||
pxNewTCB->uxPriority, \
|
||||
(U32)pxNewTCB->pxStack, \
|
||||
((U32)pxNewTCB->pxTopOfStack - (U32)pxNewTCB->pxStack) \
|
||||
); \
|
||||
}
|
||||
#else
|
||||
#define traceTASK_CREATE(pxNewTCB) if (pxNewTCB != NULL) { \
|
||||
SEGGER_SYSVIEW_OnTaskCreate((U32)pxNewTCB); \
|
||||
SYSVIEW_AddTask((U32)pxNewTCB, \
|
||||
&(pxNewTCB->pcTaskName[0]), \
|
||||
pxNewTCB->uxPriority, \
|
||||
(U32)pxNewTCB->pxStack, \
|
||||
(U32)(pxNewTCB->pxStack-pxNewTCB->pxTopOfStack) \
|
||||
); \
|
||||
}
|
||||
#endif
|
||||
#define traceTASK_PRIORITY_SET(pxTask, uxNewPriority) { \
|
||||
SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET+apiID_VTASKPRIORITYSET, \
|
||||
SEGGER_SYSVIEW_ShrinkId((U32)pxTCB), \
|
||||
uxNewPriority \
|
||||
); \
|
||||
SYSVIEW_UpdateTask((U32)pxTask, \
|
||||
&(pxTask->pcTaskName[0]), \
|
||||
uxNewPriority, \
|
||||
(U32)pxTask->pxStack, \
|
||||
0 \
|
||||
); \
|
||||
}
|
||||
//
|
||||
// Define INCLUDE_xTaskGetIdleTaskHandle as 1 in FreeRTOSConfig.h to allow identification of Idle state.
|
||||
//
|
||||
#if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
|
||||
#define traceTASK_SWITCHED_IN() if(prvGetTCBFromHandle(NULL) == xTaskGetIdleTaskHandle()) { \
|
||||
SEGGER_SYSVIEW_OnIdle(); \
|
||||
} else { \
|
||||
SEGGER_SYSVIEW_OnTaskStartExec((U32)pxCurrentTCB[xPortGetCoreID()]); \
|
||||
}
|
||||
#else
|
||||
#define traceTASK_SWITCHED_IN() { \
|
||||
if (memcmp(pxCurrentTCB[xPortGetCoreID()]->pcTaskName, "IDLE", 5) != 0) { \
|
||||
SEGGER_SYSVIEW_OnTaskStartExec((U32)pxCurrentTCB[xPortGetCoreID()]); \
|
||||
} else { \
|
||||
SEGGER_SYSVIEW_OnIdle(); \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
|
||||
#define traceMOVED_TASK_TO_READY_STATE(pxTCB) SEGGER_SYSVIEW_OnTaskStartReady((U32)pxTCB)
|
||||
#define traceREADDED_TASK_TO_READY_STATE(pxTCB)
|
||||
|
||||
#define traceMOVED_TASK_TO_DELAYED_LIST() SEGGER_SYSVIEW_OnTaskStopReady((U32)pxCurrentTCB[xPortGetCoreID()], (1u << 2))
|
||||
#define traceMOVED_TASK_TO_OVERFLOW_DELAYED_LIST() SEGGER_SYSVIEW_OnTaskStopReady((U32)pxCurrentTCB[xPortGetCoreID()], (1u << 2))
|
||||
#define traceMOVED_TASK_TO_SUSPENDED_LIST(pxTCB) SEGGER_SYSVIEW_OnTaskStopReady((U32)pxTCB, ((3u << 3) | 3))
|
||||
|
||||
#define traceISR_EXIT_TO_SCHEDULER() SEGGER_SYSVIEW_RecordExitISRToScheduler()
|
||||
#define traceISR_EXIT() SEGGER_SYSVIEW_RecordExitISR()
|
||||
#define traceISR_ENTER(_n_) SEGGER_SYSVIEW_RecordEnterISR(_n_)
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* API functions
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void SYSVIEW_AddTask (U32 xHandle, const char* pcTaskName, unsigned uxCurrentPriority, U32 pxStack, unsigned uStackHighWaterMark);
|
||||
void SYSVIEW_UpdateTask (U32 xHandle, const char* pcTaskName, unsigned uxCurrentPriority, U32 pxStack, unsigned uStackHighWaterMark);
|
||||
void SYSVIEW_DeleteTask (U32 xHandle);
|
||||
void SYSVIEW_SendTaskInfo (U32 TaskID, const char* sName, unsigned Prio, U32 StackBase, unsigned StackSize);
|
||||
void SYSVIEW_RecordU32x4 (unsigned Id, U32 Para0, U32 Para1, U32 Para2, U32 Para3);
|
||||
void SYSVIEW_RecordU32x5 (unsigned Id, U32 Para0, U32 Para1, U32 Para2, U32 Para3, U32 Para4);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/*************************** End of file ****************************/
|
||||
@@ -1,215 +0,0 @@
|
||||
// Copyright 2017 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include "string.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "SEGGER_RTT.h"
|
||||
#include "SEGGER_SYSVIEW.h"
|
||||
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_app_trace.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
const static char *TAG = "segger_rtt";
|
||||
|
||||
#define SYSVIEW_EVENTS_BUF_SZ 255U
|
||||
|
||||
// size of down channel data buf
|
||||
#define SYSVIEW_DOWN_BUF_SIZE 32
|
||||
#define SEGGER_HOST_WAIT_TMO 500 //us
|
||||
#define SEGGER_STOP_WAIT_TMO 1000000 //us
|
||||
|
||||
static uint8_t s_events_buf[SYSVIEW_EVENTS_BUF_SZ];
|
||||
static uint16_t s_events_buf_filled;
|
||||
static uint8_t s_down_buf[SYSVIEW_DOWN_BUF_SIZE];
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* Public code
|
||||
*
|
||||
**********************************************************************
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* SEGGER_RTT_ESP32_FlushNoLock()
|
||||
*
|
||||
* Function description
|
||||
* Flushes buffered events.
|
||||
*
|
||||
* Parameters
|
||||
* min_sz Threshold for flushing data. If current filling level is above this value, data will be flushed. TRAX destinations only.
|
||||
* tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly.
|
||||
*
|
||||
* Return value
|
||||
* None.
|
||||
*/
|
||||
void SEGGER_RTT_ESP32_FlushNoLock(unsigned long min_sz, unsigned long tmo)
|
||||
{
|
||||
esp_err_t res = esp_apptrace_write(ESP_APPTRACE_DEST_TRAX, s_events_buf, s_events_buf_filled, tmo);
|
||||
if (res != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to flush buffered events (%d)!\n", res);
|
||||
}
|
||||
// flush even if we failed to write buffered events, because no new events will be sent after STOP
|
||||
res = esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, min_sz, tmo);
|
||||
if (res != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to flush apptrace data (%d)!\n", res);
|
||||
}
|
||||
s_events_buf_filled = 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* SEGGER_RTT_ReadNoLock()
|
||||
*
|
||||
* Function description
|
||||
* Reads characters from SEGGER real-time-terminal control block
|
||||
* which have been previously stored by the host.
|
||||
* Do not lock against interrupts and multiple access.
|
||||
*
|
||||
* Parameters
|
||||
* BufferIndex Index of Down-buffer to be used (e.g. 0 for "Terminal").
|
||||
* pBuffer Pointer to buffer provided by target application, to copy characters from RTT-down-buffer to.
|
||||
* BufferSize Size of the target application buffer.
|
||||
*
|
||||
* Return value
|
||||
* Number of bytes that have been read.
|
||||
*/
|
||||
unsigned SEGGER_RTT_ReadNoLock(unsigned BufferIndex, void* pData, unsigned BufferSize) {
|
||||
uint32_t size = BufferSize;
|
||||
esp_err_t res = esp_apptrace_read(ESP_APPTRACE_DEST_TRAX, pData, &size, 0);
|
||||
if (res != ESP_OK) {
|
||||
return 0;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* SEGGER_RTT_WriteSkipNoLock
|
||||
*
|
||||
* Function description
|
||||
* Stores a specified number of characters in SEGGER RTT
|
||||
* control block which is then read by the host.
|
||||
* SEGGER_RTT_WriteSkipNoLock does not lock the application and
|
||||
* skips all data, if the data does not fit into the buffer.
|
||||
*
|
||||
* Parameters
|
||||
* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal").
|
||||
* pBuffer Pointer to character array. Does not need to point to a \0 terminated string.
|
||||
* NumBytes Number of bytes to be stored in the SEGGER RTT control block.
|
||||
*
|
||||
* Return value
|
||||
* Number of bytes which have been stored in the "Up"-buffer.
|
||||
*
|
||||
* Notes
|
||||
* (1) If there is not enough space in the "Up"-buffer, all data is dropped.
|
||||
* (2) For performance reasons this function does not call Init()
|
||||
* and may only be called after RTT has been initialized.
|
||||
* Either by calling SEGGER_RTT_Init() or calling another RTT API function first.
|
||||
*/
|
||||
unsigned SEGGER_RTT_WriteSkipNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) {
|
||||
uint8_t *pbuf = (uint8_t *)pBuffer;
|
||||
uint8_t event_id = *pbuf;
|
||||
|
||||
if (NumBytes > SYSVIEW_EVENTS_BUF_SZ) {
|
||||
ESP_LOGE(TAG, "Too large event %u bytes!", NumBytes);
|
||||
return 0;
|
||||
}
|
||||
if (xPortGetCoreID()) { // dual core specific code
|
||||
// use the highest - 1 bit of event ID to indicate core ID
|
||||
// the highest bit can not be used due to event ID encoding method
|
||||
// this reduces supported ID range to [0..63] (for 1 byte IDs) plus [128..16383] (for 2 bytes IDs)
|
||||
if (*pbuf & 0x80) { // 2 bytes ID
|
||||
*(pbuf + 1) |= (1 << 6);
|
||||
} else if (NumBytes != 10 || *pbuf != 0) { // ignore sync sequence
|
||||
*pbuf |= (1 << 6);
|
||||
}
|
||||
}
|
||||
if (s_events_buf_filled + NumBytes > SYSVIEW_EVENTS_BUF_SZ) {
|
||||
esp_err_t res = esp_apptrace_write(ESP_APPTRACE_DEST_TRAX, s_events_buf, s_events_buf_filled, SEGGER_HOST_WAIT_TMO);
|
||||
if (res != ESP_OK) {
|
||||
return 0; // skip current data buffer only, accumulated events are kept
|
||||
}
|
||||
s_events_buf_filled = 0;
|
||||
}
|
||||
memcpy(&s_events_buf[s_events_buf_filled], pBuffer, NumBytes);
|
||||
s_events_buf_filled += NumBytes;
|
||||
if (event_id == SYSVIEW_EVTID_TRACE_STOP) {
|
||||
SEGGER_RTT_ESP32_FlushNoLock(0, SEGGER_STOP_WAIT_TMO);
|
||||
}
|
||||
return NumBytes;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* SEGGER_RTT_ConfigUpBuffer
|
||||
*
|
||||
* Function description
|
||||
* Run-time configuration of a specific up-buffer (T->H).
|
||||
* Buffer to be configured is specified by index.
|
||||
* This includes: Buffer address, size, name, flags, ...
|
||||
*
|
||||
* Parameters
|
||||
* BufferIndex Index of the buffer to configure.
|
||||
* sName Pointer to a constant name string.
|
||||
* pBuffer Pointer to a buffer to be used.
|
||||
* BufferSize Size of the buffer.
|
||||
* Flags Operating modes. Define behavior if buffer is full (not enough space for entire message).
|
||||
*
|
||||
* Return value
|
||||
* >= 0 - O.K.
|
||||
* < 0 - Error
|
||||
*
|
||||
* Additional information
|
||||
* Buffer 0 is configured on compile-time.
|
||||
* May only be called once per buffer.
|
||||
* Buffer name and flags can be reconfigured using the appropriate functions.
|
||||
*/
|
||||
int SEGGER_RTT_ConfigUpBuffer(unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) {
|
||||
s_events_buf_filled = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* SEGGER_RTT_ConfigDownBuffer
|
||||
*
|
||||
* Function description
|
||||
* Run-time configuration of a specific down-buffer (H->T).
|
||||
* Buffer to be configured is specified by index.
|
||||
* This includes: Buffer address, size, name, flags, ...
|
||||
*
|
||||
* Parameters
|
||||
* BufferIndex Index of the buffer to configure.
|
||||
* sName Pointer to a constant name string.
|
||||
* pBuffer Pointer to a buffer to be used.
|
||||
* BufferSize Size of the buffer.
|
||||
* Flags Operating modes. Define behavior if buffer is full (not enough space for entire message).
|
||||
*
|
||||
* Return value
|
||||
* >= 0 O.K.
|
||||
* < 0 Error
|
||||
*
|
||||
* Additional information
|
||||
* Buffer 0 is configured on compile-time.
|
||||
* May only be called once per buffer.
|
||||
* Buffer name and flags can be reconfigured using the appropriate functions.
|
||||
*/
|
||||
int SEGGER_RTT_ConfigDownBuffer(unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) {
|
||||
esp_apptrace_down_buffer_config(s_down_buf, sizeof(s_down_buf));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*************************** End of file ****************************/
|
||||
@@ -1,6 +0,0 @@
|
||||
set(COMPONENT_SRCDIRS ".")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
set(COMPONENT_REQUIRES unity)
|
||||
|
||||
register_component()
|
||||
@@ -1,5 +0,0 @@
|
||||
#
|
||||
#Component Makefile
|
||||
#
|
||||
|
||||
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
|
||||
@@ -1,40 +0,0 @@
|
||||
set(COMPONENT_SRCS "esp_ota_ops.c"
|
||||
"esp_app_desc.c")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS "include")
|
||||
|
||||
set(COMPONENT_REQUIRES spi_flash partition_table bootloader_support)
|
||||
|
||||
register_component()
|
||||
|
||||
# esp_app_desc structure is added as an undefined symbol because otherwise the
|
||||
# linker will ignore this structure as it has no other files depending on it.
|
||||
target_link_libraries(${COMPONENT_TARGET} "-u esp_app_desc")
|
||||
|
||||
# cut PROJECT_VER and PROJECT_NAME to required 32 characters.
|
||||
string(SUBSTRING "${PROJECT_VER}" 0 31 PROJECT_VER_CUT)
|
||||
string(SUBSTRING "${PROJECT_NAME}" 0 31 PROJECT_NAME_CUT)
|
||||
|
||||
set_source_files_properties(
|
||||
SOURCE "esp_app_desc.c"
|
||||
PROPERTIES COMPILE_DEFINITIONS
|
||||
"PROJECT_VER=\"${PROJECT_VER_CUT}\"; PROJECT_NAME=\"${PROJECT_NAME_CUT}\"")
|
||||
|
||||
# Add custom target for generating empty otadata partition for flashing
|
||||
if(OTADATA_PARTITION_OFFSET AND OTADATA_PARTITION_SIZE)
|
||||
add_custom_command(OUTPUT "${IDF_BUILD_ARTIFACTS_DIR}/${BLANK_OTADATA_FILE}"
|
||||
COMMAND ${PYTHON} ${IDF_PATH}/components/partition_table/parttool.py
|
||||
--partition-type data --partition-subtype ota -q
|
||||
--partition-table-file ${PARTITION_CSV_PATH} generate_blank_partition_file
|
||||
--output "${IDF_BUILD_ARTIFACTS_DIR}/${BLANK_OTADATA_FILE}")
|
||||
|
||||
add_custom_target(blank_ota_data ALL DEPENDS "${IDF_BUILD_ARTIFACTS_DIR}/${BLANK_OTADATA_FILE}")
|
||||
add_dependencies(flash blank_ota_data)
|
||||
endif()
|
||||
|
||||
set(otatool_py ${PYTHON} ${COMPONENT_PATH}/otatool.py)
|
||||
|
||||
add_custom_target(read_otadata DEPENDS "${PARTITION_CSV_PATH}"
|
||||
COMMAND ${otatool_py} --partition-table-file ${PARTITION_CSV_PATH} read_otadata)
|
||||
|
||||
add_custom_target(erase_otadata DEPENDS "${PARTITION_CSV_PATH}"
|
||||
COMMAND ${otatool_py} --partition-table-file ${PARTITION_CSV_PATH} erase_otadata)
|
||||
@@ -1,35 +0,0 @@
|
||||
menu "Application manager"
|
||||
|
||||
config APP_COMPILE_TIME_DATE
|
||||
bool "Use time/date stamp for app"
|
||||
default y
|
||||
help
|
||||
If set, then the app will be built with the current time/date stamp. It is stored in the app description
|
||||
structure. If not set, time/date stamp will be excluded from app image. This can be useful for getting the
|
||||
same binary image files made from the same source, but at different times.
|
||||
|
||||
config APP_EXCLUDE_PROJECT_VER_VAR
|
||||
bool "Exclude PROJECT_VER from firmware image"
|
||||
default n
|
||||
help
|
||||
The PROJECT_VER variable from the build system will not affect the firmware image.
|
||||
This value will not be contained in the esp_app_desc structure.
|
||||
|
||||
config APP_EXCLUDE_PROJECT_NAME_VAR
|
||||
bool "Exclude PROJECT_NAME from firmware image"
|
||||
default n
|
||||
help
|
||||
The PROJECT_NAME variable from the build system will not affect the firmware image.
|
||||
This value will not be contained in the esp_app_desc structure.
|
||||
|
||||
config APP_RETRIEVE_LEN_ELF_SHA
|
||||
int "The length of APP ELF SHA is stored in RAM(chars)"
|
||||
default 16
|
||||
range 8 64
|
||||
help
|
||||
At startup, the app will read this many hex characters from the embedded APP ELF SHA-256 hash value
|
||||
and store it in static RAM. This ensures the app ELF SHA-256 value is always available
|
||||
if it needs to be printed by the panic handler code.
|
||||
Changing this value will change the size of a static buffer, in bytes.
|
||||
|
||||
endmenu # "Application manager"
|
||||
@@ -1,49 +0,0 @@
|
||||
# Generate partition binary
|
||||
#
|
||||
.PHONY: blank_ota_data erase_otadata read_otadata
|
||||
|
||||
OTATOOL_PY := $(PYTHON) $(COMPONENT_PATH)/otatool.py
|
||||
PARTTOOL_PY := $(PYTHON) $(IDF_PATH)/components/partition_table/parttool.py
|
||||
|
||||
# Generate blank partition file
|
||||
BLANK_OTA_DATA_FILE = $(BUILD_DIR_BASE)/ota_data_initial.bin
|
||||
|
||||
# Copy PARTITION_TABLE_CSV_PATH definition here from $IDF_PATH/components/partition_table/Makefile.projbuild
|
||||
# to avoid undefined variables warning for PARTITION_TABLE_CSV_PATH
|
||||
ifndef PARTITION_TABLE_CSV_PATH
|
||||
PARTITION_TABLE_ROOT := $(call dequote,$(if $(CONFIG_PARTITION_TABLE_CUSTOM),$(PROJECT_PATH),$(IDF_PATH)/components/partition_table))
|
||||
PARTITION_TABLE_CSV_PATH := $(call dequote,$(abspath $(PARTITION_TABLE_ROOT)/$(call dequote,$(CONFIG_PARTITION_TABLE_FILENAME))))
|
||||
endif
|
||||
|
||||
$(BLANK_OTA_DATA_FILE): partition_table_get_info $(PARTITION_TABLE_CSV_PATH) | check_python_dependencies
|
||||
$(shell if [ "$(OTA_DATA_OFFSET)" != "" ] && [ "$(OTA_DATA_SIZE)" != "" ]; then \
|
||||
$(PARTTOOL_PY) --partition-type data --partition-subtype ota --partition-table-file $(PARTITION_TABLE_CSV_PATH) \
|
||||
-q generate_blank_partition_file --output $(BLANK_OTA_DATA_FILE); \
|
||||
fi; )
|
||||
$(eval BLANK_OTA_DATA_FILE = $(shell if [ "$(OTA_DATA_OFFSET)" != "" ] && [ "$(OTA_DATA_SIZE)" != "" ]; then \
|
||||
echo $(BLANK_OTA_DATA_FILE); else echo " "; fi) )
|
||||
|
||||
blank_ota_data: $(BLANK_OTA_DATA_FILE)
|
||||
|
||||
# If there is no otadata partition, both OTA_DATA_OFFSET and BLANK_OTA_DATA_FILE
|
||||
# expand to empty values.
|
||||
ESPTOOL_ALL_FLASH_ARGS += $(OTA_DATA_OFFSET) $(BLANK_OTA_DATA_FILE)
|
||||
|
||||
erase_otadata: $(PARTITION_TABLE_CSV_PATH) partition_table_get_info | check_python_dependencies
|
||||
$(OTATOOL_PY) --partition-table-file $(PARTITION_TABLE_CSV_PATH) erase_otadata
|
||||
|
||||
read_otadata: $(PARTITION_TABLE_CSV_PATH) partition_table_get_info | check_python_dependencies
|
||||
$(OTATOOL_PY) --partition-table-file $(PARTITION_TABLE_CSV_PATH) read_otadata
|
||||
|
||||
erase_ota: erase_otadata
|
||||
@echo "WARNING: erase_ota is deprecated. Use erase_otadata instead."
|
||||
|
||||
all: blank_ota_data
|
||||
flash: blank_ota_data
|
||||
|
||||
TMP_DEFINES := $(BUILD_DIR_BASE)/app_update/tmp_cppflags.txt
|
||||
export TMP_DEFINES
|
||||
|
||||
clean:
|
||||
rm -f $(BLANK_OTA_DATA_FILE)
|
||||
rm -f $(TMP_DEFINES)
|
||||
51
components/app_update/component.mk
Normal file → Executable file
51
components/app_update/component.mk
Normal file → Executable file
@@ -3,54 +3,3 @@
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
|
||||
# esp_app_desc structure is added as an undefined symbol because otherwise the
|
||||
# linker will ignore this structure as it has no other files depending on it.
|
||||
COMPONENT_ADD_LDFLAGS += -u esp_app_desc
|
||||
|
||||
ifndef IS_BOOTLOADER_BUILD
|
||||
GET_PROJECT_VER ?=
|
||||
ifeq ("${PROJECT_VER}", "")
|
||||
ifeq ("$(wildcard ${PROJECT_PATH}/version.txt)","")
|
||||
|
||||
GET_PROJECT_VER := $(shell cd ${PROJECT_PATH} && git describe --always --tags --dirty 2> /dev/null)
|
||||
ifeq ("${GET_PROJECT_VER}", "")
|
||||
GET_PROJECT_VER := "1"
|
||||
$(info Project is not inside a git repository, will not use 'git describe' to determine PROJECT_VER.)
|
||||
endif
|
||||
|
||||
else
|
||||
# read from version.txt
|
||||
GET_PROJECT_VER := $(shell cat ${PROJECT_PATH}/version.txt)
|
||||
endif
|
||||
endif
|
||||
# If ``PROJECT_VER`` variable set in project Makefile file, its value will be used.
|
||||
# Else, if the ``$PROJECT_PATH/version.txt`` exists, its contents will be used as ``PROJECT_VER``.
|
||||
# Else, if the project is located inside a Git repository, the output of git describe will be used.
|
||||
# Otherwise, ``PROJECT_VER`` will be "1".
|
||||
|
||||
ifeq ("${PROJECT_VER}", "")
|
||||
PROJECT_VER:= $(GET_PROJECT_VER)
|
||||
else
|
||||
PROJECT_VER:= $(PROJECT_VER)
|
||||
endif
|
||||
|
||||
# cut PROJECT_VER and PROJECT_NAME to required 32 characters.
|
||||
PROJECT_VER_CUT := $(shell echo "$(PROJECT_VER)" | cut -c 1-31)
|
||||
PROJECT_NAME_CUT := $(shell echo "$(PROJECT_NAME)" | cut -c 1-31)
|
||||
|
||||
$(info App "$(PROJECT_NAME_CUT)" version: $(PROJECT_VER_CUT))
|
||||
|
||||
NEW_DEFINES:= "$(PROJECT_VER_CUT) $(PROJECT_NAME_CUT) $(IDF_VER)"
|
||||
ifeq ("$(wildcard ${TMP_DEFINES})","")
|
||||
OLD_DEFINES:= ""
|
||||
else
|
||||
OLD_DEFINES:= "$(shell cat $(TMP_DEFINES))"
|
||||
endif
|
||||
|
||||
# If NEW_DEFINES (PROJECT_VER, PROJECT_NAME) were changed then rebuild only esp_app_desc.
|
||||
ifneq (${NEW_DEFINES}, ${OLD_DEFINES})
|
||||
$(shell echo $(NEW_DEFINES) > $(TMP_DEFINES); rm -f esp_app_desc.o;)
|
||||
endif
|
||||
|
||||
esp_app_desc.o: CPPFLAGS += -D PROJECT_VER=\""$(PROJECT_VER_CUT)"\" -D PROJECT_NAME=\""$(PROJECT_NAME_CUT)"\"
|
||||
endif
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/param.h>
|
||||
#include "esp_ota_ops.h"
|
||||
#include "esp_attr.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
// Application version info
|
||||
const __attribute__((section(".rodata_desc"))) esp_app_desc_t esp_app_desc = {
|
||||
.magic_word = ESP_APP_DESC_MAGIC_WORD,
|
||||
#ifdef CONFIG_APP_EXCLUDE_PROJECT_VER_VAR
|
||||
.version = "",
|
||||
#else
|
||||
.version = PROJECT_VER,
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR
|
||||
.project_name = "",
|
||||
#else
|
||||
.project_name = PROJECT_NAME,
|
||||
#endif
|
||||
.idf_ver = IDF_VER,
|
||||
|
||||
#ifdef CONFIG_APP_SECURE_VERSION
|
||||
.secure_version = CONFIG_APP_SECURE_VERSION,
|
||||
#else
|
||||
.secure_version = 0,
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_APP_COMPILE_TIME_DATE
|
||||
.time = __TIME__,
|
||||
.date = __DATE__,
|
||||
#else
|
||||
.time = "",
|
||||
.date = "",
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#ifndef CONFIG_APP_EXCLUDE_PROJECT_VER_VAR
|
||||
_Static_assert(sizeof(PROJECT_VER) <= sizeof(esp_app_desc.version), "PROJECT_VER is longer than version field in structure");
|
||||
#endif
|
||||
_Static_assert(sizeof(IDF_VER) <= sizeof(esp_app_desc.idf_ver), "IDF_VER is longer than idf_ver field in structure");
|
||||
#ifndef CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR
|
||||
_Static_assert(sizeof(PROJECT_NAME) <= sizeof(esp_app_desc.project_name), "PROJECT_NAME is longer than project_name field in structure");
|
||||
#endif
|
||||
|
||||
const esp_app_desc_t *esp_ota_get_app_description(void)
|
||||
{
|
||||
return &esp_app_desc;
|
||||
}
|
||||
|
||||
/* The following two functions may be called from the panic handler
|
||||
* or core dump, hence IRAM_ATTR.
|
||||
*/
|
||||
|
||||
static inline char IRAM_ATTR to_hex_digit(unsigned val)
|
||||
{
|
||||
return (val < 10) ? ('0' + val) : ('a' + val - 10);
|
||||
}
|
||||
|
||||
__attribute__((constructor)) void esp_ota_init_app_elf_sha256(void)
|
||||
{
|
||||
esp_ota_get_app_elf_sha256(NULL, 0);
|
||||
}
|
||||
|
||||
/* The esp_app_desc.app_elf_sha256 should be possible to print in panic handler during cache is disabled.
|
||||
* But because the cache is disabled the reading esp_app_desc.app_elf_sha256 is not right and
|
||||
* can lead to a complete lock-up of the CPU.
|
||||
* For this reason we do a reading of esp_app_desc.app_elf_sha256 while start up in esp_ota_init_app_elf_sha256()
|
||||
* and keep it in the static s_app_elf_sha256 value.
|
||||
*/
|
||||
int IRAM_ATTR esp_ota_get_app_elf_sha256(char* dst, size_t size)
|
||||
{
|
||||
static char s_app_elf_sha256[CONFIG_APP_RETRIEVE_LEN_ELF_SHA / 2];
|
||||
static bool first_call = true;
|
||||
if (first_call) {
|
||||
first_call = false;
|
||||
const uint8_t* src = esp_app_desc.app_elf_sha256;
|
||||
for (size_t i = 0; i < sizeof(s_app_elf_sha256); ++i) {
|
||||
s_app_elf_sha256[i] = src[i];
|
||||
}
|
||||
}
|
||||
if (dst == NULL || size == 0) {
|
||||
return 0;
|
||||
}
|
||||
size_t n = MIN((size - 1) / 2, sizeof(s_app_elf_sha256));
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
dst[2*i] = to_hex_digit(s_app_elf_sha256[i] >> 4);
|
||||
dst[2*i + 1] = to_hex_digit(s_app_elf_sha256[i] & 0xf);
|
||||
}
|
||||
dst[2*n] = 0;
|
||||
return 2*n + 1;
|
||||
}
|
||||
@@ -28,7 +28,6 @@
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_flash_encrypt.h"
|
||||
#include "esp_spi_flash.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "esp_ota_ops.h"
|
||||
@@ -36,14 +35,11 @@
|
||||
#include "rom/crc.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_flash_data_types.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "sys/param.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_efuse.h"
|
||||
|
||||
|
||||
#define SUB_TYPE_ID(i) (i & 0x0F)
|
||||
#define OTA_MAX(a,b) ((a) >= (b) ? (a) : (b))
|
||||
#define OTA_MIN(a,b) ((a) <= (b) ? (a) : (b))
|
||||
#define SUB_TYPE_ID(i) (i & 0x0F)
|
||||
|
||||
typedef struct ota_ops_entry_ {
|
||||
uint32_t handle;
|
||||
@@ -55,10 +51,19 @@ typedef struct ota_ops_entry_ {
|
||||
LIST_ENTRY(ota_ops_entry_) entries;
|
||||
} ota_ops_entry_t;
|
||||
|
||||
/* OTA selection structure (two copies in the OTA data partition.)
|
||||
Size of 32 bytes is friendly to flash encryption */
|
||||
typedef struct {
|
||||
uint32_t ota_seq;
|
||||
uint8_t seq_label[24];
|
||||
uint32_t crc; /* CRC32 of ota_seq field only */
|
||||
} ota_select;
|
||||
|
||||
static LIST_HEAD(ota_ops_entries_head, ota_ops_entry_) s_ota_ops_entries_head =
|
||||
LIST_HEAD_INITIALIZER(s_ota_ops_entries_head);
|
||||
|
||||
static uint32_t s_ota_ops_last_handle = 0;
|
||||
static ota_select s_ota_select[2];
|
||||
|
||||
const static char *TAG = "esp_ota_ops";
|
||||
|
||||
@@ -71,63 +76,6 @@ static bool is_ota_partition(const esp_partition_t *p)
|
||||
&& p->subtype < ESP_PARTITION_SUBTYPE_APP_OTA_MAX);
|
||||
}
|
||||
|
||||
// Read otadata partition and fill array from two otadata structures.
|
||||
// Also return pointer to otadata info partition.
|
||||
static const esp_partition_t *read_otadata(esp_ota_select_entry_t *two_otadata)
|
||||
{
|
||||
const esp_partition_t *otadata_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
|
||||
|
||||
if (otadata_partition == NULL) {
|
||||
ESP_LOGE(TAG, "not found otadata");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
spi_flash_mmap_handle_t ota_data_map;
|
||||
const void *result = NULL;
|
||||
esp_err_t err = esp_partition_mmap(otadata_partition, 0, otadata_partition->size, SPI_FLASH_MMAP_DATA, &result, &ota_data_map);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "mmap otadata filed. Err=0x%8x", err);
|
||||
return NULL;
|
||||
} else {
|
||||
memcpy(&two_otadata[0], result, sizeof(esp_ota_select_entry_t));
|
||||
memcpy(&two_otadata[1], result + SPI_FLASH_SEC_SIZE, sizeof(esp_ota_select_entry_t));
|
||||
spi_flash_munmap(ota_data_map);
|
||||
}
|
||||
return otadata_partition;
|
||||
}
|
||||
|
||||
static esp_err_t image_validate(const esp_partition_t *partition, esp_image_load_mode_t load_mode)
|
||||
{
|
||||
esp_image_metadata_t data;
|
||||
const esp_partition_pos_t part_pos = {
|
||||
.offset = partition->address,
|
||||
.size = partition->size,
|
||||
};
|
||||
|
||||
if (esp_image_verify(load_mode, &part_pos, &data) != ESP_OK) {
|
||||
return ESP_ERR_OTA_VALIDATE_FAILED;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SECURE_SIGNED_ON_UPDATE
|
||||
esp_err_t ret = esp_secure_boot_verify_signature(partition->address, data.image_len);
|
||||
if (ret != ESP_OK) {
|
||||
return ESP_ERR_OTA_VALIDATE_FAILED;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_ota_img_states_t set_new_state_otadata(void)
|
||||
{
|
||||
#ifdef CONFIG_APP_ROLLBACK_ENABLE
|
||||
ESP_LOGD(TAG, "Monitoring the first boot of the app is enabled.");
|
||||
return ESP_OTA_IMG_NEW;
|
||||
#else
|
||||
return ESP_OTA_IMG_UNDEFINED;
|
||||
#endif
|
||||
}
|
||||
|
||||
esp_err_t esp_ota_begin(const esp_partition_t *partition, size_t image_size, esp_ota_handle_t *out_handle)
|
||||
{
|
||||
ota_ops_entry_t *new_entry;
|
||||
@@ -146,27 +94,15 @@ esp_err_t esp_ota_begin(const esp_partition_t *partition, size_t image_size, esp
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
const esp_partition_t* running_partition = esp_ota_get_running_partition();
|
||||
if (partition == running_partition) {
|
||||
if (partition == esp_ota_get_running_partition()) {
|
||||
return ESP_ERR_OTA_PARTITION_CONFLICT;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_APP_ROLLBACK_ENABLE
|
||||
esp_ota_img_states_t ota_state_running_part;
|
||||
if (esp_ota_get_state_partition(running_partition, &ota_state_running_part) == ESP_OK) {
|
||||
if (ota_state_running_part == ESP_OTA_IMG_PENDING_VERIFY) {
|
||||
ESP_LOGE(TAG, "Running app has not confirmed state (ESP_OTA_IMG_PENDING_VERIFY)");
|
||||
return ESP_ERR_OTA_ROLLBACK_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// If input image size is 0 or OTA_SIZE_UNKNOWN, erase entire partition
|
||||
if ((image_size == 0) || (image_size == OTA_SIZE_UNKNOWN)) {
|
||||
ret = esp_partition_erase_range(partition, 0, partition->size);
|
||||
} else {
|
||||
const int aligned_erase_size = (image_size + SPI_FLASH_SEC_SIZE - 1) & ~(SPI_FLASH_SEC_SIZE - 1);
|
||||
ret = esp_partition_erase_range(partition, 0, aligned_erase_size);
|
||||
ret = esp_partition_erase_range(partition, 0, (image_size / SPI_FLASH_SEC_SIZE + 1) * SPI_FLASH_SEC_SIZE);
|
||||
}
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
@@ -208,8 +144,9 @@ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void *data, size_t size)
|
||||
if (it->handle == handle) {
|
||||
// must erase the partition before writing to it
|
||||
assert(it->erased_size > 0 && "must erase the partition before writing to it");
|
||||
if (it->wrote_size == 0 && it->partial_bytes == 0 && size > 0 && data_bytes[0] != ESP_IMAGE_HEADER_MAGIC) {
|
||||
ESP_LOGE(TAG, "OTA image has invalid magic byte (expected 0xE9, saw 0x%02x)", data_bytes[0]);
|
||||
|
||||
if(it->wrote_size == 0 && size > 0 && data_bytes[0] != 0xE9) {
|
||||
ESP_LOGE(TAG, "OTA image has invalid magic byte (expected 0xE9, saw 0x%02x", data_bytes[0]);
|
||||
return ESP_ERR_OTA_VALIDATE_FAILED;
|
||||
}
|
||||
|
||||
@@ -219,7 +156,7 @@ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void *data, size_t size)
|
||||
|
||||
/* check if we have partially written data from earlier */
|
||||
if (it->partial_bytes != 0) {
|
||||
copy_len = MIN(16 - it->partial_bytes, size);
|
||||
copy_len = OTA_MIN(16 - it->partial_bytes, size);
|
||||
memcpy(it->partial_data + it->partial_bytes, data_bytes, copy_len);
|
||||
it->partial_bytes += copy_len;
|
||||
if (it->partial_bytes != 16) {
|
||||
@@ -254,13 +191,14 @@ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void *data, size_t size)
|
||||
}
|
||||
|
||||
//if go to here ,means don't find the handle
|
||||
ESP_LOGE(TAG,"not found the handle");
|
||||
ESP_LOGE(TAG,"not found the handle")
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_err_t esp_ota_end(esp_ota_handle_t handle)
|
||||
{
|
||||
ota_ops_entry_t *it;
|
||||
size_t image_size;
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
for (it = LIST_FIRST(&s_ota_ops_entries_head); it != NULL; it = LIST_NEXT(it, entries)) {
|
||||
@@ -292,36 +230,50 @@ esp_err_t esp_ota_end(esp_ota_handle_t handle)
|
||||
it->partial_bytes = 0;
|
||||
}
|
||||
|
||||
esp_image_metadata_t data;
|
||||
const esp_partition_pos_t part_pos = {
|
||||
.offset = it->part->address,
|
||||
.size = it->part->size,
|
||||
};
|
||||
|
||||
if (esp_image_verify(ESP_IMAGE_VERIFY, &part_pos, &data) != ESP_OK) {
|
||||
if (esp_image_basic_verify(it->part->address, true, &image_size) != ESP_OK) {
|
||||
ret = ESP_ERR_OTA_VALIDATE_FAILED;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_ENABLED
|
||||
ret = esp_secure_boot_verify_signature(it->part->address, image_size);
|
||||
if (ret != ESP_OK) {
|
||||
ret = ESP_ERR_OTA_VALIDATE_FAILED;
|
||||
goto cleanup;
|
||||
}
|
||||
#endif
|
||||
|
||||
cleanup:
|
||||
LIST_REMOVE(it, entries);
|
||||
free(it);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t rewrite_ota_seq(esp_ota_select_entry_t *two_otadata, uint32_t seq, uint8_t sec_id, const esp_partition_t *ota_data_partition)
|
||||
static uint32_t ota_select_crc(const ota_select *s)
|
||||
{
|
||||
if (two_otadata == NULL || sec_id > 1) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return crc32_le(UINT32_MAX, (uint8_t *)&s->ota_seq, 4);
|
||||
}
|
||||
|
||||
two_otadata[sec_id].ota_seq = seq;
|
||||
two_otadata[sec_id].crc = bootloader_common_ota_select_crc(&two_otadata[sec_id]);
|
||||
esp_err_t ret = esp_partition_erase_range(ota_data_partition, sec_id * SPI_FLASH_SEC_SIZE, SPI_FLASH_SEC_SIZE);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
static bool ota_select_valid(const ota_select *s)
|
||||
{
|
||||
return s->ota_seq != UINT32_MAX && s->crc == ota_select_crc(s);
|
||||
}
|
||||
|
||||
static esp_err_t rewrite_ota_seq(uint32_t seq, uint8_t sec_id, const esp_partition_t *ota_data_partition)
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
if (sec_id == 0 || sec_id == 1) {
|
||||
s_ota_select[sec_id].ota_seq = seq;
|
||||
s_ota_select[sec_id].crc = ota_select_crc(&s_ota_select[sec_id]);
|
||||
ret = esp_partition_erase_range(ota_data_partition, sec_id * SPI_FLASH_SEC_SIZE, SPI_FLASH_SEC_SIZE);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
} else {
|
||||
return esp_partition_write(ota_data_partition, SPI_FLASH_SEC_SIZE * sec_id, &s_ota_select[sec_id].ota_seq, sizeof(ota_select));
|
||||
}
|
||||
} else {
|
||||
return esp_partition_write(ota_data_partition, SPI_FLASH_SEC_SIZE * sec_id, &two_otadata[sec_id], sizeof(esp_ota_select_entry_t));
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,166 +289,185 @@ static uint8_t get_ota_partition_count(void)
|
||||
|
||||
static esp_err_t esp_rewrite_ota_data(esp_partition_subtype_t subtype)
|
||||
{
|
||||
esp_ota_select_entry_t otadata[2];
|
||||
const esp_partition_t *otadata_partition = read_otadata(otadata);
|
||||
if (otadata_partition == NULL) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
esp_err_t ret;
|
||||
const esp_partition_t *find_partition = NULL;
|
||||
uint16_t ota_app_count = 0;
|
||||
uint32_t i = 0;
|
||||
uint32_t seq;
|
||||
static spi_flash_mmap_memory_t ota_data_map;
|
||||
const void *result = NULL;
|
||||
|
||||
int ota_app_count = get_ota_partition_count();
|
||||
if (SUB_TYPE_ID(subtype) >= ota_app_count) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
//esp32_idf use two sector for store information about which partition is running
|
||||
//it defined the two sector as ota data partition,two structure esp_ota_select_entry_t is saved in the two sector
|
||||
//named data in first sector as otadata[0], second sector data as otadata[1]
|
||||
//e.g.
|
||||
//if otadata[0].ota_seq == otadata[1].ota_seq == 0xFFFFFFFF,means ota info partition is in init status
|
||||
//so it will boot factory application(if there is),if there's no factory application,it will boot ota[0] application
|
||||
//if otadata[0].ota_seq != 0 and otadata[1].ota_seq != 0,it will choose a max seq ,and get value of max_seq%max_ota_app_number
|
||||
//and boot a subtype (mask 0x0F) value is (max_seq - 1)%max_ota_app_number,so if want switch to run ota[x],can use next formulas.
|
||||
//for example, if otadata[0].ota_seq = 4, otadata[1].ota_seq = 5, and there are 8 ota application,
|
||||
//current running is (5-1)%8 = 4,running ota[4],so if we want to switch to run ota[7],
|
||||
//we should add otadata[0].ota_seq (is 4) to 4 ,(8-1)%8=7,then it will boot ota[7]
|
||||
//if A=(B - C)%D
|
||||
//then B=(A + C)%D + D*n ,n= (0,1,2...)
|
||||
//so current ota app sub type id is x , dest bin subtype is y,total ota app count is n
|
||||
//seq will add (x + n*1 + 1 - seq)%n
|
||||
|
||||
int active_otadata = bootloader_common_get_active_otadata(otadata);
|
||||
if (active_otadata != -1) {
|
||||
uint32_t seq = otadata[active_otadata].ota_seq;
|
||||
uint32_t i = 0;
|
||||
while (seq > (SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count) {
|
||||
i++;
|
||||
find_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
|
||||
if (find_partition != NULL) {
|
||||
ota_app_count = get_ota_partition_count();
|
||||
//esp32_idf use two sector for store information about which partition is running
|
||||
//it defined the two sector as ota data partition,two structure ota_select is saved in the two sector
|
||||
//named data in first sector as s_ota_select[0], second sector data as s_ota_select[1]
|
||||
//e.g.
|
||||
//if s_ota_select[0].ota_seq == s_ota_select[1].ota_seq == 0xFFFFFFFF,means ota info partition is in init status
|
||||
//so it will boot factory application(if there is),if there's no factory application,it will boot ota[0] application
|
||||
//if s_ota_select[0].ota_seq != 0 and s_ota_select[1].ota_seq != 0,it will choose a max seq ,and get value of max_seq%max_ota_app_number
|
||||
//and boot a subtype (mask 0x0F) value is (max_seq - 1)%max_ota_app_number,so if want switch to run ota[x],can use next formulas.
|
||||
//for example, if s_ota_select[0].ota_seq = 4, s_ota_select[1].ota_seq = 5, and there are 8 ota application,
|
||||
//current running is (5-1)%8 = 4,running ota[4],so if we want to switch to run ota[7],
|
||||
//we should add s_ota_select[0].ota_seq (is 4) to 4 ,(8-1)%8=7,then it will boot ota[7]
|
||||
//if A=(B - C)%D
|
||||
//then B=(A + C)%D + D*n ,n= (0,1,2...)
|
||||
//so current ota app sub type id is x , dest bin subtype is y,total ota app count is n
|
||||
//seq will add (x + n*1 + 1 - seq)%n
|
||||
if (SUB_TYPE_ID(subtype) >= ota_app_count) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
int next_otadata = (~active_otadata)&1; // if 0 -> will be next 1. and if 1 -> will be next 0.
|
||||
otadata[next_otadata].ota_state = set_new_state_otadata();
|
||||
return rewrite_ota_seq(otadata, (SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count, next_otadata, otadata_partition);
|
||||
|
||||
ret = esp_partition_mmap(find_partition, 0, find_partition->size, SPI_FLASH_MMAP_DATA, &result, &ota_data_map);
|
||||
if (ret != ESP_OK) {
|
||||
result = NULL;
|
||||
return ret;
|
||||
} else {
|
||||
memcpy(&s_ota_select[0], result, sizeof(ota_select));
|
||||
memcpy(&s_ota_select[1], result + SPI_FLASH_SEC_SIZE, sizeof(ota_select));
|
||||
spi_flash_munmap(ota_data_map);
|
||||
}
|
||||
|
||||
if (ota_select_valid(&s_ota_select[0]) && ota_select_valid(&s_ota_select[1])) {
|
||||
seq = OTA_MAX(s_ota_select[0].ota_seq, s_ota_select[1].ota_seq);
|
||||
while (seq > (SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count) {
|
||||
i++;
|
||||
}
|
||||
|
||||
if (s_ota_select[0].ota_seq >= s_ota_select[1].ota_seq) {
|
||||
return rewrite_ota_seq((SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count, 1, find_partition);
|
||||
} else {
|
||||
return rewrite_ota_seq((SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count, 0, find_partition);
|
||||
}
|
||||
|
||||
} else if (ota_select_valid(&s_ota_select[0])) {
|
||||
while (s_ota_select[0].ota_seq > (SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count) {
|
||||
i++;
|
||||
}
|
||||
return rewrite_ota_seq((SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count, 1, find_partition);
|
||||
|
||||
} else if (ota_select_valid(&s_ota_select[1])) {
|
||||
while (s_ota_select[1].ota_seq > (SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count) {
|
||||
i++;
|
||||
}
|
||||
return rewrite_ota_seq((SUB_TYPE_ID(subtype) + 1) % ota_app_count + i * ota_app_count, 0, find_partition);
|
||||
|
||||
} else {
|
||||
/* Both OTA slots are invalid, probably because unformatted... */
|
||||
return rewrite_ota_seq(SUB_TYPE_ID(subtype) + 1, 0, find_partition);
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Both OTA slots are invalid, probably because unformatted... */
|
||||
int next_otadata = 0;
|
||||
otadata[next_otadata].ota_state = set_new_state_otadata();
|
||||
return rewrite_ota_seq(otadata, SUB_TYPE_ID(subtype) + 1, next_otadata, otadata_partition);
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t esp_ota_set_boot_partition(const esp_partition_t *partition)
|
||||
{
|
||||
size_t image_size;
|
||||
const esp_partition_t *find_partition = NULL;
|
||||
if (partition == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (image_validate(partition, ESP_IMAGE_VERIFY) != ESP_OK) {
|
||||
if (esp_image_basic_verify(partition->address, true, &image_size) != ESP_OK) {
|
||||
return ESP_ERR_OTA_VALIDATE_FAILED;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_ENABLED
|
||||
esp_err_t ret = esp_secure_boot_verify_signature(partition->address, image_size);
|
||||
if (ret != ESP_OK) {
|
||||
return ESP_ERR_OTA_VALIDATE_FAILED;
|
||||
}
|
||||
#endif
|
||||
// if set boot partition to factory bin ,just format ota info partition
|
||||
if (partition->type == ESP_PARTITION_TYPE_APP) {
|
||||
if (partition->subtype == ESP_PARTITION_SUBTYPE_APP_FACTORY) {
|
||||
const esp_partition_t *find_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
|
||||
find_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
|
||||
if (find_partition != NULL) {
|
||||
return esp_partition_erase_range(find_partition, 0, find_partition->size);
|
||||
} else {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
} else {
|
||||
#ifdef CONFIG_APP_ANTI_ROLLBACK
|
||||
esp_app_desc_t partition_app_desc;
|
||||
esp_err_t err = esp_ota_get_partition_description(partition, &partition_app_desc);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
// try to find this partition in flash,if not find it ,return error
|
||||
find_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
|
||||
if (find_partition != NULL) {
|
||||
return esp_rewrite_ota_data(partition->subtype);
|
||||
} else {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (esp_efuse_check_secure_version(partition_app_desc.secure_version) == false) {
|
||||
ESP_LOGE(TAG, "This a new partition can not be booted due to a secure version is lower than stored in efuse. Partition will be erased.");
|
||||
esp_err_t err = esp_partition_erase_range(partition, 0, partition->size);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
return ESP_ERR_OTA_SMALL_SEC_VER;
|
||||
}
|
||||
#endif
|
||||
return esp_rewrite_ota_data(partition->subtype);
|
||||
}
|
||||
} else {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
static const esp_partition_t *find_default_boot_partition(void)
|
||||
{
|
||||
// This logic matches the logic of bootloader get_selected_boot_partition() & load_boot_image().
|
||||
|
||||
// Default to factory if present
|
||||
const esp_partition_t *result = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL);
|
||||
if (result != NULL) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Try first OTA slot if no factory partition
|
||||
for (esp_partition_subtype_t s = ESP_PARTITION_SUBTYPE_APP_OTA_MIN; s != ESP_PARTITION_SUBTYPE_APP_OTA_MAX; s++) {
|
||||
result = esp_partition_find_first(ESP_PARTITION_TYPE_APP, s, NULL);
|
||||
if (result != NULL) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Test app slot if present
|
||||
result = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_TEST, NULL);
|
||||
if (result != NULL) {
|
||||
return result;
|
||||
}
|
||||
|
||||
ESP_LOGE(TAG, "invalid partition table, no app partitions");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const esp_partition_t *esp_ota_get_boot_partition(void)
|
||||
{
|
||||
esp_ota_select_entry_t otadata[2];
|
||||
const esp_partition_t *otadata_partition = read_otadata(otadata);
|
||||
if (otadata_partition == NULL) {
|
||||
esp_err_t ret;
|
||||
const esp_partition_t *find_partition = NULL;
|
||||
static spi_flash_mmap_memory_t ota_data_map;
|
||||
const void *result = NULL;
|
||||
uint16_t ota_app_count = 0;
|
||||
find_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
|
||||
|
||||
if (find_partition == NULL) {
|
||||
ESP_LOGE(TAG, "not found ota data");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ota_app_count = get_ota_partition_count();
|
||||
ret = esp_partition_mmap(find_partition, 0, find_partition->size, SPI_FLASH_MMAP_DATA, &result, &ota_data_map);
|
||||
if (ret != ESP_OK) {
|
||||
spi_flash_munmap(ota_data_map);
|
||||
ESP_LOGE(TAG, "mmap ota data filed");
|
||||
return NULL;
|
||||
} else {
|
||||
memcpy(&s_ota_select[0], result, sizeof(ota_select));
|
||||
memcpy(&s_ota_select[1], result + 0x1000, sizeof(ota_select));
|
||||
spi_flash_munmap(ota_data_map);
|
||||
}
|
||||
ota_app_count = get_ota_partition_count();
|
||||
|
||||
ESP_LOGD(TAG, "found ota app max = %d", ota_app_count);
|
||||
|
||||
if ((bootloader_common_ota_select_invalid(&otadata[0]) &&
|
||||
bootloader_common_ota_select_invalid(&otadata[1])) ||
|
||||
ota_app_count == 0) {
|
||||
ESP_LOGD(TAG, "finding factory app...");
|
||||
return find_default_boot_partition();
|
||||
if (s_ota_select[0].ota_seq == 0xFFFFFFFF && s_ota_select[1].ota_seq == 0xFFFFFFFF) {
|
||||
ESP_LOGD(TAG, "finding factory app......");
|
||||
|
||||
return esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL);
|
||||
} else if (ota_select_valid(&s_ota_select[0]) && ota_select_valid(&s_ota_select[1])) {
|
||||
ESP_LOGD(TAG, "finding ota_%d app......", \
|
||||
ESP_PARTITION_SUBTYPE_APP_OTA_MIN + ((OTA_MAX(s_ota_select[0].ota_seq, s_ota_select[1].ota_seq) - 1) % ota_app_count));
|
||||
|
||||
return esp_partition_find_first(ESP_PARTITION_TYPE_APP, \
|
||||
ESP_PARTITION_SUBTYPE_APP_OTA_MIN + ((OTA_MAX(s_ota_select[0].ota_seq, s_ota_select[1].ota_seq) - 1) % ota_app_count), NULL);
|
||||
} else if (ota_select_valid(&s_ota_select[0])) {
|
||||
ESP_LOGD(TAG, "finding ota_%d app......", \
|
||||
ESP_PARTITION_SUBTYPE_APP_OTA_MIN + (s_ota_select[0].ota_seq - 1) % ota_app_count);
|
||||
|
||||
return esp_partition_find_first(ESP_PARTITION_TYPE_APP, \
|
||||
ESP_PARTITION_SUBTYPE_APP_OTA_MIN + (s_ota_select[0].ota_seq - 1) % ota_app_count, NULL);
|
||||
|
||||
} else if (ota_select_valid(&s_ota_select[1])) {
|
||||
ESP_LOGD(TAG, "finding ota_%d app......", \
|
||||
ESP_PARTITION_SUBTYPE_APP_OTA_MIN + (s_ota_select[1].ota_seq - 1) % ota_app_count);
|
||||
|
||||
return esp_partition_find_first(ESP_PARTITION_TYPE_APP, \
|
||||
ESP_PARTITION_SUBTYPE_APP_OTA_MIN + (s_ota_select[1].ota_seq - 1) % ota_app_count, NULL);
|
||||
|
||||
} else {
|
||||
int active_otadata = bootloader_common_get_active_otadata(otadata);
|
||||
if (active_otadata != -1) {
|
||||
int ota_slot = (otadata[active_otadata].ota_seq - 1) % ota_app_count; // Actual OTA partition selection
|
||||
ESP_LOGD(TAG, "finding ota_%d app...", ESP_PARTITION_SUBTYPE_APP_OTA_MIN + ota_slot);
|
||||
return esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_MIN + ota_slot, NULL);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "ota data invalid, no current app. Assuming factory");
|
||||
return find_default_boot_partition();
|
||||
}
|
||||
ESP_LOGE(TAG, "ota data invalid, no current app. Assuming factory");
|
||||
return esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const esp_partition_t* esp_ota_get_running_partition(void)
|
||||
{
|
||||
static const esp_partition_t *curr_partition = NULL;
|
||||
|
||||
/*
|
||||
* Currently running partition is unlikely to change across reset cycle,
|
||||
* so it can be cached here, and avoid lookup on every flash write operation.
|
||||
*/
|
||||
if (curr_partition != NULL) {
|
||||
return curr_partition;
|
||||
}
|
||||
|
||||
/* Find the flash address of this exact function. By definition that is part
|
||||
of the currently running firmware. Then find the enclosing partition. */
|
||||
|
||||
size_t phys_offs = spi_flash_cache2phys(esp_ota_get_running_partition);
|
||||
|
||||
assert (phys_offs != SPI_FLASH_CACHE2PHYS_FAIL); /* indicates cache2phys lookup is buggy */
|
||||
@@ -510,7 +481,6 @@ const esp_partition_t* esp_ota_get_running_partition(void)
|
||||
const esp_partition_t *p = esp_partition_get(it);
|
||||
if (p->address <= phys_offs && p->address + p->size > phys_offs) {
|
||||
esp_partition_iterator_release(it);
|
||||
curr_partition = p;
|
||||
return p;
|
||||
}
|
||||
it = esp_partition_next(it);
|
||||
@@ -567,265 +537,3 @@ const esp_partition_t* esp_ota_get_next_update_partition(const esp_partition_t *
|
||||
return default_ota;
|
||||
|
||||
}
|
||||
|
||||
esp_err_t esp_ota_get_partition_description(const esp_partition_t *partition, esp_app_desc_t *app_desc)
|
||||
{
|
||||
if (partition == NULL || app_desc == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if(partition->type != ESP_PARTITION_TYPE_APP) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
esp_err_t err = esp_partition_read(partition, sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t), app_desc, sizeof(esp_app_desc_t));
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (app_desc->magic_word != ESP_APP_DESC_MAGIC_WORD) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_APP_ANTI_ROLLBACK
|
||||
static esp_err_t esp_ota_set_anti_rollback(void) {
|
||||
const esp_app_desc_t *app_desc = esp_ota_get_app_description();
|
||||
return esp_efuse_update_secure_version(app_desc->secure_version);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Checks applications on the slots which can be booted in case of rollback.
|
||||
// Returns true if the slots have at least one app (except the running app).
|
||||
bool esp_ota_check_rollback_is_possible(void)
|
||||
{
|
||||
esp_ota_select_entry_t otadata[2];
|
||||
if (read_otadata(otadata) == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int ota_app_count = get_ota_partition_count();
|
||||
if (ota_app_count == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool valid_otadata[2];
|
||||
valid_otadata[0] = bootloader_common_ota_select_valid(&otadata[0]);
|
||||
valid_otadata[1] = bootloader_common_ota_select_valid(&otadata[1]);
|
||||
|
||||
int active_ota = bootloader_common_select_otadata(otadata, valid_otadata, true);
|
||||
if (active_ota == -1) {
|
||||
return false;
|
||||
}
|
||||
int last_active_ota = (~active_ota)&1;
|
||||
|
||||
const esp_partition_t *partition = NULL;
|
||||
#ifndef CONFIG_APP_ANTI_ROLLBACK
|
||||
if (valid_otadata[last_active_ota] == false) {
|
||||
partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL);
|
||||
if (partition != NULL) {
|
||||
if(image_validate(partition, ESP_IMAGE_VERIFY_SILENT) == ESP_OK) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (valid_otadata[last_active_ota] == true) {
|
||||
int slot = (otadata[last_active_ota].ota_seq - 1) % ota_app_count;
|
||||
partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_MIN + slot, NULL);
|
||||
if (partition != NULL) {
|
||||
if(image_validate(partition, ESP_IMAGE_VERIFY_SILENT) == ESP_OK) {
|
||||
#ifdef CONFIG_APP_ANTI_ROLLBACK
|
||||
esp_app_desc_t app_desc;
|
||||
if (esp_ota_get_partition_description(partition, &app_desc) == ESP_OK &&
|
||||
esp_efuse_check_secure_version(app_desc.secure_version) == true) {
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// if valid == false - will done rollback with reboot. After reboot will boot previous OTA[x] or Factory partition.
|
||||
// if valid == true - it confirm that current OTA[x] is workable. Reboot will not happen.
|
||||
static esp_err_t esp_ota_current_ota_is_workable(bool valid)
|
||||
{
|
||||
esp_ota_select_entry_t otadata[2];
|
||||
const esp_partition_t *otadata_partition = read_otadata(otadata);
|
||||
if (otadata_partition == NULL) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
int active_otadata = bootloader_common_get_active_otadata(otadata);
|
||||
if (active_otadata != -1 && get_ota_partition_count() != 0) {
|
||||
if (valid == true && otadata[active_otadata].ota_state != ESP_OTA_IMG_VALID) {
|
||||
otadata[active_otadata].ota_state = ESP_OTA_IMG_VALID;
|
||||
ESP_LOGD(TAG, "OTA[current] partition is marked as VALID");
|
||||
esp_err_t err = rewrite_ota_seq(otadata, otadata[active_otadata].ota_seq, active_otadata, otadata_partition);
|
||||
#ifdef CONFIG_APP_ANTI_ROLLBACK
|
||||
if (err == ESP_OK) {
|
||||
return esp_ota_set_anti_rollback();
|
||||
}
|
||||
#endif
|
||||
return err;
|
||||
} else if (valid == false) {
|
||||
if (esp_ota_check_rollback_is_possible() == false) {
|
||||
ESP_LOGE(TAG, "Rollback is not possible, do not have any suitable apps in slots");
|
||||
return ESP_ERR_OTA_ROLLBACK_FAILED;
|
||||
}
|
||||
ESP_LOGD(TAG, "OTA[current] partition is marked as INVALID");
|
||||
otadata[active_otadata].ota_state = ESP_OTA_IMG_INVALID;
|
||||
esp_err_t err = rewrite_ota_seq(otadata, otadata[active_otadata].ota_seq, active_otadata, otadata_partition);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
ESP_LOGI(TAG, "Rollback to previously worked partition. Restart.");
|
||||
esp_restart();
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Running firmware is factory");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_ota_mark_app_valid_cancel_rollback()
|
||||
{
|
||||
return esp_ota_current_ota_is_workable(true);
|
||||
}
|
||||
|
||||
esp_err_t esp_ota_mark_app_invalid_rollback_and_reboot()
|
||||
{
|
||||
return esp_ota_current_ota_is_workable(false);
|
||||
}
|
||||
|
||||
static bool check_invalid_otadata (const esp_ota_select_entry_t *s) {
|
||||
return s->ota_seq != UINT32_MAX &&
|
||||
s->crc == bootloader_common_ota_select_crc(s) &&
|
||||
(s->ota_state == ESP_OTA_IMG_INVALID ||
|
||||
s->ota_state == ESP_OTA_IMG_ABORTED);
|
||||
}
|
||||
|
||||
static int get_last_invalid_otadata(const esp_ota_select_entry_t *two_otadata)
|
||||
{
|
||||
|
||||
bool invalid_otadata[2];
|
||||
invalid_otadata[0] = check_invalid_otadata(&two_otadata[0]);
|
||||
invalid_otadata[1] = check_invalid_otadata(&two_otadata[1]);
|
||||
int num_invalid_otadata = bootloader_common_select_otadata(two_otadata, invalid_otadata, false);
|
||||
ESP_LOGD(TAG, "Invalid otadata[%d]", num_invalid_otadata);
|
||||
return num_invalid_otadata;
|
||||
}
|
||||
|
||||
const esp_partition_t* esp_ota_get_last_invalid_partition()
|
||||
{
|
||||
esp_ota_select_entry_t otadata[2];
|
||||
if (read_otadata(otadata) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int invalid_otadata = get_last_invalid_otadata(otadata);
|
||||
|
||||
int ota_app_count = get_ota_partition_count();
|
||||
if (invalid_otadata != -1 && ota_app_count != 0) {
|
||||
int ota_slot = (otadata[invalid_otadata].ota_seq - 1) % ota_app_count;
|
||||
ESP_LOGD(TAG, "Find invalid ota_%d app", ESP_PARTITION_SUBTYPE_APP_OTA_MIN + ota_slot);
|
||||
|
||||
const esp_partition_t* invalid_partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_MIN + ota_slot, NULL);
|
||||
if (invalid_partition != NULL) {
|
||||
if (image_validate(invalid_partition, ESP_IMAGE_VERIFY_SILENT) != ESP_OK) {
|
||||
ESP_LOGD(TAG, "Last invalid partition has corrupted app");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return invalid_partition;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
esp_err_t esp_ota_get_state_partition(const esp_partition_t *partition, esp_ota_img_states_t *ota_state)
|
||||
{
|
||||
if (partition == NULL || ota_state == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!is_ota_partition(partition)) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
esp_ota_select_entry_t otadata[2];
|
||||
int ota_app_count = get_ota_partition_count();
|
||||
if (read_otadata(otadata) == NULL || ota_app_count == 0) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
int req_ota_slot = partition->subtype - ESP_PARTITION_SUBTYPE_APP_OTA_MIN;
|
||||
bool not_found = true;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
int ota_slot = (otadata[i].ota_seq - 1) % ota_app_count;
|
||||
if (ota_slot == req_ota_slot && otadata[i].crc == bootloader_common_ota_select_crc(&otadata[i])) {
|
||||
*ota_state = otadata[i].ota_state;
|
||||
not_found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (not_found) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_ota_erase_last_boot_app_partition(void)
|
||||
{
|
||||
esp_ota_select_entry_t otadata[2];
|
||||
const esp_partition_t* ota_data_partition = read_otadata(otadata);
|
||||
if (ota_data_partition == NULL) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
int active_otadata = bootloader_common_get_active_otadata(otadata);
|
||||
int ota_app_count = get_ota_partition_count();
|
||||
if (active_otadata == -1 || ota_app_count == 0) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
int inactive_otadata = (~active_otadata)&1;
|
||||
if (otadata[inactive_otadata].ota_seq == UINT32_MAX || otadata[inactive_otadata].crc != bootloader_common_ota_select_crc(&otadata[inactive_otadata])) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
int ota_slot = (otadata[inactive_otadata].ota_seq - 1) % ota_app_count; // Actual OTA partition selection
|
||||
ESP_LOGD(TAG, "finding last_boot_app_partition ota_%d app...", ESP_PARTITION_SUBTYPE_APP_OTA_MIN + ota_slot);
|
||||
|
||||
const esp_partition_t* last_boot_app_partition_from_otadata = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_MIN + ota_slot, NULL);
|
||||
if (last_boot_app_partition_from_otadata == NULL) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
const esp_partition_t* running_partition = esp_ota_get_running_partition();
|
||||
if (running_partition == NULL || last_boot_app_partition_from_otadata == running_partition) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t err = esp_partition_erase_range(last_boot_app_partition_from_otadata, 0, last_boot_app_partition_from_otadata->size);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
int sec_id = inactive_otadata;
|
||||
err = esp_partition_erase_range(ota_data_partition, sec_id * SPI_FLASH_SEC_SIZE, SPI_FLASH_SEC_SIZE);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
123
components/app_update/include/esp_ota_ops.h
Normal file → Executable file
123
components/app_update/include/esp_ota_ops.h
Normal file → Executable file
@@ -20,8 +20,7 @@
|
||||
#include <stddef.h>
|
||||
#include "esp_err.h"
|
||||
#include "esp_partition.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_flash_data_types.h"
|
||||
#include "esp_spi_flash.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
@@ -34,10 +33,6 @@ extern "C"
|
||||
#define ESP_ERR_OTA_PARTITION_CONFLICT (ESP_ERR_OTA_BASE + 0x01) /*!< Error if request was to write or erase the current running partition */
|
||||
#define ESP_ERR_OTA_SELECT_INFO_INVALID (ESP_ERR_OTA_BASE + 0x02) /*!< Error if OTA data partition contains invalid content */
|
||||
#define ESP_ERR_OTA_VALIDATE_FAILED (ESP_ERR_OTA_BASE + 0x03) /*!< Error if OTA app image is invalid */
|
||||
#define ESP_ERR_OTA_SMALL_SEC_VER (ESP_ERR_OTA_BASE + 0x04) /*!< Error if the firmware has a secure version less than the running firmware. */
|
||||
#define ESP_ERR_OTA_ROLLBACK_FAILED (ESP_ERR_OTA_BASE + 0x05) /*!< Error if flash does not have valid firmware in passive partition and hence rollback is not possible */
|
||||
#define ESP_ERR_OTA_ROLLBACK_INVALID_STATE (ESP_ERR_OTA_BASE + 0x06) /*!< Error if current active firmware is still marked in pending validation state (ESP_OTA_IMG_PENDING_VERIFY), essentially first boot of firmware image post upgrade and hence firmware upgrade is not possible */
|
||||
|
||||
|
||||
/**
|
||||
* @brief Opaque handle for an application OTA update
|
||||
@@ -47,24 +42,6 @@ extern "C"
|
||||
*/
|
||||
typedef uint32_t esp_ota_handle_t;
|
||||
|
||||
/**
|
||||
* @brief Return esp_app_desc structure. This structure includes app version.
|
||||
*
|
||||
* Return description for running app.
|
||||
* @return Pointer to esp_app_desc structure.
|
||||
*/
|
||||
const esp_app_desc_t *esp_ota_get_app_description(void);
|
||||
|
||||
/**
|
||||
* @brief Fill the provided buffer with SHA256 of the ELF file, formatted as hexadecimal, null-terminated.
|
||||
* If the buffer size is not sufficient to fit the entire SHA256 in hex plus a null terminator,
|
||||
* the largest possible number of bytes will be written followed by a null.
|
||||
* @param dst Destination buffer
|
||||
* @param size Size of the buffer
|
||||
* @return Number of bytes written to dst (including null terminator)
|
||||
*/
|
||||
int esp_ota_get_app_elf_sha256(char* dst, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Commence an OTA update writing to the specified partition.
|
||||
|
||||
@@ -76,10 +53,6 @@ int esp_ota_get_app_elf_sha256(char* dst, size_t size);
|
||||
* On success, this function allocates memory that remains in use
|
||||
* until esp_ota_end() is called with the returned handle.
|
||||
*
|
||||
* Note: If the rollback option is enabled and the running application has the ESP_OTA_IMG_PENDING_VERIFY state then
|
||||
* it will lead to the ESP_ERR_OTA_ROLLBACK_INVALID_STATE error. Confirm the running app before to run download a new app,
|
||||
* use esp_ota_mark_app_valid_cancel_rollback() function for it (this should be done as early as possible when you first download a new application).
|
||||
*
|
||||
* @param partition Pointer to info for partition which will receive the OTA update. Required.
|
||||
* @param image_size Size of new OTA app image. Partition will be erased in order to receive this size of image. If 0 or OTA_SIZE_UNKNOWN, the entire partition is erased.
|
||||
* @param out_handle On success, returns a handle which should be used for subsequent esp_ota_write() and esp_ota_end() calls.
|
||||
@@ -93,7 +66,6 @@ int esp_ota_get_app_elf_sha256(char* dst, size_t size);
|
||||
* - ESP_ERR_OTA_SELECT_INFO_INVALID: The OTA data partition contains invalid data.
|
||||
* - ESP_ERR_INVALID_SIZE: Partition doesn't fit in configured flash size.
|
||||
* - ESP_ERR_FLASH_OP_TIMEOUT or ESP_ERR_FLASH_OP_FAIL: Flash write failed.
|
||||
* - ESP_ERR_OTA_ROLLBACK_INVALID_STATE: If the running app has not confirmed state. Before performing an update, the application must be valid.
|
||||
*/
|
||||
esp_err_t esp_ota_begin(const esp_partition_t* partition, size_t image_size, esp_ota_handle_t* out_handle);
|
||||
|
||||
@@ -154,17 +126,10 @@ esp_err_t esp_ota_set_boot_partition(const esp_partition_t* partition);
|
||||
*
|
||||
* If esp_ota_set_boot_partition() has been called, the partition which was set by that function will be returned.
|
||||
*
|
||||
* If esp_ota_set_boot_partition() has not been called, the result is usually the same as esp_ota_get_running_partition().
|
||||
* The two results are not equal if the configured boot partition does not contain a valid app (meaning that the running partition
|
||||
* will be an app that the bootloader chose via fallback).
|
||||
* If esp_ota_set_boot_partition() has not been called, the result is
|
||||
* equivalent to esp_ota_get_running_partition().
|
||||
*
|
||||
* If the OTA data partition is not present or not valid then the result is the first app partition found in the
|
||||
* partition table. In priority order, this means: the factory app, the first OTA app slot, or the test app partition.
|
||||
*
|
||||
* Note that there is no guarantee the returned partition is a valid app. Use esp_image_verify(ESP_IMAGE_VERIFY, ...) to verify if the
|
||||
* returned partition contains a bootable image.
|
||||
*
|
||||
* @return Pointer to info for partition structure, or NULL if partition table is invalid or a flash read operation failed. Any returned pointer is valid for the lifetime of the application.
|
||||
* @return Pointer to info for partition structure, or NULL if no partition is found or flash read operation failed. Returned pointer is valid for the lifetime of the application.
|
||||
*/
|
||||
const esp_partition_t* esp_ota_get_boot_partition(void);
|
||||
|
||||
@@ -177,9 +142,6 @@ const esp_partition_t* esp_ota_get_boot_partition(void);
|
||||
* esp_ota_set_boot_partition(). Only the app whose code is currently
|
||||
* running will have its partition information returned.
|
||||
*
|
||||
* The partition returned by this function may also differ from esp_ota_get_boot_partition() if the configured boot
|
||||
* partition is somehow invalid, and the bootloader fell back to a different app partition at boot.
|
||||
*
|
||||
* @return Pointer to info for partition structure, or NULL if no partition is found or flash read operation failed. Returned pointer is valid for the lifetime of the application.
|
||||
*/
|
||||
const esp_partition_t* esp_ota_get_running_partition(void);
|
||||
@@ -199,83 +161,6 @@ const esp_partition_t* esp_ota_get_running_partition(void);
|
||||
*/
|
||||
const esp_partition_t* esp_ota_get_next_update_partition(const esp_partition_t *start_from);
|
||||
|
||||
/**
|
||||
* @brief Returns esp_app_desc structure for app partition. This structure includes app version.
|
||||
*
|
||||
* Returns a description for the requested app partition.
|
||||
* @param[in] partition Pointer to app partition. (only app partition)
|
||||
* @param[out] app_desc Structure of info about app.
|
||||
* @return
|
||||
* - ESP_OK Successful.
|
||||
* - ESP_ERR_NOT_FOUND app_desc structure is not found. Magic word is incorrect.
|
||||
* - ESP_ERR_NOT_SUPPORTED Partition is not application.
|
||||
* - ESP_ERR_INVALID_ARG Arguments is NULL or if partition's offset exceeds partition size.
|
||||
* - ESP_ERR_INVALID_SIZE Read would go out of bounds of the partition.
|
||||
* - or one of error codes from lower-level flash driver.
|
||||
*/
|
||||
esp_err_t esp_ota_get_partition_description(const esp_partition_t *partition, esp_app_desc_t *app_desc);
|
||||
|
||||
/**
|
||||
* @brief This function is called to indicate that the running app is working well.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: if successful.
|
||||
*/
|
||||
esp_err_t esp_ota_mark_app_valid_cancel_rollback();
|
||||
|
||||
/**
|
||||
* @brief This function is called to roll back to the previously workable app with reboot.
|
||||
*
|
||||
* If rollback is successful then device will reset else API will return with error code.
|
||||
* Checks applications on a flash drive that can be booted in case of rollback.
|
||||
* If the flash does not have at least one app (except the running app) then rollback is not possible.
|
||||
* @return
|
||||
* - ESP_FAIL: if not successful.
|
||||
* - ESP_ERR_OTA_ROLLBACK_FAILED: The rollback is not possible due to flash does not have any apps.
|
||||
*/
|
||||
esp_err_t esp_ota_mark_app_invalid_rollback_and_reboot();
|
||||
|
||||
/**
|
||||
* @brief Returns last partition with invalid state (ESP_OTA_IMG_INVALID or ESP_OTA_IMG_ABORTED).
|
||||
*
|
||||
* @return partition.
|
||||
*/
|
||||
const esp_partition_t* esp_ota_get_last_invalid_partition();
|
||||
|
||||
/**
|
||||
* @brief Returns state for given partition.
|
||||
*
|
||||
* @param[in] partition Pointer to partition.
|
||||
* @param[out] ota_state state of partition (if this partition has a record in otadata).
|
||||
* @return
|
||||
* - ESP_OK: Successful.
|
||||
* - ESP_ERR_INVALID_ARG: partition or ota_state arguments were NULL.
|
||||
* - ESP_ERR_NOT_SUPPORTED: partition is not ota.
|
||||
* - ESP_ERR_NOT_FOUND: Partition table does not have otadata or state was not found for given partition.
|
||||
*/
|
||||
esp_err_t esp_ota_get_state_partition(const esp_partition_t *partition, esp_ota_img_states_t *ota_state);
|
||||
|
||||
/**
|
||||
* @brief Erase previous boot app partition and corresponding otadata select for this partition.
|
||||
*
|
||||
* When current app is marked to as valid then you can erase previous app partition.
|
||||
* @return
|
||||
* - ESP_OK: Successful, otherwise ESP_ERR.
|
||||
*/
|
||||
esp_err_t esp_ota_erase_last_boot_app_partition(void);
|
||||
|
||||
/**
|
||||
* @brief Checks applications on the slots which can be booted in case of rollback.
|
||||
*
|
||||
* These applications should be valid (marked in otadata as not UNDEFINED, INVALID or ABORTED and crc is good) and be able booted,
|
||||
* and secure_version of app >= secure_version of efuse (if anti-rollback is enabled).
|
||||
*
|
||||
* @return
|
||||
* - True: Returns true if the slots have at least one app (except the running app).
|
||||
* - False: The rollback is not possible.
|
||||
*/
|
||||
bool esp_ota_check_rollback_is_possible(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,343 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# otatool is used to perform ota-level operations - flashing ota partition
|
||||
# erasing ota partition and switching ota partition
|
||||
#
|
||||
# Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# 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.
|
||||
from __future__ import print_function, division
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import binascii
|
||||
import subprocess
|
||||
import tempfile
|
||||
import collections
|
||||
import struct
|
||||
|
||||
__version__ = '1.0'
|
||||
|
||||
IDF_COMPONENTS_PATH = os.path.expandvars(os.path.join("$IDF_PATH", "components"))
|
||||
|
||||
PARTTOOL_PY = os.path.join(IDF_COMPONENTS_PATH, "partition_table", "parttool.py")
|
||||
|
||||
SPI_FLASH_SEC_SIZE = 0x2000
|
||||
|
||||
quiet = False
|
||||
|
||||
|
||||
def status(msg):
|
||||
if not quiet:
|
||||
print(msg)
|
||||
|
||||
|
||||
def _invoke_parttool(parttool_args, args, output=False, partition=None):
|
||||
invoke_args = []
|
||||
|
||||
if partition:
|
||||
invoke_args += [sys.executable, PARTTOOL_PY] + partition
|
||||
else:
|
||||
invoke_args += [sys.executable, PARTTOOL_PY, "--partition-type", "data", "--partition-subtype", "ota"]
|
||||
|
||||
if quiet:
|
||||
invoke_args += ["-q"]
|
||||
|
||||
if args.port != "":
|
||||
invoke_args += ["--port", args.port]
|
||||
|
||||
if args.partition_table_file:
|
||||
invoke_args += ["--partition-table-file", args.partition_table_file]
|
||||
|
||||
if args.partition_table_offset:
|
||||
invoke_args += ["--partition-table-offset", args.partition_table_offset]
|
||||
|
||||
invoke_args += parttool_args
|
||||
|
||||
if output:
|
||||
return subprocess.check_output(invoke_args)
|
||||
else:
|
||||
return subprocess.check_call(invoke_args)
|
||||
|
||||
|
||||
def _get_otadata_contents(args, check=True):
|
||||
global quiet
|
||||
|
||||
if check:
|
||||
check_args = ["get_partition_info", "--info", "offset", "size"]
|
||||
|
||||
quiet = True
|
||||
output = _invoke_parttool(check_args, args, True).split(b" ")
|
||||
quiet = args.quiet
|
||||
|
||||
if not output:
|
||||
raise RuntimeError("No ota_data partition found")
|
||||
|
||||
with tempfile.NamedTemporaryFile(delete=False) as f:
|
||||
f_name = f.name
|
||||
|
||||
try:
|
||||
invoke_args = ["read_partition", "--output", f_name]
|
||||
_invoke_parttool(invoke_args, args)
|
||||
with open(f_name, "rb") as f:
|
||||
contents = f.read()
|
||||
finally:
|
||||
os.unlink(f_name)
|
||||
|
||||
return contents
|
||||
|
||||
|
||||
def _get_otadata_status(otadata_contents):
|
||||
status = []
|
||||
|
||||
otadata_status = collections.namedtuple("otadata_status", "seq crc")
|
||||
|
||||
for i in range(2):
|
||||
start = i * (SPI_FLASH_SEC_SIZE >> 1)
|
||||
|
||||
seq = bytearray(otadata_contents[start:start + 4])
|
||||
crc = bytearray(otadata_contents[start + 28:start + 32])
|
||||
|
||||
seq = struct.unpack('>I', seq)
|
||||
crc = struct.unpack('>I', crc)
|
||||
|
||||
status.append(otadata_status(seq[0], crc[0]))
|
||||
|
||||
return status
|
||||
|
||||
|
||||
def read_otadata(args):
|
||||
status("Reading ota_data partition contents...")
|
||||
otadata_info = _get_otadata_contents(args)
|
||||
otadata_info = _get_otadata_status(otadata_info)
|
||||
|
||||
print(otadata_info)
|
||||
|
||||
print("\t\t{:11}\t{:8s}|\t{:8s}\t{:8s}".format("OTA_SEQ", "CRC", "OTA_SEQ", "CRC"))
|
||||
print("Firmware: 0x{:8x} \t 0x{:8x} |\t0x{:8x} \t 0x{:8x}".format(otadata_info[0].seq, otadata_info[0].crc,
|
||||
otadata_info[1].seq, otadata_info[1].crc))
|
||||
|
||||
|
||||
def erase_otadata(args):
|
||||
status("Erasing ota_data partition contents...")
|
||||
_invoke_parttool(["erase_partition"], args)
|
||||
status("Erased ota_data partition contents")
|
||||
|
||||
|
||||
def switch_otadata(args):
|
||||
sys.path.append(os.path.join(IDF_COMPONENTS_PATH, "partition_table"))
|
||||
import gen_esp32part as gen
|
||||
|
||||
with tempfile.NamedTemporaryFile(delete=False) as f:
|
||||
f_name = f.name
|
||||
|
||||
try:
|
||||
def is_otadata_status_valid(status):
|
||||
seq = status.seq % (1 << 32)
|
||||
crc = hex(binascii.crc32(struct.pack("I", seq), 0xFFFFFFFF) % (1 << 32))
|
||||
return seq < (int('0xFFFFFFFF', 16) % (1 << 32)) and status.crc == crc
|
||||
|
||||
status("Looking for ota app partitions...")
|
||||
|
||||
# In order to get the number of ota app partitions, we need the partition table
|
||||
partition_table = None
|
||||
invoke_args = ["get_partition_info", "--table", f_name]
|
||||
|
||||
_invoke_parttool(invoke_args, args)
|
||||
|
||||
partition_table = open(f_name, "rb").read()
|
||||
partition_table = gen.PartitionTable.from_binary(partition_table)
|
||||
|
||||
ota_partitions = list()
|
||||
|
||||
for i in range(gen.NUM_PARTITION_SUBTYPE_APP_OTA):
|
||||
ota_partition = filter(lambda p: p.subtype == (gen.MIN_PARTITION_SUBTYPE_APP_OTA + i), partition_table)
|
||||
|
||||
try:
|
||||
ota_partitions.append(list(ota_partition)[0])
|
||||
except IndexError:
|
||||
break
|
||||
|
||||
ota_partitions = sorted(ota_partitions, key=lambda p: p.subtype)
|
||||
|
||||
if not ota_partitions:
|
||||
raise RuntimeError("No ota app partitions found")
|
||||
|
||||
status("Verifying partition to switch to exists...")
|
||||
|
||||
# Look for the app partition to switch to
|
||||
ota_partition_next = None
|
||||
|
||||
try:
|
||||
if args.name:
|
||||
ota_partition_next = filter(lambda p: p.name == args.name, ota_partitions)
|
||||
else:
|
||||
ota_partition_next = filter(lambda p: p.subtype - gen.MIN_PARTITION_SUBTYPE_APP_OTA == args.slot, ota_partitions)
|
||||
|
||||
ota_partition_next = list(ota_partition_next)[0]
|
||||
except IndexError:
|
||||
raise RuntimeError("Partition to switch to not found")
|
||||
|
||||
otadata_contents = _get_otadata_contents(args)
|
||||
otadata_status = _get_otadata_status(otadata_contents)
|
||||
|
||||
# Find the copy to base the computation for ota sequence number on
|
||||
otadata_compute_base = -1
|
||||
|
||||
# Both are valid, take the max as computation base
|
||||
if is_otadata_status_valid(otadata_status[0]) and is_otadata_status_valid(otadata_status[1]):
|
||||
if otadata_status[0].seq >= otadata_status[1].seq:
|
||||
otadata_compute_base = 0
|
||||
else:
|
||||
otadata_compute_base = 1
|
||||
# Only one copy is valid, use that
|
||||
elif is_otadata_status_valid(otadata_status[0]):
|
||||
otadata_compute_base = 0
|
||||
elif is_otadata_status_valid(otadata_status[1]):
|
||||
otadata_compute_base = 1
|
||||
# Both are invalid (could be initial state - all 0xFF's)
|
||||
else:
|
||||
pass
|
||||
|
||||
ota_seq_next = 0
|
||||
ota_partitions_num = len(ota_partitions)
|
||||
|
||||
target_seq = (ota_partition_next.subtype & 0x0F) + 1
|
||||
|
||||
# Find the next ota sequence number
|
||||
if otadata_compute_base == 0 or otadata_compute_base == 1:
|
||||
base_seq = otadata_status[otadata_compute_base].seq % (1 << 32)
|
||||
|
||||
i = 0
|
||||
while base_seq > target_seq % ota_partitions_num + i * ota_partitions_num:
|
||||
i += 1
|
||||
|
||||
ota_seq_next = target_seq % ota_partitions_num + i * ota_partitions_num
|
||||
else:
|
||||
ota_seq_next = target_seq
|
||||
|
||||
# Create binary data from computed values
|
||||
ota_seq_next = struct.pack("I", ota_seq_next)
|
||||
ota_seq_crc_next = binascii.crc32(ota_seq_next, 0xFFFFFFFF) % (1 << 32)
|
||||
ota_seq_crc_next = struct.pack("I", ota_seq_crc_next)
|
||||
|
||||
with open(f_name, "wb") as otadata_next_file:
|
||||
start = (1 if otadata_compute_base == 0 else 0) * (SPI_FLASH_SEC_SIZE >> 1)
|
||||
|
||||
otadata_next_file.write(otadata_contents)
|
||||
|
||||
otadata_next_file.seek(start)
|
||||
otadata_next_file.write(ota_seq_next)
|
||||
|
||||
otadata_next_file.seek(start + 28)
|
||||
otadata_next_file.write(ota_seq_crc_next)
|
||||
|
||||
otadata_next_file.flush()
|
||||
|
||||
_invoke_parttool(["write_partition", "--input", f_name], args)
|
||||
status("Updated ota_data partition")
|
||||
finally:
|
||||
os.unlink(f_name)
|
||||
|
||||
|
||||
def _get_partition_specifier(args):
|
||||
if args.name:
|
||||
return ["--partition-name", args.name]
|
||||
else:
|
||||
return ["--partition-type", "app", "--partition-subtype", "ota_" + str(args.slot)]
|
||||
|
||||
|
||||
def read_ota_partition(args):
|
||||
invoke_args = ["read_partition", "--output", args.output]
|
||||
_invoke_parttool(invoke_args, args, partition=_get_partition_specifier(args))
|
||||
status("Read ota partition contents to file {}".format(args.output))
|
||||
|
||||
|
||||
def write_ota_partition(args):
|
||||
invoke_args = ["write_partition", "--input", args.input]
|
||||
_invoke_parttool(invoke_args, args, partition=_get_partition_specifier(args))
|
||||
status("Written contents of file {} to ota partition".format(args.input))
|
||||
|
||||
|
||||
def erase_ota_partition(args):
|
||||
invoke_args = ["erase_partition"]
|
||||
_invoke_parttool(invoke_args, args, partition=_get_partition_specifier(args))
|
||||
status("Erased contents of ota partition")
|
||||
|
||||
|
||||
def main():
|
||||
if sys.version_info[0] < 3:
|
||||
print("WARNING: Support for Python 2 is deprecated and will be removed in future versions.")
|
||||
elif sys.version_info[0] == 3 and sys.version_info[1] < 6:
|
||||
print("WARNING: Python 3 versions older than 3.6 are not supported.")
|
||||
global quiet
|
||||
|
||||
parser = argparse.ArgumentParser("ESP-IDF OTA Partitions Tool")
|
||||
|
||||
parser.add_argument("--quiet", "-q", help="suppress stderr messages", action="store_true")
|
||||
|
||||
# There are two possible sources for the partition table: a device attached to the host
|
||||
# or a partition table CSV/binary file. These sources are mutually exclusive.
|
||||
partition_table_info_source_args = parser.add_mutually_exclusive_group()
|
||||
|
||||
partition_table_info_source_args.add_argument("--port", "-p", help="port where the device to read the partition table from is attached", default="")
|
||||
partition_table_info_source_args.add_argument("--partition-table-file", "-f", help="file (CSV/binary) to read the partition table from", default="")
|
||||
|
||||
parser.add_argument("--partition-table-offset", "-o", help="offset to read the partition table from", default="0x8000")
|
||||
|
||||
subparsers = parser.add_subparsers(dest="operation", help="run otatool -h for additional help")
|
||||
|
||||
# Specify the supported operations
|
||||
subparsers.add_parser("read_otadata", help="read otadata partition")
|
||||
subparsers.add_parser("erase_otadata", help="erase otadata partition")
|
||||
|
||||
slot_or_name_parser = argparse.ArgumentParser(add_help=False)
|
||||
slot_or_name_parser_args = slot_or_name_parser.add_mutually_exclusive_group()
|
||||
slot_or_name_parser_args.add_argument("--slot", help="slot number of the ota partition", type=int)
|
||||
slot_or_name_parser_args.add_argument("--name", help="name of the ota partition")
|
||||
|
||||
subparsers.add_parser("switch_otadata", help="switch otadata partition", parents=[slot_or_name_parser])
|
||||
|
||||
read_ota_partition_subparser = subparsers.add_parser("read_ota_partition", help="read contents of an ota partition", parents=[slot_or_name_parser])
|
||||
read_ota_partition_subparser.add_argument("--output", help="file to write the contents of the ota partition to")
|
||||
|
||||
write_ota_partition_subparser = subparsers.add_parser("write_ota_partition", help="write contents to an ota partition", parents=[slot_or_name_parser])
|
||||
write_ota_partition_subparser.add_argument("--input", help="file whose contents to write to the ota partition")
|
||||
|
||||
subparsers.add_parser("erase_ota_partition", help="erase contents of an ota partition", parents=[slot_or_name_parser])
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
quiet = args.quiet
|
||||
|
||||
# No operation specified, display help and exit
|
||||
if args.operation is None:
|
||||
if not quiet:
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
# Else execute the operation
|
||||
operation_func = globals()[args.operation]
|
||||
|
||||
if quiet:
|
||||
# If exceptions occur, suppress and exit quietly
|
||||
try:
|
||||
operation_func(args)
|
||||
except Exception:
|
||||
sys.exit(2)
|
||||
else:
|
||||
operation_func(args)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,9 +0,0 @@
|
||||
|
||||
# Set empty otadata partition file for flashing, if OTA data partition in
|
||||
# partition table
|
||||
# (NB: because of component dependency, we know partition_table
|
||||
# project_include.cmake has already been included.)
|
||||
|
||||
if(OTADATA_PARTITION_OFFSET AND OTADATA_PARTITION_SIZE AND IDF_BUILD_ARTIFACTS)
|
||||
set(BLANK_OTADATA_FILE "ota_data_initial.bin")
|
||||
endif()
|
||||
@@ -1,6 +0,0 @@
|
||||
set(COMPONENT_SRCDIRS ".")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
set(COMPONENT_REQUIRES unity test_utils app_update bootloader_support nvs_flash)
|
||||
|
||||
register_component()
|
||||
@@ -1,50 +0,0 @@
|
||||
#include <string.h>
|
||||
#include "esp_ota_ops.h"
|
||||
#include "unity.h"
|
||||
|
||||
TEST_CASE("esp_ota_get_app_elf_sha256 test", "[esp_app_desc]")
|
||||
{
|
||||
const int sha256_hex_len = CONFIG_APP_RETRIEVE_LEN_ELF_SHA;
|
||||
char dst[sha256_hex_len + 2];
|
||||
const char fill = 0xcc;
|
||||
int res;
|
||||
size_t len;
|
||||
|
||||
char ref_sha256[sha256_hex_len + 1];
|
||||
const esp_app_desc_t* desc = esp_ota_get_app_description();
|
||||
for (int i = 0; i < sizeof(ref_sha256) / 2; ++i) {
|
||||
snprintf(ref_sha256 + 2*i, 3, "%02x", desc->app_elf_sha256[i]);
|
||||
}
|
||||
ref_sha256[sha256_hex_len] = 0;
|
||||
|
||||
printf("Ref: %s\n", ref_sha256);
|
||||
|
||||
memset(dst, fill, sizeof(dst));
|
||||
len = sizeof(dst);
|
||||
res = esp_ota_get_app_elf_sha256(dst, len);
|
||||
printf("%d: %s (%d)\n", len, dst, res);
|
||||
TEST_ASSERT_EQUAL(sha256_hex_len + 1, res);
|
||||
TEST_ASSERT_EQUAL(0, memcmp(dst, ref_sha256, res - 1));
|
||||
TEST_ASSERT_EQUAL_HEX(0, dst[sha256_hex_len]);
|
||||
TEST_ASSERT_EQUAL_HEX(fill, dst[sha256_hex_len + 1]);
|
||||
|
||||
memset(dst, fill, sizeof(dst));
|
||||
len = 9;
|
||||
res = esp_ota_get_app_elf_sha256(dst, len);
|
||||
printf("%d: %s (%d)\n", len, dst, res);
|
||||
TEST_ASSERT_EQUAL(9, res);
|
||||
TEST_ASSERT_EQUAL(0, memcmp(dst, ref_sha256, res - 1));
|
||||
TEST_ASSERT_EQUAL_HEX(0, dst[8]);
|
||||
TEST_ASSERT_EQUAL_HEX(fill, dst[9]);
|
||||
|
||||
memset(dst, fill, sizeof(dst));
|
||||
len = 8;
|
||||
res = esp_ota_get_app_elf_sha256(dst, len);
|
||||
printf("%d: %s (%d)\n", len, dst, res);
|
||||
// should output even number of characters plus '\0'
|
||||
TEST_ASSERT_EQUAL(7, res);
|
||||
TEST_ASSERT_EQUAL(0, memcmp(dst, ref_sha256, res - 1));
|
||||
TEST_ASSERT_EQUAL_HEX(0, dst[6]);
|
||||
TEST_ASSERT_EQUAL_HEX(fill, dst[7]);
|
||||
TEST_ASSERT_EQUAL_HEX(fill, dst[8]);
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <unity.h>
|
||||
#include <test_utils.h>
|
||||
#include <esp_ota_ops.h>
|
||||
#include "bootloader_common.h"
|
||||
|
||||
|
||||
/* These OTA tests currently don't assume an OTA partition exists
|
||||
on the device, so they're a bit limited
|
||||
@@ -84,26 +84,3 @@ TEST_CASE("esp_ota_get_next_update_partition logic", "[ota]")
|
||||
TEST_ASSERT_EQUAL_PTR(ota_0, p);
|
||||
}
|
||||
|
||||
TEST_CASE("esp_ota_get_partition_description ", "[ota]")
|
||||
{
|
||||
const esp_partition_t *running = esp_ota_get_running_partition();
|
||||
TEST_ASSERT_NOT_NULL(running);
|
||||
esp_app_desc_t app_desc1, app_desc2;
|
||||
TEST_ESP_OK(esp_ota_get_partition_description(running, &app_desc1));
|
||||
const esp_partition_pos_t running_pos = {
|
||||
.offset = running->address,
|
||||
.size = running->size
|
||||
};
|
||||
TEST_ESP_OK(bootloader_common_get_partition_description(&running_pos, &app_desc2));
|
||||
|
||||
TEST_ASSERT_EQUAL_MEMORY_MESSAGE((uint8_t *)&app_desc1, (uint8_t *)&app_desc2, sizeof(app_desc1), "must be the same");
|
||||
|
||||
const esp_partition_t *not_app = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
|
||||
TEST_ASSERT_NOT_NULL(not_app);
|
||||
TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, esp_ota_get_partition_description(not_app, &app_desc1));
|
||||
const esp_partition_pos_t not_app_pos = {
|
||||
.offset = not_app->address,
|
||||
.size = not_app->size
|
||||
};
|
||||
TEST_ESP_ERR(ESP_ERR_NOT_FOUND, bootloader_common_get_partition_description(¬_app_pos, &app_desc1));
|
||||
}
|
||||
|
||||
@@ -1,732 +0,0 @@
|
||||
/*
|
||||
* Tests for switching between partitions: factory, OTAx, test.
|
||||
*/
|
||||
|
||||
#include <esp_types.h>
|
||||
#include <stdio.h>
|
||||
#include "string.h"
|
||||
|
||||
#include "rom/spi_flash.h"
|
||||
#include "rom/rtc.h"
|
||||
#include "rom/ets_sys.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "unity.h"
|
||||
|
||||
#include "bootloader_common.h"
|
||||
#include "../include_bootloader/bootloader_flash.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_ota_ops.h"
|
||||
#include "esp_partition.h"
|
||||
#include "esp_flash_partitions.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#include "driver/gpio.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
RTC_DATA_ATTR static int boot_count = 0;
|
||||
static const char *TAG = "ota_test";
|
||||
|
||||
/* @brief Copies a current app to next partition using handle.
|
||||
*
|
||||
* @param[in] update_handle - Handle of API ota.
|
||||
* @param[in] cur_app - Current app.
|
||||
*/
|
||||
static void copy_app_partition(esp_ota_handle_t update_handle, const esp_partition_t *curr_app)
|
||||
{
|
||||
const void *partition_bin = NULL;
|
||||
spi_flash_mmap_handle_t data_map;
|
||||
TEST_ESP_OK(esp_partition_mmap(curr_app, 0, curr_app->size, SPI_FLASH_MMAP_DATA, &partition_bin, &data_map));
|
||||
TEST_ESP_OK(esp_ota_write(update_handle, (const void *)partition_bin, curr_app->size));
|
||||
spi_flash_munmap(data_map);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BOOTLOADER_FACTORY_RESET) || defined(CONFIG_BOOTLOADER_APP_TEST)
|
||||
/* @brief Copies partition from source partition to destination partition.
|
||||
*
|
||||
* Partitions can be of any types and subtypes.
|
||||
* @param[in] dst_partition - Destination partition
|
||||
* @param[in] src_partition - Source partition
|
||||
*/
|
||||
static void copy_partition(const esp_partition_t *dst_partition, const esp_partition_t *src_partition)
|
||||
{
|
||||
const void *partition_bin = NULL;
|
||||
spi_flash_mmap_handle_t data_map;
|
||||
TEST_ESP_OK(esp_partition_mmap(src_partition, 0, src_partition->size, SPI_FLASH_MMAP_DATA, &partition_bin, &data_map));
|
||||
TEST_ESP_OK(esp_partition_erase_range(dst_partition, 0, dst_partition->size));
|
||||
TEST_ESP_OK(esp_partition_write(dst_partition, 0, (const void *)partition_bin, dst_partition->size));
|
||||
spi_flash_munmap(data_map);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* @brief Get the next partition of OTA for the update.
|
||||
*
|
||||
* @return The next partition of OTA(OTA0-15).
|
||||
*/
|
||||
static const esp_partition_t * get_next_update_partition(void)
|
||||
{
|
||||
const esp_partition_t *update_partition = esp_ota_get_next_update_partition(NULL);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, update_partition);
|
||||
ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x", update_partition->subtype, update_partition->address);
|
||||
return update_partition;
|
||||
}
|
||||
|
||||
/* @brief Copies a current app to next partition (OTA0-15) and then configure OTA data for a new boot partition.
|
||||
*
|
||||
* @param[in] cur_app_partition - Current app.
|
||||
* @param[in] next_app_partition - Next app for boot.
|
||||
*/
|
||||
static void copy_current_app_to_next_part(const esp_partition_t *cur_app_partition, const esp_partition_t *next_app_partition)
|
||||
{
|
||||
esp_ota_get_next_update_partition(NULL);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, next_app_partition);
|
||||
ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x", next_app_partition->subtype, next_app_partition->address);
|
||||
|
||||
esp_ota_handle_t update_handle = 0;
|
||||
TEST_ESP_OK(esp_ota_begin(next_app_partition, OTA_SIZE_UNKNOWN, &update_handle));
|
||||
|
||||
copy_app_partition(update_handle, cur_app_partition);
|
||||
|
||||
TEST_ESP_OK(esp_ota_end(update_handle));
|
||||
TEST_ESP_OK(esp_ota_set_boot_partition(next_app_partition));
|
||||
}
|
||||
|
||||
/* @brief Erase otadata partition
|
||||
*/
|
||||
static void erase_ota_data(void)
|
||||
{
|
||||
const esp_partition_t *data_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, data_partition);
|
||||
TEST_ESP_OK(esp_partition_erase_range(data_partition, 0, 2 * SPI_FLASH_SEC_SIZE));
|
||||
}
|
||||
|
||||
/* @brief Reboots ESP using mode deep sleep. This mode guaranty that RTC_DATA_ATTR variables is not reset.
|
||||
*/
|
||||
static void reboot_as_deep_sleep(void)
|
||||
{
|
||||
esp_sleep_enable_timer_wakeup(2000);
|
||||
esp_deep_sleep_start();
|
||||
}
|
||||
|
||||
/* @brief Copies a current app to next partition (OTA0-15), after that ESP is rebooting and run this (the next) OTAx.
|
||||
*/
|
||||
static void copy_current_app_to_next_part_and_reboot()
|
||||
{
|
||||
const esp_partition_t *cur_app = esp_ota_get_running_partition();
|
||||
copy_current_app_to_next_part(cur_app, get_next_update_partition());
|
||||
reboot_as_deep_sleep();
|
||||
}
|
||||
|
||||
/* @brief Get running app.
|
||||
*
|
||||
* @return The next partition of OTA(OTA0-15).
|
||||
*/
|
||||
static const esp_partition_t* get_running_firmware(void)
|
||||
{
|
||||
const esp_partition_t *configured = esp_ota_get_boot_partition();
|
||||
const esp_partition_t *running = esp_ota_get_running_partition();
|
||||
ESP_LOGI(TAG, "Running partition type %d subtype %d (offset 0x%08x)",
|
||||
running->type, running->subtype, running->address);
|
||||
ESP_LOGI(TAG, "Configured partition type %d subtype %d (offset 0x%08x)",
|
||||
configured->type, configured->subtype, configured->address);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, configured);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, running);
|
||||
if (running->subtype != ESP_PARTITION_SUBTYPE_APP_TEST) {
|
||||
TEST_ASSERT_EQUAL_PTR(running, configured);
|
||||
}
|
||||
return running;
|
||||
}
|
||||
|
||||
// type of a corrupt ota_data
|
||||
typedef enum {
|
||||
CORR_CRC_1_SECTOR_OTA_DATA = (1 << 0), /*!< Corrupt CRC only 1 sector of ota_data */
|
||||
CORR_CRC_2_SECTOR_OTA_DATA = (1 << 1), /*!< Corrupt CRC only 2 sector of ota_data */
|
||||
} corrupt_ota_data_t;
|
||||
|
||||
/* @brief Get two copies ota_data from otadata partition.
|
||||
*
|
||||
* @param[in] otadata_partition - otadata partition.
|
||||
* @param[out] ota_data_0 - First copy from otadata_partition.
|
||||
* @param[out] ota_data_1 - Second copy from otadata_partition.
|
||||
*/
|
||||
static void get_ota_data(const esp_partition_t *otadata_partition, esp_ota_select_entry_t *ota_data_0, esp_ota_select_entry_t *ota_data_1)
|
||||
{
|
||||
uint32_t offset = otadata_partition->address;
|
||||
uint32_t size = otadata_partition->size;
|
||||
if (offset != 0) {
|
||||
const esp_ota_select_entry_t *ota_select_map;
|
||||
ota_select_map = bootloader_mmap(offset, size);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, ota_select_map);
|
||||
|
||||
memcpy(ota_data_0, ota_select_map, sizeof(esp_ota_select_entry_t));
|
||||
memcpy(ota_data_1, (uint8_t *)ota_select_map + SPI_FLASH_SEC_SIZE, sizeof(esp_ota_select_entry_t));
|
||||
bootloader_munmap(ota_select_map);
|
||||
}
|
||||
}
|
||||
|
||||
/* @brief Writes a ota_data into required sector of otadata_partition.
|
||||
*
|
||||
* @param[in] otadata_partition - Partition information otadata.
|
||||
* @param[in] ota_data - otadata structure.
|
||||
* @param[in] sec_id - Sector number 0 or 1.
|
||||
*/
|
||||
static void write_ota_data(const esp_partition_t *otadata_partition, esp_ota_select_entry_t *ota_data, int sec_id)
|
||||
{
|
||||
esp_partition_write(otadata_partition, SPI_FLASH_SEC_SIZE * sec_id, &ota_data[sec_id], sizeof(esp_ota_select_entry_t));
|
||||
}
|
||||
|
||||
/* @brief Makes a corrupt of ota_data.
|
||||
* @param[in] err - type error
|
||||
*/
|
||||
static void corrupt_ota_data(corrupt_ota_data_t err)
|
||||
{
|
||||
esp_ota_select_entry_t ota_data[2];
|
||||
|
||||
const esp_partition_t *otadata_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, otadata_partition);
|
||||
get_ota_data(otadata_partition, &ota_data[0], &ota_data[1]);
|
||||
|
||||
if (err & CORR_CRC_1_SECTOR_OTA_DATA) {
|
||||
ota_data[0].crc = 0;
|
||||
}
|
||||
if (err & CORR_CRC_2_SECTOR_OTA_DATA) {
|
||||
ota_data[1].crc = 0;
|
||||
}
|
||||
TEST_ESP_OK(esp_partition_erase_range(otadata_partition, 0, otadata_partition->size));
|
||||
write_ota_data(otadata_partition, &ota_data[0], 0);
|
||||
write_ota_data(otadata_partition, &ota_data[1], 1);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BOOTLOADER_FACTORY_RESET) || defined(CONFIG_BOOTLOADER_APP_TEST)
|
||||
/* @brief Sets the pin number to output and sets output level as low. After reboot (deep sleep) this pin keep the same level.
|
||||
*
|
||||
* The output level of the pad will be force locked and can not be changed.
|
||||
* Power down or call gpio_hold_dis will disable this function.
|
||||
*
|
||||
* @param[in] num_pin - Pin number
|
||||
*/
|
||||
static void set_output_pin(uint32_t num_pin)
|
||||
{
|
||||
TEST_ESP_OK(gpio_hold_dis(num_pin));
|
||||
|
||||
gpio_config_t io_conf;
|
||||
io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = (1ULL << num_pin);
|
||||
io_conf.pull_down_en = 0;
|
||||
io_conf.pull_up_en = 0;
|
||||
TEST_ESP_OK(gpio_config(&io_conf));
|
||||
|
||||
TEST_ESP_OK(gpio_set_level(num_pin, 0));
|
||||
TEST_ESP_OK(gpio_hold_en(num_pin));
|
||||
}
|
||||
|
||||
/* @brief Unset the pin number hold function.
|
||||
*/
|
||||
static void reset_output_pin(uint32_t num_pin)
|
||||
{
|
||||
TEST_ESP_OK(gpio_hold_dis(num_pin));
|
||||
TEST_ESP_OK(gpio_reset_pin(num_pin));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void mark_app_valid(void)
|
||||
{
|
||||
#ifdef CONFIG_APP_ROLLBACK_ENABLE
|
||||
TEST_ESP_OK(esp_ota_mark_app_valid_cancel_rollback());
|
||||
#endif
|
||||
}
|
||||
|
||||
/* @brief Checks and prepares the partition so that the factory app is launched after that.
|
||||
*/
|
||||
static void start_test(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "boot count 1 - reset");
|
||||
boot_count = 1;
|
||||
erase_ota_data();
|
||||
reboot_as_deep_sleep();
|
||||
}
|
||||
|
||||
static void test_flow1(void)
|
||||
{
|
||||
boot_count++;
|
||||
ESP_LOGI(TAG, "boot count %d", boot_count);
|
||||
const esp_partition_t *cur_app = get_running_firmware();
|
||||
switch (boot_count) {
|
||||
case 2:
|
||||
ESP_LOGI(TAG, "Factory");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, cur_app->subtype);
|
||||
copy_current_app_to_next_part_and_reboot(cur_app);
|
||||
break;
|
||||
case 3:
|
||||
ESP_LOGI(TAG, "OTA0");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_0, cur_app->subtype);
|
||||
mark_app_valid();
|
||||
copy_current_app_to_next_part_and_reboot(cur_app);
|
||||
break;
|
||||
case 4:
|
||||
ESP_LOGI(TAG, "OTA1");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_1, cur_app->subtype);
|
||||
mark_app_valid();
|
||||
copy_current_app_to_next_part_and_reboot(cur_app);
|
||||
break;
|
||||
case 5:
|
||||
ESP_LOGI(TAG, "OTA0");
|
||||
mark_app_valid();
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_0, cur_app->subtype);
|
||||
erase_ota_data();
|
||||
break;
|
||||
default:
|
||||
erase_ota_data();
|
||||
TEST_FAIL_MESSAGE("Unexpected stage");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 1 Stage: After POWER_RESET erase OTA_DATA for this test -> reboot through deep sleep.
|
||||
// 2 Stage: run factory -> check it -> copy factory to OTA0 -> reboot --//--
|
||||
// 3 Stage: run OTA0 -> check it -> copy OTA0 to OTA1 -> reboot --//--
|
||||
// 4 Stage: run OTA1 -> check it -> copy OTA1 to OTA0 -> reboot --//--
|
||||
// 5 Stage: run OTA0 -> check it -> erase OTA_DATA for next tests -> PASS
|
||||
TEST_CASE_MULTIPLE_STAGES("Switching between factory, OTA0, OTA1, OTA0", "[app_update][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow1, test_flow1, test_flow1, test_flow1);
|
||||
|
||||
static void test_flow2(void)
|
||||
{
|
||||
boot_count++;
|
||||
ESP_LOGI(TAG, "boot count %d", boot_count);
|
||||
const esp_partition_t *cur_app = get_running_firmware();
|
||||
switch (boot_count) {
|
||||
case 2:
|
||||
ESP_LOGI(TAG, "Factory");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, cur_app->subtype);
|
||||
copy_current_app_to_next_part_and_reboot(cur_app);
|
||||
break;
|
||||
case 3:
|
||||
ESP_LOGI(TAG, "OTA0");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_0, cur_app->subtype);
|
||||
mark_app_valid();
|
||||
copy_current_app_to_next_part(cur_app, get_next_update_partition());
|
||||
corrupt_ota_data(CORR_CRC_1_SECTOR_OTA_DATA);
|
||||
reboot_as_deep_sleep();
|
||||
break;
|
||||
case 4:
|
||||
ESP_LOGI(TAG, "Factory");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, cur_app->subtype);
|
||||
erase_ota_data();
|
||||
break;
|
||||
default:
|
||||
erase_ota_data();
|
||||
TEST_FAIL_MESSAGE("Unexpected stage");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 1 Stage: After POWER_RESET erase OTA_DATA for this test -> reboot through deep sleep.
|
||||
// 2 Stage: run factory -> check it -> copy factory to OTA0 -> reboot --//--
|
||||
// 3 Stage: run OTA0 -> check it -> corrupt ota data -> reboot --//--
|
||||
// 4 Stage: run factory -> check it -> erase OTA_DATA for next tests -> PASS
|
||||
TEST_CASE_MULTIPLE_STAGES("Switching between factory, OTA0, corrupt ota_sec1, factory", "[app_update][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow2, test_flow2, test_flow2);
|
||||
|
||||
static void test_flow3(void)
|
||||
{
|
||||
boot_count++;
|
||||
ESP_LOGI(TAG, "boot count %d", boot_count);
|
||||
const esp_partition_t *cur_app = get_running_firmware();
|
||||
switch (boot_count) {
|
||||
case 2:
|
||||
ESP_LOGI(TAG, "Factory");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, cur_app->subtype);
|
||||
copy_current_app_to_next_part_and_reboot(cur_app);
|
||||
break;
|
||||
case 3:
|
||||
ESP_LOGI(TAG, "OTA0");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_0, cur_app->subtype);
|
||||
mark_app_valid();
|
||||
copy_current_app_to_next_part_and_reboot(cur_app);
|
||||
break;
|
||||
case 4:
|
||||
ESP_LOGI(TAG, "OTA1");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_1, cur_app->subtype);
|
||||
mark_app_valid();
|
||||
copy_current_app_to_next_part(cur_app, get_next_update_partition());
|
||||
corrupt_ota_data(CORR_CRC_2_SECTOR_OTA_DATA);
|
||||
reboot_as_deep_sleep();
|
||||
break;
|
||||
case 5:
|
||||
ESP_LOGI(TAG, "OTA0");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_0, cur_app->subtype);
|
||||
erase_ota_data();
|
||||
break;
|
||||
default:
|
||||
erase_ota_data();
|
||||
TEST_FAIL_MESSAGE("Unexpected stage");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 1 Stage: After POWER_RESET erase OTA_DATA for this test -> reboot through deep sleep.
|
||||
// 2 Stage: run factory -> check it -> copy factory to OTA0 -> reboot --//--
|
||||
// 3 Stage: run OTA0 -> check it -> copy OTA0 to OTA1 -> reboot --//--
|
||||
// 3 Stage: run OTA1 -> check it -> corrupt ota sector2 -> reboot --//--
|
||||
// 4 Stage: run OTA0 -> check it -> erase OTA_DATA for next tests -> PASS
|
||||
TEST_CASE_MULTIPLE_STAGES("Switching between factory, OTA0, OTA1, currupt ota_sec2, OTA0", "[app_update][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow3, test_flow3, test_flow3, test_flow3);
|
||||
|
||||
#ifdef CONFIG_BOOTLOADER_FACTORY_RESET
|
||||
#define STORAGE_NAMESPACE "update_ota"
|
||||
|
||||
static void test_flow4(void)
|
||||
{
|
||||
boot_count++;
|
||||
ESP_LOGI(TAG, "boot count %d", boot_count);
|
||||
const esp_partition_t *cur_app = get_running_firmware();
|
||||
nvs_handle handle = 0;
|
||||
int boot_count_nvs = 0;
|
||||
switch (boot_count) {
|
||||
case 2:
|
||||
ESP_LOGI(TAG, "Factory");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, cur_app->subtype);
|
||||
|
||||
TEST_ESP_OK(nvs_flash_erase());
|
||||
TEST_ESP_OK(nvs_flash_init());
|
||||
TEST_ESP_OK(nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &handle));
|
||||
TEST_ESP_OK(nvs_set_i32(handle, "boot_count", boot_count));
|
||||
TEST_ESP_OK(nvs_commit(handle));
|
||||
nvs_close(handle);
|
||||
nvs_flash_deinit();
|
||||
|
||||
copy_current_app_to_next_part_and_reboot(cur_app);
|
||||
break;
|
||||
case 3:
|
||||
ESP_LOGI(TAG, "OTA0");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_0, cur_app->subtype);
|
||||
mark_app_valid();
|
||||
TEST_ESP_OK(nvs_flash_init());
|
||||
TEST_ESP_OK(nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &handle));
|
||||
TEST_ESP_OK(nvs_get_i32(handle, "boot_count", &boot_count_nvs));
|
||||
TEST_ASSERT_EQUAL(boot_count_nvs + 1, boot_count);
|
||||
nvs_close(handle);
|
||||
nvs_flash_deinit();
|
||||
|
||||
set_output_pin(CONFIG_BOOTLOADER_NUM_PIN_FACTORY_RESET);
|
||||
|
||||
reboot_as_deep_sleep();
|
||||
break;
|
||||
case 4:
|
||||
reset_output_pin(CONFIG_BOOTLOADER_NUM_PIN_FACTORY_RESET);
|
||||
ESP_LOGI(TAG, "Factory");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, cur_app->subtype);
|
||||
|
||||
int boot_count_nvs;
|
||||
TEST_ESP_OK(nvs_flash_init());
|
||||
TEST_ESP_OK(nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &handle));
|
||||
TEST_ESP_ERR(ESP_ERR_NVS_NOT_FOUND, nvs_get_i32(handle, "boot_count", &boot_count_nvs));
|
||||
nvs_close(handle);
|
||||
nvs_flash_deinit();
|
||||
|
||||
erase_ota_data();
|
||||
break;
|
||||
default:
|
||||
reset_output_pin(CONFIG_BOOTLOADER_NUM_PIN_FACTORY_RESET);
|
||||
erase_ota_data();
|
||||
TEST_FAIL_MESSAGE("Unexpected stage");
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 1 Stage: After POWER_RESET erase OTA_DATA for this test -> reboot through deep sleep.
|
||||
// 2 Stage: run factory -> check it -> copy factory to OTA0 -> reboot --//--
|
||||
// 3 Stage: run OTA0 -> check it -> set_pin_factory_reset -> reboot --//--
|
||||
// 4 Stage: run factory -> check it -> erase OTA_DATA for next tests -> PASS
|
||||
TEST_CASE_MULTIPLE_STAGES("Switching between factory, OTA0, sets pin_factory_reset, factory", "[app_update][timeout=90][ignore][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow4, test_flow4, test_flow4);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BOOTLOADER_APP_TEST
|
||||
static void test_flow5(void)
|
||||
{
|
||||
boot_count++;
|
||||
ESP_LOGI(TAG, "boot count %d", boot_count);
|
||||
const esp_partition_t *cur_app = get_running_firmware();
|
||||
switch (boot_count) {
|
||||
case 2:
|
||||
ESP_LOGI(TAG, "Factory");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, cur_app->subtype);
|
||||
|
||||
set_output_pin(CONFIG_BOOTLOADER_NUM_PIN_APP_TEST);
|
||||
|
||||
copy_partition(esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_TEST, NULL), cur_app);
|
||||
esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_OTA, NULL);
|
||||
reboot_as_deep_sleep();
|
||||
break;
|
||||
case 3:
|
||||
reset_output_pin(CONFIG_BOOTLOADER_NUM_PIN_APP_TEST);
|
||||
ESP_LOGI(TAG, "Test");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_TEST, cur_app->subtype);
|
||||
reboot_as_deep_sleep();
|
||||
break;
|
||||
case 4:
|
||||
ESP_LOGI(TAG, "Factory");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, cur_app->subtype);
|
||||
erase_ota_data();
|
||||
break;
|
||||
default:
|
||||
reset_output_pin(CONFIG_BOOTLOADER_NUM_PIN_APP_TEST);
|
||||
erase_ota_data();
|
||||
TEST_FAIL_MESSAGE("Unexpected stage");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 1 Stage: After POWER_RESET erase OTA_DATA for this test -> reboot through deep sleep.
|
||||
// 2 Stage: run factory -> check it -> copy factory to Test and set pin_test_app -> reboot --//--
|
||||
// 3 Stage: run test -> check it -> reset pin_test_app -> reboot --//--
|
||||
// 4 Stage: run factory -> check it -> erase OTA_DATA for next tests -> PASS
|
||||
TEST_CASE_MULTIPLE_STAGES("Switching between factory, test, factory", "[app_update][timeout=90][ignore][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow5, test_flow5, test_flow5);
|
||||
#endif
|
||||
|
||||
static const esp_partition_t* app_update(void)
|
||||
{
|
||||
const esp_partition_t *cur_app = get_running_firmware();
|
||||
const esp_partition_t* update_partition = esp_ota_get_next_update_partition(NULL);
|
||||
TEST_ASSERT_NOT_NULL(update_partition);
|
||||
esp_ota_handle_t update_handle = 0;
|
||||
TEST_ESP_OK(esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle));
|
||||
copy_app_partition(update_handle, cur_app);
|
||||
TEST_ESP_OK(esp_ota_end(update_handle));
|
||||
TEST_ESP_OK(esp_ota_set_boot_partition(update_partition));
|
||||
return update_partition;
|
||||
}
|
||||
|
||||
|
||||
static void test_rollback1(void)
|
||||
{
|
||||
boot_count++;
|
||||
ESP_LOGI(TAG, "boot count %d", boot_count);
|
||||
const esp_partition_t *cur_app = get_running_firmware();
|
||||
esp_ota_img_states_t ota_state = 0x5555AAAA;
|
||||
const esp_partition_t* update_partition = NULL;
|
||||
switch (boot_count) {
|
||||
case 2:
|
||||
ESP_LOGI(TAG, "Factory");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, cur_app->subtype);
|
||||
TEST_ASSERT_NULL(esp_ota_get_last_invalid_partition());
|
||||
TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, esp_ota_get_state_partition(cur_app, &ota_state));
|
||||
update_partition = app_update();
|
||||
TEST_ESP_OK(esp_ota_get_state_partition(update_partition, &ota_state));
|
||||
#ifndef CONFIG_APP_ROLLBACK_ENABLE
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_UNDEFINED, ota_state);
|
||||
#else
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_NEW, ota_state);
|
||||
#endif
|
||||
reboot_as_deep_sleep();
|
||||
break;
|
||||
case 3:
|
||||
ESP_LOGI(TAG, "OTA0");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_0, cur_app->subtype);
|
||||
TEST_ASSERT_NULL(esp_ota_get_last_invalid_partition());
|
||||
TEST_ESP_OK(esp_ota_get_state_partition(cur_app, &ota_state));
|
||||
#ifndef CONFIG_APP_ROLLBACK_ENABLE
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_UNDEFINED, ota_state);
|
||||
#else
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_PENDING_VERIFY, ota_state);
|
||||
#endif
|
||||
TEST_ESP_OK(esp_ota_mark_app_valid_cancel_rollback());
|
||||
TEST_ESP_OK(esp_ota_get_state_partition(cur_app, &ota_state));
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_VALID, ota_state);
|
||||
reboot_as_deep_sleep();
|
||||
break;
|
||||
case 4:
|
||||
ESP_LOGI(TAG, "OTA0");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_0, cur_app->subtype);
|
||||
TEST_ESP_OK(esp_ota_get_state_partition(cur_app, &ota_state));
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_VALID, ota_state);
|
||||
TEST_ESP_OK(esp_ota_mark_app_invalid_rollback_and_reboot());
|
||||
break;
|
||||
default:
|
||||
erase_ota_data();
|
||||
TEST_FAIL_MESSAGE("Unexpected stage");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_rollback1_1(void)
|
||||
{
|
||||
boot_count = 5;
|
||||
esp_ota_img_states_t ota_state = 0x5555AAAA;
|
||||
ESP_LOGI(TAG, "boot count %d", boot_count);
|
||||
const esp_partition_t *cur_app = get_running_firmware();
|
||||
ESP_LOGI(TAG, "Factory");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, cur_app->subtype);
|
||||
|
||||
const esp_partition_t *invalid_partition = esp_ota_get_last_invalid_partition();
|
||||
const esp_partition_t* next_update_partition = esp_ota_get_next_update_partition(NULL);
|
||||
TEST_ASSERT_NOT_NULL(invalid_partition);
|
||||
TEST_ASSERT_NOT_NULL(next_update_partition);
|
||||
TEST_ASSERT_EQUAL_PTR(invalid_partition, next_update_partition);
|
||||
TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, esp_ota_get_state_partition(cur_app, &ota_state));
|
||||
TEST_ESP_OK(esp_ota_get_state_partition(invalid_partition, &ota_state));
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_INVALID, ota_state);
|
||||
|
||||
erase_ota_data();
|
||||
}
|
||||
|
||||
// 1 Stage: After POWER_RESET erase OTA_DATA for this test -> reboot through deep sleep.
|
||||
// 2 Stage: run factory -> check it -> copy factory to next app slot -> reboot --//--
|
||||
// 3 Stage: run OTA0 -> check it -> esp_ota_mark_app_valid_cancel_rollback() -> reboot --//--
|
||||
// 4 Stage: run OTA0 -> check it -> esp_ota_mark_app_invalid_rollback_and_reboot() -> reboot
|
||||
// 5 Stage: run factory -> check it -> erase OTA_DATA for next tests -> PASS
|
||||
TEST_CASE_MULTIPLE_STAGES("Test rollback. factory, OTA0, OTA0, rollback -> factory", "[app_update][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, SW_CPU_RESET]", start_test, test_rollback1, test_rollback1, test_rollback1, test_rollback1_1);
|
||||
|
||||
static void test_rollback2(void)
|
||||
{
|
||||
boot_count++;
|
||||
ESP_LOGI(TAG, "boot count %d", boot_count);
|
||||
const esp_partition_t *cur_app = get_running_firmware();
|
||||
esp_ota_img_states_t ota_state = 0x5555AAAA;
|
||||
const esp_partition_t* update_partition = NULL;
|
||||
switch (boot_count) {
|
||||
case 2:
|
||||
ESP_LOGI(TAG, "Factory");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, cur_app->subtype);
|
||||
TEST_ASSERT_NULL(esp_ota_get_last_invalid_partition());
|
||||
TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, esp_ota_get_state_partition(cur_app, &ota_state));
|
||||
update_partition = app_update();
|
||||
TEST_ESP_OK(esp_ota_get_state_partition(update_partition, &ota_state));
|
||||
#ifndef CONFIG_APP_ROLLBACK_ENABLE
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_UNDEFINED, ota_state);
|
||||
#else
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_NEW, ota_state);
|
||||
#endif
|
||||
reboot_as_deep_sleep();
|
||||
break;
|
||||
case 3:
|
||||
ESP_LOGI(TAG, "OTA0");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_0, cur_app->subtype);
|
||||
TEST_ASSERT_NULL(esp_ota_get_last_invalid_partition());
|
||||
TEST_ESP_OK(esp_ota_get_state_partition(cur_app, &ota_state));
|
||||
#ifndef CONFIG_APP_ROLLBACK_ENABLE
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_UNDEFINED, ota_state);
|
||||
#else
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_PENDING_VERIFY, ota_state);
|
||||
#endif
|
||||
TEST_ESP_OK(esp_ota_mark_app_valid_cancel_rollback());
|
||||
TEST_ASSERT_NULL(esp_ota_get_last_invalid_partition());
|
||||
TEST_ESP_OK(esp_ota_get_state_partition(cur_app, &ota_state));
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_VALID, ota_state);
|
||||
update_partition = app_update();
|
||||
TEST_ESP_OK(esp_ota_get_state_partition(update_partition, &ota_state));
|
||||
#ifndef CONFIG_APP_ROLLBACK_ENABLE
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_UNDEFINED, ota_state);
|
||||
#else
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_NEW, ota_state);
|
||||
#endif
|
||||
reboot_as_deep_sleep();
|
||||
break;
|
||||
case 4:
|
||||
ESP_LOGI(TAG, "OTA1");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_1, cur_app->subtype);
|
||||
TEST_ASSERT_NULL(esp_ota_get_last_invalid_partition());
|
||||
TEST_ESP_OK(esp_ota_get_state_partition(cur_app, &ota_state));
|
||||
#ifndef CONFIG_APP_ROLLBACK_ENABLE
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_UNDEFINED, ota_state);
|
||||
TEST_ESP_OK(esp_ota_mark_app_invalid_rollback_and_reboot());
|
||||
#else
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_PENDING_VERIFY, ota_state);
|
||||
reboot_as_deep_sleep();
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
erase_ota_data();
|
||||
TEST_FAIL_MESSAGE("Unexpected stage");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_rollback2_1(void)
|
||||
{
|
||||
boot_count = 5;
|
||||
esp_ota_img_states_t ota_state = 0x5555AAAA;
|
||||
ESP_LOGI(TAG, "boot count %d", boot_count);
|
||||
const esp_partition_t *cur_app = get_running_firmware();
|
||||
ESP_LOGI(TAG, "OTA0");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_0, cur_app->subtype);
|
||||
|
||||
const esp_partition_t *invalid_partition = esp_ota_get_last_invalid_partition();
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_1, invalid_partition->subtype);
|
||||
const esp_partition_t* next_update_partition = esp_ota_get_next_update_partition(NULL);
|
||||
TEST_ASSERT_NOT_NULL(invalid_partition);
|
||||
TEST_ASSERT_NOT_NULL(next_update_partition);
|
||||
TEST_ASSERT_EQUAL_PTR(invalid_partition, next_update_partition);
|
||||
TEST_ESP_OK(esp_ota_get_state_partition(cur_app, &ota_state));
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_VALID, ota_state);
|
||||
TEST_ESP_OK(esp_ota_get_state_partition(invalid_partition, &ota_state));
|
||||
#ifndef CONFIG_APP_ROLLBACK_ENABLE
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_INVALID, ota_state);
|
||||
#else
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_ABORTED, ota_state);
|
||||
#endif
|
||||
erase_ota_data();
|
||||
}
|
||||
|
||||
// 1 Stage: After POWER_RESET erase OTA_DATA for this test -> reboot through deep sleep.
|
||||
// 2 Stage: run factory -> check it -> copy factory to next app slot -> reboot --//--
|
||||
// 3 Stage: run OTA0 -> check it -> esp_ota_mark_app_valid_cancel_rollback(), copy to next app slot -> reboot --//--
|
||||
// 4 Stage: run OTA1 -> check it -> PENDING_VERIFY/esp_ota_mark_app_invalid_rollback_and_reboot() -> reboot
|
||||
// 5 Stage: run OTA0(rollback) -> check it -> erase OTA_DATA for next tests -> PASS
|
||||
TEST_CASE_MULTIPLE_STAGES("Test rollback. factory, OTA0, OTA1, rollback -> OTA0", "[app_update][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, SW_CPU_RESET]", start_test, test_rollback2, test_rollback2, test_rollback2, test_rollback2_1);
|
||||
|
||||
static void test_erase_last_app_flow(void)
|
||||
{
|
||||
boot_count++;
|
||||
ESP_LOGI(TAG, "boot count %d", boot_count);
|
||||
const esp_partition_t *cur_app = get_running_firmware();
|
||||
switch (boot_count) {
|
||||
case 2:
|
||||
ESP_LOGI(TAG, "Factory");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, cur_app->subtype);
|
||||
app_update();
|
||||
reboot_as_deep_sleep();
|
||||
break;
|
||||
case 3:
|
||||
ESP_LOGI(TAG, "OTA0");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_0, cur_app->subtype);
|
||||
mark_app_valid();
|
||||
app_update();
|
||||
reboot_as_deep_sleep();
|
||||
break;
|
||||
case 4:
|
||||
ESP_LOGI(TAG, "OTA1");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_OTA_1, cur_app->subtype);
|
||||
TEST_ESP_OK(esp_ota_erase_last_boot_app_partition());
|
||||
TEST_ESP_OK(esp_ota_mark_app_invalid_rollback_and_reboot());
|
||||
reboot_as_deep_sleep();
|
||||
break;
|
||||
default:
|
||||
erase_ota_data();
|
||||
TEST_FAIL_MESSAGE("Unexpected stage");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_erase_last_app_rollback(void)
|
||||
{
|
||||
boot_count = 5;
|
||||
ESP_LOGI(TAG, "boot count %d", boot_count);
|
||||
const esp_partition_t *cur_app = get_running_firmware();
|
||||
ESP_LOGI(TAG, "erase_last_app");
|
||||
TEST_ASSERT_EQUAL(ESP_PARTITION_SUBTYPE_APP_FACTORY, cur_app->subtype);
|
||||
TEST_ESP_ERR(ESP_FAIL, esp_ota_erase_last_boot_app_partition());
|
||||
erase_ota_data();
|
||||
}
|
||||
|
||||
// 1 Stage: After POWER_RESET erase OTA_DATA for this test -> reboot through deep sleep.
|
||||
// 2 Stage: run factory -> check it -> copy factory to OTA0 -> reboot --//--
|
||||
// 3 Stage: run OTA0 -> check it -> copy factory to OTA1 -> reboot --//--
|
||||
// 4 Stage: run OTA1 -> check it -> erase OTA0 and rollback -> reboot
|
||||
// 5 Stage: run factory -> check it -> erase OTA_DATA for next tests -> PASS
|
||||
TEST_CASE_MULTIPLE_STAGES("Test erase_last_boot_app_partition. factory, OTA1, OTA0, factory", "[app_update][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET, SW_CPU_RESET]", start_test, test_erase_last_app_flow, test_erase_last_app_flow, test_erase_last_app_flow, test_erase_last_app_rollback);
|
||||
@@ -1,6 +0,0 @@
|
||||
set(COMPONENT_ADD_INCLUDEDIRS asio/asio/include port/include)
|
||||
set(COMPONENT_SRCS "asio/asio/src/asio.cpp")
|
||||
|
||||
set(COMPONENT_REQUIRES lwip)
|
||||
|
||||
register_component()
|
||||
Submodule components/asio/asio deleted from 55efc179b7
@@ -1,6 +0,0 @@
|
||||
COMPONENT_ADD_INCLUDEDIRS := asio/asio/include port/include
|
||||
COMPONENT_PRIV_INCLUDEDIRS := private_include
|
||||
COMPONENT_SRCDIRS := asio/asio/src
|
||||
COMPONENT_OBJEXCLUDE := asio/asio/src/asio_ssl.o
|
||||
|
||||
COMPONENT_SUBMODULES += asio
|
||||
@@ -1,45 +0,0 @@
|
||||
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// 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.
|
||||
#ifndef _ESP_ASIO_CONFIG_H_
|
||||
#define _ESP_ASIO_CONFIG_H_
|
||||
|
||||
//
|
||||
// Enabling exceptions only when they are enabled in menuconfig
|
||||
//
|
||||
# include <sdkconfig.h>
|
||||
# ifndef CONFIG_CXX_EXCEPTIONS
|
||||
# define ASIO_NO_EXCEPTIONS
|
||||
# endif // CONFIG_CXX_EXCEPTIONS
|
||||
|
||||
//
|
||||
// LWIP compatifility inet and address macros/functions
|
||||
//
|
||||
# define LWIP_COMPAT_SOCKET_INET 1
|
||||
# define LWIP_COMPAT_SOCKET_ADDR 1
|
||||
|
||||
//
|
||||
// Specific ASIO feature flags
|
||||
//
|
||||
# define ASIO_DISABLE_SERIAL_PORT
|
||||
# define ASIO_SEPARATE_COMPILATION
|
||||
# define ASIO_STANDALONE
|
||||
# define ASIO_NO_TYPEID
|
||||
# define ASIO_DISABLE_SIGNAL
|
||||
# define ASIO_HAS_PTHREADS
|
||||
# define ASIO_DISABLE_EPOLL
|
||||
# define ASIO_DISABLE_EVENTFD
|
||||
# define ASIO_DISABLE_SIGNAL
|
||||
# define ASIO_DISABLE_SIGACTION
|
||||
|
||||
#endif // _ESP_ASIO_CONFIG_H_
|
||||
@@ -1,39 +0,0 @@
|
||||
|
||||
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// 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.
|
||||
#ifndef _ESP_EXCEPTION_H_
|
||||
#define _ESP_EXCEPTION_H_
|
||||
|
||||
//
|
||||
// This exception stub is enabled only if exceptions are disabled in menuconfig
|
||||
//
|
||||
#if !defined(CONFIG_CXX_EXCEPTIONS) && defined (ASIO_NO_EXCEPTIONS)
|
||||
|
||||
#include "esp_log.h"
|
||||
|
||||
//
|
||||
// asio exception stub
|
||||
//
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
template <typename Exception>
|
||||
void throw_exception(const Exception& e)
|
||||
{
|
||||
ESP_LOGE("esp32_asio_exception", "Caught exception: %s!", e.what());
|
||||
abort();
|
||||
}
|
||||
}}
|
||||
#endif // CONFIG_CXX_EXCEPTIONS==1 && defined (ASIO_NO_EXCEPTIONS)
|
||||
|
||||
#endif // _ESP_EXCEPTION_H_
|
||||
@@ -1,30 +0,0 @@
|
||||
if(CONFIG_AWS_IOT_SDK)
|
||||
set(COMPONENT_ADD_INCLUDEDIRS "include aws-iot-device-sdk-embedded-C/include")
|
||||
set(aws_sdk_dir aws-iot-device-sdk-embedded-C/src)
|
||||
set(COMPONENT_SRCS "${aws_sdk_dir}/aws_iot_jobs_interface.c"
|
||||
"${aws_sdk_dir}/aws_iot_jobs_json.c"
|
||||
"${aws_sdk_dir}/aws_iot_jobs_topics.c"
|
||||
"${aws_sdk_dir}/aws_iot_jobs_types.c"
|
||||
"${aws_sdk_dir}/aws_iot_json_utils.c"
|
||||
"${aws_sdk_dir}/aws_iot_mqtt_client.c"
|
||||
"${aws_sdk_dir}/aws_iot_mqtt_client_common_internal.c"
|
||||
"${aws_sdk_dir}/aws_iot_mqtt_client_connect.c"
|
||||
"${aws_sdk_dir}/aws_iot_mqtt_client_publish.c"
|
||||
"${aws_sdk_dir}/aws_iot_mqtt_client_subscribe.c"
|
||||
"${aws_sdk_dir}/aws_iot_mqtt_client_unsubscribe.c"
|
||||
"${aws_sdk_dir}/aws_iot_mqtt_client_yield.c"
|
||||
"${aws_sdk_dir}/aws_iot_shadow.c"
|
||||
"${aws_sdk_dir}/aws_iot_shadow_actions.c"
|
||||
"${aws_sdk_dir}/aws_iot_shadow_json.c"
|
||||
"${aws_sdk_dir}/aws_iot_shadow_records.c"
|
||||
"port/network_mbedtls_wrapper.c"
|
||||
"port/threads_freertos.c"
|
||||
"port/timer.c")
|
||||
else()
|
||||
message(STATUS "Building empty aws_iot component due to configuration")
|
||||
endif()
|
||||
|
||||
set(COMPONENT_REQUIRES "mbedtls")
|
||||
set(COMPONENT_PRIV_REQUIRES "jsmn")
|
||||
|
||||
register_component()
|
||||
@@ -1,8 +1,8 @@
|
||||
menuconfig AWS_IOT_SDK
|
||||
bool "Amazon Web Services IoT Platform"
|
||||
help
|
||||
Select this option to enable support for the AWS IoT platform,
|
||||
via the esp-idf component for the AWS IoT Device C SDK.
|
||||
Select this option to enable support for the AWS IoT platform,
|
||||
via the esp-idf component for the AWS IoT Device C SDK.
|
||||
|
||||
config AWS_IOT_MQTT_HOST
|
||||
string "AWS IoT Endpoint Hostname"
|
||||
@@ -30,135 +30,3 @@ config AWS_IOT_MQTT_PORT
|
||||
If you need per-device port numbers for different regions, you can
|
||||
override the default port number in your app.
|
||||
|
||||
|
||||
config AWS_IOT_MQTT_TX_BUF_LEN
|
||||
int "MQTT TX Buffer Length"
|
||||
depends on AWS_IOT_SDK
|
||||
default 512
|
||||
range 32 65536
|
||||
help
|
||||
Maximum MQTT transmit buffer size. This is the maximum MQTT
|
||||
message length (including protocol overhead) which can be sent.
|
||||
|
||||
Sending longer messages will fail.
|
||||
|
||||
config AWS_IOT_MQTT_RX_BUF_LEN
|
||||
int "MQTT RX Buffer Length"
|
||||
depends on AWS_IOT_SDK
|
||||
default 512
|
||||
range 32 65536
|
||||
help
|
||||
Maximum MQTT receive buffer size. This is the maximum MQTT
|
||||
message length (including protocol overhead) which can be
|
||||
received.
|
||||
|
||||
Longer messages are dropped.
|
||||
|
||||
|
||||
|
||||
config AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS
|
||||
int "Maximum MQTT Topic Filters"
|
||||
depends on AWS_IOT_SDK
|
||||
default 5
|
||||
range 1 100
|
||||
help
|
||||
Maximum number of concurrent MQTT topic filters.
|
||||
|
||||
|
||||
config AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL
|
||||
int "Auto reconnect initial interval (ms)"
|
||||
depends on AWS_IOT_SDK
|
||||
default 1000
|
||||
range 10 3600000
|
||||
help
|
||||
Initial delay before making first reconnect attempt, if the AWS IoT connection fails.
|
||||
Client will perform exponential backoff, starting from this value.
|
||||
|
||||
config AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL
|
||||
int "Auto reconnect maximum interval (ms)"
|
||||
depends on AWS_IOT_SDK
|
||||
default 128000
|
||||
range 10 3600000
|
||||
help
|
||||
Maximum delay between reconnection attempts. If the exponentially increased delay
|
||||
interval reaches this value, the client will stop automatically attempting to reconnect.
|
||||
|
||||
menu "Thing Shadow"
|
||||
depends on AWS_IOT_SDK
|
||||
|
||||
config AWS_IOT_OVERRIDE_THING_SHADOW_RX_BUFFER
|
||||
bool "Override Shadow RX buffer size"
|
||||
depends on AWS_IOT_SDK
|
||||
default n
|
||||
help
|
||||
Allows setting a different Thing Shadow RX buffer
|
||||
size. This is the maximum size of a Thing Shadow
|
||||
message in bytes, plus one.
|
||||
|
||||
If not overridden, the default value is the MQTT RX Buffer length plus one. If overriden, do not set
|
||||
higher than the default value.
|
||||
|
||||
config AWS_IOT_SHADOW_MAX_SIZE_OF_RX_BUFFER
|
||||
int "Maximum RX Buffer (bytes)"
|
||||
depends on AWS_IOT_OVERRIDE_THING_SHADOW_RX_BUFFER
|
||||
default 513
|
||||
range 32 65536
|
||||
help
|
||||
Allows setting a different Thing Shadow RX buffer size.
|
||||
This is the maximum size of a Thing Shadow message in bytes,
|
||||
plus one.
|
||||
|
||||
|
||||
config AWS_IOT_SHADOW_MAX_SIZE_OF_UNIQUE_CLIENT_ID_BYTES
|
||||
int "Maximum unique client ID size (bytes)"
|
||||
depends on AWS_IOT_SDK
|
||||
default 80
|
||||
range 4 1000
|
||||
help
|
||||
Maximum size of the Unique Client Id.
|
||||
|
||||
config AWS_IOT_SHADOW_MAX_SIMULTANEOUS_ACKS
|
||||
int "Maximum simultaneous responses"
|
||||
depends on AWS_IOT_SDK
|
||||
default 10
|
||||
range 1 100
|
||||
help
|
||||
At any given time we will wait for this many responses. This will correlate to the rate at which the
|
||||
shadow actions are requested
|
||||
|
||||
config AWS_IOT_SHADOW_MAX_SIMULTANEOUS_THINGNAMES
|
||||
int "Maximum simultaneous Thing Name operations"
|
||||
depends on AWS_IOT_SDK
|
||||
default 10
|
||||
range 1 100
|
||||
help
|
||||
We could perform shadow action on any thing Name and this is maximum Thing Names we can act on at any
|
||||
given time
|
||||
|
||||
config AWS_IOT_SHADOW_MAX_JSON_TOKEN_EXPECTED
|
||||
int "Maximum expected JSON tokens"
|
||||
depends on AWS_IOT_SDK
|
||||
default 120
|
||||
help
|
||||
These are the max tokens that is expected to be in the Shadow JSON document. Includes the metadata which
|
||||
is published
|
||||
|
||||
config AWS_IOT_SHADOW_MAX_SHADOW_TOPIC_LENGTH_WITHOUT_THINGNAME
|
||||
int "Maximum topic length (not including Thing Name)"
|
||||
depends on AWS_IOT_SDK
|
||||
default 60
|
||||
range 10 1000
|
||||
help
|
||||
All shadow actions have to be published or subscribed to a topic which is of the format
|
||||
$aws/things/{thingName}/shadow/update/accepted. This refers to the size of the topic without the Thing
|
||||
Name
|
||||
|
||||
config AWS_IOT_SHADOW_MAX_SIZE_OF_THING_NAME
|
||||
int "Maximum Thing Name length"
|
||||
depends on AWS_IOT_SDK
|
||||
default 20
|
||||
range 4 1000
|
||||
help
|
||||
Maximum length of a Thing Name.
|
||||
|
||||
endmenu # Thing Shadow
|
||||
|
||||
Submodule components/aws_iot/aws-iot-device-sdk-embedded-C updated: 299183238f...7132505b00
@@ -37,29 +37,24 @@
|
||||
#define AWS_IOT_MY_THING_NAME "ESP32" ///< Thing Name of the Shadow this device is associated with
|
||||
|
||||
// MQTT PubSub
|
||||
#define AWS_IOT_MQTT_TX_BUF_LEN CONFIG_AWS_IOT_MQTT_TX_BUF_LEN ///< Any time a message is sent out through the MQTT layer. The message is copied into this buffer anytime a publish is done. This will also be used in the case of Thing Shadow
|
||||
#define AWS_IOT_MQTT_RX_BUF_LEN CONFIG_AWS_IOT_MQTT_RX_BUF_LEN ///< Any message that comes into the device should be less than this buffer size. If a received message is bigger than this buffer size the message will be dropped.
|
||||
#define AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS CONFIG_AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS ///< Maximum number of topic filters the MQTT client can handle at any given time. This should be increased appropriately when using Thing Shadow
|
||||
#define AWS_IOT_MQTT_TX_BUF_LEN 512 ///< Any time a message is sent out through the MQTT layer. The message is copied into this buffer anytime a publish is done. This will also be used in the case of Thing Shadow
|
||||
#define AWS_IOT_MQTT_RX_BUF_LEN 512 ///< Any message that comes into the device should be less than this buffer size. If a received message is bigger than this buffer size the message will be dropped.
|
||||
#define AWS_IOT_MQTT_NUM_SUBSCRIBE_HANDLERS 5 ///< Maximum number of topic filters the MQTT client can handle at any given time. This should be increased appropriately when using Thing Shadow
|
||||
|
||||
// Thing Shadow specific configs
|
||||
#ifdef CONFIG_AWS_IOT_OVERRIDE_THING_SHADOW_RX_BUFFER
|
||||
#define SHADOW_MAX_SIZE_OF_RX_BUFFER CONFIG_AWS_IOT_SHADOW_MAX_SIZE_OF_RX_BUFFER ///< Maximum size of the SHADOW buffer to store the received Shadow message, including NULL terminating byte
|
||||
#else
|
||||
#define SHADOW_MAX_SIZE_OF_RX_BUFFER (AWS_IOT_MQTT_RX_BUF_LEN + 1)
|
||||
#endif
|
||||
|
||||
#define SHADOW_MAX_SIZE_OF_RX_BUFFER (AWS_IOT_MQTT_RX_BUF_LEN + 1) ///< Maximum size of the SHADOW buffer to store the received Shadow message
|
||||
#define MAX_SIZE_OF_UNIQUE_CLIENT_ID_BYTES 80 ///< Maximum size of the Unique Client Id. For More info on the Client Id refer \ref response "Acknowledgments"
|
||||
#define MAX_SIZE_CLIENT_ID_WITH_SEQUENCE (MAX_SIZE_OF_UNIQUE_CLIENT_ID_BYTES + 10) ///< This is size of the extra sequence number that will be appended to the Unique client Id
|
||||
#define MAX_SIZE_CLIENT_TOKEN_CLIENT_SEQUENCE (MAX_SIZE_CLIENT_ID_WITH_SEQUENCE + 20) ///< This is size of the the total clientToken key and value pair in the JSON
|
||||
#define MAX_ACKS_TO_COMEIN_AT_ANY_GIVEN_TIME CONFIG_AWS_IOT_SHADOW_MAX_SIMULTANEOUS_ACKS ///< At Any given time we will wait for this many responses. This will correlate to the rate at which the shadow actions are requested
|
||||
#define MAX_THINGNAME_HANDLED_AT_ANY_GIVEN_TIME CONFIG_AWS_IOT_SHADOW_MAX_SIMULTANEOUS_THINGNAMES ///< We could perform shadow action on any thing Name and this is maximum Thing Names we can act on at any given time
|
||||
#define MAX_JSON_TOKEN_EXPECTED CONFIG_AWS_IOT_SHADOW_MAX_JSON_TOKEN_EXPECTED ///< These are the max tokens that is expected to be in the Shadow JSON document. Include the metadata that gets published
|
||||
#define MAX_SHADOW_TOPIC_LENGTH_WITHOUT_THINGNAME CONFIG_AWS_IOT_SHADOW_MAX_SHADOW_TOPIC_LENGTH_WITHOUT_THINGNAME ///< All shadow actions have to be published or subscribed to a topic which is of the formablogt $aws/things/{thingName}/shadow/update/accepted. This refers to the size of the topic without the Thing Name
|
||||
#define MAX_SIZE_OF_THING_NAME CONFIG_AWS_IOT_SHADOW_MAX_SIZE_OF_THING_NAME ///< The Thing Name should not be bigger than this value. Modify this if the Thing Name needs to be bigger
|
||||
#define MAX_ACKS_TO_COMEIN_AT_ANY_GIVEN_TIME 10 ///< At Any given time we will wait for this many responses. This will correlate to the rate at which the shadow actions are requested
|
||||
#define MAX_THINGNAME_HANDLED_AT_ANY_GIVEN_TIME 10 ///< We could perform shadow action on any thing Name and this is maximum Thing Names we can act on at any given time
|
||||
#define MAX_JSON_TOKEN_EXPECTED 120 ///< These are the max tokens that is expected to be in the Shadow JSON document. Include the metadata that gets published
|
||||
#define MAX_SHADOW_TOPIC_LENGTH_WITHOUT_THINGNAME 60 ///< All shadow actions have to be published or subscribed to a topic which is of the formablogt $aws/things/{thingName}/shadow/update/accepted. This refers to the size of the topic without the Thing Name
|
||||
#define MAX_SIZE_OF_THING_NAME 20 ///< The Thing Name should not be bigger than this value. Modify this if the Thing Name needs to be bigger
|
||||
#define MAX_SHADOW_TOPIC_LENGTH_BYTES (MAX_SHADOW_TOPIC_LENGTH_WITHOUT_THINGNAME + MAX_SIZE_OF_THING_NAME) ///< This size includes the length of topic with Thing Name
|
||||
|
||||
// Auto Reconnect specific config
|
||||
#define AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL CONFIG_AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL ///< Minimum time before the First reconnect attempt is made as part of the exponential back-off algorithm
|
||||
#define AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL CONFIG_AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL ///< Maximum time interval after which exponential back-off will stop attempting to reconnect.
|
||||
#define AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL 1000 ///< Minimum time before the First reconnect attempt is made as part of the exponential back-off algorithm
|
||||
#define AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL 128000 ///< Maximum time interval after which exponential back-off will stop attempting to reconnect.
|
||||
|
||||
#endif /* _AWS_IOT_CONFIG_H_ */
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#endif
|
||||
|
||||
#include "mbedtls/platform.h"
|
||||
#include "mbedtls/net_sockets.h"
|
||||
#include "mbedtls/net.h"
|
||||
#include "mbedtls/ssl.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
|
||||
@@ -236,17 +236,6 @@ IoT_Error_t iot_tls_connect(Network *pNetwork, TLSConnectParams *params) {
|
||||
|
||||
mbedtls_ssl_conf_read_timeout(&(tlsDataParams->conf), pNetwork->tlsConnectParams.timeout_ms);
|
||||
|
||||
#ifdef CONFIG_MBEDTLS_SSL_ALPN
|
||||
/* Use the AWS IoT ALPN extension for MQTT, if port 443 is requested */
|
||||
if (pNetwork->tlsConnectParams.DestinationPort == 443) {
|
||||
const char *alpnProtocols[] = { "x-amzn-mqtt-ca", NULL };
|
||||
if ((ret = mbedtls_ssl_conf_alpn_protocols(&(tlsDataParams->conf), alpnProtocols)) != 0) {
|
||||
ESP_LOGE(TAG, "failed! mbedtls_ssl_conf_alpn_protocols returned -0x%x", -ret);
|
||||
return SSL_CONNECTION_ERROR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if((ret = mbedtls_ssl_setup(&(tlsDataParams->ssl), &(tlsDataParams->conf))) != 0) {
|
||||
ESP_LOGE(TAG, "failed! mbedtls_ssl_setup returned -0x%x", -ret);
|
||||
return SSL_CONNECTION_ERROR;
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# bootloader component logic is all in project_include.cmake,
|
||||
# and subproject/CMakeLists.txt.
|
||||
#
|
||||
# This file is only included so the build system finds the
|
||||
# component
|
||||
|
||||
|
||||
@@ -1,544 +1,217 @@
|
||||
menu "Bootloader config"
|
||||
choice LOG_BOOTLOADER_LEVEL
|
||||
bool "Bootloader log verbosity"
|
||||
default LOG_BOOTLOADER_LEVEL_INFO
|
||||
help
|
||||
Specify how much output to see in bootloader logs.
|
||||
choice LOG_BOOTLOADER_LEVEL
|
||||
bool "Bootloader log verbosity"
|
||||
default LOG_BOOTLOADER_LEVEL_INFO
|
||||
help
|
||||
Specify how much output to see in bootloader logs.
|
||||
|
||||
config LOG_BOOTLOADER_LEVEL_NONE
|
||||
bool "No output"
|
||||
config LOG_BOOTLOADER_LEVEL_ERROR
|
||||
bool "Error"
|
||||
config LOG_BOOTLOADER_LEVEL_WARN
|
||||
bool "Warning"
|
||||
config LOG_BOOTLOADER_LEVEL_INFO
|
||||
bool "Info"
|
||||
config LOG_BOOTLOADER_LEVEL_DEBUG
|
||||
bool "Debug"
|
||||
config LOG_BOOTLOADER_LEVEL_VERBOSE
|
||||
bool "Verbose"
|
||||
endchoice
|
||||
config LOG_BOOTLOADER_LEVEL_NONE
|
||||
bool "No output"
|
||||
config LOG_BOOTLOADER_LEVEL_ERROR
|
||||
bool "Error"
|
||||
config LOG_BOOTLOADER_LEVEL_WARN
|
||||
bool "Warning"
|
||||
config LOG_BOOTLOADER_LEVEL_INFO
|
||||
bool "Info"
|
||||
config LOG_BOOTLOADER_LEVEL_DEBUG
|
||||
bool "Debug"
|
||||
config LOG_BOOTLOADER_LEVEL_VERBOSE
|
||||
bool "Verbose"
|
||||
endchoice
|
||||
|
||||
config LOG_BOOTLOADER_LEVEL
|
||||
int
|
||||
default 0 if LOG_BOOTLOADER_LEVEL_NONE
|
||||
default 1 if LOG_BOOTLOADER_LEVEL_ERROR
|
||||
default 2 if LOG_BOOTLOADER_LEVEL_WARN
|
||||
default 3 if LOG_BOOTLOADER_LEVEL_INFO
|
||||
default 4 if LOG_BOOTLOADER_LEVEL_DEBUG
|
||||
default 5 if LOG_BOOTLOADER_LEVEL_VERBOSE
|
||||
config LOG_BOOTLOADER_LEVEL
|
||||
int
|
||||
default 0 if LOG_BOOTLOADER_LEVEL_NONE
|
||||
default 1 if LOG_BOOTLOADER_LEVEL_ERROR
|
||||
default 2 if LOG_BOOTLOADER_LEVEL_WARN
|
||||
default 3 if LOG_BOOTLOADER_LEVEL_INFO
|
||||
default 4 if LOG_BOOTLOADER_LEVEL_DEBUG
|
||||
default 5 if LOG_BOOTLOADER_LEVEL_VERBOSE
|
||||
|
||||
config BOOTLOADER_SPI_WP_PIN
|
||||
int "SPI Flash WP Pin when customising pins via eFuse (read help)"
|
||||
range 0 33
|
||||
default 7
|
||||
depends on FLASHMODE_QIO || FLASHMODE_QOUT
|
||||
help
|
||||
This value is ignored unless flash mode is set to QIO or QOUT *and* the SPI flash pins have been
|
||||
overriden by setting the eFuses SPI_PAD_CONFIG_xxx.
|
||||
endmenu
|
||||
|
||||
When this is the case, the eFuse config only defines 3 of the 4 Quad I/O data pins. The WP pin (aka ESP32
|
||||
pin "SD_DATA_3" or SPI flash pin "IO2") is not specified in eFuse. That pin number is compiled into the
|
||||
bootloader instead.
|
||||
|
||||
The default value (GPIO 7) is correct for WP pin on ESP32-D2WD integrated flash.
|
||||
|
||||
choice BOOTLOADER_VDDSDIO_BOOST
|
||||
bool "VDDSDIO LDO voltage"
|
||||
default BOOTLOADER_VDDSDIO_BOOST_1_9V
|
||||
help
|
||||
If this option is enabled, and VDDSDIO LDO is set to 1.8V (using eFuse
|
||||
or MTDI bootstrapping pin), bootloader will change LDO settings to
|
||||
output 1.9V instead. This helps prevent flash chip from browning out
|
||||
during flash programming operations.
|
||||
|
||||
This option has no effect if VDDSDIO is set to 3.3V, or if the internal
|
||||
VDDSDIO regulator is disabled via eFuse.
|
||||
|
||||
config BOOTLOADER_VDDSDIO_BOOST_1_8V
|
||||
bool "1.8V"
|
||||
depends on !ESPTOOLPY_FLASHFREQ_80M
|
||||
config BOOTLOADER_VDDSDIO_BOOST_1_9V
|
||||
bool "1.9V"
|
||||
endchoice
|
||||
|
||||
config BOOTLOADER_FACTORY_RESET
|
||||
bool "GPIO triggers factory reset"
|
||||
default N
|
||||
help
|
||||
Allows to reset the device to factory settings:
|
||||
- clear one or more data partitions;
|
||||
- boot from "factory" partition.
|
||||
The factory reset will occur if there is a GPIO input pulled low while device starts up.
|
||||
See settings below.
|
||||
|
||||
config BOOTLOADER_NUM_PIN_FACTORY_RESET
|
||||
int "Number of the GPIO input for factory reset"
|
||||
depends on BOOTLOADER_FACTORY_RESET
|
||||
range 0 39
|
||||
default 4
|
||||
help
|
||||
The selected GPIO will be configured as an input with internal pull-up enabled.
|
||||
To trigger a factory reset, this GPIO must be pulled low on reset.
|
||||
Note that GPIO34-39 do not have an internal pullup and an external one must be provided.
|
||||
|
||||
config BOOTLOADER_OTA_DATA_ERASE
|
||||
bool "Clear OTA data on factory reset (select factory partition)"
|
||||
depends on BOOTLOADER_FACTORY_RESET
|
||||
help
|
||||
The device will boot from "factory" partition (or OTA slot 0 if no factory partition is present) after a
|
||||
factory reset.
|
||||
|
||||
config BOOTLOADER_DATA_FACTORY_RESET
|
||||
string "Comma-separated names of partitions to clear on factory reset"
|
||||
depends on BOOTLOADER_FACTORY_RESET
|
||||
default "nvs"
|
||||
help
|
||||
Allows customers to select which data partitions will be erased while factory reset.
|
||||
|
||||
Specify the names of partitions as a comma-delimited with optional spaces for readability. (Like this:
|
||||
"nvs, phy_init, ...")
|
||||
Make sure that the name specified in the partition table and here are the same.
|
||||
Partitions of type "app" cannot be specified here.
|
||||
|
||||
config BOOTLOADER_APP_TEST
|
||||
bool "GPIO triggers boot from test app partition"
|
||||
default N
|
||||
help
|
||||
Allows to run the test app from "TEST" partition.
|
||||
A boot from "test" partition will occur if there is a GPIO input pulled low while device starts up.
|
||||
See settings below.
|
||||
|
||||
config BOOTLOADER_NUM_PIN_APP_TEST
|
||||
int "Number of the GPIO input to boot TEST partition"
|
||||
depends on BOOTLOADER_APP_TEST
|
||||
range 0 39
|
||||
default 18
|
||||
help
|
||||
The selected GPIO will be configured as an input with internal pull-up enabled.
|
||||
To trigger a test app, this GPIO must be pulled low on reset.
|
||||
After the GPIO input is deactivated and the device reboots, the old application will boot.
|
||||
(factory or OTA[x]).
|
||||
Note that GPIO34-39 do not have an internal pullup and an external one must be provided.
|
||||
|
||||
config BOOTLOADER_HOLD_TIME_GPIO
|
||||
int "Hold time of GPIO for reset/test mode (seconds)"
|
||||
depends on BOOTLOADER_FACTORY_RESET || BOOTLOADER_APP_TEST
|
||||
default 5
|
||||
help
|
||||
The GPIO must be held low continuously for this period of time after reset
|
||||
before a factory reset or test partition boot (as applicable) is performed.
|
||||
|
||||
config BOOTLOADER_WDT_ENABLE
|
||||
bool "Use RTC watchdog in start code"
|
||||
default y
|
||||
help
|
||||
Tracks the execution time of startup code.
|
||||
If the execution time is exceeded, the RTC_WDT will restart system.
|
||||
It is also useful to prevent a lock up in start code caused by an unstable power source.
|
||||
NOTE: Tracks the execution time starts from the bootloader code - re-set timeout, while selecting the
|
||||
source for slow_clk - and ends calling app_main.
|
||||
Re-set timeout is needed due to WDT uses a SLOW_CLK clock source. After changing a frequency slow_clk a
|
||||
time of WDT needs to re-set for new frequency.
|
||||
slow_clk depends on ESP32_RTC_CLOCK_SOURCE (INTERNAL_RC or EXTERNAL_CRYSTAL).
|
||||
|
||||
config BOOTLOADER_WDT_DISABLE_IN_USER_CODE
|
||||
bool "Allows RTC watchdog disable in user code"
|
||||
depends on BOOTLOADER_WDT_ENABLE
|
||||
default n
|
||||
help
|
||||
If it is set, the client must itself reset or disable rtc_wdt in their code (app_main()).
|
||||
Otherwise rtc_wdt will be disabled before calling app_main function.
|
||||
Use function rtc_wdt_feed() for resetting counter of rtc_wdt.
|
||||
Use function rtc_wdt_disable() for disabling rtc_wdt.
|
||||
|
||||
config BOOTLOADER_WDT_TIME_MS
|
||||
int "Timeout for RTC watchdog (ms)"
|
||||
depends on BOOTLOADER_WDT_ENABLE
|
||||
default 9000
|
||||
range 0 120000
|
||||
help
|
||||
Verify that this parameter is correct and more then the execution time.
|
||||
Pay attention to options such as reset to factory, trigger test partition and encryption on boot
|
||||
- these options can increase the execution time.
|
||||
Note: RTC_WDT will reset while encryption operations will be performed.
|
||||
|
||||
config APP_ROLLBACK_ENABLE
|
||||
bool "Enable app rollback support"
|
||||
default n
|
||||
help
|
||||
After updating the app, the bootloader runs a new app with the "ESP_OTA_IMG_PENDING_VERIFY" state set.
|
||||
This state prevents the re-run of this app. After the first boot of the new app in the user code, the
|
||||
function should be called to confirm the operability of the app or vice versa about its non-operability.
|
||||
If the app is working, then it is marked as valid. Otherwise, it is marked as not valid and rolls back to
|
||||
the previous working app. A reboot is performed, and the app is booted before the software update.
|
||||
Note: If during the first boot a new app the power goes out or the WDT works, then roll back will happen.
|
||||
Rollback is possible only between the apps with the same security versions.
|
||||
|
||||
config APP_ANTI_ROLLBACK
|
||||
bool "Enable app anti-rollback support"
|
||||
depends on APP_ROLLBACK_ENABLE
|
||||
default n
|
||||
help
|
||||
This option prevents rollback to previous firmware/application image with lower security version.
|
||||
|
||||
config APP_SECURE_VERSION
|
||||
int "eFuse secure version of app"
|
||||
depends on APP_ANTI_ROLLBACK
|
||||
default 0
|
||||
help
|
||||
The secure version is the sequence number stored in the header of each firmware.
|
||||
The security version is set in the bootloader, version is recorded in the eFuse field
|
||||
as the number of set ones. The allocated number of bits in the efuse field
|
||||
for storing the security version is limited (see APP_SECURE_VERSION_SIZE_EFUSE_FIELD option).
|
||||
|
||||
Bootloader: When bootloader selects an app to boot, an app is selected that has
|
||||
a security version greater or equal that recorded in eFuse field.
|
||||
The app is booted with a higher (or equal) secure version.
|
||||
|
||||
The security version is worth increasing if in previous versions there is
|
||||
a significant vulnerability and their use is not acceptable.
|
||||
|
||||
Your partition table should has a scheme with ota_0 + ota_1 (without factory).
|
||||
|
||||
config APP_SECURE_VERSION_SIZE_EFUSE_FIELD
|
||||
int "Size of the efuse secure version field"
|
||||
depends on APP_ANTI_ROLLBACK
|
||||
range 1 32
|
||||
default 32
|
||||
help
|
||||
The size of the efuse secure version field. Its length is limited to 32 bits.
|
||||
This determines how many times the security version can be increased.
|
||||
|
||||
config EFUSE_SECURE_VERSION_EMULATE
|
||||
bool "Emulate operations with efuse secure version(only test)"
|
||||
default n
|
||||
depends on APP_ANTI_ROLLBACK
|
||||
help
|
||||
This option allow emulate read/write operations with efuse secure version.
|
||||
It allow to test anti-rollback implemention without permanent write eFuse bits.
|
||||
In partition table should be exist this partition `emul_efuse, data, 5, , 0x2000`.
|
||||
|
||||
endmenu # Bootloader
|
||||
|
||||
|
||||
menu "Security features"
|
||||
visible if !IDF_CMAKE
|
||||
|
||||
# These three are the actual options to check in code,
|
||||
# selected by the displayed options
|
||||
config SECURE_SIGNED_ON_BOOT
|
||||
bool
|
||||
default y
|
||||
depends on SECURE_BOOT_ENABLED || SECURE_SIGNED_ON_BOOT_NO_SECURE_BOOT
|
||||
|
||||
config SECURE_SIGNED_ON_UPDATE
|
||||
bool
|
||||
default y
|
||||
depends on SECURE_BOOT_ENABLED || SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
|
||||
config SECURE_SIGNED_APPS
|
||||
bool
|
||||
default y
|
||||
depends on SECURE_SIGNED_ON_BOOT || SECURE_SIGNED_ON_UPDATE
|
||||
|
||||
|
||||
config SECURE_SIGNED_APPS_NO_SECURE_BOOT
|
||||
bool "Require signed app images"
|
||||
default n
|
||||
depends on !SECURE_BOOT_ENABLED
|
||||
help
|
||||
Require apps to be signed to verify their integrity.
|
||||
|
||||
This option uses the same app signature scheme as hardware secure boot, but unlike hardware secure boot it
|
||||
does not prevent the bootloader from being physically updated. This means that the device can be secured
|
||||
against remote network access, but not physical access. Compared to using hardware Secure Boot this option
|
||||
is much simpler to implement.
|
||||
|
||||
config SECURE_SIGNED_ON_BOOT_NO_SECURE_BOOT
|
||||
bool "Bootloader verifies app signatures"
|
||||
default n
|
||||
depends on SECURE_SIGNED_APPS_NO_SECURE_BOOT
|
||||
help
|
||||
If this option is set, the bootloader will be compiled with code to verify that an app is signed before
|
||||
booting it.
|
||||
|
||||
If hardware secure boot is enabled, this option is always enabled and cannot be disabled.
|
||||
If hardware secure boot is not enabled, this option doesn't add significant security by itself so most
|
||||
users will want to leave it disabled.
|
||||
|
||||
config SECURE_SIGNED_ON_UPDATE_NO_SECURE_BOOT
|
||||
bool "Verify app signature on update"
|
||||
default y
|
||||
depends on SECURE_SIGNED_APPS_NO_SECURE_BOOT
|
||||
help
|
||||
If this option is set, any OTA updated apps will have the signature verified before being considered valid.
|
||||
|
||||
When enabled, the signature is automatically checked whenever the esp_ota_ops.h APIs are used for OTA
|
||||
updates, or esp_image_format.h APIs are used to verify apps.
|
||||
|
||||
If hardware secure boot is enabled, this option is always enabled and cannot be disabled.
|
||||
If hardware secure boot is not enabled, this option still adds significant security against network-based
|
||||
attackers by preventing spoofing of OTA updates.
|
||||
|
||||
config SECURE_BOOT_ENABLED
|
||||
bool "Enable hardware secure boot in bootloader (READ DOCS FIRST)"
|
||||
default n
|
||||
help
|
||||
Build a bootloader which enables secure boot on first boot.
|
||||
|
||||
Once enabled, secure boot will not boot a modified bootloader. The bootloader will only load a partition
|
||||
table or boot an app if the data has a verified digital signature. There are implications for reflashing
|
||||
updated apps once secure boot is enabled.
|
||||
|
||||
When enabling secure boot, JTAG and ROM BASIC Interpreter are permanently disabled by default.
|
||||
|
||||
Refer to https://docs.espressif.com/projects/esp-idf/en/latest/security/secure-boot.html before enabling.
|
||||
|
||||
choice SECURE_BOOTLOADER_MODE
|
||||
bool "Secure bootloader mode"
|
||||
depends on SECURE_BOOT_ENABLED
|
||||
default SECURE_BOOTLOADER_ONE_TIME_FLASH
|
||||
|
||||
config SECURE_BOOTLOADER_ONE_TIME_FLASH
|
||||
bool "One-time flash"
|
||||
help
|
||||
On first boot, the bootloader will generate a key which is not readable externally or by software. A
|
||||
digest is generated from the bootloader image itself. This digest will be verified on each subsequent
|
||||
boot.
|
||||
|
||||
Enabling this option means that the bootloader cannot be changed after the first time it is booted.
|
||||
config SECURE_BOOT_ENABLED
|
||||
bool "Enable secure boot in bootloader (READ DOCS FIRST)"
|
||||
default N
|
||||
help
|
||||
Build a bootloader which enables secure boot on first boot.
|
||||
|
||||
config SECURE_BOOTLOADER_REFLASHABLE
|
||||
bool "Reflashable"
|
||||
help
|
||||
Generate a reusable secure bootloader key, derived (via SHA-256) from the secure boot signing key.
|
||||
Once enabled, secure boot will not boot a modified bootloader. The bootloader will only load a partition table or boot an app if the data has a verified digital signature. There are implications for reflashing updated apps once secure boot is enabled.
|
||||
|
||||
This allows the secure bootloader to be re-flashed by anyone with access to the secure boot signing
|
||||
key.
|
||||
|
||||
This option is less secure than one-time flash, because a leak of the digest key from one device
|
||||
allows reflashing of any device that uses it.
|
||||
|
||||
endchoice
|
||||
When enabling secure boot, JTAG and ROM BASIC Interpreter are permanently disabled by default.
|
||||
|
||||
config SECURE_BOOT_BUILD_SIGNED_BINARIES
|
||||
bool "Sign binaries during build"
|
||||
depends on SECURE_SIGNED_APPS
|
||||
default y
|
||||
help
|
||||
Once secure boot or signed app requirement is enabled, app images are required to be signed.
|
||||
Refer to http://esp-idf.readthedocs.io/en/latest/security/secure-boot.html before enabling.
|
||||
|
||||
If enabled (default), these binary files are signed as part of the build process. The file named in
|
||||
"Secure boot private signing key" will be used to sign the image.
|
||||
choice SECURE_BOOTLOADER_MODE
|
||||
bool "Secure bootloader mode"
|
||||
depends on SECURE_BOOT_ENABLED
|
||||
default SECURE_BOOTLOADER_ONE_TIME_FLASH
|
||||
|
||||
If disabled, unsigned app/partition data will be built. They must be signed manually using espsecure.py
|
||||
(for example, on a remote signing server.)
|
||||
config SECURE_BOOTLOADER_ONE_TIME_FLASH
|
||||
bool "One-time flash"
|
||||
help
|
||||
On first boot, the bootloader will generate a key which is not readable externally or by software. A digest is generated from the bootloader image itself. This digest will be verified on each subsequent boot.
|
||||
|
||||
config SECURE_BOOT_SIGNING_KEY
|
||||
string "Secure boot private signing key"
|
||||
depends on SECURE_BOOT_BUILD_SIGNED_BINARIES
|
||||
default secure_boot_signing_key.pem
|
||||
help
|
||||
Path to the key file used to sign app images.
|
||||
Enabling this option means that the bootloader cannot be changed after the first time it is booted.
|
||||
|
||||
Key file is an ECDSA private key (NIST256p curve) in PEM format.
|
||||
|
||||
Path is evaluated relative to the project directory.
|
||||
|
||||
You can generate a new signing key by running the following command:
|
||||
espsecure.py generate_signing_key secure_boot_signing_key.pem
|
||||
config SECURE_BOOTLOADER_REFLASHABLE
|
||||
bool "Reflashable"
|
||||
help
|
||||
Generate a reusable secure bootloader key, derived (via SHA-256) from the secure boot signing key.
|
||||
|
||||
See https://docs.espressif.com/projects/esp-idf/en/latest/security/secure-boot.html for details.
|
||||
|
||||
config SECURE_BOOT_VERIFICATION_KEY
|
||||
string "Secure boot public signature verification key"
|
||||
depends on SECURE_SIGNED_APPS && !SECURE_BOOT_BUILD_SIGNED_BINARIES
|
||||
default signature_verification_key.bin
|
||||
help
|
||||
Path to a public key file used to verify signed images. This key is compiled into the bootloader and/or
|
||||
app, to verify app images.
|
||||
This allows the secure bootloader to be re-flashed by anyone with access to the secure boot signing key.
|
||||
|
||||
Key file is in raw binary format, and can be extracted from a
|
||||
PEM formatted private key using the espsecure.py
|
||||
extract_public_key command.
|
||||
This option is less secure than one-time flash, because a leak of the digest key from one device allows reflashing of any device that uses it.
|
||||
|
||||
Refer to https://docs.espressif.com/projects/esp-idf/en/latest/security/secure-boot.html before enabling.
|
||||
endchoice
|
||||
|
||||
choice SECURE_BOOTLOADER_KEY_ENCODING
|
||||
bool "Hardware Key Encoding"
|
||||
depends on SECURE_BOOTLOADER_REFLASHABLE
|
||||
default SECURE_BOOTLOADER_NO_ENCODING
|
||||
help
|
||||
config SECURE_BOOT_BUILD_SIGNED_BINARIES
|
||||
bool "Sign binaries during build"
|
||||
depends on SECURE_BOOT_ENABLED
|
||||
default y
|
||||
help
|
||||
Once secure boot is enabled, bootloader will only boot if partition table and app image are signed.
|
||||
|
||||
In reflashable secure bootloader mode, a hardware key is derived from the signing key (with SHA-256) and
|
||||
can be written to eFuse with espefuse.py.
|
||||
If enabled, these binary files are signed as part of the build process. The file named in "Secure boot private signing key" will be used to sign the image.
|
||||
|
||||
Normally this is a 256-bit key, but if 3/4 Coding Scheme is used on the device then the eFuse key is
|
||||
truncated to 192 bits.
|
||||
If disabled, unsigned app/partition data will be built. They must be signed manually using espsecure.py (for example, on a remote signing server.)
|
||||
|
||||
This configuration item doesn't change any firmware code, it only changes the size of key binary which is
|
||||
generated at build time.
|
||||
|
||||
config SECURE_BOOTLOADER_KEY_ENCODING_256BIT
|
||||
bool "No encoding (256 bit key)"
|
||||
|
||||
config SECURE_BOOTLOADER_KEY_ENCODING_192BIT
|
||||
bool "3/4 encoding (192 bit key)"
|
||||
config SECURE_BOOT_SIGNING_KEY
|
||||
string "Secure boot private signing key"
|
||||
depends on SECURE_BOOT_BUILD_SIGNED_BINARIES
|
||||
default secure_boot_signing_key.pem
|
||||
help
|
||||
Path to the key file used to sign partition tables and app images for secure boot. Once secure boot is enabled, bootloader will only boot if partition table and app image are signed.
|
||||
|
||||
endchoice
|
||||
|
||||
config SECURE_BOOT_INSECURE
|
||||
bool "Allow potentially insecure options"
|
||||
depends on SECURE_BOOT_ENABLED
|
||||
default N
|
||||
help
|
||||
You can disable some of the default protections offered by secure boot, in order to enable testing or a
|
||||
custom combination of security features.
|
||||
|
||||
Only enable these options if you are very sure.
|
||||
|
||||
Refer to https://docs.espressif.com/projects/esp-idf/en/latest/security/secure-boot.html before enabling.
|
||||
|
||||
config FLASH_ENCRYPTION_ENABLED
|
||||
bool "Enable flash encryption on boot (READ DOCS FIRST)"
|
||||
default N
|
||||
help
|
||||
If this option is set, flash contents will be encrypted by the bootloader on first boot.
|
||||
|
||||
Note: After first boot, the system will be permanently encrypted. Re-flashing an encrypted
|
||||
system is complicated and not always possible.
|
||||
|
||||
Read https://docs.espressif.com/projects/esp-idf/en/latest/security/flash-encryption.html before enabling.
|
||||
|
||||
config FLASH_ENCRYPTION_INSECURE
|
||||
bool "Allow potentially insecure options"
|
||||
depends on FLASH_ENCRYPTION_ENABLED
|
||||
default N
|
||||
help
|
||||
You can disable some of the default protections offered by flash encryption, in order to enable testing or
|
||||
a custom combination of security features.
|
||||
|
||||
Only enable these options if you are very sure.
|
||||
|
||||
Refer to https://docs.espressif.com/projects/esp-idf/en/latest/security/secure-boot.html and
|
||||
https://docs.espressif.com/projects/esp-idf/en/latest/security/flash-encryption.html for details.
|
||||
|
||||
menu "Potentially insecure options"
|
||||
visible if FLASH_ENCRYPTION_INSECURE || SECURE_BOOT_INSECURE
|
||||
|
||||
# NOTE: Options in this menu NEED to have SECURE_BOOT_INSECURE
|
||||
# and/or FLASH_ENCRYPTION_INSECURE in "depends on", as the menu
|
||||
# itself doesn't enable/disable its children (if it's not set,
|
||||
# it's possible for the insecure menu to be disabled but the insecure option
|
||||
# to remain on which is very bad.)
|
||||
|
||||
config SECURE_BOOT_ALLOW_ROM_BASIC
|
||||
bool "Leave ROM BASIC Interpreter available on reset"
|
||||
depends on SECURE_BOOT_INSECURE || FLASH_ENCRYPTION_INSECURE
|
||||
default N
|
||||
help
|
||||
By default, the BASIC ROM Console starts on reset if no valid bootloader is
|
||||
read from the flash.
|
||||
|
||||
When either flash encryption or secure boot are enabled, the default is to
|
||||
disable this BASIC fallback mode permanently via eFuse.
|
||||
|
||||
If this option is set, this eFuse is not burned and the BASIC ROM Console may
|
||||
remain accessible. Only set this option in testing environments.
|
||||
|
||||
config SECURE_BOOT_ALLOW_JTAG
|
||||
bool "Allow JTAG Debugging"
|
||||
depends on SECURE_BOOT_INSECURE || FLASH_ENCRYPTION_INSECURE
|
||||
default N
|
||||
help
|
||||
If not set (default), the bootloader will permanently disable JTAG (across entire chip) on first boot
|
||||
when either secure boot or flash encryption is enabled.
|
||||
|
||||
Setting this option leaves JTAG on for debugging, which negates all protections of flash encryption
|
||||
and some of the protections of secure boot.
|
||||
|
||||
Only set this option in testing environments.
|
||||
|
||||
config SECURE_BOOT_ALLOW_SHORT_APP_PARTITION
|
||||
bool "Allow app partition length not 64KB aligned"
|
||||
depends on SECURE_BOOT_INSECURE
|
||||
help
|
||||
If not set (default), app partition size must be a multiple of 64KB. App images are padded to 64KB
|
||||
length, and the bootloader checks any trailing bytes after the signature (before the next 64KB
|
||||
boundary) have not been written. This is because flash cache maps entire 64KB pages into the address
|
||||
space. This prevents an attacker from appending unverified data after the app image in the flash,
|
||||
causing it to be mapped into the address space.
|
||||
|
||||
Setting this option allows the app partition length to be unaligned, and disables padding of the app
|
||||
image to this length. It is generally not recommended to set this option, unless you have a legacy
|
||||
partitioning scheme which doesn't support 64KB aligned partition lengths.
|
||||
|
||||
config FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_ENCRYPT
|
||||
bool "Leave UART bootloader encryption enabled"
|
||||
depends on FLASH_ENCRYPTION_INSECURE
|
||||
default N
|
||||
help
|
||||
If not set (default), the bootloader will permanently disable UART bootloader encryption access on
|
||||
first boot. If set, the UART bootloader will still be able to access hardware encryption.
|
||||
|
||||
It is recommended to only set this option in testing environments.
|
||||
|
||||
config FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_DECRYPT
|
||||
bool "Leave UART bootloader decryption enabled"
|
||||
depends on FLASH_ENCRYPTION_INSECURE
|
||||
default N
|
||||
help
|
||||
If not set (default), the bootloader will permanently disable UART bootloader decryption access on
|
||||
first boot. If set, the UART bootloader will still be able to access hardware decryption.
|
||||
|
||||
Only set this option in testing environments. Setting this option allows complete bypass of flash
|
||||
encryption.
|
||||
|
||||
config FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_CACHE
|
||||
bool "Leave UART bootloader flash cache enabled"
|
||||
depends on FLASH_ENCRYPTION_INSECURE
|
||||
default N
|
||||
help
|
||||
If not set (default), the bootloader will permanently disable UART bootloader flash cache access on
|
||||
first boot. If set, the UART bootloader will still be able to access the flash cache.
|
||||
|
||||
Only set this option in testing environments.
|
||||
|
||||
endmenu # Potentially Insecure
|
||||
|
||||
config FLASH_ENCRYPTION_DISABLE_PLAINTEXT
|
||||
bool "Disable serial reflashing of plaintext firmware"
|
||||
depends on FLASH_ENCRYPTION_ENABLED
|
||||
default y if SECURE_BOOT_ENABLED
|
||||
default n if !SECURE_BOOT_ENABLED
|
||||
help
|
||||
If this option is enabled, flash encryption is permanently enabled after first boot by write-protecting
|
||||
the FLASH_CRYPT_CNT efuse. This is the recommended configuration for a secure production system.
|
||||
|
||||
If this option is disabled, FLASH_CRYPT_CNT is left writeable and up to 4 plaintext re-flashes are allowed.
|
||||
An attacker with physical access will be able to read out encrypted flash contents until all plaintext
|
||||
re-flashes have been used up.
|
||||
|
||||
If this option is disabled and hardware Secure Boot is enabled, Secure Boot must be configured in
|
||||
Reflashable mode so that a new Secure Boot digest can be flashed at the same time as plaintext firmware.
|
||||
This combination is not secure and should not be used for a production system.
|
||||
|
||||
config SECURE_DISABLE_ROM_DL_MODE
|
||||
bool "Permanently disable ROM Download Mode"
|
||||
depends on ESP32_REV_MIN_3
|
||||
default n
|
||||
help
|
||||
If set, during startup the app will burn an eFuse bit to permanently disable the UART ROM
|
||||
Download Mode. This prevents any future use of esptool.py, espefuse.py and similar tools.
|
||||
|
||||
Once disabled, if the SoC is booted with strapping pins set for ROM Download Mode
|
||||
then an error is printed instead.
|
||||
|
||||
It is recommended to enable this option in any production application where Flash
|
||||
Encryption and/or Secure Boot is enabled and access to Download Mode is not required.
|
||||
|
||||
It is also possible to permanently disable Download Mode by calling
|
||||
esp_efuse_disable_rom_download_mode() at runtime.
|
||||
|
||||
endmenu # Security features
|
||||
Key file is an ECDSA private key (NIST256p curve) in PEM format.
|
||||
|
||||
Path is evaluated relative to the project directory.
|
||||
|
||||
You can generate a new signing key by running the following command:
|
||||
espsecure.py generate_signing_key secure_boot_signing_key.pem
|
||||
|
||||
See docs/security/secure-boot.rst for details.
|
||||
|
||||
config SECURE_BOOT_VERIFICATION_KEY
|
||||
string "Secure boot public signature verification key"
|
||||
depends on SECURE_BOOT_ENABLED && !SECURE_BOOT_BUILD_SIGNED_BINARIES
|
||||
default signature_verification_key.bin
|
||||
help
|
||||
Path to a public key file used to verify signed images. This key is compiled into the bootloader,
|
||||
and may also be used to verify signatures on OTA images after download.
|
||||
|
||||
Key file is in raw binary format, and can be extracted from a
|
||||
PEM formatted private key using the espsecure.py
|
||||
extract_public_key command.
|
||||
|
||||
Refer to http://esp-idf.readthedocs.io/en/latest/security/secure-boot.html before enabling.
|
||||
|
||||
config SECURE_BOOT_INSECURE
|
||||
bool "Allow potentially insecure options"
|
||||
depends on SECURE_BOOT_ENABLED
|
||||
default N
|
||||
help
|
||||
You can disable some of the default protections offered by secure boot, in order to enable testing or a custom combination of security features.
|
||||
|
||||
Only enable these options if you are very sure.
|
||||
|
||||
Refer to http://esp-idf.readthedocs.io/en/latest/security/secure-boot.html before enabling.
|
||||
|
||||
config FLASH_ENCRYPTION_ENABLED
|
||||
bool "Enable flash encryption on boot (READ DOCS FIRST)"
|
||||
default N
|
||||
help
|
||||
If this option is set, flash contents will be encrypted by the bootloader on first boot.
|
||||
|
||||
Note: After first boot, the system will be permanently encrypted. Re-flashing an encrypted
|
||||
system is complicated and not always possible.
|
||||
|
||||
Read http://esp-idf.readthedocs.io/en/latest/security/flash-encryption.html before enabling.
|
||||
|
||||
config FLASH_ENCRYPTION_INSECURE
|
||||
bool "Allow potentially insecure options"
|
||||
depends on FLASH_ENCRYPTION_ENABLED
|
||||
default N
|
||||
help
|
||||
You can disable some of the default protections offered by flash encryption, in order to enable testing or a custom combination of security features.
|
||||
|
||||
Only enable these options if you are very sure.
|
||||
|
||||
Refer to docs/security/secure-boot.rst and docs/security/flash-encryption.rst for details.
|
||||
|
||||
menu "Potentially insecure options"
|
||||
visible if FLASH_ENCRYPTION_INSECURE || SECURE_BOOT_INSECURE
|
||||
|
||||
# NOTE: Options in this menu NEED to have SECURE_BOOT_INSECURE
|
||||
# and/or FLASH_ENCRYPTION_INSECURE in "depends on", as the menu
|
||||
# itself doesn't enable/disable its children (if it's not set,
|
||||
# it's possible for the insecure menu to be disabled but the insecure option
|
||||
# to remain on which is very bad.)
|
||||
|
||||
config SECURE_BOOT_ALLOW_ROM_BASIC
|
||||
bool "Leave ROM BASIC Interpreter available on reset"
|
||||
depends on SECURE_BOOT_INSECURE
|
||||
default N
|
||||
help
|
||||
If not set (default), bootloader permanently disables ROM BASIC (on UART console) as a fallback if the bootloader image becomes invalid. This happens on first boot.
|
||||
|
||||
Only set this option in testing environments.
|
||||
|
||||
config SECURE_BOOT_ALLOW_JTAG
|
||||
bool "Allow JTAG Debugging"
|
||||
depends on SECURE_BOOT_INSECURE || FLASH_ENCRYPTION_INSECURE
|
||||
default N
|
||||
help
|
||||
If not set (default), the bootloader will permanently disable JTAG (across entire chip) on first boot when either secure boot or flash encryption is enabled.
|
||||
|
||||
Setting this option leaves JTAG on for debugging, which negates all protections of flash encryption and some of the protections of secure boot.
|
||||
|
||||
Only set this option in testing environments.
|
||||
|
||||
|
||||
config FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_ENCRYPT
|
||||
bool "Leave UART bootloader encryption enabled"
|
||||
depends on FLASH_ENCRYPTION_INSECURE
|
||||
default N
|
||||
help
|
||||
If not set (default), the bootloader will permanently disable UART bootloader encryption access on first boot. If set, the UART bootloader will still be able to access hardware encryption.
|
||||
|
||||
It is recommended to only set this option in testing environments.
|
||||
|
||||
config FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_DECRYPT
|
||||
bool "Leave UART bootloader decryption enabled"
|
||||
depends on FLASH_ENCRYPTION_INSECURE
|
||||
default N
|
||||
help
|
||||
If not set (default), the bootloader will permanently disable UART bootloader decryption access on first boot. If set, the UART bootloader will still be able to access hardware decryption.
|
||||
|
||||
Only set this option in testing environments. Setting this option allows complete bypass of flash encryption.
|
||||
|
||||
config FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_CACHE
|
||||
bool "Leave UART bootloader flash cache enabled"
|
||||
depends on FLASH_ENCRYPTION_INSECURE
|
||||
default N
|
||||
help
|
||||
If not set (default), the bootloader will permanently disable UART bootloader flash cache access on first boot. If set, the UART bootloader will still be able to access the flash cache.
|
||||
|
||||
Only set this option in testing environments.
|
||||
|
||||
config SECURE_BOOT_TEST_MODE
|
||||
bool "Secure boot test mode: don't permanently set any efuses"
|
||||
depends on SECURE_BOOT_INSECURE
|
||||
default N
|
||||
help
|
||||
If this option is set, all permanent secure boot changes (via Efuse) are disabled.
|
||||
|
||||
Log output will state changes which would be applied, but they will not be.
|
||||
|
||||
This option is for testing purposes only - it completely disables secure boot protection.
|
||||
|
||||
|
||||
endmenu # potentially insecure
|
||||
|
||||
endmenu
|
||||
@@ -1,19 +1,20 @@
|
||||
# Bootloader component (top-level project parts)
|
||||
#
|
||||
# Bootloader component
|
||||
#
|
||||
# The bootloader is not a real component that gets linked into the project.
|
||||
# Instead it is an entire standalone project (in subproject/) that gets
|
||||
# built in the upper project's build directory. This Makefile.projbuild provides
|
||||
# the glue to build the bootloader project from the original project. It
|
||||
# basically runs Make in the subproject/ directory but it needs to
|
||||
# zero some variables the ESP-IDF project.mk makefile exports first, to not
|
||||
# let them interfere.
|
||||
# Instead it is an entire standalone project ( in src/) that gets built in
|
||||
# the upper projects build directory. This Makefile.projbuild provides the
|
||||
# glue to build the bootloader project from the original project. It
|
||||
# basically runs Make in the src/ directory but it needs to zero some variables
|
||||
# the ESP-IDF project.mk makefile exports first, to not let them interfere.
|
||||
#
|
||||
ifndef IS_BOOTLOADER_BUILD
|
||||
|
||||
BOOTLOADER_COMPONENT_PATH := $(COMPONENT_PATH)
|
||||
BOOTLOADER_BUILD_DIR=$(abspath $(BUILD_DIR_BASE)/bootloader)
|
||||
BOOTLOADER_BIN=$(BOOTLOADER_BUILD_DIR)/bootloader.bin
|
||||
|
||||
# signing key path is resolved relative to the project directory
|
||||
CONFIG_SECURE_BOOT_SIGNING_KEY ?=
|
||||
SECURE_BOOT_SIGNING_KEY=$(abspath $(call dequote,$(CONFIG_SECURE_BOOT_SIGNING_KEY)))
|
||||
export SECURE_BOOT_SIGNING_KEY # used by bootloader_support component
|
||||
|
||||
@@ -21,42 +22,28 @@ export SECURE_BOOT_SIGNING_KEY # used by bootloader_support component
|
||||
BOOTLOADER_OFFSET := 0x1000
|
||||
|
||||
# Custom recursive make for bootloader sub-project
|
||||
#
|
||||
# NB: Some variables are cleared in the environment, not
|
||||
# overriden, because they need to be re-defined in the child
|
||||
# project.
|
||||
BOOTLOADER_MAKE= +\
|
||||
PROJECT_PATH= \
|
||||
COMPONENT_DIRS= \
|
||||
$(MAKE) -C $(BOOTLOADER_COMPONENT_PATH)/subproject \
|
||||
V=$(V) \
|
||||
BUILD_DIR_BASE=$(BOOTLOADER_BUILD_DIR) \
|
||||
TEST_COMPONENTS= \
|
||||
TESTS_ALL= \
|
||||
EXCLUDE_COMPONENTS=
|
||||
BOOTLOADER_MAKE=+$(MAKE) -C $(BOOTLOADER_COMPONENT_PATH)/src \
|
||||
V=$(V) BUILD_DIR_BASE=$(BOOTLOADER_BUILD_DIR) TEST_COMPONENTS= TESTS_ALL=
|
||||
|
||||
.PHONY: bootloader-clean bootloader-flash bootloader-list-components bootloader $(BOOTLOADER_BIN)
|
||||
.PHONY: bootloader-clean bootloader-flash bootloader $(BOOTLOADER_BIN)
|
||||
|
||||
$(BOOTLOADER_BIN): $(SDKCONFIG_MAKEFILE)
|
||||
$(BOOTLOADER_MAKE) $@
|
||||
|
||||
clean: bootloader-clean
|
||||
|
||||
bootloader-list-components:
|
||||
$(BOOTLOADER_MAKE) list-components
|
||||
|
||||
ifndef CONFIG_SECURE_BOOT_ENABLED
|
||||
# If secure boot disabled, bootloader flashing is integrated
|
||||
# with 'make flash' and no warnings are printed.
|
||||
|
||||
bootloader: $(BOOTLOADER_BIN) | check_python_dependencies
|
||||
bootloader: $(BOOTLOADER_BIN)
|
||||
@echo $(SEPARATOR)
|
||||
@echo "Bootloader built. Default flash command is:"
|
||||
@echo "$(ESPTOOLPY_WRITE_FLASH) $(BOOTLOADER_OFFSET) $^"
|
||||
|
||||
ESPTOOL_ALL_FLASH_ARGS += $(BOOTLOADER_OFFSET) $(BOOTLOADER_BIN)
|
||||
|
||||
bootloader-flash: $(BOOTLOADER_BIN) $(call prereq_if_explicit,erase_flash) | check_python_dependencies
|
||||
bootloader-flash: $(BOOTLOADER_BIN) $(call prereq_if_explicit,erase_flash)
|
||||
$(ESPTOOLPY_WRITE_FLASH) 0x1000 $^
|
||||
|
||||
else ifdef CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH
|
||||
@@ -67,7 +54,7 @@ else ifdef CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH
|
||||
# The flashing command is deliberately printed without an auto-reset
|
||||
# step, so the device doesn't immediately reset to flash itself.
|
||||
|
||||
bootloader: $(BOOTLOADER_BIN) | check_python_dependencies
|
||||
bootloader: $(BOOTLOADER_BIN)
|
||||
@echo $(SEPARATOR)
|
||||
@echo "Bootloader built. One-time flash command is:"
|
||||
@echo "$(subst hard_reset,no_reset,$(ESPTOOLPY_WRITE_FLASH)) $(BOOTLOADER_OFFSET) $(BOOTLOADER_BIN)"
|
||||
@@ -78,18 +65,12 @@ else ifdef CONFIG_SECURE_BOOTLOADER_REFLASHABLE
|
||||
# Reflashable secure bootloader
|
||||
# generates a digest binary (bootloader + digest)
|
||||
|
||||
ifdef CONFIG_SECURE_BOOTLOADER_KEY_ENCODING_192BIT
|
||||
KEY_DIGEST_LEN=192
|
||||
else
|
||||
KEY_DIGEST_LEN=256
|
||||
endif
|
||||
|
||||
BOOTLOADER_DIGEST_BIN := $(BOOTLOADER_BUILD_DIR)/bootloader-reflash-digest.bin
|
||||
SECURE_BOOTLOADER_KEY := $(BOOTLOADER_BUILD_DIR)/secure-bootloader-key-$(KEY_DIGEST_LEN).bin
|
||||
SECURE_BOOTLOADER_KEY := $(BOOTLOADER_BUILD_DIR)/secure-bootloader-key.bin
|
||||
|
||||
ifdef CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES
|
||||
$(SECURE_BOOTLOADER_KEY): $(SECURE_BOOT_SIGNING_KEY) | check_python_dependencies
|
||||
$(ESPSECUREPY) digest_private_key --keylen $(KEY_DIGEST_LEN) -k $< $@
|
||||
$(SECURE_BOOTLOADER_KEY): $(SECURE_BOOT_SIGNING_KEY)
|
||||
$(ESPSECUREPY) digest_private_key -k $< $@
|
||||
else
|
||||
$(SECURE_BOOTLOADER_KEY):
|
||||
@echo "No pre-generated key for a reflashable secure bootloader is available, due to signing configuration."
|
||||
@@ -111,23 +92,29 @@ bootloader: $(BOOTLOADER_DIGEST_BIN)
|
||||
@echo "* After first boot, only re-flashes of this kind (with same key) will be accepted."
|
||||
@echo "* Not recommended to re-use the same secure boot keyfile on multiple production devices."
|
||||
|
||||
$(BOOTLOADER_DIGEST_BIN): $(BOOTLOADER_BIN) $(SECURE_BOOTLOADER_KEY) | check_python_dependencies
|
||||
$(BOOTLOADER_DIGEST_BIN): $(BOOTLOADER_BIN) $(SECURE_BOOTLOADER_KEY)
|
||||
@echo "DIGEST $(notdir $@)"
|
||||
$(ESPSECUREPY) digest_secure_bootloader -k $(SECURE_BOOTLOADER_KEY) -o $@ $<
|
||||
$(Q) $(ESPSECUREPY) digest_secure_bootloader -k $(SECURE_BOOTLOADER_KEY) -o $@ $<
|
||||
|
||||
else # CONFIG_SECURE_BOOT_ENABLED && !CONFIG_SECURE_BOOTLOADER_REFLASHABLE && !CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH
|
||||
else
|
||||
bootloader:
|
||||
@echo "Invalid bootloader target: bad sdkconfig?"
|
||||
@exit 1
|
||||
endif
|
||||
|
||||
ifndef CONFIG_SECURE_BOOT_ENABLED
|
||||
# don't build bootloader by default if secure boot is enabled
|
||||
# don't build bootloader by default is secure boot is enabled
|
||||
all_binaries: $(BOOTLOADER_BIN)
|
||||
endif
|
||||
|
||||
bootloader-clean: $(SDKCONFIG_MAKEFILE)
|
||||
bootloader-clean:
|
||||
$(BOOTLOADER_MAKE) app-clean
|
||||
ifdef CONFIG_SECURE_BOOTLOADER_REFLASHABLE
|
||||
rm -f $(SECURE_BOOTLOADER_KEY) $(BOOTLOADER_DIGEST_BIN)
|
||||
|
||||
$(BOOTLOADER_BUILD_DIR):
|
||||
mkdir -p $@
|
||||
|
||||
else
|
||||
CFLAGS += -D BOOTLOADER_BUILD=1 -I $(IDF_PATH)/components/esp32/include
|
||||
|
||||
endif
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# bootloader component is special, as bootloader is also a project.
|
||||
#
|
||||
# This top-level component is only configuration files for the IDF project.
|
||||
#
|
||||
# See Makefile.projbuild for the targets which actually build the bootloader.
|
||||
COMPONENT_CONFIG_ONLY := 1
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
# This is for tracking the top level project path
|
||||
if(BOOTLOADER_BUILD)
|
||||
set(main_project_path "${CMAKE_BINARY_DIR}/../..")
|
||||
else()
|
||||
set(main_project_path "${IDF_PROJECT_PATH}")
|
||||
endif()
|
||||
|
||||
get_filename_component(secure_boot_signing_key
|
||||
"${CONFIG_SECURE_BOOT_SIGNING_KEY}"
|
||||
ABSOLUTE BASE_DIR "${main_project_path}")
|
||||
if(NOT EXISTS ${secure_boot_signing_key})
|
||||
# If the signing key is not found, create a phony gen_secure_boot_signing_key target that
|
||||
# fails the build. fail_at_build_time also touches CMakeCache.txt to cause a cmake run next time
|
||||
# (to pick up a new signing key if one exists, etc.)
|
||||
fail_at_build_time(gen_secure_boot_signing_key
|
||||
"Secure Boot Signing Key ${CONFIG_SECURE_BOOT_SIGNING_KEY} does not exist. Generate using:"
|
||||
"\tespsecure.py generate_signing_key ${CONFIG_SECURE_BOOT_SIGNING_KEY}")
|
||||
else()
|
||||
add_custom_target(gen_secure_boot_signing_key)
|
||||
endif()
|
||||
|
||||
if(BOOTLOADER_BUILD OR NOT IDF_BUILD_ARTIFACTS)
|
||||
return() # don't keep recursing, generate on project builds
|
||||
endif()
|
||||
|
||||
# Glue to build the bootloader subproject binary as an external
|
||||
# cmake project under this one
|
||||
#
|
||||
#
|
||||
set(bootloader_build_dir "${IDF_BUILD_ARTIFACTS_DIR}/bootloader")
|
||||
set(bootloader_binary_files
|
||||
"${bootloader_build_dir}/bootloader.elf"
|
||||
"${bootloader_build_dir}/bootloader.bin"
|
||||
"${bootloader_build_dir}/bootloader.map"
|
||||
)
|
||||
|
||||
# These additional files may get generated
|
||||
if(CONFIG_SECURE_BOOTLOADER_REFLASHABLE)
|
||||
set(bootloader_binary_files
|
||||
${bootloader_binary_files}
|
||||
"${bootloader_build_dir}/bootloader-reflash-digest.bin"
|
||||
"${bootloader_build_dir}/secure-bootloader-key-192.bin"
|
||||
"${bootloader_build_dir}/secure-bootloader-key-256.bin"
|
||||
)
|
||||
endif()
|
||||
|
||||
if((NOT CONFIG_SECURE_BOOT_ENABLED) OR
|
||||
CONFIG_SECURE_BOOTLOADER_REFLASHABLE OR
|
||||
CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH)
|
||||
externalproject_add(bootloader
|
||||
# TODO: support overriding the bootloader in COMPONENT_PATHS
|
||||
SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/subproject"
|
||||
BINARY_DIR "${bootloader_build_dir}"
|
||||
CMAKE_ARGS -DSDKCONFIG=${SDKCONFIG} -DIDF_PATH=${IDF_PATH}
|
||||
-DSECURE_BOOT_SIGNING_KEY=${secure_boot_signing_key}
|
||||
-DEXTRA_COMPONENT_DIRS=${CMAKE_CURRENT_LIST_DIR}
|
||||
INSTALL_COMMAND ""
|
||||
BUILD_ALWAYS 1 # no easy way around this...
|
||||
BUILD_BYPRODUCTS ${bootloader_binary_files}
|
||||
DEPENDS gen_secure_boot_signing_key
|
||||
)
|
||||
else()
|
||||
fail_at_build_time(bootloader "Invalid bootloader target: bad sdkconfig?")
|
||||
endif()
|
||||
|
||||
# this is a hack due to an (annoying) shortcoming in cmake, it can't
|
||||
# extend the 'clean' target to the external project
|
||||
# see thread: https://cmake.org/pipermail/cmake/2016-December/064660.html
|
||||
#
|
||||
# So for now we just have the top-level build remove the final build products...
|
||||
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY
|
||||
ADDITIONAL_MAKE_CLEAN_FILES
|
||||
${bootloader_binary_files})
|
||||
21
components/bootloader/src/Makefile
Normal file
21
components/bootloader/src/Makefile
Normal file
@@ -0,0 +1,21 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := bootloader
|
||||
|
||||
#We cannot include the esp32 component directly but we need its includes.
|
||||
#This is fixed by adding CFLAGS from Makefile.projbuild
|
||||
COMPONENTS := esptool_py bootloader bootloader_support log spi_flash micro-ecc soc
|
||||
|
||||
# The bootloader pseudo-component is also included in this build, for its Kconfig.projbuild to be included.
|
||||
#
|
||||
# IS_BOOTLOADER_BUILD tells the component Makefile.projbuild to be a no-op
|
||||
IS_BOOTLOADER_BUILD := 1
|
||||
export IS_BOOTLOADER_BUILD
|
||||
|
||||
# include the top-level "project" include directory, for sdkconfig.h
|
||||
CFLAGS += -I$(BUILD_DIR_BASE)/../include
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
@@ -28,25 +28,17 @@ extern "C"
|
||||
|
||||
#define SPI_ERROR_LOG "spi flash error"
|
||||
|
||||
#define MAX_OTA_SLOTS 16
|
||||
|
||||
typedef struct {
|
||||
esp_partition_pos_t ota_info;
|
||||
esp_partition_pos_t factory;
|
||||
esp_partition_pos_t test;
|
||||
esp_partition_pos_t ota[MAX_OTA_SLOTS];
|
||||
esp_partition_pos_t ota[16];
|
||||
uint32_t app_count;
|
||||
uint32_t selected_subtype;
|
||||
} bootloader_state_t;
|
||||
|
||||
bool flash_encrypt(bootloader_state_t *bs);
|
||||
|
||||
/* Indices used by index_to_partition are the OTA index
|
||||
number, or these special constants */
|
||||
#define FACTORY_INDEX (-1)
|
||||
#define TEST_APP_INDEX (-2)
|
||||
#define INVALID_INDEX (-99)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
857
components/bootloader/src/main/bootloader_start.c
Normal file
857
components/bootloader/src/main/bootloader_start.c
Normal file
@@ -0,0 +1,857 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// 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.
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "esp_attr.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "rom/cache.h"
|
||||
#include "rom/efuse.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "rom/spi_flash.h"
|
||||
#include "rom/crc.h"
|
||||
#include "rom/rtc.h"
|
||||
#include "rom/uart.h"
|
||||
#include "rom/gpio.h"
|
||||
#include "rom/secure_boot.h"
|
||||
|
||||
#include "soc/soc.h"
|
||||
#include "soc/cpu.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/timer_group_reg.h"
|
||||
#include "soc/gpio_reg.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_flash_encrypt.h"
|
||||
#include "esp_flash_partitions.h"
|
||||
#include "bootloader_flash.h"
|
||||
#include "bootloader_random.h"
|
||||
#include "bootloader_config.h"
|
||||
|
||||
#include "flash_qio_mode.h"
|
||||
|
||||
extern int _bss_start;
|
||||
extern int _bss_end;
|
||||
|
||||
static const char* TAG = "boot";
|
||||
/*
|
||||
We arrive here after the bootloader finished loading the program from flash. The hardware is mostly uninitialized,
|
||||
flash cache is down and the app CPU is in reset. We do have a stack, so we can do the initialization in C.
|
||||
*/
|
||||
|
||||
|
||||
void bootloader_main();
|
||||
static void unpack_load_app(const esp_partition_pos_t *app_node);
|
||||
void print_flash_info(const esp_image_header_t* pfhdr);
|
||||
static void set_cache_and_start_app(uint32_t drom_addr,
|
||||
uint32_t drom_load_addr,
|
||||
uint32_t drom_size,
|
||||
uint32_t irom_addr,
|
||||
uint32_t irom_load_addr,
|
||||
uint32_t irom_size,
|
||||
uint32_t entry_addr);
|
||||
static void update_flash_config(const esp_image_header_t* pfhdr);
|
||||
static void clock_configure(void);
|
||||
static void uart_console_configure(void);
|
||||
static void wdt_reset_check(void);
|
||||
|
||||
void IRAM_ATTR call_start_cpu0()
|
||||
{
|
||||
cpu_configure_region_protection();
|
||||
|
||||
//Clear bss
|
||||
memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start));
|
||||
|
||||
/* completely reset MMU for both CPUs
|
||||
(in case serial bootloader was running) */
|
||||
Cache_Read_Disable(0);
|
||||
Cache_Read_Disable(1);
|
||||
Cache_Flush(0);
|
||||
Cache_Flush(1);
|
||||
mmu_init(0);
|
||||
DPORT_REG_SET_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR);
|
||||
mmu_init(1);
|
||||
DPORT_REG_CLR_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR);
|
||||
/* (above steps probably unnecessary for most serial bootloader
|
||||
usage, all that's absolutely needed is that we unmask DROM0
|
||||
cache on the following two lines - normal ROM boot exits with
|
||||
DROM0 cache unmasked, but serial bootloader exits with it
|
||||
masked. However can't hurt to be thorough and reset
|
||||
everything.)
|
||||
|
||||
The lines which manipulate DPORT_APP_CACHE_MMU_IA_CLR bit are
|
||||
necessary to work around a hardware bug.
|
||||
*/
|
||||
DPORT_REG_CLR_BIT(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CACHE_MASK_DROM0);
|
||||
DPORT_REG_CLR_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MASK_DROM0);
|
||||
|
||||
bootloader_main();
|
||||
}
|
||||
|
||||
|
||||
/** @brief Load partition table
|
||||
*
|
||||
* Parse partition table, get useful data such as location of
|
||||
* OTA data partition, factory app partition, and test app partition.
|
||||
*
|
||||
* @param bs bootloader state structure used to save read data
|
||||
* @return return true if the partition table was succesfully loaded and MD5 checksum is valid.
|
||||
*/
|
||||
bool load_partition_table(bootloader_state_t* bs)
|
||||
{
|
||||
const esp_partition_info_t *partitions;
|
||||
const int ESP_PARTITION_TABLE_DATA_LEN = 0xC00; /* length of actual data (signature is appended to this) */
|
||||
char *partition_usage;
|
||||
esp_err_t err;
|
||||
int num_partitions;
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_ENABLED
|
||||
if(esp_secure_boot_enabled()) {
|
||||
ESP_LOGI(TAG, "Verifying partition table signature...");
|
||||
err = esp_secure_boot_verify_signature(ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to verify partition table signature.");
|
||||
return false;
|
||||
}
|
||||
ESP_LOGD(TAG, "Partition table signature verified");
|
||||
}
|
||||
#endif
|
||||
|
||||
partitions = bootloader_mmap(ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN);
|
||||
if (!partitions) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN);
|
||||
return false;
|
||||
}
|
||||
ESP_LOGD(TAG, "mapped partition table 0x%x at 0x%x", ESP_PARTITION_TABLE_ADDR, (intptr_t)partitions);
|
||||
|
||||
err = esp_partition_table_basic_verify(partitions, true, &num_partitions);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to verify partition table");
|
||||
return false;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Partition Table:");
|
||||
ESP_LOGI(TAG, "## Label Usage Type ST Offset Length");
|
||||
|
||||
for(int i = 0; i < num_partitions; i++) {
|
||||
const esp_partition_info_t *partition = &partitions[i];
|
||||
ESP_LOGD(TAG, "load partition table entry 0x%x", (intptr_t)partition);
|
||||
ESP_LOGD(TAG, "type=%x subtype=%x", partition->type, partition->subtype);
|
||||
partition_usage = "unknown";
|
||||
|
||||
/* valid partition table */
|
||||
switch(partition->type) {
|
||||
case PART_TYPE_APP: /* app partition */
|
||||
switch(partition->subtype) {
|
||||
case PART_SUBTYPE_FACTORY: /* factory binary */
|
||||
bs->factory = partition->pos;
|
||||
partition_usage = "factory app";
|
||||
break;
|
||||
case PART_SUBTYPE_TEST: /* test binary */
|
||||
bs->test = partition->pos;
|
||||
partition_usage = "test app";
|
||||
break;
|
||||
default:
|
||||
/* OTA binary */
|
||||
if ((partition->subtype & ~PART_SUBTYPE_OTA_MASK) == PART_SUBTYPE_OTA_FLAG) {
|
||||
bs->ota[partition->subtype & PART_SUBTYPE_OTA_MASK] = partition->pos;
|
||||
++bs->app_count;
|
||||
partition_usage = "OTA app";
|
||||
}
|
||||
else {
|
||||
partition_usage = "Unknown app";
|
||||
}
|
||||
break;
|
||||
}
|
||||
break; /* PART_TYPE_APP */
|
||||
case PART_TYPE_DATA: /* data partition */
|
||||
switch(partition->subtype) {
|
||||
case PART_SUBTYPE_DATA_OTA: /* ota data */
|
||||
bs->ota_info = partition->pos;
|
||||
partition_usage = "OTA data";
|
||||
break;
|
||||
case PART_SUBTYPE_DATA_RF:
|
||||
partition_usage = "RF data";
|
||||
break;
|
||||
case PART_SUBTYPE_DATA_WIFI:
|
||||
partition_usage = "WiFi data";
|
||||
break;
|
||||
default:
|
||||
partition_usage = "Unknown data";
|
||||
break;
|
||||
}
|
||||
break; /* PARTITION_USAGE_DATA */
|
||||
default: /* other partition type */
|
||||
break;
|
||||
}
|
||||
|
||||
/* print partition type info */
|
||||
ESP_LOGI(TAG, "%2d %-16s %-16s %02x %02x %08x %08x", i, partition->label, partition_usage,
|
||||
partition->type, partition->subtype,
|
||||
partition->pos.offset, partition->pos.size);
|
||||
}
|
||||
|
||||
bootloader_munmap(partitions);
|
||||
|
||||
ESP_LOGI(TAG,"End of partition table");
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t ota_select_crc(const esp_ota_select_entry_t *s)
|
||||
{
|
||||
return crc32_le(UINT32_MAX, (uint8_t*)&s->ota_seq, 4);
|
||||
}
|
||||
|
||||
static bool ota_select_valid(const esp_ota_select_entry_t *s)
|
||||
{
|
||||
return s->ota_seq != UINT32_MAX && s->crc == ota_select_crc(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @function : bootloader_main
|
||||
* @description: entry function of 2nd bootloader
|
||||
*
|
||||
* @inputs: void
|
||||
*/
|
||||
|
||||
void bootloader_main()
|
||||
{
|
||||
clock_configure();
|
||||
uart_console_configure();
|
||||
wdt_reset_check();
|
||||
ESP_LOGI(TAG, "ESP-IDF %s 2nd stage bootloader", IDF_VER);
|
||||
#if defined(CONFIG_SECURE_BOOT_ENABLED) || defined(CONFIG_FLASH_ENCRYPTION_ENABLED)
|
||||
esp_err_t err;
|
||||
#endif
|
||||
esp_image_header_t fhdr;
|
||||
bootloader_state_t bs;
|
||||
esp_rom_spiflash_result_t spiRet1,spiRet2;
|
||||
esp_ota_select_entry_t sa,sb;
|
||||
const esp_ota_select_entry_t *ota_select_map;
|
||||
|
||||
memset(&bs, 0, sizeof(bs));
|
||||
|
||||
ESP_LOGI(TAG, "compile time " __TIME__ );
|
||||
ets_set_appcpu_boot_addr(0);
|
||||
|
||||
/* disable watch dog here */
|
||||
REG_CLR_BIT( RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN );
|
||||
REG_CLR_BIT( TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN );
|
||||
|
||||
#ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH
|
||||
const uint32_t spiconfig = ets_efuse_get_spiconfig();
|
||||
if(spiconfig != EFUSE_SPICONFIG_SPI_DEFAULTS && spiconfig != EFUSE_SPICONFIG_HSPI_DEFAULTS) {
|
||||
ESP_LOGE(TAG, "SPI flash pins are overridden. \"Enable SPI flash ROM driver patched functions\" must be enabled in menuconfig");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
esp_rom_spiflash_unlock();
|
||||
|
||||
ESP_LOGI(TAG, "Enabling RNG early entropy source...");
|
||||
bootloader_random_enable();
|
||||
|
||||
#if CONFIG_FLASHMODE_QIO || CONFIG_FLASHMODE_QOUT
|
||||
bootloader_enable_qio_mode();
|
||||
#endif
|
||||
|
||||
if(esp_image_load_header(0x1000, true, &fhdr) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed to load bootloader header!");
|
||||
return;
|
||||
}
|
||||
|
||||
print_flash_info(&fhdr);
|
||||
|
||||
update_flash_config(&fhdr);
|
||||
|
||||
if (!load_partition_table(&bs)) {
|
||||
ESP_LOGE(TAG, "load partition table error!");
|
||||
return;
|
||||
}
|
||||
|
||||
esp_partition_pos_t load_part_pos;
|
||||
|
||||
if (bs.ota_info.offset != 0) { // check if partition table has OTA info partition
|
||||
//ESP_LOGE("OTA info sector handling is not implemented");
|
||||
if (bs.ota_info.size < 2 * SPI_SEC_SIZE) {
|
||||
ESP_LOGE(TAG, "ERROR: ota_info partition size %d is too small (minimum %d bytes)", bs.ota_info.size, sizeof(esp_ota_select_entry_t));
|
||||
return;
|
||||
}
|
||||
ota_select_map = bootloader_mmap(bs.ota_info.offset, bs.ota_info.size);
|
||||
if (!ota_select_map) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", bs.ota_info.offset, bs.ota_info.size);
|
||||
return;
|
||||
}
|
||||
memcpy(&sa, ota_select_map, sizeof(esp_ota_select_entry_t));
|
||||
memcpy(&sb, (uint8_t *)ota_select_map + SPI_SEC_SIZE, sizeof(esp_ota_select_entry_t));
|
||||
bootloader_munmap(ota_select_map);
|
||||
ESP_LOGD(TAG, "OTA sequence values A 0x%08x B 0x%08x", sa.ota_seq, sb.ota_seq);
|
||||
if(sa.ota_seq == 0xFFFFFFFF && sb.ota_seq == 0xFFFFFFFF) {
|
||||
ESP_LOGD(TAG, "OTA sequence numbers both empty (all-0xFF");
|
||||
// init status flash
|
||||
if (bs.factory.offset != 0) { // if have factory bin,boot factory bin
|
||||
ESP_LOGD(TAG, "Defaulting to factory image");
|
||||
load_part_pos = bs.factory;
|
||||
} else {
|
||||
ESP_LOGD(TAG, "No factory image, defaulting to OTA 0");
|
||||
load_part_pos = bs.ota[0];
|
||||
sa.ota_seq = 0x01;
|
||||
sa.crc = ota_select_crc(&sa);
|
||||
sb.ota_seq = 0x00;
|
||||
sb.crc = ota_select_crc(&sb);
|
||||
|
||||
Cache_Read_Disable(0);
|
||||
spiRet1 = esp_rom_spiflash_erase_sector(bs.ota_info.offset/0x1000);
|
||||
spiRet2 = esp_rom_spiflash_erase_sector(bs.ota_info.offset/0x1000+1);
|
||||
if (spiRet1 != ESP_ROM_SPIFLASH_RESULT_OK || spiRet2 != ESP_ROM_SPIFLASH_RESULT_OK ) {
|
||||
ESP_LOGE(TAG, SPI_ERROR_LOG);
|
||||
return;
|
||||
}
|
||||
spiRet1 = esp_rom_spiflash_write(bs.ota_info.offset,(uint32_t *)&sa,sizeof(esp_ota_select_entry_t));
|
||||
spiRet2 = esp_rom_spiflash_write(bs.ota_info.offset + 0x1000,(uint32_t *)&sb,sizeof(esp_ota_select_entry_t));
|
||||
if (spiRet1 != ESP_ROM_SPIFLASH_RESULT_OK || spiRet2 != ESP_ROM_SPIFLASH_RESULT_OK ) {
|
||||
ESP_LOGE(TAG, SPI_ERROR_LOG);
|
||||
return;
|
||||
}
|
||||
Cache_Read_Enable(0);
|
||||
}
|
||||
//TODO:write data in ota info
|
||||
} else {
|
||||
if(ota_select_valid(&sa) && ota_select_valid(&sb)) {
|
||||
ESP_LOGD(TAG, "Both OTA sequence valid, using OTA slot %d", MAX(sa.ota_seq, sb.ota_seq)-1);
|
||||
load_part_pos = bs.ota[(MAX(sa.ota_seq, sb.ota_seq) - 1)%bs.app_count];
|
||||
} else if(ota_select_valid(&sa)) {
|
||||
ESP_LOGD(TAG, "Only OTA sequence A is valid, using OTA slot %d", sa.ota_seq - 1);
|
||||
load_part_pos = bs.ota[(sa.ota_seq - 1) % bs.app_count];
|
||||
} else if(ota_select_valid(&sb)) {
|
||||
ESP_LOGD(TAG, "Only OTA sequence B is valid, using OTA slot %d", sa.ota_seq - 1);
|
||||
load_part_pos = bs.ota[(sb.ota_seq - 1) % bs.app_count];
|
||||
} else if (bs.factory.offset != 0) {
|
||||
ESP_LOGE(TAG, "ota data partition invalid, falling back to factory");
|
||||
load_part_pos = bs.factory;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "ota data partition invalid and no factory, can't boot");
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (bs.factory.offset != 0) { // otherwise, look for factory app partition
|
||||
load_part_pos = bs.factory;
|
||||
} else if (bs.test.offset != 0) { // otherwise, look for test app parition
|
||||
load_part_pos = bs.test;
|
||||
} else { // nothing to load, bail out
|
||||
ESP_LOGE(TAG, "nothing to load");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_ENABLED
|
||||
/* Generate secure digest from this bootloader to protect future
|
||||
modifications */
|
||||
ESP_LOGI(TAG, "Checking secure boot...");
|
||||
err = esp_secure_boot_permanently_enable();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Bootloader digest generation failed (%d). SECURE BOOT IS NOT ENABLED.", err);
|
||||
/* Allow booting to continue, as the failure is probably
|
||||
due to user-configured EFUSEs for testing...
|
||||
*/
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FLASH_ENCRYPTION_ENABLED
|
||||
/* encrypt flash */
|
||||
ESP_LOGI(TAG, "Checking flash encryption...");
|
||||
bool flash_encryption_enabled = esp_flash_encryption_enabled();
|
||||
err = esp_flash_encrypt_check_and_update();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Flash encryption check failed (%d).", err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!flash_encryption_enabled && esp_flash_encryption_enabled()) {
|
||||
/* Flash encryption was just enabled for the first time,
|
||||
so issue a system reset to ensure flash encryption
|
||||
cache resets properly */
|
||||
ESP_LOGI(TAG, "Resetting with flash encryption enabled...");
|
||||
REG_WRITE(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_SYS_RST);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
ESP_LOGI(TAG, "Disabling RNG early entropy source...");
|
||||
bootloader_random_disable();
|
||||
|
||||
// copy loaded segments to RAM, set up caches for mapped segments, and start application
|
||||
ESP_LOGI(TAG, "Loading app partition at offset %08x", load_part_pos);
|
||||
unpack_load_app(&load_part_pos);
|
||||
}
|
||||
|
||||
static void unpack_load_app(const esp_partition_pos_t* partition)
|
||||
{
|
||||
esp_err_t err;
|
||||
esp_image_header_t image_header;
|
||||
uint32_t image_length;
|
||||
|
||||
/* TODO: verify the app image as part of OTA boot decision, so can have fallbacks */
|
||||
err = esp_image_basic_verify(partition->offset, true, &image_length);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to verify app image @ 0x%x (%d)", partition->offset, err);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_ENABLED
|
||||
if (esp_secure_boot_enabled()) {
|
||||
ESP_LOGI(TAG, "Verifying app signature @ 0x%x (length 0x%x)", partition->offset, image_length);
|
||||
err = esp_secure_boot_verify_signature(partition->offset, image_length);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "App image @ 0x%x failed signature verification (%d)", partition->offset, err);
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "App signature is valid");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (esp_image_load_header(partition->offset, true, &image_header) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to load app image header @ 0x%x", partition->offset);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t drom_addr = 0;
|
||||
uint32_t drom_load_addr = 0;
|
||||
uint32_t drom_size = 0;
|
||||
uint32_t irom_addr = 0;
|
||||
uint32_t irom_load_addr = 0;
|
||||
uint32_t irom_size = 0;
|
||||
|
||||
/* Reload the RTC memory segments whenever a non-deepsleep reset
|
||||
is occurring */
|
||||
bool load_rtc_memory = rtc_get_reset_reason(0) != DEEPSLEEP_RESET;
|
||||
|
||||
ESP_LOGD(TAG, "bin_header: %u %u %u %u %08x", image_header.magic,
|
||||
image_header.segment_count,
|
||||
image_header.spi_mode,
|
||||
image_header.spi_size,
|
||||
(unsigned)image_header.entry_addr);
|
||||
|
||||
/* Important: From here on this function cannot access any global data (bss/data segments),
|
||||
as loading the app image may overwrite these.
|
||||
*/
|
||||
for (int segment = 0; segment < image_header.segment_count; segment++) {
|
||||
esp_image_segment_header_t segment_header;
|
||||
uint32_t data_offs;
|
||||
if(esp_image_load_segment_header(segment, partition->offset,
|
||||
&image_header, true,
|
||||
&segment_header, &data_offs) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed to load segment header #%d", segment);
|
||||
return;
|
||||
}
|
||||
|
||||
const uint32_t address = segment_header.load_addr;
|
||||
bool load = true;
|
||||
bool map = false;
|
||||
if (address == 0x00000000) { // padding, ignore block
|
||||
load = false;
|
||||
}
|
||||
if (address == 0x00000004) {
|
||||
load = false; // md5 checksum block
|
||||
// TODO: actually check md5
|
||||
}
|
||||
|
||||
if (address >= SOC_DROM_LOW && address < SOC_DROM_HIGH) {
|
||||
ESP_LOGD(TAG, "found drom segment, map from %08x to %08x", data_offs,
|
||||
segment_header.load_addr);
|
||||
drom_addr = data_offs;
|
||||
drom_load_addr = segment_header.load_addr;
|
||||
drom_size = segment_header.data_len + sizeof(segment_header);
|
||||
load = false;
|
||||
map = true;
|
||||
}
|
||||
|
||||
if (address >= SOC_IROM_LOW && address < SOC_IROM_HIGH) {
|
||||
ESP_LOGD(TAG, "found irom segment, map from %08x to %08x", data_offs,
|
||||
segment_header.load_addr);
|
||||
irom_addr = data_offs;
|
||||
irom_load_addr = segment_header.load_addr;
|
||||
irom_size = segment_header.data_len + sizeof(segment_header);
|
||||
load = false;
|
||||
map = true;
|
||||
}
|
||||
|
||||
if (!load_rtc_memory && address >= SOC_RTC_IRAM_LOW && address < SOC_RTC_IRAM_HIGH) {
|
||||
ESP_LOGD(TAG, "Skipping RTC code segment at %08x\n", data_offs);
|
||||
load = false;
|
||||
}
|
||||
|
||||
if (!load_rtc_memory && address >= SOC_RTC_DATA_LOW && address < SOC_RTC_DATA_HIGH) {
|
||||
ESP_LOGD(TAG, "Skipping RTC data segment at %08x\n", data_offs);
|
||||
load = false;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "segment %d: paddr=0x%08x vaddr=0x%08x size=0x%05x (%6d) %s", segment, data_offs - sizeof(esp_image_segment_header_t),
|
||||
segment_header.load_addr, segment_header.data_len, segment_header.data_len, (load)?"load":(map)?"map":"");
|
||||
|
||||
if (load) {
|
||||
intptr_t sp, start_addr, end_addr;
|
||||
ESP_LOGV(TAG, "bootloader_mmap data_offs=%08x data_len=%08x", data_offs, segment_header.data_len);
|
||||
|
||||
start_addr = segment_header.load_addr;
|
||||
end_addr = start_addr + segment_header.data_len;
|
||||
|
||||
/* Before loading segment, check it doesn't clobber
|
||||
bootloader RAM... */
|
||||
|
||||
if (end_addr < 0x40000000) {
|
||||
sp = (intptr_t)get_sp();
|
||||
if (end_addr > sp) {
|
||||
ESP_LOGE(TAG, "Segment %d end address %08x overlaps bootloader stack %08x - can't load",
|
||||
segment, end_addr, sp);
|
||||
return;
|
||||
}
|
||||
if (end_addr > sp - 256) {
|
||||
/* We don't know for sure this is the stack high water mark, so warn if
|
||||
it seems like we may overflow.
|
||||
*/
|
||||
ESP_LOGW(TAG, "Segment %d end address %08x close to stack pointer %08x",
|
||||
segment, end_addr, sp);
|
||||
}
|
||||
}
|
||||
|
||||
const void *data = bootloader_mmap(data_offs, segment_header.data_len);
|
||||
if(!data) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%xc, 0x%x) failed",
|
||||
data_offs, segment_header.data_len);
|
||||
return;
|
||||
}
|
||||
memcpy((void *)segment_header.load_addr, data, segment_header.data_len);
|
||||
bootloader_munmap(data);
|
||||
}
|
||||
}
|
||||
|
||||
set_cache_and_start_app(drom_addr,
|
||||
drom_load_addr,
|
||||
drom_size,
|
||||
irom_addr,
|
||||
irom_load_addr,
|
||||
irom_size,
|
||||
image_header.entry_addr);
|
||||
}
|
||||
|
||||
static void set_cache_and_start_app(
|
||||
uint32_t drom_addr,
|
||||
uint32_t drom_load_addr,
|
||||
uint32_t drom_size,
|
||||
uint32_t irom_addr,
|
||||
uint32_t irom_load_addr,
|
||||
uint32_t irom_size,
|
||||
uint32_t entry_addr)
|
||||
{
|
||||
ESP_LOGD(TAG, "configure drom and irom and start");
|
||||
Cache_Read_Disable( 0 );
|
||||
Cache_Flush( 0 );
|
||||
uint32_t drom_page_count = (drom_size + 64*1024 - 1) / (64*1024); // round up to 64k
|
||||
ESP_LOGV(TAG, "d mmu set paddr=%08x vaddr=%08x size=%d n=%d", drom_addr & 0xffff0000, drom_load_addr & 0xffff0000, drom_size, drom_page_count );
|
||||
int rc = cache_flash_mmu_set( 0, 0, drom_load_addr & 0xffff0000, drom_addr & 0xffff0000, 64, drom_page_count );
|
||||
ESP_LOGV(TAG, "rc=%d", rc );
|
||||
rc = cache_flash_mmu_set( 1, 0, drom_load_addr & 0xffff0000, drom_addr & 0xffff0000, 64, drom_page_count );
|
||||
ESP_LOGV(TAG, "rc=%d", rc );
|
||||
uint32_t irom_page_count = (irom_size + 64*1024 - 1) / (64*1024); // round up to 64k
|
||||
ESP_LOGV(TAG, "i mmu set paddr=%08x vaddr=%08x size=%d n=%d", irom_addr & 0xffff0000, irom_load_addr & 0xffff0000, irom_size, irom_page_count );
|
||||
rc = cache_flash_mmu_set( 0, 0, irom_load_addr & 0xffff0000, irom_addr & 0xffff0000, 64, irom_page_count );
|
||||
ESP_LOGV(TAG, "rc=%d", rc );
|
||||
rc = cache_flash_mmu_set( 1, 0, irom_load_addr & 0xffff0000, irom_addr & 0xffff0000, 64, irom_page_count );
|
||||
ESP_LOGV(TAG, "rc=%d", rc );
|
||||
DPORT_REG_CLR_BIT( DPORT_PRO_CACHE_CTRL1_REG, (DPORT_PRO_CACHE_MASK_IRAM0) | (DPORT_PRO_CACHE_MASK_IRAM1 & 0) | (DPORT_PRO_CACHE_MASK_IROM0 & 0) | DPORT_PRO_CACHE_MASK_DROM0 | DPORT_PRO_CACHE_MASK_DRAM1 );
|
||||
DPORT_REG_CLR_BIT( DPORT_APP_CACHE_CTRL1_REG, (DPORT_APP_CACHE_MASK_IRAM0) | (DPORT_APP_CACHE_MASK_IRAM1 & 0) | (DPORT_APP_CACHE_MASK_IROM0 & 0) | DPORT_APP_CACHE_MASK_DROM0 | DPORT_APP_CACHE_MASK_DRAM1 );
|
||||
Cache_Read_Enable( 0 );
|
||||
|
||||
// Application will need to do Cache_Flush(1) and Cache_Read_Enable(1)
|
||||
|
||||
ESP_LOGD(TAG, "start: 0x%08x", entry_addr);
|
||||
typedef void (*entry_t)(void);
|
||||
entry_t entry = ((entry_t) entry_addr);
|
||||
|
||||
// TODO: we have used quite a bit of stack at this point.
|
||||
// use "movsp" instruction to reset stack back to where ROM stack starts.
|
||||
(*entry)();
|
||||
}
|
||||
|
||||
static void update_flash_config(const esp_image_header_t* pfhdr)
|
||||
{
|
||||
uint32_t size;
|
||||
switch(pfhdr->spi_size) {
|
||||
case ESP_IMAGE_FLASH_SIZE_1MB:
|
||||
size = 1;
|
||||
break;
|
||||
case ESP_IMAGE_FLASH_SIZE_2MB:
|
||||
size = 2;
|
||||
break;
|
||||
case ESP_IMAGE_FLASH_SIZE_4MB:
|
||||
size = 4;
|
||||
break;
|
||||
case ESP_IMAGE_FLASH_SIZE_8MB:
|
||||
size = 8;
|
||||
break;
|
||||
case ESP_IMAGE_FLASH_SIZE_16MB:
|
||||
size = 16;
|
||||
break;
|
||||
default:
|
||||
size = 2;
|
||||
}
|
||||
Cache_Read_Disable( 0 );
|
||||
// Set flash chip size
|
||||
esp_rom_spiflash_config_param(g_rom_flashchip.device_id, size * 0x100000, 0x10000, 0x1000, 0x100, 0xffff);
|
||||
// TODO: set mode
|
||||
// TODO: set frequency
|
||||
Cache_Flush(0);
|
||||
Cache_Read_Enable( 0 );
|
||||
}
|
||||
|
||||
void print_flash_info(const esp_image_header_t* phdr)
|
||||
{
|
||||
#if (BOOT_LOG_LEVEL >= BOOT_LOG_LEVEL_NOTICE)
|
||||
|
||||
ESP_LOGD(TAG, "magic %02x", phdr->magic );
|
||||
ESP_LOGD(TAG, "segments %02x", phdr->segment_count );
|
||||
ESP_LOGD(TAG, "spi_mode %02x", phdr->spi_mode );
|
||||
ESP_LOGD(TAG, "spi_speed %02x", phdr->spi_speed );
|
||||
ESP_LOGD(TAG, "spi_size %02x", phdr->spi_size );
|
||||
|
||||
const char* str;
|
||||
switch ( phdr->spi_speed ) {
|
||||
case ESP_IMAGE_SPI_SPEED_40M:
|
||||
str = "40MHz";
|
||||
break;
|
||||
case ESP_IMAGE_SPI_SPEED_26M:
|
||||
str = "26.7MHz";
|
||||
break;
|
||||
case ESP_IMAGE_SPI_SPEED_20M:
|
||||
str = "20MHz";
|
||||
break;
|
||||
case ESP_IMAGE_SPI_SPEED_80M:
|
||||
str = "80MHz";
|
||||
break;
|
||||
default:
|
||||
str = "20MHz";
|
||||
break;
|
||||
}
|
||||
ESP_LOGI(TAG, "SPI Speed : %s", str );
|
||||
|
||||
/* SPI mode could have been set to QIO during boot already,
|
||||
so test the SPI registers not the flash header */
|
||||
uint32_t spi_ctrl = REG_READ(SPI_CTRL_REG(0));
|
||||
if (spi_ctrl & SPI_FREAD_QIO) {
|
||||
str = "QIO";
|
||||
} else if (spi_ctrl & SPI_FREAD_QUAD) {
|
||||
str = "QOUT";
|
||||
} else if (spi_ctrl & SPI_FREAD_DIO) {
|
||||
str = "DIO";
|
||||
} else if (spi_ctrl & SPI_FREAD_DUAL) {
|
||||
str = "DOUT";
|
||||
} else if (spi_ctrl & SPI_FASTRD_MODE) {
|
||||
str = "FAST READ";
|
||||
} else {
|
||||
str = "SLOW READ";
|
||||
}
|
||||
ESP_LOGI(TAG, "SPI Mode : %s", str );
|
||||
|
||||
switch ( phdr->spi_size ) {
|
||||
case ESP_IMAGE_FLASH_SIZE_1MB:
|
||||
str = "1MB";
|
||||
break;
|
||||
case ESP_IMAGE_FLASH_SIZE_2MB:
|
||||
str = "2MB";
|
||||
break;
|
||||
case ESP_IMAGE_FLASH_SIZE_4MB:
|
||||
str = "4MB";
|
||||
break;
|
||||
case ESP_IMAGE_FLASH_SIZE_8MB:
|
||||
str = "8MB";
|
||||
break;
|
||||
case ESP_IMAGE_FLASH_SIZE_16MB:
|
||||
str = "16MB";
|
||||
break;
|
||||
default:
|
||||
str = "2MB";
|
||||
break;
|
||||
}
|
||||
ESP_LOGI(TAG, "SPI Flash Size : %s", str );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void clock_configure(void)
|
||||
{
|
||||
/* Set CPU to 80MHz. Keep other clocks unmodified. */
|
||||
rtc_cpu_freq_t cpu_freq = RTC_CPU_FREQ_80M;
|
||||
|
||||
/* On ESP32 rev 0, switching to 80MHz if clock was previously set to
|
||||
* 240 MHz may cause the chip to lock up (see section 3.5 of the errata
|
||||
* document). For rev. 0, switch to 240 instead if it was chosen in
|
||||
* menuconfig.
|
||||
*/
|
||||
uint32_t chip_ver_reg = REG_READ(EFUSE_BLK0_RDATA3_REG);
|
||||
if ((chip_ver_reg & EFUSE_RD_CHIP_VER_REV1_M) == 0 &&
|
||||
CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ == 240) {
|
||||
cpu_freq = RTC_CPU_FREQ_240M;
|
||||
}
|
||||
|
||||
uart_tx_wait_idle(0);
|
||||
rtc_clk_config_t clk_cfg = RTC_CLK_CONFIG_DEFAULT();
|
||||
clk_cfg.xtal_freq = CONFIG_ESP32_XTAL_FREQ;
|
||||
clk_cfg.cpu_freq = cpu_freq;
|
||||
clk_cfg.slow_freq = rtc_clk_slow_freq_get();
|
||||
clk_cfg.fast_freq = rtc_clk_fast_freq_get();
|
||||
rtc_clk_init(clk_cfg);
|
||||
/* As a slight optimization, if 32k XTAL was enabled in sdkconfig, we enable
|
||||
* it here. Usually it needs some time to start up, so we amortize at least
|
||||
* part of the start up time by enabling 32k XTAL early.
|
||||
* App startup code will wait until the oscillator has started up.
|
||||
*/
|
||||
#ifdef CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
|
||||
if (!rtc_clk_32k_enabled()) {
|
||||
rtc_clk_32k_bootstrap();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void uart_console_configure(void)
|
||||
{
|
||||
#if CONFIG_CONSOLE_UART_NONE
|
||||
ets_install_putc1(NULL);
|
||||
ets_install_putc2(NULL);
|
||||
#else // CONFIG_CONSOLE_UART_NONE
|
||||
const int uart_num = CONFIG_CONSOLE_UART_NUM;
|
||||
|
||||
uartAttach();
|
||||
ets_install_uart_printf();
|
||||
|
||||
// ROM bootloader may have put a lot of text into UART0 FIFO.
|
||||
// Wait for it to be printed.
|
||||
uart_tx_wait_idle(0);
|
||||
|
||||
#if CONFIG_CONSOLE_UART_CUSTOM
|
||||
// Some constants to make the following code less upper-case
|
||||
const int uart_tx_gpio = CONFIG_CONSOLE_UART_TX_GPIO;
|
||||
const int uart_rx_gpio = CONFIG_CONSOLE_UART_RX_GPIO;
|
||||
// Switch to the new UART (this just changes UART number used for
|
||||
// ets_printf in ROM code).
|
||||
uart_tx_switch(uart_num);
|
||||
// If console is attached to UART1 or if non-default pins are used,
|
||||
// need to reconfigure pins using GPIO matrix
|
||||
if (uart_num != 0 || uart_tx_gpio != 1 || uart_rx_gpio != 3) {
|
||||
// Change pin mode for GPIO1/3 from UART to GPIO
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_GPIO3);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_GPIO1);
|
||||
// Route GPIO signals to/from pins
|
||||
// (arrays should be optimized away by the compiler)
|
||||
const uint32_t tx_idx_list[3] = { U0TXD_OUT_IDX, U1TXD_OUT_IDX, U2TXD_OUT_IDX };
|
||||
const uint32_t rx_idx_list[3] = { U0RXD_IN_IDX, U1RXD_IN_IDX, U2RXD_IN_IDX };
|
||||
const uint32_t tx_idx = tx_idx_list[uart_num];
|
||||
const uint32_t rx_idx = rx_idx_list[uart_num];
|
||||
gpio_matrix_out(uart_tx_gpio, tx_idx, 0, 0);
|
||||
gpio_matrix_in(uart_rx_gpio, rx_idx, 0);
|
||||
}
|
||||
#endif // CONFIG_CONSOLE_UART_CUSTOM
|
||||
|
||||
// Set configured UART console baud rate
|
||||
const int uart_baud = CONFIG_CONSOLE_UART_BAUDRATE;
|
||||
uart_div_modify(uart_num, (rtc_clk_apb_freq_get() << 4) / uart_baud);
|
||||
|
||||
#endif // CONFIG_CONSOLE_UART_NONE
|
||||
}
|
||||
|
||||
static void wdt_reset_cpu0_info_enable(void)
|
||||
{
|
||||
//We do not reset core1 info here because it didn't work before cpu1 was up. So we put it into call_start_cpu1.
|
||||
DPORT_REG_SET_BIT(DPORT_PRO_CPU_RECORD_CTRL_REG, DPORT_PRO_CPU_PDEBUG_ENABLE | DPORT_PRO_CPU_RECORD_ENABLE);
|
||||
DPORT_REG_CLR_BIT(DPORT_PRO_CPU_RECORD_CTRL_REG, DPORT_PRO_CPU_RECORD_ENABLE);
|
||||
}
|
||||
|
||||
static void wdt_reset_info_dump(int cpu)
|
||||
{
|
||||
uint32_t inst = 0, pid = 0, stat = 0, data = 0, pc = 0,
|
||||
lsstat = 0, lsaddr = 0, lsdata = 0, dstat = 0;
|
||||
char *cpu_name = cpu ? "APP" : "PRO";
|
||||
|
||||
if (cpu == 0) {
|
||||
stat = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_STATUS_REG);
|
||||
pid = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PID_REG);
|
||||
inst = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGINST_REG);
|
||||
dstat = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGSTATUS_REG);
|
||||
data = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGDATA_REG);
|
||||
pc = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGPC_REG);
|
||||
lsstat = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGLS0STAT_REG);
|
||||
lsaddr = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGLS0ADDR_REG);
|
||||
lsdata = DPORT_REG_READ(DPORT_PRO_CPU_RECORD_PDEBUGLS0DATA_REG);
|
||||
|
||||
} else {
|
||||
stat = DPORT_REG_READ(DPORT_APP_CPU_RECORD_STATUS_REG);
|
||||
pid = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PID_REG);
|
||||
inst = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGINST_REG);
|
||||
dstat = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGSTATUS_REG);
|
||||
data = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGDATA_REG);
|
||||
pc = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGPC_REG);
|
||||
lsstat = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGLS0STAT_REG);
|
||||
lsaddr = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGLS0ADDR_REG);
|
||||
lsdata = DPORT_REG_READ(DPORT_APP_CPU_RECORD_PDEBUGLS0DATA_REG);
|
||||
}
|
||||
if (DPORT_RECORD_PDEBUGINST_SZ(inst) == 0 &&
|
||||
DPORT_RECORD_PDEBUGSTATUS_BBCAUSE(dstat) == DPORT_RECORD_PDEBUGSTATUS_BBCAUSE_WAITI) {
|
||||
ESP_LOGW(TAG, "WDT reset info: %s CPU PC=0x%x (waiti mode)", cpu_name, pc);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "WDT reset info: %s CPU PC=0x%x", cpu_name, pc);
|
||||
}
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU STATUS 0x%08x", cpu_name, stat);
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU PID 0x%08x", cpu_name, pid);
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGINST 0x%08x", cpu_name, inst);
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGSTATUS 0x%08x", cpu_name, dstat);
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGDATA 0x%08x", cpu_name, data);
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGPC 0x%08x", cpu_name, pc);
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGLS0STAT 0x%08x", cpu_name, lsstat);
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGLS0ADDR 0x%08x", cpu_name, lsaddr);
|
||||
ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGLS0DATA 0x%08x", cpu_name, lsdata);
|
||||
}
|
||||
|
||||
static void wdt_reset_check(void)
|
||||
{
|
||||
int wdt_rst = 0;
|
||||
RESET_REASON rst_reas[2];
|
||||
|
||||
rst_reas[0] = rtc_get_reset_reason(0);
|
||||
rst_reas[1] = rtc_get_reset_reason(1);
|
||||
if (rst_reas[0] == RTCWDT_SYS_RESET || rst_reas[0] == TG0WDT_SYS_RESET || rst_reas[0] == TG1WDT_SYS_RESET ||
|
||||
rst_reas[0] == TGWDT_CPU_RESET || rst_reas[0] == RTCWDT_CPU_RESET) {
|
||||
ESP_LOGW(TAG, "PRO CPU has been reset by WDT.");
|
||||
wdt_rst = 1;
|
||||
}
|
||||
if (rst_reas[1] == RTCWDT_SYS_RESET || rst_reas[1] == TG0WDT_SYS_RESET || rst_reas[1] == TG1WDT_SYS_RESET ||
|
||||
rst_reas[1] == TGWDT_CPU_RESET || rst_reas[1] == RTCWDT_CPU_RESET) {
|
||||
ESP_LOGW(TAG, "APP CPU has been reset by WDT.");
|
||||
wdt_rst = 1;
|
||||
}
|
||||
if (wdt_rst) {
|
||||
// if reset by WDT dump info from trace port
|
||||
wdt_reset_info_dump(0);
|
||||
wdt_reset_info_dump(1);
|
||||
}
|
||||
wdt_reset_cpu0_info_enable();
|
||||
}
|
||||
20
components/bootloader/src/main/component.mk
Normal file
20
components/bootloader/src/main/component.mk
Normal file
@@ -0,0 +1,20 @@
|
||||
#
|
||||
# Main bootloader Makefile.
|
||||
#
|
||||
# This is basically the same as a component makefile, but in the case of the bootloader
|
||||
# we pull in bootloader-specific linker arguments.
|
||||
#
|
||||
|
||||
LINKER_SCRIPTS := \
|
||||
esp32.bootloader.ld \
|
||||
$(IDF_PATH)/components/esp32/ld/esp32.rom.ld \
|
||||
$(IDF_PATH)/components/esp32/ld/esp32.peripherals.ld \
|
||||
esp32.bootloader.rom.ld
|
||||
|
||||
ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH
|
||||
LINKER_SCRIPTS += $(IDF_PATH)/components/esp32/ld/esp32.rom.spiflash.ld
|
||||
endif
|
||||
|
||||
COMPONENT_ADD_LDFLAGS := -L $(COMPONENT_PATH) -lmain $(addprefix -T ,$(LINKER_SCRIPTS))
|
||||
|
||||
COMPONENT_ADD_LINKER_DEPS := $(LINKER_SCRIPTS)
|
||||
148
components/bootloader/src/main/esp32.bootloader.ld
Normal file
148
components/bootloader/src/main/esp32.bootloader.ld
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
Linker file used to link the bootloader.
|
||||
|
||||
*WARNING* For now this linker dumps everything into IRAM/DRAM. ToDo: move
|
||||
some/most stuff to DROM/IROM.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/* THESE ARE THE VIRTUAL RUNTIME ADDRESSES */
|
||||
/* The load addresses are defined later using the AT statements. */
|
||||
MEMORY
|
||||
{
|
||||
/* All these values assume the flash cache is on, and have the blocks this uses subtracted from the length
|
||||
of the various regions. The 'data access port' dram/drom regions map to the same iram/irom regions but
|
||||
are connected to the data port of the CPU and eg allow bytewise access. */
|
||||
dport0_seg (RW) : org = 0x3FF00000, len = 0x10 /* IO */
|
||||
iram_seg (RWX) : org = 0x40080000, len = 0x400 /* 1k of IRAM used by bootloader functions which need to flush/enable APP CPU cache */
|
||||
iram_pool_1_seg (RWX) : org = 0x40078000, len = 0x8000 /* IRAM POOL1, used for APP CPU cache. We can abuse it in bootloader because APP CPU is still held in reset, until we enable APP CPU cache */
|
||||
dram_seg (RW) : org = 0x3FFF0000, len = 0x10000 /* 64k at the end of DRAM, after ROM bootloader stack */
|
||||
}
|
||||
|
||||
/* Default entry point: */
|
||||
ENTRY(call_start_cpu0);
|
||||
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.iram1.text :
|
||||
{
|
||||
_init_start = ABSOLUTE(.);
|
||||
*(.UserEnter.literal);
|
||||
*(.UserEnter.text);
|
||||
. = ALIGN (16);
|
||||
*(.entry.text)
|
||||
*(.init.literal)
|
||||
*(.init)
|
||||
_init_end = ABSOLUTE(.);
|
||||
|
||||
/* Code marked as runnning out of IRAM */
|
||||
_iram_text_start = ABSOLUTE(.);
|
||||
*(.iram1 .iram1.*)
|
||||
_iram_text_end = ABSOLUTE(.);
|
||||
} > iram_seg
|
||||
|
||||
|
||||
/* Shared RAM */
|
||||
.dram0.bss (NOLOAD) :
|
||||
{
|
||||
. = ALIGN (8);
|
||||
_bss_start = ABSOLUTE(.);
|
||||
*(.dynsbss)
|
||||
*(.sbss)
|
||||
*(.sbss.*)
|
||||
*(.gnu.linkonce.sb.*)
|
||||
*(.scommon)
|
||||
*(.sbss2)
|
||||
*(.sbss2.*)
|
||||
*(.gnu.linkonce.sb2.*)
|
||||
*(.dynbss)
|
||||
KEEP(*(.bss))
|
||||
*(.bss.*)
|
||||
*(.gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
. = ALIGN (8);
|
||||
_bss_end = ABSOLUTE(.);
|
||||
} >dram_seg
|
||||
|
||||
|
||||
.dram0.data :
|
||||
{
|
||||
_data_start = ABSOLUTE(.);
|
||||
KEEP(*(.data))
|
||||
KEEP(*(.data.*))
|
||||
KEEP(*(.gnu.linkonce.d.*))
|
||||
KEEP(*(.data1))
|
||||
KEEP(*(.sdata))
|
||||
KEEP(*(.sdata.*))
|
||||
KEEP(*(.gnu.linkonce.s.*))
|
||||
KEEP(*(.sdata2))
|
||||
KEEP(*(.sdata2.*))
|
||||
KEEP(*(.gnu.linkonce.s2.*))
|
||||
KEEP(*(.jcr))
|
||||
_data_end = ABSOLUTE(.);
|
||||
} >dram_seg
|
||||
|
||||
|
||||
|
||||
|
||||
.dram0.rodata :
|
||||
{
|
||||
_rodata_start = ABSOLUTE(.);
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
*(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */
|
||||
*(.gnu.linkonce.r.*)
|
||||
*(.rodata1)
|
||||
__XT_EXCEPTION_TABLE_ = ABSOLUTE(.);
|
||||
*(.xt_except_table)
|
||||
*(.gcc_except_table)
|
||||
*(.gnu.linkonce.e.*)
|
||||
*(.gnu.version_r)
|
||||
*(.eh_frame)
|
||||
. = (. + 3) & ~ 3;
|
||||
/* C++ constructor and destructor tables, properly ordered: */
|
||||
__init_array_start = ABSOLUTE(.);
|
||||
KEEP (*crtbegin.o(.ctors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
__init_array_end = ABSOLUTE(.);
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
/* C++ exception handlers table: */
|
||||
__XT_EXCEPTION_DESCS_ = ABSOLUTE(.);
|
||||
*(.xt_except_desc)
|
||||
*(.gnu.linkonce.h.*)
|
||||
__XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.);
|
||||
*(.xt_except_desc_end)
|
||||
*(.dynamic)
|
||||
*(.gnu.version_d)
|
||||
_rodata_end = ABSOLUTE(.);
|
||||
/* Literals are also RO data. */
|
||||
_lit4_start = ABSOLUTE(.);
|
||||
*(*.lit4)
|
||||
*(.lit4.*)
|
||||
*(.gnu.linkonce.lit4.*)
|
||||
_lit4_end = ABSOLUTE(.);
|
||||
. = ALIGN(4);
|
||||
_heap_start = ABSOLUTE(.);
|
||||
} >dram_seg
|
||||
|
||||
.iram_pool_1.text :
|
||||
{
|
||||
_stext = .;
|
||||
_text_start = ABSOLUTE(.);
|
||||
*(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
|
||||
*(.irom0.text) /* catch stray ICACHE_RODATA_ATTR */
|
||||
*(.fini.literal)
|
||||
*(.fini)
|
||||
*(.gnu.version)
|
||||
_text_end = ABSOLUTE(.);
|
||||
_etext = .;
|
||||
} >iram_pool_1_seg
|
||||
|
||||
}
|
||||
1
components/bootloader/src/main/esp32.bootloader.rom.ld
Normal file
1
components/bootloader/src/main/esp32.bootloader.rom.ld
Normal file
@@ -0,0 +1 @@
|
||||
PROVIDE ( ets_update_cpu_frequency = 0x40008550 ); /* Updates g_ticks_per_us on the current CPU only; not on the other core */
|
||||
266
components/bootloader/src/main/flash_qio_mode.c
Normal file
266
components/bootloader/src/main/flash_qio_mode.c
Normal file
@@ -0,0 +1,266 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// 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.
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "flash_qio_mode.h"
|
||||
#include "esp_log.h"
|
||||
#include "rom/spi_flash.h"
|
||||
#include "rom/efuse.h"
|
||||
#include "soc/spi_struct.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
/* SPI flash controller */
|
||||
#define SPIFLASH SPI1
|
||||
|
||||
/* SPI commands (actual on-wire commands not SPI controller bitmasks)
|
||||
Suitable for use with the execute_flash_command static function.
|
||||
*/
|
||||
#define CMD_RDID 0x9F
|
||||
#define CMD_WRSR 0x01
|
||||
#define CMD_WRSR2 0x31 /* Not all SPI flash uses this command */
|
||||
#define CMD_WREN 0x06
|
||||
#define CMD_WRDI 0x04
|
||||
#define CMD_RDSR 0x05
|
||||
#define CMD_RDSR2 0x35 /* Not all SPI flash uses this command */
|
||||
|
||||
|
||||
#define ESP32_D2WD_WP_GPIO 7 /* ESP32-D2WD has this GPIO wired to WP pin of flash */
|
||||
|
||||
static const char *TAG = "qio_mode";
|
||||
|
||||
typedef unsigned (*read_status_fn_t)();
|
||||
typedef void (*write_status_fn_t)(unsigned);
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
const char *manufacturer;
|
||||
uint8_t mfg_id; /* 8-bit JEDEC manufacturer ID */
|
||||
uint16_t flash_id; /* 16-bit JEDEC flash chip ID */
|
||||
uint16_t id_mask; /* Bits to match on in flash chip ID */
|
||||
read_status_fn_t read_status_fn;
|
||||
write_status_fn_t write_status_fn;
|
||||
uint8_t status_qio_bit;
|
||||
} qio_info_t;
|
||||
|
||||
/* Read 8 bit status using RDSR command */
|
||||
static unsigned read_status_8b_rdsr();
|
||||
/* Read 8 bit status (second byte) using RDSR2 command */
|
||||
static unsigned read_status_8b_rdsr2();
|
||||
/* read 16 bit status using RDSR & RDSR2 (low and high bytes) */
|
||||
static unsigned read_status_16b_rdsr_rdsr2();
|
||||
|
||||
/* Write 8 bit status using WRSR */
|
||||
static void write_status_8b_wrsr(unsigned new_status);
|
||||
/* Write 8 bit status (second byte) using WRSR2 */
|
||||
static void write_status_8b_wrsr2(unsigned new_status);
|
||||
/* Write 16 bit status using WRSR */
|
||||
static void write_status_16b_wrsr(unsigned new_status);
|
||||
|
||||
/* Array of known flash chips and data to enable Quad I/O mode
|
||||
|
||||
Manufacturer & flash ID can be tested by running "esptool.py
|
||||
flash_id"
|
||||
|
||||
If manufacturer ID matches, and flash ID ORed with flash ID mask
|
||||
matches, enable_qio_mode() will execute "Read Cmd", test if bit
|
||||
number "QIE Bit" is set, and if not set it will call "Write Cmd"
|
||||
with this bit set.
|
||||
|
||||
Searching of this table stops when the first match is found.
|
||||
*/
|
||||
const static qio_info_t chip_data[] = {
|
||||
/* Manufacturer, mfg_id, flash_id, id mask, Read Status, Write Status, QIE Bit */
|
||||
{ "MXIC", 0xC2, 0x2000, 0xFF00, read_status_8b_rdsr, write_status_8b_wrsr, 6 },
|
||||
{ "ISSI", 0x9D, 0x4000, 0xCF00, read_status_8b_rdsr, write_status_8b_wrsr, 6 }, /* IDs 0x40xx, 0x70xx */
|
||||
{ "WinBond", 0xEF, 0x4000, 0xFF00, read_status_16b_rdsr_rdsr2, write_status_16b_wrsr, 9 },
|
||||
|
||||
/* Final entry is default entry, if no other IDs have matched.
|
||||
|
||||
This approach works for chips including:
|
||||
GigaDevice (mfg ID 0xC8, flash IDs including 4016),
|
||||
FM25Q32 (QOUT mode only, mfg ID 0xA1, flash IDs including 4016)
|
||||
*/
|
||||
{ NULL, 0xFF, 0xFFFF, 0xFFFF, read_status_8b_rdsr2, write_status_8b_wrsr2, 1 },
|
||||
};
|
||||
|
||||
#define NUM_CHIPS (sizeof(chip_data) / sizeof(qio_info_t))
|
||||
|
||||
static void enable_qio_mode(read_status_fn_t read_status_fn,
|
||||
write_status_fn_t write_status_fn,
|
||||
uint8_t status_qio_bit);
|
||||
|
||||
/* Generic function to use the "user command" SPI controller functionality
|
||||
to send commands to the SPI flash and read the respopnse.
|
||||
|
||||
The command passed here is always the on-the-wire command given to the SPI flash unit.
|
||||
*/
|
||||
static uint32_t execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len);
|
||||
|
||||
/* dummy_len_plus values defined in ROM for SPI flash configuration */
|
||||
extern uint8_t g_rom_spiflash_dummy_len_plus[];
|
||||
|
||||
void bootloader_enable_qio_mode(void)
|
||||
{
|
||||
uint32_t raw_flash_id;
|
||||
uint8_t mfg_id;
|
||||
uint16_t flash_id;
|
||||
int i;
|
||||
|
||||
ESP_LOGD(TAG, "Probing for QIO mode enable...");
|
||||
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
|
||||
|
||||
/* Set up some of the SPIFLASH user/ctrl variables which don't change
|
||||
while we're probing using execute_flash_command() */
|
||||
SPIFLASH.ctrl.val = 0;
|
||||
SPIFLASH.user.usr_dummy = 0;
|
||||
SPIFLASH.user.usr_addr = 0;
|
||||
SPIFLASH.user.usr_command = 1;
|
||||
SPIFLASH.user2.usr_command_bitlen = 7;
|
||||
|
||||
raw_flash_id = execute_flash_command(CMD_RDID, 0, 0, 24);
|
||||
ESP_LOGD(TAG, "Raw SPI flash chip id 0x%x", raw_flash_id);
|
||||
|
||||
mfg_id = raw_flash_id & 0xFF;
|
||||
flash_id = (raw_flash_id >> 16) | (raw_flash_id & 0xFF00);
|
||||
ESP_LOGD(TAG, "Manufacturer ID 0x%02x chip ID 0x%04x", mfg_id, flash_id);
|
||||
|
||||
for (i = 0; i < NUM_CHIPS-1; i++) {
|
||||
const qio_info_t *chip = &chip_data[i];
|
||||
if (mfg_id == chip->mfg_id && (flash_id & chip->id_mask) == (chip->flash_id & chip->id_mask)) {
|
||||
ESP_LOGI(TAG, "Enabling QIO for flash chip %s", chip_data[i].manufacturer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == NUM_CHIPS - 1) {
|
||||
ESP_LOGI(TAG, "Enabling default flash chip QIO");
|
||||
}
|
||||
|
||||
enable_qio_mode(chip_data[i].read_status_fn,
|
||||
chip_data[i].write_status_fn,
|
||||
chip_data[i].status_qio_bit);
|
||||
}
|
||||
|
||||
static void enable_qio_mode(read_status_fn_t read_status_fn,
|
||||
write_status_fn_t write_status_fn,
|
||||
uint8_t status_qio_bit)
|
||||
{
|
||||
uint32_t status;
|
||||
const uint32_t spiconfig = ets_efuse_get_spiconfig();
|
||||
|
||||
if (spiconfig != EFUSE_SPICONFIG_SPI_DEFAULTS && spiconfig != EFUSE_SPICONFIG_HSPI_DEFAULTS) {
|
||||
// spiconfig specifies a custom efuse pin configuration. This config defines all pins -except- WP.
|
||||
//
|
||||
// For now, in this situation we only support Quad I/O mode for ESP32-D2WD where WP pin is known.
|
||||
uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_RESERVE);
|
||||
uint32_t pkg_ver = chip_ver & 0x7;
|
||||
const uint32_t PKG_VER_ESP32_D2WD = 2; // TODO: use chip detection API once available
|
||||
if (pkg_ver != PKG_VER_ESP32_D2WD) {
|
||||
ESP_LOGE(TAG, "Quad I/O is only supported for standard pin numbers or ESP32-D2WD. Falling back to Dual I/O.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
|
||||
|
||||
status = read_status_fn();
|
||||
ESP_LOGD(TAG, "Initial flash chip status 0x%x", status);
|
||||
|
||||
if ((status & (1<<status_qio_bit)) == 0) {
|
||||
execute_flash_command(CMD_WREN, 0, 0, 0);
|
||||
write_status_fn(status | (1<<status_qio_bit));
|
||||
|
||||
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
|
||||
|
||||
status = read_status_fn();
|
||||
ESP_LOGD(TAG, "Updated flash chip status 0x%x", status);
|
||||
if ((status & (1<<status_qio_bit)) == 0) {
|
||||
ESP_LOGE(TAG, "Failed to set QIE bit, not enabling QIO mode");
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
ESP_LOGD(TAG, "QIO mode already enabled in flash");
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Enabling QIO mode...");
|
||||
|
||||
esp_rom_spiflash_read_mode_t mode;
|
||||
#if CONFIG_FLASHMODE_QOUT
|
||||
mode = ESP_ROM_SPIFLASH_QOUT_MODE;
|
||||
#else
|
||||
mode = ESP_ROM_SPIFLASH_QIO_MODE;
|
||||
#endif
|
||||
|
||||
esp_rom_spiflash_config_readmode(mode);
|
||||
|
||||
esp_rom_spiflash_select_qio_pins(ESP32_D2WD_WP_GPIO, spiconfig);
|
||||
}
|
||||
|
||||
static unsigned read_status_8b_rdsr()
|
||||
{
|
||||
return execute_flash_command(CMD_RDSR, 0, 0, 8);
|
||||
}
|
||||
|
||||
static unsigned read_status_8b_rdsr2()
|
||||
{
|
||||
return execute_flash_command(CMD_RDSR2, 0, 0, 8);
|
||||
}
|
||||
|
||||
static unsigned read_status_16b_rdsr_rdsr2()
|
||||
{
|
||||
return execute_flash_command(CMD_RDSR, 0, 0, 8) | (execute_flash_command(CMD_RDSR2, 0, 0, 8) << 8);
|
||||
}
|
||||
|
||||
static void write_status_8b_wrsr(unsigned new_status)
|
||||
{
|
||||
execute_flash_command(CMD_WRSR, new_status, 8, 0);
|
||||
}
|
||||
|
||||
static void write_status_8b_wrsr2(unsigned new_status)
|
||||
{
|
||||
execute_flash_command(CMD_WRSR2, new_status, 8, 0);
|
||||
}
|
||||
|
||||
static void write_status_16b_wrsr(unsigned new_status)
|
||||
{
|
||||
execute_flash_command(CMD_WRSR, new_status, 16, 0);
|
||||
}
|
||||
|
||||
static uint32_t execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len)
|
||||
{
|
||||
SPIFLASH.user2.usr_command_value = command;
|
||||
SPIFLASH.user.usr_miso = miso_len > 0;
|
||||
SPIFLASH.miso_dlen.usr_miso_dbitlen = miso_len ? (miso_len - 1) : 0;
|
||||
SPIFLASH.user.usr_mosi = mosi_len > 0;
|
||||
SPIFLASH.mosi_dlen.usr_mosi_dbitlen = mosi_len ? (mosi_len - 1) : 0;
|
||||
SPIFLASH.data_buf[0] = mosi_data;
|
||||
|
||||
if (g_rom_spiflash_dummy_len_plus[1]) {
|
||||
/* When flash pins are mapped via GPIO matrix, need a dummy cycle before reading via MISO */
|
||||
if (miso_len > 0) {
|
||||
SPIFLASH.user.usr_dummy = 1;
|
||||
SPIFLASH.user1.usr_dummy_cyclelen = g_rom_spiflash_dummy_len_plus[1] - 1;
|
||||
} else {
|
||||
SPIFLASH.user.usr_dummy = 0;
|
||||
SPIFLASH.user1.usr_dummy_cyclelen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
SPIFLASH.cmd.usr = 1;
|
||||
while(SPIFLASH.cmd.usr != 0)
|
||||
{ }
|
||||
|
||||
return SPIFLASH.data_buf[0];
|
||||
}
|
||||
@@ -24,14 +24,6 @@ extern "C" {
|
||||
*/
|
||||
void bootloader_enable_qio_mode(void);
|
||||
|
||||
/**
|
||||
* @brief Read flash ID by sending 0x9F command
|
||||
* @return flash raw ID
|
||||
* mfg_id = (ID >> 16) & 0xFF;
|
||||
flash_id = ID & 0xffff;
|
||||
*/
|
||||
uint32_t bootloader_read_flash_id();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,137 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
if(NOT SDKCONFIG)
|
||||
message(FATAL_ERROR "Bootloader subproject expects the SDKCONFIG variable to be passed "
|
||||
"in by the parent build process.")
|
||||
endif()
|
||||
|
||||
if(NOT IDF_PATH)
|
||||
message(FATAL_ERROR "Bootloader subproject expects the IDF_PATH variable to be passed "
|
||||
"in by the parent build process.")
|
||||
endif()
|
||||
|
||||
set(COMPONENTS bootloader esptool_py esp32 partition_table soc bootloader_support log spi_flash micro-ecc soc main efuse)
|
||||
set(BOOTLOADER_BUILD 1)
|
||||
add_definitions(-DBOOTLOADER_BUILD=1)
|
||||
|
||||
set(COMPONENT_REQUIRES_COMMON log esp32 soc)
|
||||
|
||||
include("${IDF_PATH}/tools/cmake/project.cmake")
|
||||
project(bootloader)
|
||||
|
||||
target_linker_script(bootloader.elf
|
||||
"main/esp32.bootloader.ld"
|
||||
"main/esp32.bootloader.rom.ld"
|
||||
)
|
||||
|
||||
# as cmake won't attach linker args to a header-only library, attach
|
||||
# linker args directly to the bootloader.elf
|
||||
set(ESP32_BOOTLOADER_LINKER_SCRIPTS
|
||||
"${IDF_PATH}/components/esp32/ld/esp32.rom.ld"
|
||||
"${IDF_PATH}/components/esp32/ld/esp32.rom.spiram_incompatible_fns.ld"
|
||||
"${IDF_PATH}/components/esp32/ld/esp32.peripherals.ld")
|
||||
|
||||
target_linker_script(bootloader.elf ${ESP32_BOOTLOADER_LINKER_SCRIPTS})
|
||||
|
||||
target_link_libraries(bootloader.elf gcc)
|
||||
|
||||
set(secure_boot_signing_key ${SECURE_BOOT_SIGNING_KEY})
|
||||
|
||||
string(REPLACE ";" " " espsecurepy "${ESPSECUREPY}")
|
||||
string(REPLACE ";" " " espefusepy "${ESPEFUSEPY}")
|
||||
set(esptoolpy_write_flash "${ESPTOOLPY_WRITE_FLASH_STR}")
|
||||
|
||||
if(CONFIG_SECURE_BOOTLOADER_REFLASHABLE)
|
||||
if(CONFIG_SECURE_BOOTLOADER_KEY_ENCODING_192BIT)
|
||||
set(key_digest_len 192)
|
||||
else()
|
||||
set(key_digest_len 256)
|
||||
endif()
|
||||
|
||||
get_filename_component(bootloader_digest_bin
|
||||
"bootloader-reflash-digest.bin"
|
||||
ABSOLUTE BASE_DIR "${CMAKE_BINARY_DIR}")
|
||||
|
||||
get_filename_component(secure_bootloader_key
|
||||
"secure-bootloader-key-${key_digest_len}.bin"
|
||||
ABSOLUTE BASE_DIR "${CMAKE_BINARY_DIR}")
|
||||
|
||||
add_custom_command(OUTPUT "${secure_bootloader_key}"
|
||||
COMMAND ${ESPSECUREPY} digest_private_key
|
||||
--keylen "${key_digest_len}"
|
||||
--keyfile "${secure_boot_signing_key}"
|
||||
"${secure_bootloader_key}"
|
||||
VERBATIM)
|
||||
|
||||
if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)
|
||||
add_custom_target(gen_secure_bootloader_key ALL DEPENDS "${secure_bootloader_key}")
|
||||
else()
|
||||
if(NOT EXISTS "${secure_bootloader_key}")
|
||||
message(FATAL_ERROR
|
||||
"No pre-generated key for a reflashable secure bootloader is available, "
|
||||
"due to signing configuration."
|
||||
"\nTo generate one, you can use this command:"
|
||||
"\n\t${espsecurepy} generate_flash_encryption_key ${secure_bootloader_key}"
|
||||
"\nIf a signing key is present, then instead use:"
|
||||
"\n\t${ESPSECUREPY} digest_private_key "
|
||||
"--keylen (192/256) --keyfile KEYFILE "
|
||||
"${secure_bootloader_key}")
|
||||
endif()
|
||||
add_custom_target(gen_secure_bootloader_key)
|
||||
endif()
|
||||
|
||||
add_custom_command(OUTPUT "${bootloader_digest_bin}"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "DIGEST ${bootloader_digest_bin}"
|
||||
COMMAND ${ESPSECUREPY} digest_secure_bootloader --keyfile "${secure_bootloader_key}"
|
||||
-o "${bootloader_digest_bin}" "${CMAKE_BINARY_DIR}/bootloader.bin"
|
||||
DEPENDS gen_secure_bootloader_key "${CMAKE_BINARY_DIR}/bootloader.bin"
|
||||
VERBATIM)
|
||||
|
||||
add_custom_target (gen_bootloader_digest_bin ALL DEPENDS "${bootloader_digest_bin}")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH)
|
||||
add_custom_command(TARGET bootloader POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"=============================================================================="
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"Bootloader built. Secure boot enabled, so bootloader not flashed automatically."
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"One-time flash command is:"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"\t${esptoolpy_write_flash} ${BOOTLOADER_OFFSET} ${CMAKE_BINARY_DIR}/bootloader.bin"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"* IMPORTANT: After first boot, BOOTLOADER CANNOT BE RE-FLASHED on same device"
|
||||
VERBATIM)
|
||||
|
||||
elseif(CONFIG_SECURE_BOOTLOADER_REFLASHABLE)
|
||||
add_custom_command(TARGET bootloader POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"=============================================================================="
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"Bootloader built and secure digest generated."
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"Secure boot enabled, so bootloader not flashed automatically."
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"Burn secure boot key to efuse using:"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"\t${espefusepy} burn_key secure_boot ${secure_bootloader_key}"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"First time flash command is:"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"\t${esptoolpy_write_flash} ${BOOTLOADER_OFFSET} ${CMAKE_BINARY_DIR}/bootloader.bin"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"=============================================================================="
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"To reflash the bootloader after initial flash:"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"\t${esptoolpy_write_flash} 0x0 ${bootloader_digest_bin}"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"=============================================================================="
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"* After first boot, only re-flashes of this kind (with same key) will be accepted."
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"* Not recommended to re-use the same secure boot keyfile on multiple production devices."
|
||||
DEPENDS gen_secure_bootloader_key gen_bootloader_digest_bin
|
||||
VERBATIM)
|
||||
endif()
|
||||
@@ -1,32 +0,0 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
ifeq ("$(MAKELEVEL)","0")
|
||||
$(error Bootloader makefile expects to be run as part of 'make bootloader' from a top-level project.)
|
||||
endif
|
||||
|
||||
PROJECT_NAME := bootloader
|
||||
|
||||
COMPONENTS := esptool_py bootloader_support log spi_flash micro-ecc soc main efuse
|
||||
|
||||
# Clear C and CXX from top level project
|
||||
CFLAGS =
|
||||
CXXFLAGS =
|
||||
|
||||
#We cannot include the esp32 component directly but we need its includes.
|
||||
CFLAGS += -I $(IDF_PATH)/components/esp32/include
|
||||
|
||||
# The bootloader pseudo-component is also included in this build, for its Kconfig.projbuild to be included.
|
||||
#
|
||||
# IS_BOOTLOADER_BUILD tells the component Makefile.projbuild to be a no-op
|
||||
IS_BOOTLOADER_BUILD := 1
|
||||
export IS_BOOTLOADER_BUILD
|
||||
|
||||
# BOOTLOADER_BUILD macro is the same, for source file changes
|
||||
CFLAGS += -D BOOTLOADER_BUILD=1
|
||||
|
||||
# include the top-level "project" include directory, for sdkconfig.h
|
||||
CFLAGS += -I$(BUILD_DIR_BASE)/../include
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
@@ -1,4 +0,0 @@
|
||||
set(COMPONENT_SRCS "bootloader_start.c")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS "")
|
||||
set(COMPONENT_REQUIRES "bootloader bootloader_support")
|
||||
register_component()
|
||||
@@ -1,115 +0,0 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// 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.
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "rom/gpio.h"
|
||||
#include "rom/spi_flash.h"
|
||||
#include "bootloader_config.h"
|
||||
#include "bootloader_init.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "rom/rtc.h"
|
||||
|
||||
static const char* TAG = "boot";
|
||||
|
||||
static int select_partition_number (bootloader_state_t *bs);
|
||||
static int selected_boot_partition(const bootloader_state_t *bs);
|
||||
/*
|
||||
* We arrive here after the ROM bootloader finished loading this second stage bootloader from flash.
|
||||
* The hardware is mostly uninitialized, flash cache is down and the app CPU is in reset.
|
||||
* We do have a stack, so we can do the initialization in C.
|
||||
*/
|
||||
void __attribute__((noreturn)) call_start_cpu0()
|
||||
{
|
||||
// 1. Hardware initialization
|
||||
if (bootloader_init() != ESP_OK) {
|
||||
bootloader_reset();
|
||||
}
|
||||
|
||||
// 2. Select the number of boot partition
|
||||
bootloader_state_t bs = { 0 };
|
||||
int boot_index = select_partition_number(&bs);
|
||||
if (boot_index == INVALID_INDEX) {
|
||||
bootloader_reset();
|
||||
}
|
||||
|
||||
// 3. Load the app image for booting
|
||||
bootloader_utility_load_boot_image(&bs, boot_index);
|
||||
}
|
||||
|
||||
// Select the number of boot partition
|
||||
static int select_partition_number (bootloader_state_t *bs)
|
||||
{
|
||||
// 1. Load partition table
|
||||
if (!bootloader_utility_load_partition_table(bs)) {
|
||||
ESP_LOGE(TAG, "load partition table error!");
|
||||
return INVALID_INDEX;
|
||||
}
|
||||
|
||||
// 2. Select the number of boot partition
|
||||
return selected_boot_partition(bs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Selects a boot partition.
|
||||
* The conditions for switching to another firmware are checked.
|
||||
*/
|
||||
static int selected_boot_partition(const bootloader_state_t *bs)
|
||||
{
|
||||
int boot_index = bootloader_utility_get_selected_boot_partition(bs);
|
||||
if (boot_index == INVALID_INDEX) {
|
||||
return boot_index; // Unrecoverable failure (not due to corrupt ota data or bad partition contents)
|
||||
}
|
||||
if (rtc_get_reset_reason(0) != DEEPSLEEP_RESET) {
|
||||
// Factory firmware.
|
||||
#ifdef CONFIG_BOOTLOADER_FACTORY_RESET
|
||||
if (bootloader_common_check_long_hold_gpio(CONFIG_BOOTLOADER_NUM_PIN_FACTORY_RESET, CONFIG_BOOTLOADER_HOLD_TIME_GPIO) == 1) {
|
||||
ESP_LOGI(TAG, "Detect a condition of the factory reset");
|
||||
bool ota_data_erase = false;
|
||||
#ifdef CONFIG_BOOTLOADER_OTA_DATA_ERASE
|
||||
ota_data_erase = true;
|
||||
#endif
|
||||
const char *list_erase = CONFIG_BOOTLOADER_DATA_FACTORY_RESET;
|
||||
ESP_LOGI(TAG, "Data partitions to erase: %s", list_erase);
|
||||
if (bootloader_common_erase_part_type_data(list_erase, ota_data_erase) == false) {
|
||||
ESP_LOGE(TAG, "Not all partitions were erased");
|
||||
}
|
||||
return bootloader_utility_get_selected_boot_partition(bs);
|
||||
}
|
||||
#endif
|
||||
// TEST firmware.
|
||||
#ifdef CONFIG_BOOTLOADER_APP_TEST
|
||||
if (bootloader_common_check_long_hold_gpio(CONFIG_BOOTLOADER_NUM_PIN_APP_TEST, CONFIG_BOOTLOADER_HOLD_TIME_GPIO) == 1) {
|
||||
ESP_LOGI(TAG, "Detect a boot condition of the test firmware");
|
||||
if (bs->test.offset != 0) {
|
||||
boot_index = TEST_APP_INDEX;
|
||||
return boot_index;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Test firmware is not found in partition table");
|
||||
return INVALID_INDEX;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// Customer implementation.
|
||||
// if (gpio_pin_1 == true && ...){
|
||||
// boot_index = required_boot_partition;
|
||||
// } ...
|
||||
}
|
||||
return boot_index;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
#
|
||||
# Main bootloader Makefile.
|
||||
#
|
||||
# This is basically the same as a component makefile, but in the case of the bootloader
|
||||
# we pull in bootloader-specific linker arguments.
|
||||
#
|
||||
|
||||
LINKER_SCRIPTS := \
|
||||
esp32.bootloader.ld \
|
||||
$(IDF_PATH)/components/esp32/ld/esp32.rom.ld \
|
||||
$(IDF_PATH)/components/esp32/ld/esp32.rom.spiram_incompatible_fns.ld \
|
||||
$(IDF_PATH)/components/esp32/ld/esp32.peripherals.ld \
|
||||
esp32.bootloader.rom.ld
|
||||
|
||||
ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH
|
||||
LINKER_SCRIPTS += $(IDF_PATH)/components/esp32/ld/esp32.rom.spiflash.ld
|
||||
endif
|
||||
|
||||
COMPONENT_ADD_LDFLAGS += -L $(COMPONENT_PATH) $(addprefix -T ,$(LINKER_SCRIPTS))
|
||||
|
||||
COMPONENT_ADD_LINKER_DEPS := $(LINKER_SCRIPTS)
|
||||
@@ -1,170 +0,0 @@
|
||||
/*
|
||||
Linker file used to link the bootloader.
|
||||
*/
|
||||
|
||||
|
||||
/* Simplified memory map for the bootloader
|
||||
|
||||
The main purpose is to make sure the bootloader can load into main memory
|
||||
without overwriting itself.
|
||||
*/
|
||||
|
||||
MEMORY
|
||||
{
|
||||
/* I/O */
|
||||
dport0_seg (RW) : org = 0x3FF00000, len = 0x10
|
||||
/* IRAM POOL1, used for APP CPU cache. Bootloader runs from here during the final stage of loading the app because APP CPU is still held in reset, the main app enables APP CPU cache */
|
||||
iram_loader_seg (RWX) : org = 0x40078000, len = 0x8000 /* 32KB, APP CPU cache */
|
||||
/* 63kB, IRAM. We skip the first 1k to prevent the entry point being
|
||||
placed into the same range as exception vectors in the app.
|
||||
This leads to idf_monitor decoding ROM bootloader "entry 0x40080xxx"
|
||||
message as one of the exception vectors, which looks scary to users.
|
||||
*/
|
||||
iram_seg (RWX) : org = 0x40080400, len = 0xfc00
|
||||
/* 64k at the end of DRAM, after ROM bootloader stack */
|
||||
dram_seg (RW) : org = 0x3FFF0000, len = 0x10000
|
||||
}
|
||||
|
||||
/* Default entry point: */
|
||||
ENTRY(call_start_cpu0);
|
||||
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
|
||||
.iram_loader.text :
|
||||
{
|
||||
. = ALIGN (16);
|
||||
_loader_text_start = ABSOLUTE(.);
|
||||
*(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
|
||||
*(.iram1 .iram1.*) /* catch stray IRAM_ATTR */
|
||||
*liblog.a:(.literal .text .literal.* .text.*)
|
||||
*libgcc.a:(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_clock.*(.literal.esp_clk_apb_freq .text.esp_clk_apb_freq)
|
||||
*libbootloader_support.a:bootloader_common.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_flash.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_random.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_utility.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_sha.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:esp_image_format.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:flash_partitions.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot.*(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:secure_boot_signatures.*(.literal .text .literal.* .text.*)
|
||||
*libmicro-ecc.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libspi_flash.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libsoc.a:rtc_clk.*(.literal.rtc_clk_apb_freq_get .text.rtc_clk_apb_freq_get)
|
||||
*libsoc.a:rtc_wdt.*(.literal .text .literal.* .text.*)
|
||||
*libefuse.a:*.*(.literal .text .literal.* .text.*)
|
||||
*(.fini.literal)
|
||||
*(.fini)
|
||||
*(.gnu.version)
|
||||
_loader_text_end = ABSOLUTE(.);
|
||||
} > iram_loader_seg
|
||||
|
||||
.iram.text :
|
||||
{
|
||||
. = ALIGN (16);
|
||||
*(.entry.text)
|
||||
*(.init.literal)
|
||||
*(.init)
|
||||
} > iram_seg
|
||||
|
||||
|
||||
/* Shared RAM */
|
||||
.dram0.bss (NOLOAD) :
|
||||
{
|
||||
. = ALIGN (8);
|
||||
_bss_start = ABSOLUTE(.);
|
||||
*(.dynsbss)
|
||||
*(.sbss)
|
||||
*(.sbss.*)
|
||||
*(.gnu.linkonce.sb.*)
|
||||
*(.scommon)
|
||||
*(.sbss2)
|
||||
*(.sbss2.*)
|
||||
*(.gnu.linkonce.sb2.*)
|
||||
*(.dynbss)
|
||||
*(.bss)
|
||||
*(.bss.*)
|
||||
*(.gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
. = ALIGN (8);
|
||||
_bss_end = ABSOLUTE(.);
|
||||
} >dram_seg
|
||||
|
||||
.dram0.data :
|
||||
{
|
||||
_data_start = ABSOLUTE(.);
|
||||
*(.data)
|
||||
*(.data.*)
|
||||
*(.gnu.linkonce.d.*)
|
||||
*(.data1)
|
||||
*(.sdata)
|
||||
*(.sdata.*)
|
||||
*(.gnu.linkonce.s.*)
|
||||
*(.sdata2)
|
||||
*(.sdata2.*)
|
||||
*(.gnu.linkonce.s2.*)
|
||||
*(.jcr)
|
||||
_data_end = ABSOLUTE(.);
|
||||
} >dram_seg
|
||||
|
||||
.dram0.rodata :
|
||||
{
|
||||
_rodata_start = ABSOLUTE(.);
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
*(.gnu.linkonce.r.*)
|
||||
*(.rodata1)
|
||||
__XT_EXCEPTION_TABLE_ = ABSOLUTE(.);
|
||||
*(.xt_except_table)
|
||||
*(.gcc_except_table)
|
||||
*(.gnu.linkonce.e.*)
|
||||
*(.gnu.version_r)
|
||||
*(.eh_frame)
|
||||
. = (. + 3) & ~ 3;
|
||||
/* C++ constructor and destructor tables, properly ordered: */
|
||||
__init_array_start = ABSOLUTE(.);
|
||||
KEEP (*crtbegin.*(.ctors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.*) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
__init_array_end = ABSOLUTE(.);
|
||||
KEEP (*crtbegin.*(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.*) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
/* C++ exception handlers table: */
|
||||
__XT_EXCEPTION_DESCS_ = ABSOLUTE(.);
|
||||
*(.xt_except_desc)
|
||||
*(.gnu.linkonce.h.*)
|
||||
__XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.);
|
||||
*(.xt_except_desc_end)
|
||||
*(.dynamic)
|
||||
*(.gnu.version_d)
|
||||
_rodata_end = ABSOLUTE(.);
|
||||
/* Literals are also RO data. */
|
||||
_lit4_start = ABSOLUTE(.);
|
||||
*(*.lit4)
|
||||
*(.lit4.*)
|
||||
*(.gnu.linkonce.lit4.*)
|
||||
_lit4_end = ABSOLUTE(.);
|
||||
. = ALIGN(4);
|
||||
_heap_start = ABSOLUTE(.);
|
||||
} >dram_seg
|
||||
|
||||
.iram.text :
|
||||
{
|
||||
_stext = .;
|
||||
_text_start = ABSOLUTE(.);
|
||||
*(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
|
||||
*(.iram .iram.*) /* catch stray IRAM_ATTR */
|
||||
*(.fini.literal)
|
||||
*(.fini)
|
||||
*(.gnu.version)
|
||||
_text_end = ABSOLUTE(.);
|
||||
_etext = .;
|
||||
} > iram_seg
|
||||
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
PROVIDE ( ets_update_cpu_frequency = 0x40008550 ); /* Updates g_ticks_per_us on the current CPU only; not on the other core */
|
||||
PROVIDE ( MD5Final = 0x4005db1c );
|
||||
PROVIDE ( MD5Init = 0x4005da7c );
|
||||
PROVIDE ( MD5Update = 0x4005da9c );
|
||||
@@ -1,61 +0,0 @@
|
||||
set(COMPONENT_SRCS "src/bootloader_clock.c"
|
||||
"src/bootloader_common.c"
|
||||
"src/bootloader_flash.c"
|
||||
"src/bootloader_flash_config.c"
|
||||
"src/bootloader_random.c"
|
||||
"src/bootloader_sha.c"
|
||||
"src/bootloader_utility.c"
|
||||
"src/esp_image_format.c"
|
||||
"src/flash_encrypt.c"
|
||||
"src/flash_partitions.c"
|
||||
"src/flash_qio_mode.c"
|
||||
"src/secure_boot.c"
|
||||
"src/secure_boot_signatures.c")
|
||||
|
||||
if(${BOOTLOADER_BUILD})
|
||||
set(COMPONENT_ADD_INCLUDEDIRS "include include_bootloader")
|
||||
set(COMPONENT_REQUIRES)
|
||||
set(COMPONENT_PRIV_REQUIRES spi_flash micro-ecc efuse)
|
||||
list(APPEND COMPONENT_SRCS "src/bootloader_init.c")
|
||||
|
||||
if(CONFIG_SECURE_SIGNED_APPS)
|
||||
get_filename_component(secure_boot_verification_key
|
||||
"signature_verification_key.bin"
|
||||
ABSOLUTE BASE_DIR "${CMAKE_BINARY_DIR}")
|
||||
if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)
|
||||
add_custom_command(OUTPUT "${secure_boot_verification_key}"
|
||||
COMMAND ${ESPSECUREPY}
|
||||
extract_public_key --keyfile "${secure_boot_signing_key}"
|
||||
"${secure_boot_verification_key}"
|
||||
DEPENDS gen_secure_boot_signing_key
|
||||
VERBATIM)
|
||||
else()
|
||||
get_filename_component(orig_secure_boot_verification_key
|
||||
"${CONFIG_SECURE_BOOT_VERIFICATION_KEY}"
|
||||
ABSOLUTE BASE_DIR "${main_project_path}")
|
||||
if(NOT EXISTS ${orig_secure_boot_verification_key})
|
||||
message(FATAL_ERROR
|
||||
"Secure Boot Verification Public Key ${CONFIG_SECURE_BOOT_VERIFICATION_KEY} does not exist."
|
||||
"\nThis can be extracted from the private signing key."
|
||||
"\nSee docs/security/secure-boot.rst for details.")
|
||||
endif()
|
||||
|
||||
add_custom_command(OUTPUT "${secure_boot_verification_key}"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy "${orig_secure_boot_verification_key}"
|
||||
"${secure_boot_verification_key}"
|
||||
DEPENDS "${orig_secure_boot_verification_key}"
|
||||
VERBATIM)
|
||||
endif()
|
||||
set(COMPONENT_EMBED_FILES "${secure_boot_verification_key}")
|
||||
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
|
||||
"${secure_boot_verification_key}")
|
||||
endif()
|
||||
else()
|
||||
set(COMPONENT_ADD_INCLUDEDIRS "include")
|
||||
set(COMPONENT_PRIV_INCLUDEDIRS "include_bootloader")
|
||||
set(COMPONENT_REQUIRES)
|
||||
set(COMPONENT_PRIV_REQUIRES spi_flash mbedtls micro-ecc efuse)
|
||||
endif()
|
||||
|
||||
register_component()
|
||||
14
components/bootloader_support/component.mk
Normal file → Executable file
14
components/bootloader_support/component.mk
Normal file → Executable file
@@ -1,22 +1,18 @@
|
||||
COMPONENT_ADD_INCLUDEDIRS := include
|
||||
COMPONENT_PRIV_INCLUDEDIRS := include_priv
|
||||
|
||||
ifdef IS_BOOTLOADER_BUILD
|
||||
# share "include_bootloader" headers with bootloader main component
|
||||
COMPONENT_ADD_INCLUDEDIRS += include_bootloader
|
||||
else
|
||||
COMPONENT_PRIV_INCLUDEDIRS := include_bootloader
|
||||
# share "private" headers with the bootloader component
|
||||
# eventual goal: all functionality that needs this lives in bootloader_support
|
||||
COMPONENT_ADD_INCLUDEDIRS += include_priv
|
||||
endif
|
||||
|
||||
COMPONENT_SRCDIRS := src
|
||||
|
||||
ifndef IS_BOOTLOADER_BUILD
|
||||
COMPONENT_OBJEXCLUDE := src/bootloader_init.o
|
||||
endif
|
||||
|
||||
#
|
||||
# Secure boot signing key support
|
||||
#
|
||||
ifdef CONFIG_SECURE_SIGNED_APPS
|
||||
ifdef CONFIG_SECURE_BOOT_ENABLED
|
||||
|
||||
# this path is created relative to the component build directory
|
||||
SECURE_BOOT_VERIFICATION_KEY := $(abspath signature_verification_key.bin)
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
// Copyright 2017 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
/** @brief Configure clocks for early boot
|
||||
*
|
||||
* Called by bootloader, or by the app if the bootloader version is old (pre v2.1).
|
||||
*/
|
||||
void bootloader_clock_configure(void);
|
||||
@@ -1,167 +0,0 @@
|
||||
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
#include "esp_flash_data_types.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_image_format.h"
|
||||
|
||||
/// Type of hold a GPIO in low state
|
||||
typedef enum {
|
||||
GPIO_LONG_HOLD = 1, /*!< The long hold GPIO */
|
||||
GPIO_SHORT_HOLD = -1, /*!< The short hold GPIO */
|
||||
GPIO_NOT_HOLD = 0 /*!< If the GPIO input is not low */
|
||||
} esp_comm_gpio_hold_t;
|
||||
|
||||
typedef enum {
|
||||
ESP_IMAGE_BOOTLOADER,
|
||||
ESP_IMAGE_APPLICATION
|
||||
} esp_image_type;
|
||||
|
||||
/**
|
||||
* @brief Calculate crc for the OTA data select.
|
||||
*
|
||||
* @param[in] s The OTA data select.
|
||||
* @return Returns crc value.
|
||||
*/
|
||||
uint32_t bootloader_common_ota_select_crc(const esp_ota_select_entry_t *s);
|
||||
|
||||
/**
|
||||
* @brief Verifies the validity of the OTA data select
|
||||
*
|
||||
* @param[in] s The OTA data select.
|
||||
* @return Returns true on valid, false otherwise.
|
||||
*/
|
||||
bool bootloader_common_ota_select_valid(const esp_ota_select_entry_t *s);
|
||||
|
||||
/**
|
||||
* @brief Returns true if OTADATA is not marked as bootable partition.
|
||||
*
|
||||
* @param[in] s The OTA data select.
|
||||
* @return Returns true if OTADATA invalid, false otherwise.
|
||||
*/
|
||||
bool bootloader_common_ota_select_invalid(const esp_ota_select_entry_t *s);
|
||||
|
||||
/**
|
||||
* @brief Check if the GPIO input is a long hold or a short hold.
|
||||
*
|
||||
* Number of the GPIO input will be configured as an input with internal pull-up enabled.
|
||||
* If the GPIO input is held low continuously for delay_sec period then it is a long hold.
|
||||
* If the GPIO input is held low for less period then it is a short hold.
|
||||
*
|
||||
* @param[in] num_pin Number of the GPIO input.
|
||||
* @param[in] delay_sec Input must be driven low for at least this long, continuously.
|
||||
* @return esp_comm_gpio_hold_t Defines type of hold a GPIO in low state.
|
||||
*/
|
||||
esp_comm_gpio_hold_t bootloader_common_check_long_hold_gpio(uint32_t num_pin, uint32_t delay_sec);
|
||||
|
||||
/**
|
||||
* @brief Erase the partition data that is specified in the transferred list.
|
||||
*
|
||||
* @param[in] list_erase String containing a list of cleared partitions. Like this "nvs, phy". The string must be null-terminal.
|
||||
* @param[in] ota_data_erase If true then the OTA data partition will be cleared (if there is it in partition table).
|
||||
* @return Returns true on success, false otherwise.
|
||||
*/
|
||||
bool bootloader_common_erase_part_type_data(const char *list_erase, bool ota_data_erase);
|
||||
|
||||
/**
|
||||
* @brief Determines if the list contains the label
|
||||
*
|
||||
* @param[in] list A string of names delimited by commas or spaces. Like this "nvs, phy, data". The string must be null-terminated.
|
||||
* @param[in] label The substring that will be searched in the list.
|
||||
* @return Returns true if the list contains the label, false otherwise.
|
||||
*/
|
||||
bool bootloader_common_label_search(const char *list, char *label);
|
||||
|
||||
/**
|
||||
* @brief Calculates a sha-256 for a given partition or returns a appended digest.
|
||||
*
|
||||
* This function can be used to return the SHA-256 digest of application, bootloader and data partitions.
|
||||
* For apps with SHA-256 appended to the app image, the result is the appended SHA-256 value for the app image content.
|
||||
* The hash is verified before returning, if app content is invalid then the function returns ESP_ERR_IMAGE_INVALID.
|
||||
* For apps without SHA-256 appended to the image, the result is the SHA-256 of all bytes in the app image.
|
||||
* For other partition types, the result is the SHA-256 of the entire partition.
|
||||
*
|
||||
* @param[in] address Address of partition.
|
||||
* @param[in] size Size of partition.
|
||||
* @param[in] type Type of partition. For applications the type is 0, otherwise type is data.
|
||||
* @param[out] out_sha_256 Returned SHA-256 digest for a given partition.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: In case of successful operation.
|
||||
* - ESP_ERR_INVALID_ARG: The size was 0 or the sha_256 was NULL.
|
||||
* - ESP_ERR_NO_MEM: Cannot allocate memory for sha256 operation.
|
||||
* - ESP_ERR_IMAGE_INVALID: App partition doesn't contain a valid app image.
|
||||
* - ESP_FAIL: An allocation error occurred.
|
||||
*/
|
||||
esp_err_t bootloader_common_get_sha256_of_partition(uint32_t address, uint32_t size, int type, uint8_t *out_sha_256);
|
||||
|
||||
/**
|
||||
* @brief Returns the number of active otadata.
|
||||
*
|
||||
* @param[in] two_otadata Pointer on array from two otadata structures.
|
||||
*
|
||||
* @return The number of active otadata (0 or 1).
|
||||
* - -1: If it does not have active otadata.
|
||||
*/
|
||||
int bootloader_common_get_active_otadata(esp_ota_select_entry_t *two_otadata);
|
||||
|
||||
/**
|
||||
* @brief Returns the number of active otadata.
|
||||
*
|
||||
* @param[in] two_otadata Pointer on array from two otadata structures.
|
||||
* @param[in] valid_two_otadata Pointer on array from two bools. True means select.
|
||||
* @param[in] max True - will select the maximum ota_seq number, otherwise the minimum.
|
||||
*
|
||||
* @return The number of active otadata (0 or 1).
|
||||
* - -1: If it does not have active otadata.
|
||||
*/
|
||||
int bootloader_common_select_otadata(const esp_ota_select_entry_t *two_otadata, bool *valid_two_otadata, bool max);
|
||||
|
||||
/**
|
||||
* @brief Returns esp_app_desc structure for app partition. This structure includes app version.
|
||||
*
|
||||
* Returns a description for the requested app partition.
|
||||
* @param[in] partition App partition description.
|
||||
* @param[out] app_desc Structure of info about app.
|
||||
* @return
|
||||
* - ESP_OK: Successful.
|
||||
* - ESP_ERR_INVALID_ARG: The arguments passed are not valid.
|
||||
* - ESP_ERR_NOT_FOUND: app_desc structure is not found. Magic word is incorrect.
|
||||
* - ESP_FAIL: mapping is fail.
|
||||
*/
|
||||
esp_err_t bootloader_common_get_partition_description(const esp_partition_pos_t *partition, esp_app_desc_t *app_desc);
|
||||
|
||||
/**
|
||||
* @brief Get chip revision
|
||||
*
|
||||
* @return Chip revision number
|
||||
*/
|
||||
uint8_t bootloader_common_get_chip_revision(void);
|
||||
|
||||
/**
|
||||
* @brief Check if the image (bootloader and application) has valid chip ID and revision
|
||||
*
|
||||
* @param[in] img_hdr: image header
|
||||
* @param[in] type: image type, bootloader or application
|
||||
* @return
|
||||
* - ESP_OK: image and chip are matched well
|
||||
* - ESP_FAIL: image doesn't match to the chip
|
||||
*/
|
||||
esp_err_t bootloader_common_check_chip_validity(const esp_image_header_t* img_hdr, esp_image_type type);
|
||||
|
||||
/**
|
||||
* @brief Configure VDDSDIO, call this API to rise VDDSDIO to 1.9V when VDDSDIO regulator is enabled as 1.8V mode.
|
||||
*/
|
||||
void bootloader_common_vddsdio_configure();
|
||||
@@ -1,71 +0,0 @@
|
||||
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_image_format.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Update the flash id in g_rom_flashchip(global esp_rom_spiflash_chip_t structure).
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void bootloader_flash_update_id();
|
||||
|
||||
/**
|
||||
* @brief Set the flash CS setup and hold time.
|
||||
*
|
||||
* @note CS setup time is recomemded to be 1.5T, and CS hold time is recommended to be 2.5T.
|
||||
* cs_setup = 1, cs_setup_time = 0; cs_hold = 1, cs_hold_time = 1.
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void bootloader_flash_cs_timing_config();
|
||||
|
||||
/**
|
||||
* @brief Configure SPI flash clock.
|
||||
*
|
||||
* @note This function only set clock frequency for SPI0.
|
||||
*
|
||||
* @param pfhdr Pointer to App image header, from where to fetch flash settings.
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void bootloader_flash_clock_config(const esp_image_header_t* pfhdr);
|
||||
|
||||
/**
|
||||
* @brief Configure SPI flash gpio, include the IO matrix and drive strength configuration.
|
||||
*
|
||||
* @param pfhdr Pointer to App image header, from where to fetch flash settings.
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void bootloader_flash_gpio_config(const esp_image_header_t* pfhdr);
|
||||
|
||||
/**
|
||||
* @brief Configure SPI flash read dummy based on different mode and frequency.
|
||||
*
|
||||
* @param pfhdr Pointer to App image header, from where to fetch flash settings.
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void bootloader_flash_dummy_config(const esp_image_header_t* pfhdr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,34 +0,0 @@
|
||||
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
* @brief Check if half-open intervals overlap
|
||||
*
|
||||
* @param start1 interval 1 start
|
||||
* @param end1 interval 1 end
|
||||
* @param start2 interval 2 start
|
||||
* @param end2 interval 2 end
|
||||
* @return true iff [start1; end1) overlaps [start2; end2)
|
||||
*/
|
||||
static inline bool bootloader_util_regions_overlap(
|
||||
const intptr_t start1, const intptr_t end1,
|
||||
const intptr_t start2, const intptr_t end2)
|
||||
{
|
||||
return (end1 > start2 && end2 > start1) ||
|
||||
!(end1 <= start2 || end2 <= start1);
|
||||
}
|
||||
56
components/bootloader_support/include/esp_efuse.h
Normal file
56
components/bootloader_support/include/esp_efuse.h
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// 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.
|
||||
#ifndef _ESP_EFUSE_H
|
||||
#define _ESP_EFUSE_H
|
||||
|
||||
#include "soc/efuse_reg.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* @brief Permanently update values written to the efuse write registers
|
||||
*
|
||||
* After updating EFUSE_BLKx_WDATAx_REG registers with new values to
|
||||
* write, call this function to permanently write them to efuse.
|
||||
*
|
||||
* @note Setting bits in efuse is permanent, they cannot be unset.
|
||||
*
|
||||
* @note Due to this restriction you don't need to copy values to
|
||||
* Efuse write registers from the matching read registers, bits which
|
||||
* are set in the read register but unset in the matching write
|
||||
* register will be unchanged when new values are burned.
|
||||
*
|
||||
* @note This function is not threadsafe, if calling code updates
|
||||
* efuse values from multiple tasks then this is caller's
|
||||
* responsibility to serialise.
|
||||
*
|
||||
* After burning new efuses, the read registers are updated to match
|
||||
* the new efuse values.
|
||||
*/
|
||||
void esp_efuse_burn_new_values(void);
|
||||
|
||||
/* @brief Reset efuse write registers
|
||||
*
|
||||
* Efuse write registers are written to zero, to negate
|
||||
* any changes that have been staged here.
|
||||
*/
|
||||
void esp_efuse_reset(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ESP_EFUSE_H */
|
||||
|
||||
@@ -17,9 +17,7 @@
|
||||
#include <stdbool.h>
|
||||
#include "esp_attr.h"
|
||||
#include "esp_err.h"
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
#include "esp_spi_flash.h"
|
||||
#endif
|
||||
#include "soc/efuse_reg.h"
|
||||
|
||||
/**
|
||||
@@ -85,8 +83,6 @@ static inline /** @cond */ IRAM_ATTR /** @endcond */ bool esp_flash_encryption_e
|
||||
* @note Take care not to power off the device while this function
|
||||
* is running, or the partition currently being encrypted will be lost.
|
||||
*
|
||||
* @note RTC_WDT will reset while encryption operations will be performed (if RTC_WDT is configured).
|
||||
*
|
||||
* @return ESP_OK if all operations succeeded, ESP_ERR_INVALID_STATE
|
||||
* if a fatal error occured during encryption of all partitions.
|
||||
*/
|
||||
@@ -95,7 +91,6 @@ esp_err_t esp_flash_encrypt_check_and_update(void);
|
||||
|
||||
/** @brief Encrypt-in-place a block of flash sectors
|
||||
*
|
||||
* @note This function resets RTC_WDT between operations with sectors.
|
||||
* @param src_addr Source offset in flash. Should be multiple of 4096 bytes.
|
||||
* @param data_length Length of data to encrypt in bytes. Will be rounded up to next multiple of 4096 bytes.
|
||||
*
|
||||
@@ -104,18 +99,4 @@ esp_err_t esp_flash_encrypt_check_and_update(void);
|
||||
*/
|
||||
esp_err_t esp_flash_encrypt_region(uint32_t src_addr, size_t data_length);
|
||||
|
||||
/** @brief Write protect FLASH_CRYPT_CNT
|
||||
*
|
||||
* Intended to be called as a part of boot process if flash encryption
|
||||
* is enabled but secure boot is not used. This should protect against
|
||||
* serial re-flashing of an unauthorised code in absence of secure boot.
|
||||
*
|
||||
* @note To support disabling UART Download Mode on ESP32 V3 only, this function
|
||||
* doesn't write protect FLASH_CRYPT_CNT but instead sets it to the max value
|
||||
* (effectively the same result but allows burning the UART_DL_DIS efuse later on,
|
||||
* as this is otherwise also disabled if FLASH_CRYPT_CNT is write protected.)
|
||||
*
|
||||
*/
|
||||
void esp_flash_write_protect_crypt_cnt();
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,17 +17,16 @@
|
||||
#include "esp_err.h"
|
||||
#include "esp_flash_data_types.h"
|
||||
#include <stdbool.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
/* Pre-partition table fixed flash offsets */
|
||||
#define ESP_BOOTLOADER_DIGEST_OFFSET 0x0
|
||||
#define ESP_BOOTLOADER_OFFSET 0x1000 /* Offset of bootloader image. Has matching value in bootloader KConfig.projbuild file. */
|
||||
#define ESP_PARTITION_TABLE_OFFSET CONFIG_PARTITION_TABLE_OFFSET /* Offset of partition table. Backwards-compatible name.*/
|
||||
#define ESP_PARTITION_TABLE_OFFSET 0x8000 /* Offset of partition table. Has matching value in partition_table Kconfig.projbuild file. */
|
||||
|
||||
#define ESP_PARTITION_TABLE_MAX_LEN 0xC00 /* Maximum length of partition table data */
|
||||
#define ESP_PARTITION_TABLE_MAX_ENTRIES (ESP_PARTITION_TABLE_MAX_LEN / sizeof(esp_partition_info_t)) /* Maximum length of partition table data, including terminating entry */
|
||||
|
||||
/* @brief Verify the partition table
|
||||
/* @brief Verify the partition table (does not include verifying secure boot cryptographic signature)
|
||||
*
|
||||
* @param partition_table Pointer to at least ESP_PARTITION_TABLE_MAX_ENTRIES of potential partition table data. (ESP_PARTITION_TABLE_MAX_LEN bytes.)
|
||||
* @param log_errors Log errors if the partition table is invalid.
|
||||
@@ -35,13 +34,6 @@
|
||||
*
|
||||
* @return ESP_OK on success, ESP_ERR_INVALID_STATE if partition table is not valid.
|
||||
*/
|
||||
esp_err_t esp_partition_table_verify(const esp_partition_info_t *partition_table, bool log_errors, int *num_partitions);
|
||||
|
||||
|
||||
/* This function is included for compatibility with the ESP-IDF v3.x API */
|
||||
inline static __attribute__((deprecated)) esp_err_t esp_partition_table_basic_verify(const esp_partition_info_t *partition_table, bool log_errors, int *num_partitions)
|
||||
{
|
||||
return esp_partition_table_verify(partition_table, log_errors, num_partitions);
|
||||
}
|
||||
esp_err_t esp_partition_table_basic_verify(const esp_partition_info_t *partition_table, bool log_errors, int *num_partitions);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
// 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.
|
||||
#pragma once
|
||||
#ifndef __ESP32_IMAGE_FORMAT_H
|
||||
#define __ESP32_IMAGE_FORMAT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <esp_err.h>
|
||||
#include "esp_flash_partitions.h"
|
||||
|
||||
#define ESP_ERR_IMAGE_BASE 0x2000
|
||||
#define ESP_ERR_IMAGE_FLASH_FAIL (ESP_ERR_IMAGE_BASE + 1)
|
||||
@@ -36,7 +36,7 @@ typedef enum {
|
||||
} esp_image_spi_mode_t;
|
||||
|
||||
/* SPI flash clock frequency */
|
||||
typedef enum {
|
||||
enum {
|
||||
ESP_IMAGE_SPI_SPEED_40M,
|
||||
ESP_IMAGE_SPI_SPEED_26M,
|
||||
ESP_IMAGE_SPI_SPEED_20M,
|
||||
@@ -55,47 +55,17 @@ typedef enum {
|
||||
|
||||
#define ESP_IMAGE_HEADER_MAGIC 0xE9
|
||||
|
||||
/**
|
||||
* @brief ESP chip ID
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_CHIP_ID_ESP32 = 0x0000, /*!< chip ID: ESP32 */
|
||||
ESP_CHIP_ID_INVALID = 0xFFFF /*!< Invalid chip ID (we defined it to make sure the esp_chip_id_t is 2 bytes size) */
|
||||
} __attribute__((packed)) esp_chip_id_t;
|
||||
|
||||
/** @cond */
|
||||
_Static_assert(sizeof(esp_chip_id_t) == 2, "esp_chip_id_t should be 16 bit");
|
||||
/** @endcond */
|
||||
|
||||
/* Main header of binary image */
|
||||
typedef struct {
|
||||
uint8_t magic;
|
||||
uint8_t segment_count;
|
||||
/* flash read mode (esp_image_spi_mode_t as uint8_t) */
|
||||
uint8_t spi_mode;
|
||||
/* flash frequency (esp_image_spi_freq_t as uint8_t) */
|
||||
uint8_t spi_speed: 4;
|
||||
/* flash chip size (esp_image_flash_size_t as uint8_t) */
|
||||
uint8_t spi_size: 4;
|
||||
uint8_t spi_mode; /* flash read mode (esp_image_spi_mode_t as uint8_t) */
|
||||
uint8_t spi_speed: 4; /* flash frequency (esp_image_spi_freq_t as uint8_t) */
|
||||
uint8_t spi_size: 4; /* flash chip size (esp_image_flash_size_t as uint8_t) */
|
||||
uint32_t entry_addr;
|
||||
/* WP pin when SPI pins set via efuse (read by ROM bootloader, the IDF bootloader uses software to configure the WP
|
||||
* pin and sets this field to 0xEE=disabled) */
|
||||
uint8_t wp_pin;
|
||||
/* Drive settings for the SPI flash pins (read by ROM bootloader) */
|
||||
uint8_t spi_pin_drv[3];
|
||||
esp_chip_id_t chip_id; /*!< Chip identification number */
|
||||
uint8_t min_chip_rev; /*!< Minimum chip revision supported by image */
|
||||
uint8_t reserved[8]; /*!< Reserved bytes in additional header space, currently unused */
|
||||
/* If 1, a SHA256 digest "simple hash" (of the entire image) is appended after the checksum. Included in image length. This digest
|
||||
* is separate to secure boot and only used for detecting corruption. For secure boot signed images, the signature
|
||||
* is appended after this (and the simple hash is included in the signed data). */
|
||||
uint8_t hash_appended;
|
||||
} __attribute__((packed)) esp_image_header_t;
|
||||
|
||||
_Static_assert(sizeof(esp_image_header_t) == 24, "binary image header should be 24 bytes");
|
||||
|
||||
#define ESP_IMAGE_HASH_LEN 32 /* Length of the appended SHA-256 digest */
|
||||
uint8_t encrypt_flag; /* encrypt flag */
|
||||
uint8_t extra_header[15]; /* ESP32 additional header, unused by second bootloader */
|
||||
} esp_image_header_t;
|
||||
|
||||
/* Header of binary image segment */
|
||||
typedef struct {
|
||||
@@ -103,147 +73,62 @@ typedef struct {
|
||||
uint32_t data_len;
|
||||
} esp_image_segment_header_t;
|
||||
|
||||
#define ESP_APP_DESC_MAGIC_WORD 0xABCD5432 /*!< The magic word for the esp_app_desc structure that is in DROM. */
|
||||
|
||||
/**
|
||||
* @brief Description about application.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t magic_word; /*!< Magic word ESP_APP_DESC_MAGIC_WORD */
|
||||
uint32_t secure_version; /*!< Secure version */
|
||||
uint32_t reserv1[2]; /*!< --- */
|
||||
char version[32]; /*!< Application version */
|
||||
char project_name[32]; /*!< Project name */
|
||||
char time[16]; /*!< Compile time */
|
||||
char date[16]; /*!< Compile date*/
|
||||
char idf_ver[32]; /*!< Version IDF */
|
||||
uint8_t app_elf_sha256[32]; /*!< sha256 of elf file */
|
||||
uint32_t reserv2[20]; /*!< --- */
|
||||
} esp_app_desc_t;
|
||||
_Static_assert(sizeof(esp_app_desc_t) == 256, "esp_app_desc_t should be 256 bytes");
|
||||
|
||||
#define ESP_IMAGE_MAX_SEGMENTS 16
|
||||
|
||||
/* Structure to hold on-flash image metadata */
|
||||
typedef struct {
|
||||
uint32_t start_addr; /* Start address of image */
|
||||
esp_image_header_t image; /* Header for entire image */
|
||||
esp_image_segment_header_t segments[ESP_IMAGE_MAX_SEGMENTS]; /* Per-segment header data */
|
||||
uint32_t segment_data[ESP_IMAGE_MAX_SEGMENTS]; /* Data offsets for each segment */
|
||||
uint32_t image_len; /* Length of image on flash, in bytes */
|
||||
uint8_t image_digest[32]; /* appended SHA-256 digest */
|
||||
} esp_image_metadata_t;
|
||||
|
||||
/* Mode selection for esp_image_load() */
|
||||
typedef enum {
|
||||
ESP_IMAGE_VERIFY, /* Verify image contents, load metadata. Print errors. */
|
||||
ESP_IMAGE_VERIFY_SILENT, /* Verify image contents, load metadata. Don't print errors. */
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
ESP_IMAGE_LOAD, /* Verify image contents, load to memory. Print errors. */
|
||||
#endif
|
||||
} esp_image_load_mode_t;
|
||||
|
||||
/**
|
||||
* @brief Verify and (optionally, in bootloader mode) load an app image.
|
||||
*
|
||||
* This name is deprecated and is included for compatibility with the ESP-IDF v3.x API.
|
||||
* It will be removed in V4.0 version.
|
||||
* Function has been renamed to esp_image_verify().
|
||||
* Use function esp_image_verify() to verify a image. And use function bootloader_load_image() to load image from a bootloader space.
|
||||
* @brief Read an ESP image header from flash.
|
||||
*
|
||||
* If encryption is enabled, data will be transparently decrypted.
|
||||
*
|
||||
* @param mode Mode of operation (verify, silent verify, or load).
|
||||
* @param part Partition to load the app from.
|
||||
* @param[inout] data Pointer to the image metadata structure which is be filled in by this function. 'start_addr' member should be set (to the start address of the image.) Other fields will all be initialised by this function.
|
||||
* @param src_addr Address in flash to load image header. Must be 4 byte aligned.
|
||||
* @param log_errors Log error output if image header appears invalid.
|
||||
* @param[out] image_header Pointer to an esp_image_header_t struture to be filled with data. If the function fails, contents are undefined.
|
||||
*
|
||||
* Image validation checks:
|
||||
* - Magic byte.
|
||||
* - Partition smaller than 16MB.
|
||||
* - All segments & image fit in partition.
|
||||
* - 8 bit image checksum is valid.
|
||||
* - SHA-256 of image is valid (if image has this appended).
|
||||
* - (Signature) if signature verification is enabled.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if verify or load was successful
|
||||
* - ESP_ERR_IMAGE_FLASH_FAIL if a SPI flash error occurs
|
||||
* - ESP_ERR_IMAGE_INVALID if the image appears invalid.
|
||||
* - ESP_ERR_INVALID_ARG if the partition or data pointers are invalid.
|
||||
* @return ESP_OK if image header was loaded, ESP_ERR_IMAGE_FLASH_FAIL
|
||||
* if a SPI flash error occurs, ESP_ERR_IMAGE_INVALID if the image header
|
||||
* appears invalid.
|
||||
*/
|
||||
esp_err_t esp_image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data) __attribute__((deprecated));
|
||||
esp_err_t esp_image_load_header(uint32_t src_addr, bool log_errors, esp_image_header_t *image_header);
|
||||
|
||||
/**
|
||||
* @brief Verify an app image.
|
||||
* @brief Read the segment header and data offset of a segment in the image.
|
||||
*
|
||||
* If encryption is enabled, data will be transparently decrypted.
|
||||
*
|
||||
* @param mode Mode of operation (verify, silent verify, or load).
|
||||
* @param part Partition to load the app from.
|
||||
* @param[inout] data Pointer to the image metadata structure which is be filled in by this function.
|
||||
* 'start_addr' member should be set (to the start address of the image.)
|
||||
* Other fields will all be initialised by this function.
|
||||
* @param index Index of the segment to load information for.
|
||||
* @param src_addr Base address in flash of the image.
|
||||
* @param[in] image_header Pointer to the flash image header, already loaded by @ref esp_image_load_header().
|
||||
* @param log_errors Log errors reading the segment header.
|
||||
* @param[out] segment_header Pointer to a segment header structure to be filled with data. If the function fails, contents are undefined.
|
||||
* @param[out] segment_data_offset Pointer to the data offset of the segment.
|
||||
*
|
||||
* @return ESP_OK if segment_header & segment_data_offset were loaded successfully, ESP_ERR_IMAGE_FLASH_FAIL if a SPI flash error occurs, ESP_ERR_IMAGE_INVALID if the image header appears invalid, ESP_ERR_INVALID_ARG if the index is invalid.
|
||||
*/
|
||||
esp_err_t esp_image_load_segment_header(uint8_t index, uint32_t src_addr, const esp_image_header_t *image_header, bool log_errors, esp_image_segment_header_t *segment_header, uint32_t *segment_data_offset);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Non-cryptographically validate app image integrity. On success, length of image is provided to caller.
|
||||
*
|
||||
* If the image has a secure boot signature appended, the signature is not checked and this length is not included in the
|
||||
* output value.
|
||||
*
|
||||
* Image validation checks:
|
||||
* - Magic byte.
|
||||
* - Partition smaller than 16MB.
|
||||
* - All segments & image fit in partition.
|
||||
* - 8 bit image checksum is valid.
|
||||
* - SHA-256 of image is valid (if image has this appended).
|
||||
* - (Signature) if signature verification is enabled.
|
||||
* - Magic byte
|
||||
* - No single segment longer than 16MB
|
||||
* - Total image no longer than 16MB
|
||||
* - 8 bit image checksum is valid
|
||||
*
|
||||
* If flash encryption is enabled, the image will be tranpsarently decrypted.
|
||||
*
|
||||
* @param src_addr Offset of the start of the image in flash. Must be 4 byte aligned.
|
||||
* @param allow_decrypt If true and flash encryption is enabled, the image will be transparently decrypted.
|
||||
* @param log_errors Log errors verifying the image.
|
||||
* @param[out] length Length of the image, set to a value if the image is valid. Can be null.
|
||||
*
|
||||
* @return ESP_OK if image is valid, ESP_FAIL or ESP_ERR_IMAGE_INVALID on errors.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if verify or load was successful
|
||||
* - ESP_ERR_IMAGE_FLASH_FAIL if a SPI flash error occurs
|
||||
* - ESP_ERR_IMAGE_INVALID if the image appears invalid.
|
||||
* - ESP_ERR_INVALID_ARG if the partition or data pointers are invalid.
|
||||
*/
|
||||
esp_err_t esp_image_verify(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data);
|
||||
|
||||
/**
|
||||
* @brief Verify and load an app image (available only in space of bootloader).
|
||||
*
|
||||
* If encryption is enabled, data will be transparently decrypted.
|
||||
*
|
||||
* @param part Partition to load the app from.
|
||||
* @param[inout] data Pointer to the image metadata structure which is be filled in by this function.
|
||||
* 'start_addr' member should be set (to the start address of the image.)
|
||||
* Other fields will all be initialised by this function.
|
||||
*
|
||||
* Image validation checks:
|
||||
* - Magic byte.
|
||||
* - Partition smaller than 16MB.
|
||||
* - All segments & image fit in partition.
|
||||
* - 8 bit image checksum is valid.
|
||||
* - SHA-256 of image is valid (if image has this appended).
|
||||
* - (Signature) if signature verification is enabled.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK if verify or load was successful
|
||||
* - ESP_ERR_IMAGE_FLASH_FAIL if a SPI flash error occurs
|
||||
* - ESP_ERR_IMAGE_INVALID if the image appears invalid.
|
||||
* - ESP_ERR_INVALID_ARG if the partition or data pointers are invalid.
|
||||
*/
|
||||
esp_err_t bootloader_load_image(const esp_partition_pos_t *part, esp_image_metadata_t *data);
|
||||
|
||||
/**
|
||||
* @brief Verify the bootloader image.
|
||||
*
|
||||
* @param[out] If result is ESP_OK and this pointer is non-NULL, it
|
||||
* will be set to the length of the bootloader image.
|
||||
*
|
||||
* @return As per esp_image_load_metadata().
|
||||
*/
|
||||
esp_err_t esp_image_verify_bootloader(uint32_t *length);
|
||||
|
||||
/**
|
||||
* @brief Verify the bootloader image.
|
||||
*
|
||||
* @param[out] Metadata for the image. Only valid if result is ESP_OK.
|
||||
*
|
||||
* @return As per esp_image_load_metadata().
|
||||
*/
|
||||
esp_err_t esp_image_verify_bootloader_data(esp_image_metadata_t *data);
|
||||
esp_err_t esp_image_basic_verify(uint32_t src_addr, bool log_errors, uint32_t *length);
|
||||
|
||||
|
||||
typedef struct {
|
||||
@@ -254,3 +139,5 @@ typedef struct {
|
||||
uint32_t irom_load_addr;
|
||||
uint32_t irom_size;
|
||||
} esp_image_flash_mapping_t;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -11,24 +11,13 @@
|
||||
// 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.
|
||||
#pragma once
|
||||
#ifndef __ESP32_SECUREBOOT_H
|
||||
#define __ESP32_SECUREBOOT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <esp_err.h>
|
||||
#include "soc/efuse_reg.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_ENABLED
|
||||
#if !defined(CONFIG_SECURE_SIGNED_ON_BOOT) || !defined(CONFIG_SECURE_SIGNED_ON_UPDATE) || !defined(CONFIG_SECURE_SIGNED_APPS)
|
||||
#error "internal sdkconfig error, secure boot should always enable all signature options"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Support functions for secure boot features.
|
||||
|
||||
Can be compiled as part of app or bootloader code.
|
||||
@@ -46,25 +35,6 @@ static inline bool esp_secure_boot_enabled(void) {
|
||||
return REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_RD_ABS_DONE_0;
|
||||
}
|
||||
|
||||
/** @brief Generate secure digest from bootloader image
|
||||
*
|
||||
* @important This function is intended to be called from bootloader code only.
|
||||
*
|
||||
* If secure boot is not yet enabled for bootloader, this will:
|
||||
* 1) generate the secure boot key and burn it on EFUSE
|
||||
* (without enabling R/W protection)
|
||||
* 2) generate the digest from bootloader and save it
|
||||
* to flash address 0x0
|
||||
*
|
||||
* If first boot gets interrupted after calling this function
|
||||
* but before esp_secure_boot_permanently_enable() is called, then
|
||||
* the key burned on EFUSE will not be regenerated, unless manually
|
||||
* done using espefuse.py tool
|
||||
*
|
||||
* @return ESP_OK if secure boot digest is generated
|
||||
* successfully or found to be already present
|
||||
*/
|
||||
esp_err_t esp_secure_boot_generate_digest(void);
|
||||
|
||||
/** @brief Enable secure boot if it is not already enabled.
|
||||
*
|
||||
@@ -73,13 +43,9 @@ esp_err_t esp_secure_boot_generate_digest(void);
|
||||
*
|
||||
* @important This function is intended to be called from bootloader code only.
|
||||
*
|
||||
* @important This will enable r/w protection of secure boot key on EFUSE,
|
||||
* therefore it is to be ensured that esp_secure_boot_generate_digest()
|
||||
* is called before this
|
||||
*
|
||||
* If secure boot is not yet enabled for bootloader, this will
|
||||
* 1) enable R/W protection of secure boot key on EFUSE
|
||||
* 2) enable secure boot by blowing the EFUSE_RD_ABS_DONE_0 efuse.
|
||||
* generate the secure boot digest and enable secure boot by blowing
|
||||
* the EFUSE_RD_ABS_DONE_0 efuse.
|
||||
*
|
||||
* This function does not verify secure boot of the bootloader (the
|
||||
* ROM bootloader does this.)
|
||||
@@ -87,6 +53,7 @@ esp_err_t esp_secure_boot_generate_digest(void);
|
||||
* Will fail if efuses have been part-burned in a way that indicates
|
||||
* secure boot should not or could not be correctly enabled.
|
||||
*
|
||||
*
|
||||
* @return ESP_ERR_INVALID_STATE if efuse state doesn't allow
|
||||
* secure boot to be enabled cleanly. ESP_OK if secure boot
|
||||
* is enabled on this chip from now on.
|
||||
@@ -107,22 +74,12 @@ esp_err_t esp_secure_boot_permanently_enable(void);
|
||||
*/
|
||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length);
|
||||
|
||||
/** @brief Verify the secure boot signature block (deterministic ECDSA w/ SHA256) based on the SHA256 hash of some data.
|
||||
*
|
||||
* Similar to esp_secure_boot_verify_signature(), but can be used when the digest is precalculated.
|
||||
* @param sig_block Pointer to signature block data
|
||||
* @param image_digest Pointer to 32 byte buffer holding SHA-256 hash.
|
||||
*
|
||||
*/
|
||||
|
||||
/** @brief Secure boot verification block, on-flash data format. */
|
||||
typedef struct {
|
||||
uint32_t version;
|
||||
uint8_t signature[64];
|
||||
} esp_secure_boot_sig_block_t;
|
||||
|
||||
esp_err_t esp_secure_boot_verify_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest);
|
||||
|
||||
#define FLASH_OFFS_SECURE_BOOT_IV_DIGEST 0
|
||||
|
||||
/** @brief Secure boot IV+digest header */
|
||||
@@ -131,7 +88,4 @@ typedef struct {
|
||||
uint8_t digest[64];
|
||||
} esp_secure_boot_iv_digest_t;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// 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.
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
/* @brief Prepares hardware for work.
|
||||
*
|
||||
* Setting up:
|
||||
* - Disable Cache access for both CPUs;
|
||||
* - Initialise cache mmu;
|
||||
* - Setting up pins and mode for SD, SPI, UART, Clocking.
|
||||
|
||||
* @return ESP_OK - If the setting is successful.
|
||||
* ESP_FAIL - If the setting is not successful.
|
||||
*/
|
||||
esp_err_t bootloader_init();
|
||||
@@ -1,56 +0,0 @@
|
||||
// Copyright 2017 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// 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.
|
||||
#pragma once
|
||||
|
||||
/* Provide a SHA256 API for bootloader_support code,
|
||||
that can be used from bootloader or app code.
|
||||
|
||||
This header is available to source code in the bootloader & bootloader_support components only.
|
||||
Use mbedTLS APIs or include hwcrypto/sha.h to calculate SHA256 in IDF apps.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
typedef void *bootloader_sha256_handle_t;
|
||||
|
||||
bootloader_sha256_handle_t bootloader_sha256_start(void);
|
||||
|
||||
void bootloader_sha256_data(bootloader_sha256_handle_t handle, const void *data, size_t data_len);
|
||||
|
||||
void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest);
|
||||
|
||||
/**
|
||||
* @brief Converts an array to a printable string.
|
||||
*
|
||||
* This function is useful for printing SHA-256 digest.
|
||||
* \code{c}
|
||||
* // Example of using. image_hash will be printed
|
||||
* #define HASH_LEN 32 // SHA-256 digest length
|
||||
* ...
|
||||
* char hash_print[HASH_LEN * 2 + 1];
|
||||
* hash_print[HASH_LEN * 2] = 0;
|
||||
* bootloader_sha256_hex_to_str(hash_print, image_hash, HASH_LEN);
|
||||
* ESP_LOGI(TAG, %s", hash_print);
|
||||
* \endcode
|
||||
|
||||
* @param[out] out_str Output string
|
||||
* @param[in] in_array_hex Pointer to input array
|
||||
* @param[in] len Length of input array
|
||||
*
|
||||
* @return ESP_OK: Successful
|
||||
* ESP_ERR_INVALID_ARG: Error in the passed arguments
|
||||
*/
|
||||
esp_err_t bootloader_sha256_hex_to_str(char *out_str, const uint8_t *in_array_hex, size_t len);
|
||||
@@ -1,78 +0,0 @@
|
||||
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// 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.
|
||||
#pragma once
|
||||
|
||||
#include "esp_image_format.h"
|
||||
|
||||
/**
|
||||
* @brief Load partition table.
|
||||
*
|
||||
* Parse partition table, get useful data such as location of
|
||||
* OTA data partition, factory app partition, and test app partition.
|
||||
*
|
||||
* @param[out] bs Bootloader state structure used to save read data.
|
||||
* @return Return true if the partition table was succesfully loaded and MD5 checksum is valid.
|
||||
*/
|
||||
bool bootloader_utility_load_partition_table(bootloader_state_t* bs);
|
||||
|
||||
/**
|
||||
* @brief Return the index of the selected boot partition.
|
||||
*
|
||||
* This is the preferred boot partition, as determined by the partition table &
|
||||
* any OTA sequence number found in OTA data.
|
||||
* This partition will only be booted if it contains a valid app image, otherwise load_boot_image() will search
|
||||
* for a valid partition using this selection as the starting point.
|
||||
*
|
||||
* @param[in] bs Bootloader state structure.
|
||||
* @return Returns the index on success, INVALID_INDEX otherwise.
|
||||
*/
|
||||
int bootloader_utility_get_selected_boot_partition(const bootloader_state_t *bs);
|
||||
|
||||
/**
|
||||
* @brief Load the selected partition and start application.
|
||||
*
|
||||
* Start from partition 'start_index', if not bootable then work backwards to FACTORY_INDEX
|
||||
* (ie try any OTA slots in descending order and then the factory partition).
|
||||
* If still nothing, start from 'start_index + 1' and work up to highest numbered OTA partition.
|
||||
* If still nothing, try TEST_APP_INDEX.
|
||||
* Everything this function calls must be located in the iram_loader_seg segment.
|
||||
*
|
||||
* @param[in] bs Bootloader state structure.
|
||||
* @param[in] start_index The index from which the search for images begins.
|
||||
*/
|
||||
__attribute__((noreturn)) void bootloader_utility_load_boot_image(const bootloader_state_t *bs, int start_index);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Software reset the ESP32
|
||||
*
|
||||
* Bootloader code should call this in the case that it cannot proceed.
|
||||
*
|
||||
* It is not recommended to call this function from an app (if called, the app will abort).
|
||||
*/
|
||||
__attribute__((noreturn)) void bootloader_reset(void);
|
||||
|
||||
/** @brief Generates the digest of the data between offset & offset+length.
|
||||
*
|
||||
* This function should be used when the size of the data is larger than 3.2MB.
|
||||
* The MMU capacity is 3.2MB (50 pages - 64KB each). This function generates the SHA-256
|
||||
* of the data in chunks of 3.2MB, considering the MMU capacity.
|
||||
*
|
||||
* @param[in] flash_offset Offset of the data in flash.
|
||||
* @param[in] len Length of data in bytes.
|
||||
* @param[out] digest Pointer to buffer where the digest is written, if ESP_OK is returned.
|
||||
*
|
||||
* @return ESP_OK if secure boot digest is generated successfully.
|
||||
*/
|
||||
esp_err_t bootloader_sha256_flash_contents(uint32_t flash_offset, uint32_t len, uint8_t *digest);
|
||||
@@ -21,8 +21,6 @@
|
||||
#include "esp_spi_flash.h"
|
||||
|
||||
#define FLASH_SECTOR_SIZE 0x1000
|
||||
#define FLASH_BLOCK_SIZE 0x10000
|
||||
#define MMAP_ALIGNED_MASK 0x0000FFFF
|
||||
|
||||
/* Provide a Flash API for bootloader_support code,
|
||||
that can be used from bootloader or app code.
|
||||
@@ -31,13 +29,6 @@
|
||||
bootloader_support components only.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Get number of free pages
|
||||
*
|
||||
* @return Number of free pages
|
||||
*/
|
||||
uint32_t bootloader_mmap_get_free_pages(void);
|
||||
|
||||
/**
|
||||
* @brief Map a region of flash to data memory
|
||||
*
|
||||
@@ -109,31 +100,4 @@ esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool
|
||||
*/
|
||||
esp_err_t bootloader_flash_erase_sector(size_t sector);
|
||||
|
||||
/**
|
||||
* @brief Erase the Flash range.
|
||||
*
|
||||
* @param start_addr start address of flash offset
|
||||
* @param size sector aligned size to be erased
|
||||
*
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size);
|
||||
|
||||
/* Cache MMU block size */
|
||||
#define MMU_BLOCK_SIZE 0x00010000
|
||||
|
||||
/* Cache MMU address mask (MMU tables ignore bits which are zero) */
|
||||
#define MMU_FLASH_MASK (~(MMU_BLOCK_SIZE - 1))
|
||||
|
||||
/**
|
||||
* @brief Calculate the number of cache pages to map
|
||||
* @param size size of data to map
|
||||
* @param vaddr virtual address where data will be mapped
|
||||
* @return number of cache MMU pages required to do the mapping
|
||||
*/
|
||||
static inline uint32_t bootloader_cache_pages_to_map(uint32_t size, uint32_t vaddr)
|
||||
{
|
||||
return (size + (vaddr - (vaddr & MMU_FLASH_MASK)) + MMU_BLOCK_SIZE - 1) / MMU_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user