forked from espressif/esp-idf
Compare commits
343 Commits
release/v4
...
v3.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ccb4cf5b7 | ||
|
|
f8e24754d1 | ||
|
|
86975b7e8f | ||
|
|
c2bb7d7cd6 | ||
|
|
cc3ba7186f | ||
|
|
7d28c02fd5 | ||
|
|
3becdd7850 | ||
|
|
ef11260310 | ||
|
|
7b39d5e5c5 | ||
|
|
d5b0b36758 | ||
|
|
0a609be968 | ||
|
|
148a269808 | ||
|
|
5b11428f00 | ||
|
|
4cd7fd89f5 | ||
|
|
ceb56a7a72 | ||
|
|
ebfa74310c | ||
|
|
b482ba117d | ||
|
|
07735424a2 | ||
|
|
f2f5a237c0 | ||
|
|
3be1c70d46 | ||
|
|
beb34b5390 | ||
|
|
3991084777 | ||
|
|
088439c634 | ||
|
|
dbd05d8986 | ||
|
|
7c5dd19c83 | ||
|
|
a6fb161309 | ||
|
|
0929dbbc9b | ||
|
|
4c27f9ced8 | ||
|
|
b800dfe6f1 | ||
|
|
caa1ef0cb6 | ||
|
|
97e7c14f4e | ||
|
|
c157c696e7 | ||
|
|
d900cb5a35 | ||
|
|
4cb729283d | ||
|
|
6a3e160aaf | ||
|
|
70ecb7ec94 | ||
|
|
21e2c417e8 | ||
|
|
3ca82d5923 | ||
|
|
7af04d857f | ||
|
|
e070e1886f | ||
|
|
6da2bec1e8 | ||
|
|
73345bae44 | ||
|
|
2d26163019 | ||
|
|
ff2624f09c | ||
|
|
11d141e87d | ||
|
|
91f29bef17 | ||
|
|
8ed62223cd | ||
|
|
de7a50dca0 | ||
|
|
a9eac4a124 | ||
|
|
3e27184c38 | ||
|
|
5758b739f1 | ||
|
|
2d7124e319 | ||
|
|
232408981d | ||
|
|
9821e533db | ||
|
|
6d8990f39b | ||
|
|
83a9a4dc70 | ||
|
|
630ffde6bb | ||
|
|
6af30250a8 | ||
|
|
30d2f13358 | ||
|
|
d7569b5862 | ||
|
|
db9979701a | ||
|
|
dca5ed2263 | ||
|
|
0ef3af367d | ||
|
|
9afe47425b | ||
|
|
f5d33fa889 | ||
|
|
29cef5a9cc | ||
|
|
40171d7307 | ||
|
|
e64bae3a0c | ||
|
|
a71fad46d4 | ||
|
|
2c9acce0ff | ||
|
|
8e58b31a69 | ||
|
|
bf152907a4 | ||
|
|
47ca5d53df | ||
|
|
c1fe8ceb83 | ||
|
|
db38c37cf7 | ||
|
|
71ce87c79e | ||
|
|
611c300a92 | ||
|
|
b7eb82d191 | ||
|
|
933674301f | ||
|
|
3b2e231ae3 | ||
|
|
881cd4310c | ||
|
|
13e6e9f592 | ||
|
|
cfc73a6de7 | ||
|
|
62e359a4e1 | ||
|
|
ab4024c84e | ||
|
|
f4ee20165e | ||
|
|
e443467f37 | ||
|
|
a6f990ffb9 | ||
|
|
43561a40d2 | ||
|
|
55f5c2e08d | ||
|
|
e4418f4f92 | ||
|
|
968728bf95 | ||
|
|
2073a6e738 | ||
|
|
95b72a96f8 | ||
|
|
2617dee69f | ||
|
|
f94db7bba7 | ||
|
|
f7f02c9a43 | ||
|
|
52f0b86965 | ||
|
|
12bbe0f39b | ||
|
|
536b2d8a65 | ||
|
|
f5ab51c9b7 | ||
|
|
8a5c712730 | ||
|
|
2287c28b41 | ||
|
|
129ac11c31 | ||
|
|
166918e802 | ||
|
|
4b028cca86 | ||
|
|
a9d266b921 | ||
|
|
dc9c2f3b60 | ||
|
|
ae1389afd9 | ||
|
|
92f1d7ae39 | ||
|
|
f73c972280 | ||
|
|
378a5b159a | ||
|
|
2ef218059b | ||
|
|
28a8349fb8 | ||
|
|
4acc941c3d | ||
|
|
4ae01f0c9d | ||
|
|
2c4e0cf878 | ||
|
|
4b739249c2 | ||
|
|
b3f4755ac2 | ||
|
|
9185c370dc | ||
|
|
b62182d75a | ||
|
|
890a341db4 | ||
|
|
04815c2d27 | ||
|
|
0af6d8ffe3 | ||
|
|
43b2563f5a | ||
|
|
16586524e9 | ||
|
|
f60acb2196 | ||
|
|
1d2a9efa55 | ||
|
|
5ab4a9da51 | ||
|
|
b63be2e08e | ||
|
|
6cf4e14671 | ||
|
|
39f7d1ad0b | ||
|
|
d3a29c2d08 | ||
|
|
31a8a488f0 | ||
|
|
b908d4325b | ||
|
|
54c148d289 | ||
|
|
60b937b5ca | ||
|
|
b816edac3c | ||
|
|
2ee0f98d05 | ||
|
|
f83296e448 | ||
|
|
09515bdfde | ||
|
|
081b623a34 | ||
|
|
871e95087e | ||
|
|
a3b3f9ae2d | ||
|
|
fb6f343ce5 | ||
|
|
e1069de9aa | ||
|
|
a219e9f819 | ||
|
|
8f8113f5cd | ||
|
|
cf3647fe40 | ||
|
|
06651c0951 | ||
|
|
d54fadef41 | ||
|
|
3b4353da5d | ||
|
|
261c5bf6a8 | ||
|
|
6132d7bce3 | ||
|
|
1db04ae574 | ||
|
|
6d4adb46f3 | ||
|
|
e681f449bc | ||
|
|
f3725a7821 | ||
|
|
34f6773471 | ||
|
|
d0e7fd4369 | ||
|
|
13a3edee8a | ||
|
|
56866567ae | ||
|
|
bc83d470e3 | ||
|
|
a298d32d65 | ||
|
|
172a216edb | ||
|
|
d5923f0e2e | ||
|
|
cd9249970f | ||
|
|
676a27c7cf | ||
|
|
33121c3311 | ||
|
|
38509b2b95 | ||
|
|
e821c22a8c | ||
|
|
8c363321db | ||
|
|
ce279988c3 | ||
|
|
7200b8bf77 | ||
|
|
7e5cd986a9 | ||
|
|
fa1e983028 | ||
|
|
71e344da20 | ||
|
|
620bba3a66 | ||
|
|
8f7f32c0a5 | ||
|
|
3cbbc3bbac | ||
|
|
5c42c831f5 | ||
|
|
8c57aa0242 | ||
|
|
0d5609ba92 | ||
|
|
e209307297 | ||
|
|
4ac347b295 | ||
|
|
fc3aa765cf | ||
|
|
31c94b25c5 | ||
|
|
5b8d1c9da3 | ||
|
|
7f784c84d2 | ||
|
|
532c8847c7 | ||
|
|
6dc31101ce | ||
|
|
7d9330d1af | ||
|
|
618aa6a3a4 | ||
|
|
762bf705bb | ||
|
|
5988e77a3a | ||
|
|
26e7f3fde6 | ||
|
|
ba2ff1876f | ||
|
|
0757e019f4 | ||
|
|
c68390f922 | ||
|
|
8e3a1876cb | ||
|
|
cc8652d8d2 | ||
|
|
3cd8538f53 | ||
|
|
0033b31442 | ||
|
|
56afb3bd1c | ||
|
|
e622ee0f41 | ||
|
|
2d50291b05 | ||
|
|
c9b1e1df60 | ||
|
|
9a72c11e6e | ||
|
|
39dbe7daa8 | ||
|
|
554a28e8a1 | ||
|
|
7a2885885c | ||
|
|
d154723a84 | ||
|
|
16918e400e | ||
|
|
510f726935 | ||
|
|
3295ed0995 | ||
|
|
924895f832 | ||
|
|
403268a13a | ||
|
|
6b3da6b188 | ||
|
|
93b4c71595 | ||
|
|
d6badc53eb | ||
|
|
cb7aaae35e | ||
|
|
18533e132a | ||
|
|
7a7128c7a3 | ||
|
|
208d87742c | ||
|
|
dd76df7aee | ||
|
|
deba35d2e5 | ||
|
|
9fdc36ed57 | ||
|
|
184f2f0fd6 | ||
|
|
b36f4aa813 | ||
|
|
4b6ac69c04 | ||
|
|
c7d73901d0 | ||
|
|
76cc8c1c0c | ||
|
|
38a2be75a9 | ||
|
|
c85fc16282 | ||
|
|
ab888394c3 | ||
|
|
b8a2b77f70 | ||
|
|
ef8341b5bc | ||
|
|
c31217d193 | ||
|
|
16a56e2e7a | ||
|
|
1b3c6fb1a1 | ||
|
|
f7177095cf | ||
|
|
0e89436769 | ||
|
|
40067fb50f | ||
|
|
167c21b987 | ||
|
|
a2f00b0adf | ||
|
|
feecafeb0e | ||
|
|
7bbbf2d4b3 | ||
|
|
21fb5085bd | ||
|
|
82a80005b9 | ||
|
|
b354c11db7 | ||
|
|
e5672e5d7f | ||
|
|
3e972a3ffe | ||
|
|
8bd09fb0a5 | ||
|
|
e90c90d1f6 | ||
|
|
2f72645320 | ||
|
|
4be28a798f | ||
|
|
eed94b87e2 | ||
|
|
a218d4b925 | ||
|
|
015f523939 | ||
|
|
7196573605 | ||
|
|
4a698ffb75 | ||
|
|
3368783bf0 | ||
|
|
7e0e514127 | ||
|
|
541c267af3 | ||
|
|
bbfe9f4efa | ||
|
|
9bd172356e | ||
|
|
1b8dd9f173 | ||
|
|
dd33cec716 | ||
|
|
1cb29ac446 | ||
|
|
7b368fc211 | ||
|
|
d6ceb4a31a | ||
|
|
d5f9eb65e9 | ||
|
|
ce3d20dcd2 | ||
|
|
1dc461ba80 | ||
|
|
f03382b0ff | ||
|
|
2ecd007974 | ||
|
|
c6e32c1a61 | ||
|
|
2f26bb2e65 | ||
|
|
3be2b430d1 | ||
|
|
ff01bcfd88 | ||
|
|
8442255ccc | ||
|
|
c92e677da4 | ||
|
|
6d2faf4172 | ||
|
|
826146e985 | ||
|
|
2faf3c9c34 | ||
|
|
3fedc3eb28 | ||
|
|
4148beca50 | ||
|
|
c71b38c467 | ||
|
|
8e2b189252 | ||
|
|
dca83700f2 | ||
|
|
37e131f76b | ||
|
|
c76f00373f | ||
|
|
24a713b3c4 | ||
|
|
88fe438524 | ||
|
|
7f1fd0b8d3 | ||
|
|
2c91bc7a50 | ||
|
|
3cec8d0122 | ||
|
|
6381817006 | ||
|
|
14a6b33d5e | ||
|
|
6505f82a80 | ||
|
|
c05a0ae6c3 | ||
|
|
2a9555f5dd | ||
|
|
f72df315f7 | ||
|
|
e7a263938b | ||
|
|
3ed0f8e113 | ||
|
|
7e1ccb56a7 | ||
|
|
50a0b00afa | ||
|
|
be8f34065d | ||
|
|
d0eab0f3ee | ||
|
|
7a530be302 | ||
|
|
b692bda09b | ||
|
|
e4a83f856e | ||
|
|
e25152a031 | ||
|
|
885aec7aba | ||
|
|
0c2419d798 | ||
|
|
a3a58546bc | ||
|
|
2f2f0fbcbd | ||
|
|
ec4c75b692 | ||
|
|
90ddbaac16 | ||
|
|
0176f912b6 | ||
|
|
615376d14a | ||
|
|
fe516fb7c2 | ||
|
|
f5c805160b | ||
|
|
00e3f7f6b6 | ||
|
|
d6b316c375 | ||
|
|
bc04b1f53b | ||
|
|
50ceb45e6f | ||
|
|
646c7a7515 | ||
|
|
cc7e91e1a3 | ||
|
|
725f0a7545 | ||
|
|
bd0984226e | ||
|
|
f330bb50b2 | ||
|
|
4f1e27fa76 | ||
|
|
16755a2c51 | ||
|
|
936b99d756 | ||
|
|
c88cc4950e | ||
|
|
54e5e440b1 | ||
|
|
e8bcda3512 | ||
|
|
35a30072f4 | ||
|
|
edb0374b9d | ||
|
|
78539acdd1 | ||
|
|
a1546e0714 | ||
|
|
8ff6afd29f |
17
.flake8
17
.flake8
@@ -140,16 +140,15 @@ exclude =
|
||||
.git,
|
||||
__pycache__,
|
||||
# submodules
|
||||
components/bootloader/subproject/components/micro-ecc/micro-ecc,
|
||||
components/esptool_py/esptool,
|
||||
components/expat/expat,
|
||||
components/json/cJSON,
|
||||
components/libsodium/libsodium,
|
||||
components/mbedtls/mbedtls,
|
||||
components/micro-ecc/micro-ecc,
|
||||
components/nghttp/nghttp2,
|
||||
components/bt/host/nimble/nimble,
|
||||
components/libsodium/libsodium,
|
||||
components/json/cJSON,
|
||||
components/mbedtls/mbedtls,
|
||||
components/expat/expat,
|
||||
components/unity/unity,
|
||||
examples/build_system/cmake/import_lib/main/lib/tinyxml2,
|
||||
examples/build_system/cmake/import_lib/main/lib/tinyxml2
|
||||
# other third-party libraries
|
||||
tools/kconfig_new/kconfiglib.py,
|
||||
# autogenerated scripts
|
||||
@@ -160,5 +159,7 @@ exclude =
|
||||
components/wifi_provisioning/python/wifi_scan_pb2.py,
|
||||
components/wifi_provisioning/python/wifi_config_pb2.py,
|
||||
components/wifi_provisioning/python/wifi_constants_pb2.py,
|
||||
components/esp_local_ctrl/python/esp_local_ctrl_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,
|
||||
|
||||
7
.github/main.workflow
vendored
7
.github/main.workflow
vendored
@@ -3,16 +3,11 @@ workflow "Sync issues to JIRA" {
|
||||
resolves = ["Sync to JIRA"]
|
||||
}
|
||||
|
||||
workflow "Sync issue and PR comments to JIRA" {
|
||||
workflow "Sync issue comments to JIRA" {
|
||||
on = "issue_comment"
|
||||
resolves = ["Sync to JIRA"]
|
||||
}
|
||||
|
||||
workflow "Sync PRs to JIRA" {
|
||||
on = "pull_request"
|
||||
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"]
|
||||
|
||||
17
.github/workflows/release_zips.yml
vendored
17
.github/workflows/release_zips.yml
vendored
@@ -1,17 +0,0 @@
|
||||
name: Create zip file with recursive source clone for release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
|
||||
jobs:
|
||||
release_zips:
|
||||
name: Create release zip file
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Create a recursive clone source zip
|
||||
uses: espressif/github-actions/release_zips@master
|
||||
env:
|
||||
RELEASE_PROJECT_NAME: ESP-IDF
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
14
.gitignore
vendored
14
.gitignore
vendored
@@ -36,10 +36,6 @@ docs/*/xml_in/
|
||||
docs/*/man/
|
||||
docs/doxygen_sqlite3.db
|
||||
|
||||
# Downloaded font files
|
||||
docs/_static/DejaVuSans.ttf
|
||||
docs/_static/NotoSansSC-Regular.otf
|
||||
|
||||
# Unit test app files
|
||||
tools/unit-test-app/sdkconfig
|
||||
tools/unit-test-app/sdkconfig.old
|
||||
@@ -52,12 +48,22 @@ 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
|
||||
|
||||
1346
.gitlab-ci.yml
1346
.gitlab-ci.yml
File diff suppressed because it is too large
Load Diff
@@ -1,6 +0,0 @@
|
||||
# For the syntax of this file, see:
|
||||
#
|
||||
# https://docs.gitlab.com/ee/user/project/code_owners.html#the-syntax-of-code-owners-files
|
||||
#
|
||||
|
||||
* @esp-idf-codeowners/all-maintainers
|
||||
59
.gitmodules
vendored
59
.gitmodules
vendored
@@ -1,76 +1,71 @@
|
||||
#
|
||||
# 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 = 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/controller/lib"]
|
||||
path = components/bt/controller/lib
|
||||
url = ../../espressif/esp32-bt-lib.git
|
||||
[submodule "components/bt/lib"]
|
||||
path = components/bt/lib
|
||||
url = https://github.com/espressif/esp32-bt-lib.git
|
||||
|
||||
[submodule "components/bootloader/subproject/components/micro-ecc/micro-ecc"]
|
||||
path = components/bootloader/subproject/components/micro-ecc/micro-ecc
|
||||
url = ../../kmackay/micro-ecc.git
|
||||
[submodule "components/micro-ecc/micro-ecc"]
|
||||
path = components/micro-ecc/micro-ecc
|
||||
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 = 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
|
||||
url = https://github.com/jedisct1/libsodium.git
|
||||
|
||||
[submodule "components/spiffs/spiffs"]
|
||||
path = components/spiffs/spiffs
|
||||
url = ../../pellepl/spiffs.git
|
||||
url = https://github.com/pellepl/spiffs.git
|
||||
|
||||
[submodule "components/json/cJSON"]
|
||||
path = components/json/cJSON
|
||||
url = ../../DaveGamble/cJSON.git
|
||||
url = https://github.com/DaveGamble/cJSON.git
|
||||
|
||||
[submodule "components/mbedtls/mbedtls"]
|
||||
path = components/mbedtls/mbedtls
|
||||
url = ../../espressif/mbedtls.git
|
||||
url = https://github.com/espressif/mbedtls.git
|
||||
|
||||
[submodule "components/asio/asio"]
|
||||
path = components/asio/asio
|
||||
url = ../../espressif/asio.git
|
||||
url = https://github.com/espressif/asio.git
|
||||
|
||||
[submodule "components/expat/expat"]
|
||||
path = components/expat/expat
|
||||
url = ../../libexpat/libexpat.git
|
||||
url = https://github.com/libexpat/libexpat.git
|
||||
|
||||
[submodule "components/lwip/lwip"]
|
||||
path = components/lwip/lwip
|
||||
url = ../../espressif/esp-lwip.git
|
||||
url = https://github.com/espressif/esp-lwip.git
|
||||
|
||||
[submodule "components/mqtt/esp-mqtt"]
|
||||
path = components/mqtt/esp-mqtt
|
||||
url = ../../espressif/esp-mqtt.git
|
||||
url = https://github.com/espressif/esp-mqtt.git
|
||||
|
||||
[submodule "components/protobuf-c/protobuf-c"]
|
||||
path = components/protobuf-c/protobuf-c
|
||||
url = ../../protobuf-c/protobuf-c.git
|
||||
url = https://github.com/protobuf-c/protobuf-c
|
||||
|
||||
[submodule "components/unity/unity"]
|
||||
path = components/unity/unity
|
||||
url = ../../ThrowTheSwitch/Unity.git
|
||||
url = https://github.com/ThrowTheSwitch/Unity
|
||||
|
||||
[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/esp_wifi/lib_esp32"]
|
||||
path = components/esp_wifi/lib_esp32
|
||||
url = ../../espressif/esp32-wifi-lib.git
|
||||
|
||||
[submodule "components/bt/host/nimble/nimble"]
|
||||
path = components/bt/host/nimble/nimble
|
||||
url = ../../espressif/esp-nimble.git
|
||||
url = https://github.com/leethomason/tinyxml2
|
||||
|
||||
@@ -15,7 +15,7 @@ python:
|
||||
install:
|
||||
- requirements: docs/requirements.txt
|
||||
|
||||
# We need to list all the submodules included in documenation build by DOxygen
|
||||
# We need to list all the submodules included in documentation build by Doxygen
|
||||
submodules:
|
||||
include:
|
||||
- components/mqtt/esp-mqtt
|
||||
226
CMakeLists.txt
226
CMakeLists.txt
@@ -1,99 +1,161 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(esp-idf C CXX ASM)
|
||||
|
||||
if(CMAKE_CURRENT_LIST_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
message(FATAL_ERROR "Current directory '${CMAKE_CURRENT_LIST_DIR}' is not buildable. "
|
||||
"Change directories to one of the example projects in '${CMAKE_CURRENT_LIST_DIR}/examples' and try "
|
||||
"again.")
|
||||
if(NOT IDF_PATH)
|
||||
set(IDF_PATH ${CMAKE_CURRENT_LIST_DIR})
|
||||
endif()
|
||||
|
||||
unset(compile_options)
|
||||
unset(c_compile_options)
|
||||
unset(cxx_compile_options)
|
||||
unset(compile_definitions)
|
||||
unset(link_options)
|
||||
include(tools/cmake/idf_functions.cmake)
|
||||
|
||||
# Add the following build specifications here, since these seem to be dependent
|
||||
# on config values on the root Kconfig.
|
||||
#
|
||||
# Set variables that control the build configuration and the build itself
|
||||
#
|
||||
idf_set_variables()
|
||||
|
||||
if(CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE)
|
||||
list(APPEND compile_options "-Os")
|
||||
list(APPEND compile_options "-freorder-blocks")
|
||||
else()
|
||||
list(APPEND compile_options "-Og")
|
||||
kconfig_set_variables()
|
||||
|
||||
#
|
||||
# Generate a component dependencies file, enumerating components to be included in the build
|
||||
# as well as their dependencies.
|
||||
#
|
||||
execute_process(COMMAND "${CMAKE_COMMAND}"
|
||||
-D "COMPONENTS=${IDF_COMPONENTS}"
|
||||
-D "COMPONENT_REQUIRES_COMMON=${IDF_COMPONENT_REQUIRES_COMMON}"
|
||||
-D "EXCLUDE_COMPONENTS=${IDF_EXCLUDE_COMPONENTS}"
|
||||
-D "TEST_COMPONENTS=${IDF_TEST_COMPONENTS}"
|
||||
-D "TEST_EXCLUDE_COMPONENTS=${IDF_TEST_EXCLUDE_COMPONENTS}"
|
||||
-D "BUILD_TESTS=${IDF_BUILD_TESTS}"
|
||||
-D "DEPENDENCIES_FILE=${CMAKE_BINARY_DIR}/component_depends.cmake"
|
||||
-D "COMPONENT_DIRS=${IDF_COMPONENT_DIRS}"
|
||||
-D "BOOTLOADER_BUILD=${BOOTLOADER_BUILD}"
|
||||
-D "IDF_TARGET=${IDF_TARGET}"
|
||||
-D "IDF_PATH=${IDF_PATH}"
|
||||
-D "DEBUG=${DEBUG}"
|
||||
-P "${IDF_PATH}/tools/cmake/scripts/expand_requirements.cmake"
|
||||
WORKING_DIRECTORY "${PROJECT_PATH}"
|
||||
RESULT_VARIABLE expand_requirements_result)
|
||||
|
||||
if(expand_requirements_result)
|
||||
message(FATAL_ERROR "Failed to expand component requirements")
|
||||
endif()
|
||||
|
||||
if(CONFIG_COMPILER_CXX_EXCEPTIONS)
|
||||
list(APPEND cxx_compile_options "-fexceptions")
|
||||
else()
|
||||
list(APPEND cxx_compile_options "-fno-exceptions")
|
||||
include("${CMAKE_BINARY_DIR}/component_depends.cmake")
|
||||
|
||||
#
|
||||
# We now have the following component-related variables:
|
||||
#
|
||||
# IDF_COMPONENTS is the list of initial components set by the user
|
||||
# (or empty to include all components in the build).
|
||||
# BUILD_COMPONENTS is the list of components to include in the build.
|
||||
# BUILD_COMPONENT_PATHS is the paths to all of these components, obtained from the component dependencies file.
|
||||
#
|
||||
# Print the list of found components and test components
|
||||
#
|
||||
string(REPLACE ";" " " BUILD_COMPONENTS_SPACES "${BUILD_COMPONENTS}")
|
||||
message(STATUS "Component names: ${BUILD_COMPONENTS_SPACES}")
|
||||
unset(BUILD_COMPONENTS_SPACES)
|
||||
message(STATUS "Component paths: ${BUILD_COMPONENT_PATHS}")
|
||||
|
||||
# Print list of test components
|
||||
if(TESTS_ALL EQUAL 1 OR TEST_COMPONENTS)
|
||||
string(REPLACE ";" " " BUILD_TEST_COMPONENTS_SPACES "${BUILD_TEST_COMPONENTS}")
|
||||
message(STATUS "Test component names: ${BUILD_TEST_COMPONENTS_SPACES}")
|
||||
unset(BUILD_TEST_COMPONENTS_SPACES)
|
||||
message(STATUS "Test component paths: ${BUILD_TEST_COMPONENT_PATHS}")
|
||||
endif()
|
||||
|
||||
if(CONFIG_COMPILER_CXX_RTTI)
|
||||
list(APPEND cxx_compile_options "-frtti")
|
||||
else()
|
||||
list(APPEND cxx_compile_options "-fno-rtti")
|
||||
list(APPEND link_options "-fno-rtti") # used to invoke correct multilib variant (no-rtti) during linking
|
||||
# Generate project configuration
|
||||
kconfig_process_config()
|
||||
|
||||
# Include sdkconfig.cmake so rest of the build knows the configuration
|
||||
include(${SDKCONFIG_CMAKE})
|
||||
|
||||
# Verify the environment is configured correctly
|
||||
idf_verify_environment()
|
||||
|
||||
# Check git revision (may trigger reruns of cmake)
|
||||
## sets IDF_VER to IDF git revision
|
||||
idf_get_git_revision()
|
||||
|
||||
# Check that the targets set in cache, sdkconfig, and in environment all match
|
||||
idf_check_config_target()
|
||||
|
||||
## get PROJECT_VER
|
||||
if(NOT BOOTLOADER_BUILD)
|
||||
app_get_revision("${CMAKE_SOURCE_DIR}")
|
||||
endif()
|
||||
|
||||
if(CONFIG_COMPILER_DISABLE_GCC8_WARNINGS)
|
||||
list(APPEND compile_options "-Wno-parentheses"
|
||||
"-Wno-sizeof-pointer-memaccess"
|
||||
"-Wno-clobbered")
|
||||
# Add some idf-wide definitions
|
||||
idf_set_global_compile_options()
|
||||
|
||||
# doesn't use GCC_NOT_5_2_0 because idf_set_global_variables was not called before
|
||||
if(GCC_NOT_5_2_0)
|
||||
list(APPEND compile_options "-Wno-format-overflow"
|
||||
"-Wno-stringop-truncation"
|
||||
"-Wno-misleading-indentation"
|
||||
"-Wno-cast-function-type"
|
||||
"-Wno-implicit-fallthrough"
|
||||
"-Wno-unused-const-variable"
|
||||
"-Wno-switch-unreachable"
|
||||
"-Wno-format-truncation"
|
||||
"-Wno-memset-elt-size"
|
||||
"-Wno-int-in-bool-context")
|
||||
endif()
|
||||
endif()
|
||||
# generate compile_commands.json (needs to come after project)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
|
||||
|
||||
if(CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE)
|
||||
list(APPEND compile_definitions "-DNDEBUG")
|
||||
endif()
|
||||
#
|
||||
# Setup variables for linker script generation
|
||||
#
|
||||
ldgen_set_variables()
|
||||
|
||||
if(CONFIG_COMPILER_STACK_CHECK_MODE_NORM)
|
||||
list(APPEND compile_options "-fstack-protector")
|
||||
elseif(CONFIG_COMPILER_STACK_CHECK_MODE_STRONG)
|
||||
list(APPEND compile_options "-fstack-protector-strong")
|
||||
elseif(CONFIG_COMPILER_STACK_CHECK_MODE_ALL)
|
||||
list(APPEND compile_options "-fstack-protector-all")
|
||||
endif()
|
||||
|
||||
list(APPEND link_options "-fno-lto")
|
||||
|
||||
idf_build_set_property(COMPILE_OPTIONS "${compile_options}" APPEND)
|
||||
idf_build_set_property(C_COMPILE_OPTIONS "${c_compile_options}" APPEND)
|
||||
idf_build_set_property(CXX_COMPILE_OPTIONS "${cxx_compile_options}" APPEND)
|
||||
idf_build_set_property(COMPILE_DEFINITIONS "${compile_definitions}" APPEND)
|
||||
idf_build_set_property(LINK_OPTIONS "${link_options}" APPEND)
|
||||
|
||||
idf_build_get_property(build_component_targets __BUILD_COMPONENT_TARGETS)
|
||||
|
||||
# Add each component as a subdirectory, processing each component's CMakeLists.txt
|
||||
foreach(component_target ${build_component_targets})
|
||||
__component_get_property(dir ${component_target} COMPONENT_DIR)
|
||||
__component_get_property(_name ${component_target} COMPONENT_NAME)
|
||||
__component_get_property(prefix ${component_target} __PREFIX)
|
||||
__component_get_property(alias ${component_target} COMPONENT_ALIAS)
|
||||
set(COMPONENT_NAME ${_name})
|
||||
set(COMPONENT_DIR ${dir})
|
||||
set(COMPONENT_ALIAS ${alias})
|
||||
set(COMPONENT_PATH ${dir}) # for backward compatibility only, COMPONENT_DIR is preferred
|
||||
idf_build_get_property(build_prefix __PREFIX)
|
||||
set(__idf_component_context 1)
|
||||
if(NOT prefix STREQUAL build_prefix)
|
||||
add_subdirectory(${dir} ${prefix}_${_name})
|
||||
else()
|
||||
add_subdirectory(${dir} ${_name})
|
||||
endif()
|
||||
set(__idf_component_context 0)
|
||||
# Include any top-level project_include.cmake files from components
|
||||
foreach(component ${BUILD_COMPONENT_PATHS})
|
||||
set(COMPONENT_PATH "${component}")
|
||||
include_if_exists("${component}/project_include.cmake")
|
||||
unset(COMPONENT_PATH)
|
||||
endforeach()
|
||||
|
||||
#
|
||||
# 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()
|
||||
|
||||
if(IDF_BUILD_ARTIFACTS)
|
||||
# Write project description JSON file
|
||||
make_json_list("${BUILD_COMPONENTS}" build_components_json)
|
||||
make_json_list("${BUILD_COMPONENT_PATHS}" build_component_paths_json)
|
||||
configure_file("${IDF_PATH}/tools/cmake/project_description.json.in"
|
||||
"${IDF_BUILD_ARTIFACTS_DIR}/project_description.json")
|
||||
unset(build_components_json)
|
||||
unset(build_component_paths_json)
|
||||
endif()
|
||||
|
||||
set(BUILD_COMPONENTS ${BUILD_COMPONENTS} PARENT_SCOPE)
|
||||
|
||||
ldgen_add_dependencies()
|
||||
|
||||
99
Kconfig
99
Kconfig
@@ -4,12 +4,6 @@
|
||||
#
|
||||
mainmenu "Espressif IoT Development Framework Configuration"
|
||||
|
||||
# Hidden option to support checking for this specific target in C code and Kconfig files
|
||||
config IDF_TARGET_ESP32
|
||||
bool
|
||||
default "y" if IDF_TARGET="esp32"
|
||||
default "n"
|
||||
|
||||
config IDF_CMAKE
|
||||
bool
|
||||
option env="IDF_CMAKE"
|
||||
@@ -29,31 +23,28 @@ mainmenu "Espressif IoT Development Framework Configuration"
|
||||
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 SDK_TOOLPREFIX
|
||||
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 SDK_PYTHON
|
||||
string "Python interpreter"
|
||||
config PYTHON
|
||||
string "Python 2 interpreter"
|
||||
depends on !IDF_CMAKE
|
||||
default "python"
|
||||
help
|
||||
The executable name/path that is used to run python.
|
||||
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 legacy GNU Make build system only.)
|
||||
(Note: This option is used with the GNU Make build system only, not idf.py
|
||||
or CMake-based builds.)
|
||||
|
||||
config SDK_MAKE_WARN_UNDEFINED_VARIABLES
|
||||
config MAKE_WARN_UNDEFINED_VARIABLES
|
||||
bool "'make' warns on undefined variables"
|
||||
depends on !IDF_CMAKE
|
||||
default "y"
|
||||
help
|
||||
Adds --warn-undefined-variables to MAKEFLAGS. This causes make to
|
||||
@@ -63,17 +54,15 @@ mainmenu "Espressif IoT Development Framework Configuration"
|
||||
or otherwise missing, but it can be unwanted if you have Makefiles which
|
||||
depend on undefined variables expanding to an empty string.
|
||||
|
||||
(Note: this option is used with the legacy GNU Make build system only.)
|
||||
|
||||
endmenu # SDK tool configuration
|
||||
|
||||
source "$COMPONENT_KCONFIGS_PROJBUILD"
|
||||
|
||||
menu "Compiler options"
|
||||
|
||||
choice COMPILER_OPTIMIZATION
|
||||
choice OPTIMIZATION_COMPILER
|
||||
prompt "Optimization Level"
|
||||
default COMPILER_OPTIMIZATION_LEVEL_DEBUG
|
||||
default OPTIMIZATION_LEVEL_DEBUG
|
||||
help
|
||||
This option sets compiler optimization level (gcc -O argument).
|
||||
|
||||
@@ -87,15 +76,15 @@ mainmenu "Espressif IoT Development Framework Configuration"
|
||||
in project makefile, before including $(IDF_PATH)/make/project.mk. Note that
|
||||
custom optimization levels may be unsupported.
|
||||
|
||||
config COMPILER_OPTIMIZATION_LEVEL_DEBUG
|
||||
config OPTIMIZATION_LEVEL_DEBUG
|
||||
bool "Debug (-Og)"
|
||||
config COMPILER_OPTIMIZATION_LEVEL_RELEASE
|
||||
config OPTIMIZATION_LEVEL_RELEASE
|
||||
bool "Release (-Os)"
|
||||
endchoice
|
||||
|
||||
choice COMPILER_OPTIMIZATION_ASSERTION_LEVEL
|
||||
choice OPTIMIZATION_ASSERTION_LEVEL
|
||||
prompt "Assertion level"
|
||||
default COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE
|
||||
default OPTIMIZATION_ASSERTIONS_ENABLED
|
||||
help
|
||||
Assertions can be:
|
||||
|
||||
@@ -107,20 +96,20 @@ mainmenu "Espressif IoT Development Framework Configuration"
|
||||
- Disabled entirely (not recommended for most configurations.) -DNDEBUG is added
|
||||
to CPPFLAGS in this case.
|
||||
|
||||
config COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE
|
||||
config OPTIMIZATION_ASSERTIONS_ENABLED
|
||||
prompt "Enabled"
|
||||
bool
|
||||
help
|
||||
Enable assertions. Assertion content and line number will be printed on failure.
|
||||
|
||||
config COMPILER_OPTIMIZATION_ASSERTIONS_SILENT
|
||||
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 COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE
|
||||
config OPTIMIZATION_ASSERTIONS_DISABLED
|
||||
prompt "Disabled (sets -DNDEBUG)"
|
||||
bool
|
||||
help
|
||||
@@ -128,7 +117,7 @@ mainmenu "Espressif IoT Development Framework Configuration"
|
||||
|
||||
endchoice # assertions
|
||||
|
||||
menuconfig COMPILER_CXX_EXCEPTIONS
|
||||
menuconfig CXX_EXCEPTIONS
|
||||
bool "Enable C++ exceptions"
|
||||
default n
|
||||
help
|
||||
@@ -140,26 +129,17 @@ mainmenu "Espressif IoT Development Framework Configuration"
|
||||
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 COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE
|
||||
config CXX_EXCEPTIONS_EMG_POOL_SIZE
|
||||
int "Emergency Pool Size"
|
||||
default 0
|
||||
depends on COMPILER_CXX_EXCEPTIONS
|
||||
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.
|
||||
|
||||
config COMPILER_CXX_RTTI
|
||||
# Invisible option, until the toolchain with RTTI support is released.
|
||||
# Use prompt "Enable C++ run-time type info (RTTI)" when updating.
|
||||
bool
|
||||
help
|
||||
Enabling this option compiles all C++ files with RTTI support enabled.
|
||||
This increases binary size (typically by tens of kB) but allows using
|
||||
dynamic_cast conversion and typeid operator.
|
||||
|
||||
choice COMPILER_STACK_CHECK_MODE
|
||||
choice STACK_CHECK_MODE
|
||||
prompt "Stack smashing protection mode"
|
||||
default COMPILER_STACK_CHECK_MODE_NONE
|
||||
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.
|
||||
@@ -182,23 +162,23 @@ mainmenu "Espressif IoT Development Framework Configuration"
|
||||
- coverage: NORMAL < STRONG < OVERALL
|
||||
|
||||
|
||||
config COMPILER_STACK_CHECK_MODE_NONE
|
||||
config STACK_CHECK_NONE
|
||||
bool "None"
|
||||
config COMPILER_STACK_CHECK_MODE_NORM
|
||||
config STACK_CHECK_NORM
|
||||
bool "Normal"
|
||||
config COMPILER_STACK_CHECK_MODE_STRONG
|
||||
config STACK_CHECK_STRONG
|
||||
bool "Strong"
|
||||
config COMPILER_STACK_CHECK_MODE_ALL
|
||||
config STACK_CHECK_ALL
|
||||
bool "Overall"
|
||||
endchoice
|
||||
|
||||
config COMPILER_STACK_CHECK
|
||||
config STACK_CHECK
|
||||
bool
|
||||
default !COMPILER_STACK_CHECK_MODE_NONE
|
||||
default !STACK_CHECK_NONE
|
||||
help
|
||||
Stack smashing protection.
|
||||
|
||||
config COMPILER_WARN_WRITE_STRINGS
|
||||
config WARN_WRITE_STRINGS
|
||||
bool "Enable -Wwrite-strings warning flag"
|
||||
default "n"
|
||||
help
|
||||
@@ -212,7 +192,7 @@ mainmenu "Espressif IoT Development Framework Configuration"
|
||||
For C++, this warns about the deprecated conversion from string
|
||||
literals to ``char *``.
|
||||
|
||||
config COMPILER_DISABLE_GCC8_WARNINGS
|
||||
config DISABLE_GCC8_WARNINGS
|
||||
bool "Disable new warnings introduced in GCC 6 - 8"
|
||||
default "n"
|
||||
help
|
||||
@@ -225,22 +205,3 @@ mainmenu "Espressif IoT Development Framework Configuration"
|
||||
menu "Component config"
|
||||
source "$COMPONENT_KCONFIGS"
|
||||
endmenu
|
||||
|
||||
menu "Compatibility options"
|
||||
config LEGACY_INCLUDE_COMMON_HEADERS
|
||||
bool "Include headers accross components as before IDF v4.0"
|
||||
default n
|
||||
help
|
||||
Soc, esp32, and driver components, the most common
|
||||
components. Some header of these components are included
|
||||
implicitly by headers of other components before IDF v4.0.
|
||||
It's not required for high-level components, but still
|
||||
included through long header chain everywhere.
|
||||
|
||||
This is harmful to the modularity. So it's changed in IDF
|
||||
v4.0.
|
||||
|
||||
You can still include these headers in a legacy way until it
|
||||
is totally deprecated by enable this option.
|
||||
|
||||
endmenu #Compatibility options
|
||||
|
||||
86
README.md
86
README.md
@@ -1,6 +1,8 @@
|
||||
# Espressif IoT Development Framework
|
||||
|
||||
ESP-IDF is the official development framework for the [ESP32](https://espressif.com/en/products/hardware/esp32/overview) chip provided for Windows, Linux and macOS.
|
||||
[](https://docs.espressif.com/projects/esp-idf/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
|
||||
|
||||
@@ -11,14 +13,6 @@ 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.
|
||||
|
||||
## 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.
|
||||
@@ -31,62 +25,92 @@ To start your own project based on an example, copy the example project director
|
||||
|
||||
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:
|
||||
|
||||
## Setup Build Environment
|
||||
|
||||
(See the Getting Started guide listed above for a full list of required steps with more details.)
|
||||
|
||||
* Install host build dependencies mentioned in the Getting Started guide.
|
||||
* Run the install script to set up the build environment. The options include `install.bat` for Windows, and `install.sh` for Unix shells.
|
||||
* Run the export script on Windows (`export.bat`) or source it on Unix (`source export.sh`) in every shell environment before using ESP-IDF.
|
||||
|
||||
## Configuring the Project
|
||||
|
||||
`idf.py menuconfig` opens a text-based configuration menu where you can configure the project.
|
||||
`make menuconfig`
|
||||
|
||||
* Opens a text-based configuration menu for the project.
|
||||
* Use up & down arrow keys to navigate the menu.
|
||||
* Use Enter key to go into a submenu, Escape key to go out or to exit.
|
||||
* Type `?` to see a help screen. Enter key exits the help screen.
|
||||
* Use Space key, or `Y` and `N` keys to enable (Yes) and disable (No) configuration items with checkboxes "`[*]`"
|
||||
* Pressing `?` while highlighting a configuration item displays help about that item.
|
||||
* Type `/` to search the configuration items.
|
||||
|
||||
Once done configuring, press Escape multiple times to exit and say "Yes" to save the new configuration when prompted.
|
||||
|
||||
## Compiling the Project
|
||||
|
||||
`idf.py build`
|
||||
`make -j4 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:
|
||||
|
||||
`idf.py -p PORT flash`
|
||||
`make -j4 flash`
|
||||
|
||||
Replace PORT with the name of your serial port (like `COM3` on Windows, `/dev/ttyUSB0` on Linux, or `/dev/cu.usbserial-X` on MacOS. If the `-p` option is left out, `idf.py flash` will try to flash the first available serial port.
|
||||
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`.
|
||||
|
||||
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 `idf.py menuconfig`.
|
||||
|
||||
You don't need to run `idf.py build` before running `idf.py flash`, `idf.py flash` will automatically rebuild anything which needs it.
|
||||
You don't need to run `make all` before running `make flash`, `make flash` will automatically rebuild anything which needs it.
|
||||
|
||||
## Viewing Serial Output
|
||||
|
||||
The `idf.py 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](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).
|
||||
|
||||
Exit the monitor by typing Ctrl-].
|
||||
|
||||
To build, flash and monitor output in one pass, you can run:
|
||||
|
||||
`idf.py flash monitor`
|
||||
`make -j4 flash monitor`
|
||||
|
||||
## Compiling & Flashing Only the App
|
||||
|
||||
After the initial flash, you may just want to build and flash just your app, not the bootloader and partition table:
|
||||
|
||||
* `idf.py app` - build just the app.
|
||||
* `idf.py app-flash` - flash just the app.
|
||||
* `make app` - build just the app.
|
||||
* `make app-flash` - flash just the app.
|
||||
|
||||
`idf.py app-flash` will automatically rebuild the app if any source files have changed.
|
||||
`make app-flash` will automatically rebuild the app if any source files have changed.
|
||||
|
||||
(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.)
|
||||
|
||||
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:
|
||||
|
||||
```
|
||||
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.
|
||||
|
||||
A single ESP32's flash can contain multiple apps, as well as many different kinds of data (calibration data, filesystems, parameter storage, etc). For this reason a partition table is flashed to offset 0x8000 in the flash.
|
||||
|
||||
Each entry in the partition table has a name (label), type (app, data, or something else), subtype and the offset in flash where the partition is loaded.
|
||||
|
||||
The simplest way to use the partition table is to `make menuconfig` and choose one of the simple predefined partition tables:
|
||||
|
||||
* "Single factory app, no OTA"
|
||||
* "Factory app, two OTA definitions"
|
||||
|
||||
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.
|
||||
|
||||
## Erasing Flash
|
||||
|
||||
The `idf.py flash` target does not erase the entire flash contents. However it is sometimes useful to set the device back to a totally erased state, particularly when making partition table changes or OTA app updates. To erase the entire flash, run `idf.py erase_flash`.
|
||||
The `make flash` target does not erase the entire flash contents. However it is sometimes useful to set the device back to a totally erased state, particularly when making partition table changes or OTA app updates. To erase the entire flash, run `make erase_flash`.
|
||||
|
||||
This can be combined with other targets, ie `idf.py -p PORT erase_flash flash` will erase everything and then re-flash the new app, bootloader and partition table.
|
||||
This can be combined with other targets, ie `make erase_flash flash` will erase everything and then re-flash the new app, bootloader and partition table.
|
||||
|
||||
# Resources
|
||||
|
||||
|
||||
@@ -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,7 +9,8 @@
|
||||
if [ -z ${IDF_PATH} ]; then
|
||||
echo "IDF_PATH must be set before including this script."
|
||||
else
|
||||
IDF_ADD_PATHS_EXTRAS="${IDF_PATH}/components/esptool_py/esptool"
|
||||
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/"
|
||||
|
||||
@@ -1,43 +1,29 @@
|
||||
set(srcs
|
||||
"app_trace.c"
|
||||
"app_trace_util.c"
|
||||
"host_file_io.c"
|
||||
"gcov/gcov_rtio.c")
|
||||
|
||||
set(include_dirs "include")
|
||||
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 include_dirs
|
||||
list(APPEND COMPONENT_ADD_INCLUDEDIRS
|
||||
sys_view/Config
|
||||
sys_view/SEGGER
|
||||
sys_view/Sample/OS)
|
||||
|
||||
list(APPEND 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"
|
||||
"sys_view/ext/heap_trace_module.c"
|
||||
"sys_view/ext/logging.c")
|
||||
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()
|
||||
|
||||
if(CONFIG_HEAP_TRACING_TOHOST)
|
||||
list(APPEND srcs "heap_trace_tohost.c")
|
||||
endif()
|
||||
set(COMPONENT_REQUIRES)
|
||||
set(COMPONENT_PRIV_REQUIRES xtensa-debug-module)
|
||||
set(COMPONENT_ADD_LDFRAGMENTS linker.lf)
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS "${include_dirs}"
|
||||
PRIV_REQUIRES soc
|
||||
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")
|
||||
|
||||
if(CONFIG_ESP32_GCOV_ENABLE)
|
||||
# disable --coverage for this component, as it is used as transport
|
||||
# for gcov
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-fno-profile-arcs" "-fno-test-coverage")
|
||||
|
||||
# Force app_trace to also appear later than gcov in link line
|
||||
idf_component_get_property(app_trace app_trace COMPONENT_LIB)
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE
|
||||
"-Wl,--undefined=gcov_rtio_atexit" $<TARGET_FILE:${app_trace}> gcov $<TARGET_FILE:${app_trace}> c)
|
||||
endif()
|
||||
target_link_libraries(${COMPONENT_TARGET} gcov)
|
||||
|
||||
@@ -16,8 +16,8 @@ menu "Application Level Tracing"
|
||||
config ESP32_APPTRACE_ENABLE
|
||||
bool
|
||||
depends on !ESP32_TRAX
|
||||
select ESP32_MEMMAP_TRACEMEM
|
||||
select ESP32_MEMMAP_TRACEMEM_TWOBANKS
|
||||
select MEMMAP_TRACEMEM
|
||||
select MEMMAP_TRACEMEM_TWOBANKS
|
||||
default n
|
||||
help
|
||||
Enables/disable application tracing module.
|
||||
@@ -37,7 +37,7 @@ menu "Application Level Tracing"
|
||||
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_THRESH
|
||||
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
|
||||
@@ -107,14 +107,6 @@ menu "Application Level Tracing"
|
||||
help
|
||||
Configures maximum supported tasks in sysview debug
|
||||
|
||||
config SYSVIEW_BUF_WAIT_TMO
|
||||
int "Trace buffer wait timeout"
|
||||
depends on SYSVIEW_ENABLE
|
||||
default 500
|
||||
help
|
||||
Configures timeout (in us) to wait for free space in trace buffer.
|
||||
Set to -1 to wait forever and avoid lost events.
|
||||
|
||||
config SYSVIEW_EVT_OVERFLOW_ENABLE
|
||||
bool "Trace Buffer Overflow Event"
|
||||
depends on SYSVIEW_ENABLE
|
||||
|
||||
@@ -75,8 +75,7 @@
|
||||
// trace data are necessary, e.g. for analyzing crashes. On panic the latest data from current input block are exposed to host and host can read them.
|
||||
// It can happen that system panic occurs when there are very small amount of data which are not exposed to host yet (e.g. crash just after the
|
||||
// TRAX block switch). In this case the previous 16KB of collected data will be dropped and host will see the latest, but very small piece of trace.
|
||||
// It can be insufficient to diagnose the problem. To avoid such situations there is menuconfig option
|
||||
// CONFIG_ESP32_APPTRACE_POSTMORTEM_FLUSH_THRESH
|
||||
// It can be insufficient to diagnose the problem. To avoid such situations there is menuconfig option CONFIG_ESP32_APPTRACE_POSTMORTEM_FLUSH_TRAX_THRESH
|
||||
// which controls the threshold for flushing data in case of panic.
|
||||
// - Streaming mode. Tracing module enters this mode when host connects to target and sets respective bits in control registers (per core).
|
||||
// In this mode before switching the block tracing module waits for the host to read all the data from the previously exposed block.
|
||||
@@ -160,7 +159,8 @@
|
||||
#include "soc/dport_reg.h"
|
||||
#include "eri.h"
|
||||
#include "trax.h"
|
||||
#include "soc/timer_periph.h"
|
||||
#include "soc/timer_group_struct.h"
|
||||
#include "soc/timer_group_reg.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_app_trace.h"
|
||||
|
||||
@@ -929,9 +929,6 @@ esp_err_t esp_apptrace_read(esp_apptrace_dest_t dest, void *buf, uint32_t *size,
|
||||
ESP_APPTRACE_LOGE("Trace destinations other then TRAX are not supported yet!");
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
if (buf == NULL || size == NULL || *size == 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
//TODO: callback system
|
||||
esp_apptrace_tmo_init(&tmo, user_tmo);
|
||||
@@ -966,10 +963,8 @@ uint8_t *esp_apptrace_down_buffer_get(esp_apptrace_dest_t dest, uint32_t *size,
|
||||
ESP_APPTRACE_LOGE("Trace destinations other then TRAX are not supported yet!");
|
||||
return NULL;
|
||||
}
|
||||
if (size == NULL || *size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// ESP_APPTRACE_LOGE("esp_apptrace_down_buffer_get %d", *size);
|
||||
esp_apptrace_tmo_init(&tmo, user_tmo);
|
||||
return hw->get_down_buffer(size, &tmo);
|
||||
}
|
||||
@@ -990,9 +985,6 @@ esp_err_t esp_apptrace_down_buffer_put(esp_apptrace_dest_t dest, uint8_t *ptr, u
|
||||
ESP_APPTRACE_LOGE("Trace destinations other then TRAX are not supported yet!");
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
if (ptr == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_apptrace_tmo_init(&tmo, user_tmo);
|
||||
return hw->put_down_buffer(ptr, &tmo);
|
||||
@@ -1015,9 +1007,6 @@ esp_err_t esp_apptrace_write(esp_apptrace_dest_t dest, const void *data, uint32_
|
||||
ESP_APPTRACE_LOGE("Trace destinations other then TRAX are not supported yet!");
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
if (data == NULL || size == 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_apptrace_tmo_init(&tmo, user_tmo);
|
||||
ptr = hw->get_up_buffer(size, &tmo);
|
||||
@@ -1051,9 +1040,6 @@ int esp_apptrace_vprintf_to(esp_apptrace_dest_t dest, uint32_t user_tmo, const c
|
||||
ESP_APPTRACE_LOGE("Trace destinations other then TRAX are not supported yet!");
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
if (fmt == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_apptrace_tmo_init(&tmo, user_tmo);
|
||||
ESP_APPTRACE_LOGD("fmt %x", fmt);
|
||||
@@ -1115,9 +1101,6 @@ uint8_t *esp_apptrace_buffer_get(esp_apptrace_dest_t dest, uint32_t size, uint32
|
||||
ESP_APPTRACE_LOGE("Trace destinations other then TRAX are not supported yet!");
|
||||
return NULL;
|
||||
}
|
||||
if (size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
esp_apptrace_tmo_init(&tmo, user_tmo);
|
||||
return hw->get_up_buffer(size, &tmo);
|
||||
@@ -1139,9 +1122,6 @@ esp_err_t esp_apptrace_buffer_put(esp_apptrace_dest_t dest, uint8_t *ptr, uint32
|
||||
ESP_APPTRACE_LOGE("Trace destinations other then TRAX are not supported yet!");
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
if (ptr == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_apptrace_tmo_init(&tmo, user_tmo);
|
||||
return hw->put_up_buffer(ptr, &tmo);
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_app_trace_util.h"
|
||||
#include "esp32/clk.h"
|
||||
#include "esp_clk.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////// TIMEOUT /////////////////////////////////////
|
||||
|
||||
@@ -8,7 +8,11 @@ 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 \
|
||||
@@ -19,15 +23,9 @@ COMPONENT_SRCDIRS += \
|
||||
sys_view/SEGGER \
|
||||
sys_view/Sample/OS \
|
||||
sys_view/Sample/Config \
|
||||
sys_view/esp32 \
|
||||
sys_view/ext
|
||||
sys_view/esp32
|
||||
else
|
||||
ifdef CONFIG_ESP32_GCOV_ENABLE
|
||||
# do not produce gcov info for this module, it is used as transport for gcov
|
||||
CFLAGS := $(subst --coverage,,$(CFLAGS))
|
||||
COMPONENT_ADD_LDFLAGS += -Wl,--undefined=gcov_rtio_atexit
|
||||
COMPONENT_SRCDIRS += gcov
|
||||
endif
|
||||
endif
|
||||
|
||||
COMPONENT_ADD_LDFRAGMENTS += linker.lf
|
||||
|
||||
@@ -18,9 +18,10 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "soc/cpu.h"
|
||||
#include "soc/timer_periph.h"
|
||||
#include "soc/timer_group_struct.h"
|
||||
#include "soc/timer_group_reg.h"
|
||||
#include "esp_app_trace.h"
|
||||
#include "esp_private/dbg_stubs.h"
|
||||
#include "esp_dbg_stubs.h"
|
||||
|
||||
#if CONFIG_ESP32_GCOV_ENABLE
|
||||
|
||||
|
||||
@@ -1,114 +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.
|
||||
#include <sdkconfig.h>
|
||||
|
||||
#define HEAP_TRACE_SRCFILE /* don't warn on inclusion here */
|
||||
#include "esp_heap_trace.h"
|
||||
#undef HEAP_TRACE_SRCFILE
|
||||
|
||||
#if CONFIG_SYSVIEW_ENABLE
|
||||
#include "esp_app_trace.h"
|
||||
#include "esp_sysview_trace.h"
|
||||
#endif
|
||||
|
||||
#define STACK_DEPTH CONFIG_HEAP_TRACING_STACK_DEPTH
|
||||
|
||||
#ifdef CONFIG_HEAP_TRACING_TOHOST
|
||||
|
||||
#if !CONFIG_SYSVIEW_ENABLE
|
||||
#error None of the heap tracing backends is enabled! You must enable SystemView compatible tracing to use this feature.
|
||||
#endif
|
||||
|
||||
static bool s_tracing;
|
||||
|
||||
esp_err_t heap_trace_init_tohost()
|
||||
{
|
||||
if (s_tracing) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t heap_trace_start(heap_trace_mode_t mode_param)
|
||||
{
|
||||
#if CONFIG_SYSVIEW_ENABLE
|
||||
esp_err_t ret = esp_sysview_heap_trace_start((uint32_t)-1);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
s_tracing = true;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t heap_trace_stop(void)
|
||||
{
|
||||
esp_err_t ret = ESP_ERR_NOT_SUPPORTED;
|
||||
#if CONFIG_SYSVIEW_ENABLE
|
||||
ret = esp_sysview_heap_trace_stop();
|
||||
#endif
|
||||
s_tracing = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t heap_trace_resume(void)
|
||||
{
|
||||
return heap_trace_start(HEAP_TRACE_ALL);
|
||||
}
|
||||
|
||||
size_t heap_trace_get_count(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
esp_err_t heap_trace_get(size_t index, heap_trace_record_t *record)
|
||||
{
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
void heap_trace_dump(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Add a new allocation to the heap trace records */
|
||||
static IRAM_ATTR void record_allocation(const heap_trace_record_t *record)
|
||||
{
|
||||
if (!s_tracing) {
|
||||
return;
|
||||
}
|
||||
#if CONFIG_SYSVIEW_ENABLE
|
||||
esp_sysview_heap_trace_alloc(record->address, record->size, record->alloced_by);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* record a free event in the heap trace log
|
||||
|
||||
For HEAP_TRACE_ALL, this means filling in the freed_by pointer.
|
||||
For HEAP_TRACE_LEAKS, this means removing the record from the log.
|
||||
*/
|
||||
static IRAM_ATTR void record_free(void *p, void **callers)
|
||||
{
|
||||
if (!s_tracing) {
|
||||
return;
|
||||
}
|
||||
#if CONFIG_SYSVIEW_ENABLE
|
||||
esp_sysview_heap_trace_free(p, callers);
|
||||
#endif
|
||||
}
|
||||
|
||||
#include "heap_trace.inc"
|
||||
|
||||
#endif /*CONFIG_HEAP_TRACING_TOHOST*/
|
||||
|
||||
@@ -145,9 +145,6 @@ void *esp_apptrace_fopen(esp_apptrace_dest_t dest, const char *path, const char
|
||||
esp_apptrace_fopen_args_t cmd_args;
|
||||
|
||||
ESP_EARLY_LOGV(TAG, "esp_apptrace_fopen '%s' '%s'", path, mode);
|
||||
if (path == NULL || mode == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
cmd_args.path = path;
|
||||
cmd_args.path_len = strlen(path) + 1;
|
||||
@@ -216,10 +213,6 @@ size_t esp_apptrace_fwrite(esp_apptrace_dest_t dest, const void *ptr, size_t siz
|
||||
|
||||
ESP_EARLY_LOGV(TAG, "esp_apptrace_fwrite f %p l %d", stream, size*nmemb);
|
||||
|
||||
if (ptr == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
cmd_args.buf = (void *)ptr;
|
||||
cmd_args.size = size * nmemb;
|
||||
cmd_args.file = stream;
|
||||
@@ -255,10 +248,6 @@ size_t esp_apptrace_fread(esp_apptrace_dest_t dest, void *ptr, size_t size, size
|
||||
|
||||
ESP_EARLY_LOGV(TAG, "esp_apptrace_fread f %p l %d", stream, size*nmemb);
|
||||
|
||||
if (ptr == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
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,
|
||||
|
||||
@@ -1,80 +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_SYSVIEW_TRACE_H_
|
||||
#define ESP_SYSVIEW_TRACE_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "esp_err.h"
|
||||
#include "SEGGER_RTT.h" // SEGGER_RTT_ESP32_Flush
|
||||
#include "esp_app_trace_util.h" // ESP_APPTRACE_TMO_INFINITE
|
||||
|
||||
/**
|
||||
* @brief Flushes remaining data in SystemView trace buffer to host.
|
||||
*
|
||||
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly.
|
||||
*
|
||||
* @return ESP_OK.
|
||||
*/
|
||||
static inline esp_err_t esp_sysview_flush(uint32_t tmo)
|
||||
{
|
||||
SEGGER_RTT_ESP32_Flush(0, tmo);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief vprintf-like function to sent log messages to the host.
|
||||
*
|
||||
* @param format Address of format string.
|
||||
* @param args List of arguments.
|
||||
*
|
||||
* @return Number of bytes written.
|
||||
*/
|
||||
int esp_sysview_vprintf(const char * format, va_list args);
|
||||
|
||||
/**
|
||||
* @brief Starts SystemView heap tracing.
|
||||
*
|
||||
* @param tmo Timeout (in us) to wait for the host to be connected. Use -1 to wait forever.
|
||||
*
|
||||
* @return ESP_OK on success, ESP_ERR_TIMEOUT if operation has been timed out.
|
||||
*/
|
||||
esp_err_t esp_sysview_heap_trace_start(uint32_t tmo);
|
||||
|
||||
/**
|
||||
* @brief Stops SystemView heap tracing.
|
||||
*
|
||||
* @return ESP_OK.
|
||||
*/
|
||||
esp_err_t esp_sysview_heap_trace_stop(void);
|
||||
|
||||
/**
|
||||
* @brief Sends heap allocation event to the host.
|
||||
*
|
||||
* @param addr Address of allocated block.
|
||||
* @param size Size of allocated block.
|
||||
* @param callers Pointer to array with callstack addresses.
|
||||
* Array size must be CONFIG_HEAP_TRACING_STACK_DEPTH.
|
||||
*/
|
||||
void esp_sysview_heap_trace_alloc(void *addr, uint32_t size, const void *callers);
|
||||
|
||||
/**
|
||||
* @brief Sends heap de-allocation event to the host.
|
||||
*
|
||||
* @param addr Address of de-allocated block.
|
||||
* @param callers Pointer to array with callstack addresses.
|
||||
* Array size must be CONFIG_HEAP_TRACING_STACK_DEPTH.
|
||||
*/
|
||||
void esp_sysview_heap_trace_free(void *addr, const void *callers);
|
||||
|
||||
#endif //ESP_SYSVIEW_TRACE_H_
|
||||
@@ -1,19 +1,12 @@
|
||||
[mapping:app_trace]
|
||||
[mapping]
|
||||
archive: libapp_trace.a
|
||||
entries:
|
||||
app_trace (noflash)
|
||||
app_trace_util (noflash)
|
||||
if SYSVIEW_ENABLE = y:
|
||||
SEGGER_SYSVIEW (noflash)
|
||||
SEGGER_RTT_esp32 (noflash)
|
||||
SEGGER_SYSVIEW_Config_FreeRTOS (noflash)
|
||||
SEGGER_SYSVIEW_FreeRTOS (noflash)
|
||||
* (noflash)
|
||||
|
||||
[mapping:driver]
|
||||
[mapping]
|
||||
archive: libdriver.a
|
||||
entries:
|
||||
if 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)
|
||||
else:
|
||||
* (default)
|
||||
: 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,23 +0,0 @@
|
||||
# idf_create_lcov_report
|
||||
#
|
||||
# Create coverage report.
|
||||
function(idf_create_coverage_report report_dir)
|
||||
set(gcov_tool ${CONFIG_SDK_TOOLPREFIX}gcov)
|
||||
idf_build_get_property(project_name PROJECT_NAME)
|
||||
|
||||
add_custom_target(lcov-report
|
||||
COMMENT "Generating coverage report in: ${report_dir}"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Using gcov: ${gcov_tool}"
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${report_dir}/html
|
||||
COMMAND lcov --gcov-tool ${gcov_tool} -c -d ${CMAKE_CURRENT_BINARY_DIR} -o ${report_dir}/${project_name}.info
|
||||
COMMAND genhtml -o ${report_dir}/html ${report_dir}/${project_name}.info)
|
||||
endfunction()
|
||||
|
||||
# idf_clean_coverage_report
|
||||
#
|
||||
# Clean coverage report.
|
||||
function(idf_clean_coverage_report report_dir)
|
||||
add_custom_target(cov-data-clean
|
||||
COMMENT "Clean coverage report in: ${report_dir}"
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory ${report_dir})
|
||||
endfunction()
|
||||
@@ -1,4 +0,0 @@
|
||||
# sdkconfig replacement configurations for deprecated options formatted as
|
||||
# CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION
|
||||
|
||||
CONFIG_ESP32_APPTRACE_POSTMORTEM_FLUSH_TRAX_THRESH CONFIG_ESP32_APPTRACE_POSTMORTEM_FLUSH_THRESH
|
||||
@@ -160,7 +160,6 @@ unsigned SEGGER_RTT_WriteSkipNoLock (unsigned BufferIndex, const voi
|
||||
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);
|
||||
void SEGGER_RTT_ESP32_Flush (unsigned long min_sz, unsigned long tmo);
|
||||
//
|
||||
// Function macro for performance optimization
|
||||
//
|
||||
|
||||
@@ -1689,10 +1689,6 @@ void SEGGER_SYSVIEW_Stop(void) {
|
||||
RECORD_END();
|
||||
}
|
||||
|
||||
U8 SEGGER_SYSVIEW_Started(void) {
|
||||
return _SYSVIEW_Globals.EnableState;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* SEGGER_SYSVIEW_GetSysDesc()
|
||||
@@ -2682,7 +2678,7 @@ void SEGGER_SYSVIEW_ErrorfTarget(const char* s, ...) {
|
||||
void SEGGER_SYSVIEW_Print(const char* s) {
|
||||
U8* pPayload;
|
||||
U8* pPayloadStart;
|
||||
RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32 + SEGGER_SYSVIEW_MAX_STRING_LEN + 3/*1 or 3 bytes for string length*/);
|
||||
RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32 + SEGGER_SYSVIEW_MAX_STRING_LEN);
|
||||
//
|
||||
pPayload = _EncodeStr(pPayloadStart, s, SEGGER_SYSVIEW_MAX_STRING_LEN);
|
||||
ENCODE_U32(pPayload, SEGGER_SYSVIEW_LOG);
|
||||
|
||||
@@ -230,8 +230,6 @@ 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);
|
||||
// Checks whether tracing has been started
|
||||
U8 SEGGER_SYSVIEW_Started(void);
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
|
||||
@@ -63,11 +63,11 @@ Revision: $Rev: 3734 $
|
||||
*/
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "SEGGER_SYSVIEW.h"
|
||||
#include "esp32/rom/ets_sys.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_app_trace.h"
|
||||
#include "esp_app_trace_util.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp32/clk.h"
|
||||
#include "esp_clk.h"
|
||||
|
||||
extern const SEGGER_SYSVIEW_OS_API SYSVIEW_X_OS_TraceAPI;
|
||||
|
||||
|
||||
@@ -244,10 +244,8 @@ Notes:
|
||||
#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_RecordU32x4(apiFastID_OFFSET + apiID_XQUEUEGENERICSENDFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), (U32)pvItemToQueue, (U32)pxHigherPriorityTaskWoken, xCopyPosition)
|
||||
#define traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue ) SEGGER_SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XQUEUEGENERICSENDFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), (U32)pvItemToQueue, (U32)pxHigherPriorityTaskWoken, xCopyPosition)
|
||||
#define traceQUEUE_GIVE_FROM_ISR( pxQueue ) SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_XQUEUEGIVEFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), (U32)pxHigherPriorityTaskWoken)
|
||||
#define traceQUEUE_GIVE_FROM_ISR_FAILED( pxQueue ) SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_XQUEUEGIVEFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), (U32)pxHigherPriorityTaskWoken)
|
||||
#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) { \
|
||||
|
||||
@@ -16,9 +16,8 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "SEGGER_RTT.h"
|
||||
#include "SEGGER_SYSVIEW.h"
|
||||
#include "SEGGER_SYSVIEW_Conf.h"
|
||||
|
||||
#include "esp32/rom/ets_sys.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_app_trace.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
@@ -28,12 +27,8 @@ const static char *TAG = "segger_rtt";
|
||||
|
||||
// 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
|
||||
#if CONFIG_SYSVIEW_BUF_WAIT_TMO == -1
|
||||
#define SEGGER_HOST_WAIT_TMO ESP_APPTRACE_TMO_INFINITE
|
||||
#else
|
||||
#define SEGGER_HOST_WAIT_TMO CONFIG_SYSVIEW_BUF_WAIT_TMO
|
||||
#endif
|
||||
|
||||
static uint8_t s_events_buf[SYSVIEW_EVENTS_BUF_SZ];
|
||||
static uint16_t s_events_buf_filled;
|
||||
@@ -62,12 +57,9 @@ static uint8_t s_down_buf[SYSVIEW_DOWN_BUF_SIZE];
|
||||
*/
|
||||
void SEGGER_RTT_ESP32_FlushNoLock(unsigned long min_sz, unsigned long tmo)
|
||||
{
|
||||
esp_err_t res;
|
||||
if (s_events_buf_filled > 0) {
|
||||
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);
|
||||
}
|
||||
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);
|
||||
@@ -77,27 +69,6 @@ void SEGGER_RTT_ESP32_FlushNoLock(unsigned long min_sz, unsigned long tmo)
|
||||
s_events_buf_filled = 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* SEGGER_RTT_ESP32_Flush()
|
||||
*
|
||||
* 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_Flush(unsigned long min_sz, unsigned long tmo)
|
||||
{
|
||||
SEGGER_SYSVIEW_LOCK();
|
||||
SEGGER_RTT_ESP32_FlushNoLock(min_sz, tmo);
|
||||
SEGGER_SYSVIEW_UNLOCK();
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* SEGGER_RTT_ReadNoLock()
|
||||
|
||||
@@ -1,100 +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.
|
||||
#include <stdint.h>
|
||||
#include <sdkconfig.h>
|
||||
#include "SEGGER_SYSVIEW.h"
|
||||
#include "SEGGER_RTT.h"
|
||||
#include "esp_app_trace.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
const static char *TAG = "sysview_heap_trace";
|
||||
|
||||
#ifdef CONFIG_HEAP_TRACING_STACK_DEPTH
|
||||
#define CALLSTACK_SIZE CONFIG_HEAP_TRACING_STACK_DEPTH
|
||||
#else
|
||||
#define CALLSTACK_SIZE 0
|
||||
#endif
|
||||
|
||||
static SEGGER_SYSVIEW_MODULE s_esp_sysview_heap_module = {
|
||||
.sModule = "ESP32 SystemView Heap Tracing Module",
|
||||
.NumEvents = 2,
|
||||
};
|
||||
|
||||
static bool s_mod_registered;
|
||||
|
||||
|
||||
esp_err_t esp_sysview_heap_trace_start(uint32_t tmo)
|
||||
{
|
||||
uint32_t tmo_ticks = tmo/(1000*portTICK_PERIOD_MS);
|
||||
|
||||
ESP_EARLY_LOGV(TAG, "%s", __func__);
|
||||
do {
|
||||
if (tmo != (uint32_t)-1) {
|
||||
// Currently timeout implementation is simple and has granularity of 1 OS tick,
|
||||
// so just count down the number of times to call vTaskDelay
|
||||
if (tmo_ticks-- == 0) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
vTaskDelay(1);
|
||||
} while(!SEGGER_SYSVIEW_Started());
|
||||
|
||||
SEGGER_SYSVIEW_RegisterModule(&s_esp_sysview_heap_module);
|
||||
s_mod_registered = true;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_sysview_heap_trace_stop(void)
|
||||
{
|
||||
ESP_EARLY_LOGV(TAG, "%s", __func__);
|
||||
SEGGER_RTT_ESP32_Flush(0, ESP_APPTRACE_TMO_INFINITE);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void esp_sysview_heap_trace_alloc(const void *addr, uint32_t size, const void *callers)
|
||||
{
|
||||
U8 aPacket[SEGGER_SYSVIEW_INFO_SIZE + (2+CALLSTACK_SIZE)*SEGGER_SYSVIEW_QUANTA_U32];
|
||||
U8* pPayload = SEGGER_SYSVIEW_PREPARE_PACKET(aPacket);
|
||||
U32 *calls = (U32 *)callers;
|
||||
|
||||
if (!s_mod_registered) {
|
||||
return;
|
||||
}
|
||||
ESP_EARLY_LOGV(TAG, "%s %p %lu", __func__, addr, size);
|
||||
pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, (U32)addr);
|
||||
pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, size);
|
||||
for (int i = 0; i < CALLSTACK_SIZE; i++) {
|
||||
pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, calls[i]);
|
||||
}
|
||||
SEGGER_SYSVIEW_SendPacket(&aPacket[0], pPayload, s_esp_sysview_heap_module.EventOffset + 0);
|
||||
}
|
||||
|
||||
void esp_sysview_heap_trace_free(const void *addr, const void *callers)
|
||||
{
|
||||
U8 aPacket[SEGGER_SYSVIEW_INFO_SIZE + (1+CALLSTACK_SIZE)*SEGGER_SYSVIEW_QUANTA_U32];
|
||||
U8* pPayload = SEGGER_SYSVIEW_PREPARE_PACKET(aPacket);
|
||||
U32 *calls = (U32 *)callers;
|
||||
|
||||
if (!s_mod_registered) {
|
||||
return;
|
||||
}
|
||||
ESP_EARLY_LOGV(TAG, "%s %p", __func__, addr);
|
||||
pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, (U32)addr);
|
||||
for (int i = 0; i < CALLSTACK_SIZE; i++) {
|
||||
pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, calls[i]);
|
||||
}
|
||||
SEGGER_SYSVIEW_SendPacket(&aPacket[0], pPayload, s_esp_sysview_heap_module.EventOffset + 1);
|
||||
}
|
||||
@@ -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.
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <sdkconfig.h>
|
||||
#include "SEGGER_SYSVIEW_Int.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
|
||||
static portMUX_TYPE s_log_mutex = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
int esp_sysview_vprintf(const char * format, va_list args)
|
||||
{
|
||||
static char log_buffer[SEGGER_SYSVIEW_MAX_STRING_LEN];
|
||||
|
||||
portENTER_CRITICAL(&s_log_mutex);
|
||||
size_t len = vsnprintf(log_buffer, sizeof(log_buffer), format, args);
|
||||
if (len > sizeof(log_buffer) - 1) {
|
||||
log_buffer[sizeof(log_buffer - 1)] = 0;
|
||||
}
|
||||
SEGGER_SYSVIEW_Print(log_buffer);
|
||||
portEXIT_CRITICAL(&s_log_mutex);
|
||||
return len;
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
idf_component_register(SRC_DIRS "."
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES unity)
|
||||
set(COMPONENT_SRCDIRS ".")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
set(COMPONENT_REQUIRES unity)
|
||||
|
||||
register_component()
|
||||
@@ -1,57 +1,40 @@
|
||||
idf_component_register(SRCS "esp_ota_ops.c"
|
||||
"esp_app_desc.c"
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES spi_flash partition_table bootloader_support)
|
||||
set(COMPONENT_SRCS "esp_ota_ops.c"
|
||||
"esp_app_desc.c")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS "include")
|
||||
|
||||
# esp_app_desc structure is added as an undefined symbol because otherwise the
|
||||
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_LIB} INTERFACE "-u esp_app_desc")
|
||||
target_link_libraries(${COMPONENT_TARGET} "-u esp_app_desc")
|
||||
|
||||
# cut PROJECT_VER and PROJECT_NAME to required 32 characters.
|
||||
idf_build_get_property(project_ver PROJECT_VER)
|
||||
idf_build_get_property(project_name PROJECT_NAME)
|
||||
string(SUBSTRING "${project_ver}" 0 31 PROJECT_VER_CUT)
|
||||
string(SUBSTRING "${project_name}" 0 31 PROJECT_NAME_CUT)
|
||||
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
|
||||
PROPERTIES COMPILE_DEFINITIONS
|
||||
"PROJECT_VER=\"${PROJECT_VER_CUT}\"; PROJECT_NAME=\"${PROJECT_NAME_CUT}\"")
|
||||
|
||||
if(NOT BOOTLOADER_BUILD)
|
||||
partition_table_get_partition_info(otadata_offset "--partition-type data --partition-subtype ota" "offset")
|
||||
partition_table_get_partition_info(otadata_size "--partition-type data --partition-subtype ota" "size")
|
||||
# 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 for generating empty otadata partition for flashing
|
||||
if(otadata_size AND otadata_offset)
|
||||
idf_build_get_property(build_dir BUILD_DIR)
|
||||
set(blank_otadata_file ${build_dir}/ota_data_initial.bin)
|
||||
|
||||
idf_build_get_property(idf_path IDF_PATH)
|
||||
idf_build_get_property(python PYTHON)
|
||||
add_custom_command(OUTPUT ${blank_otadata_file}
|
||||
COMMAND ${python} ${idf_path}/components/partition_table/gen_empty_partition.py
|
||||
${otadata_size} ${blank_otadata_file})
|
||||
|
||||
add_custom_target(blank_ota_data ALL DEPENDS ${blank_otadata_file})
|
||||
add_dependencies(flash blank_ota_data)
|
||||
|
||||
set(otatool_py ${python} ${COMPONENT_DIR}/otatool.py)
|
||||
|
||||
set(esptool_args --esptool-args before=${CONFIG_ESPTOOLPY_BEFORE} after=${CONFIG_ESPTOOLPY_AFTER})
|
||||
|
||||
add_custom_target(read_otadata DEPENDS "${PARTITION_CSV_PATH}"
|
||||
COMMAND ${otatool_py} ${esptool_args}
|
||||
--partition-table-file ${PARTITION_CSV_PATH}
|
||||
--partition-table-offset ${PARTITION_TABLE_OFFSET}
|
||||
read_otadata)
|
||||
|
||||
add_custom_target(erase_otadata DEPENDS "${PARTITION_CSV_PATH}"
|
||||
COMMAND ${otatool_py} ${esptool_args}
|
||||
--partition-table-file ${PARTITION_CSV_PATH}
|
||||
--partition-table-offset ${PARTITION_TABLE_OFFSET}
|
||||
erase_otadata)
|
||||
|
||||
esptool_py_flash_project_args(otadata ${otadata_offset} "${blank_otadata_file}" FLASH_IN_PROJECT)
|
||||
endif()
|
||||
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)
|
||||
|
||||
@@ -22,14 +22,4 @@ menu "Application manager"
|
||||
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"
|
||||
|
||||
@@ -17,7 +17,8 @@ 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 \
|
||||
$(PYTHON) $(IDF_PATH)/components/partition_table/gen_empty_partition.py $(OTA_DATA_SIZE) $(BLANK_OTA_DATA_FILE); \
|
||||
$(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) )
|
||||
@@ -28,23 +29,17 @@ blank_ota_data: $(BLANK_OTA_DATA_FILE)
|
||||
# expand to empty values.
|
||||
ESPTOOL_ALL_FLASH_ARGS += $(OTA_DATA_OFFSET) $(BLANK_OTA_DATA_FILE)
|
||||
|
||||
ESPTOOL_ARGS := --esptool-args port=$(CONFIG_ESPTOOLPY_PORT) baud=$(CONFIG_ESPTOOLPY_BAUD) before=$(CONFIG_ESPTOOLPY_BEFORE) after=$(CONFIG_ESPTOOLPY_AFTER)
|
||||
|
||||
erase_otadata: $(PARTITION_TABLE_CSV_PATH) partition_table_get_info | check_python_dependencies
|
||||
$(OTATOOL_PY) $(ESPTOOL_ARGS) --partition-table-file $(PARTITION_TABLE_CSV_PATH) \
|
||||
--partition-table-offset $(PARTITION_TABLE_OFFSET) \
|
||||
erase_otadata
|
||||
$(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) $(ESPTOOL_ARGS) --partition-table-file $(PARTITION_TABLE_CSV_PATH) \
|
||||
--partition-table-offset $(partition_table_offset) \
|
||||
read_otadata
|
||||
$(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
|
||||
ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT
|
||||
encrypted-flash: blank_ota_data
|
||||
endif
|
||||
|
||||
TMP_DEFINES := $(BUILD_DIR_BASE)/app_update/tmp_cppflags.txt
|
||||
export TMP_DEFINES
|
||||
|
||||
@@ -34,8 +34,8 @@ const __attribute__((section(".rodata_desc"))) esp_app_desc_t esp_app_desc = {
|
||||
#endif
|
||||
.idf_ver = IDF_VER,
|
||||
|
||||
#ifdef CONFIG_BOOTLOADER_APP_SECURE_VERSION
|
||||
.secure_version = CONFIG_BOOTLOADER_APP_SECURE_VERSION,
|
||||
#ifdef CONFIG_APP_SECURE_VERSION
|
||||
.secure_version = CONFIG_APP_SECURE_VERSION,
|
||||
#else
|
||||
.secure_version = 0,
|
||||
#endif
|
||||
@@ -72,35 +72,13 @@ 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));
|
||||
size_t n = MIN((size - 1) / 2, sizeof(esp_app_desc.app_elf_sha256));
|
||||
const uint8_t* src = esp_app_desc.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*i] = to_hex_digit(src[i] >> 4);
|
||||
dst[2*i + 1] = to_hex_digit(src[i] & 0xf);
|
||||
}
|
||||
dst[2*n] = 0;
|
||||
return 2*n + 1;
|
||||
|
||||
@@ -32,17 +32,18 @@
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "esp_ota_ops.h"
|
||||
#include "sys/queue.h"
|
||||
#include "esp32/rom/crc.h"
|
||||
#include "rom/queue.h"
|
||||
#include "rom/crc.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_flash_partitions.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 SUB_TYPE_ID(i) (i & 0x0F)
|
||||
|
||||
typedef struct ota_ops_entry_ {
|
||||
uint32_t handle;
|
||||
@@ -107,12 +108,19 @@ static esp_err_t image_validate(const esp_partition_t *partition, esp_image_load
|
||||
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_BOOTLOADER_APP_ROLLBACK_ENABLE
|
||||
#ifdef CONFIG_APP_ROLLBACK_ENABLE
|
||||
ESP_LOGD(TAG, "Monitoring the first boot of the app is enabled.");
|
||||
return ESP_OTA_IMG_NEW;
|
||||
#else
|
||||
@@ -143,7 +151,7 @@ esp_err_t esp_ota_begin(const esp_partition_t *partition, size_t image_size, esp
|
||||
return ESP_ERR_OTA_PARTITION_CONFLICT;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
|
||||
#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) {
|
||||
@@ -157,8 +165,7 @@ esp_err_t esp_ota_begin(const esp_partition_t *partition, size_t image_size, esp
|
||||
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) {
|
||||
@@ -201,7 +208,7 @@ esp_err_t esp_ota_write(esp_ota_handle_t handle, const void *data, size_t size)
|
||||
// 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]);
|
||||
ESP_LOGE(TAG, "OTA image has invalid magic byte (expected 0xE9, saw 0x%02x", data_bytes[0]);
|
||||
return ESP_ERR_OTA_VALIDATE_FAILED;
|
||||
}
|
||||
|
||||
@@ -394,7 +401,7 @@ esp_err_t esp_ota_set_boot_partition(const esp_partition_t *partition)
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
} else {
|
||||
#ifdef CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
|
||||
#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) {
|
||||
@@ -582,7 +589,7 @@ esp_err_t esp_ota_get_partition_description(const esp_partition_t *partition, es
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
|
||||
#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);
|
||||
@@ -614,7 +621,7 @@ bool esp_ota_check_rollback_is_possible(void)
|
||||
int last_active_ota = (~active_ota)&1;
|
||||
|
||||
const esp_partition_t *partition = NULL;
|
||||
#ifndef CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
|
||||
#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) {
|
||||
@@ -630,7 +637,7 @@ bool esp_ota_check_rollback_is_possible(void)
|
||||
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_BOOTLOADER_APP_ANTI_ROLLBACK
|
||||
#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) {
|
||||
@@ -661,7 +668,7 @@ static esp_err_t esp_ota_current_ota_is_workable(bool 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_BOOTLOADER_APP_ANTI_ROLLBACK
|
||||
#ifdef CONFIG_APP_ANTI_ROLLBACK
|
||||
if (err == ESP_OK) {
|
||||
return esp_ota_set_anti_rollback();
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "esp_err.h"
|
||||
#include "esp_partition.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_flash_partitions.h"
|
||||
#include "esp_flash_data_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
|
||||
@@ -21,20 +21,16 @@ import argparse
|
||||
import os
|
||||
import sys
|
||||
import binascii
|
||||
import subprocess
|
||||
import tempfile
|
||||
import collections
|
||||
import struct
|
||||
|
||||
try:
|
||||
from parttool import PartitionName, PartitionType, ParttoolTarget, PARTITION_TABLE_OFFSET
|
||||
except ImportError:
|
||||
COMPONENTS_PATH = os.path.expandvars(os.path.join("$IDF_PATH", "components"))
|
||||
PARTTOOL_DIR = os.path.join(COMPONENTS_PATH, "partition_table")
|
||||
__version__ = '1.0'
|
||||
|
||||
sys.path.append(PARTTOOL_DIR)
|
||||
from parttool import PartitionName, PartitionType, ParttoolTarget, PARTITION_TABLE_OFFSET
|
||||
IDF_COMPONENTS_PATH = os.path.expandvars(os.path.join("$IDF_PATH", "components"))
|
||||
|
||||
__version__ = '2.0'
|
||||
PARTTOOL_PY = os.path.join(IDF_COMPONENTS_PATH, "partition_table", "parttool.py")
|
||||
|
||||
SPI_FLASH_SEC_SIZE = 0x2000
|
||||
|
||||
@@ -46,72 +42,121 @@ def status(msg):
|
||||
print(msg)
|
||||
|
||||
|
||||
class OtatoolTarget():
|
||||
def _invoke_parttool(parttool_args, args, output=False, partition=None):
|
||||
invoke_args = []
|
||||
|
||||
OTADATA_PARTITION = PartitionType("data", "ota")
|
||||
if partition:
|
||||
invoke_args += [sys.executable, PARTTOOL_PY] + partition
|
||||
else:
|
||||
invoke_args += [sys.executable, PARTTOOL_PY, "--partition-type", "data", "--partition-subtype", "ota"]
|
||||
|
||||
def __init__(self, port=None, baud=None, partition_table_offset=PARTITION_TABLE_OFFSET, partition_table_file=None,
|
||||
spi_flash_sec_size=SPI_FLASH_SEC_SIZE, esptool_args=[], esptool_write_args=[],
|
||||
esptool_read_args=[], esptool_erase_args=[]):
|
||||
self.target = ParttoolTarget(port, baud, partition_table_offset, partition_table_file, esptool_args,
|
||||
esptool_write_args, esptool_read_args, esptool_erase_args)
|
||||
self.spi_flash_sec_size = spi_flash_sec_size
|
||||
if quiet:
|
||||
invoke_args += ["-q"]
|
||||
|
||||
temp_file = tempfile.NamedTemporaryFile(delete=False)
|
||||
temp_file.close()
|
||||
try:
|
||||
self.target.read_partition(OtatoolTarget.OTADATA_PARTITION, temp_file.name)
|
||||
with open(temp_file.name, "rb") as f:
|
||||
self.otadata = f.read()
|
||||
except Exception:
|
||||
self.otadata = None
|
||||
finally:
|
||||
os.unlink(temp_file.name)
|
||||
if args.port != "":
|
||||
invoke_args += ["--port", args.port]
|
||||
|
||||
def _check_otadata_partition(self):
|
||||
if not self.otadata:
|
||||
raise Exception("No otadata partition found")
|
||||
if args.partition_table_file:
|
||||
invoke_args += ["--partition-table-file", args.partition_table_file]
|
||||
|
||||
def erase_otadata(self):
|
||||
self._check_otadata_partition()
|
||||
self.target.erase_partition(OtatoolTarget.OTADATA_PARTITION)
|
||||
if args.partition_table_offset:
|
||||
invoke_args += ["--partition-table-offset", args.partition_table_offset]
|
||||
|
||||
def _get_otadata_info(self):
|
||||
info = []
|
||||
invoke_args += parttool_args
|
||||
|
||||
otadata_info = collections.namedtuple("otadata_info", "seq crc")
|
||||
if output:
|
||||
return subprocess.check_output(invoke_args)
|
||||
else:
|
||||
return subprocess.check_call(invoke_args)
|
||||
|
||||
for i in range(2):
|
||||
start = i * (self.spi_flash_sec_size >> 1)
|
||||
|
||||
seq = bytearray(self.otadata[start:start + 4])
|
||||
crc = bytearray(self.otadata[start + 28:start + 32])
|
||||
def _get_otadata_contents(args, check=True):
|
||||
global quiet
|
||||
|
||||
seq = struct.unpack('>I', seq)
|
||||
crc = struct.unpack('>I', crc)
|
||||
if check:
|
||||
check_args = ["get_partition_info", "--info", "offset", "size"]
|
||||
|
||||
info.append(otadata_info(seq[0], crc[0]))
|
||||
quiet = True
|
||||
output = _invoke_parttool(check_args, args, True).split(b" ")
|
||||
quiet = args.quiet
|
||||
|
||||
return info
|
||||
if not output:
|
||||
raise RuntimeError("No ota_data partition found")
|
||||
|
||||
def _get_partition_id_from_ota_id(self, ota_id):
|
||||
if isinstance(ota_id, int):
|
||||
return PartitionType("app", "ota_" + str(ota_id))
|
||||
else:
|
||||
return PartitionName(ota_id)
|
||||
with tempfile.NamedTemporaryFile(delete=False) as f:
|
||||
f_name = f.name
|
||||
|
||||
def switch_ota_partition(self, ota_id):
|
||||
self._check_otadata_partition()
|
||||
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)
|
||||
|
||||
sys.path.append(PARTTOOL_DIR)
|
||||
import gen_esp32part as gen
|
||||
return contents
|
||||
|
||||
def is_otadata_info_valid(status):
|
||||
|
||||
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
|
||||
|
||||
partition_table = self.target.partition_table
|
||||
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()
|
||||
|
||||
@@ -126,36 +171,39 @@ class OtatoolTarget():
|
||||
ota_partitions = sorted(ota_partitions, key=lambda p: p.subtype)
|
||||
|
||||
if not ota_partitions:
|
||||
raise Exception("No ota app partitions found")
|
||||
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 isinstance(ota_id, int):
|
||||
ota_partition_next = filter(lambda p: p.subtype - gen.MIN_PARTITION_SUBTYPE_APP_OTA == ota_id, ota_partitions)
|
||||
if args.name:
|
||||
ota_partition_next = filter(lambda p: p.name == args.name, ota_partitions)
|
||||
else:
|
||||
ota_partition_next = filter(lambda p: p.name == ota_id, ota_partitions)
|
||||
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 Exception("Partition to switch to not found")
|
||||
raise RuntimeError("Partition to switch to not found")
|
||||
|
||||
otadata_info = self._get_otadata_info()
|
||||
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_info_valid(otadata_info[0]) and is_otadata_info_valid(otadata_info[1]):
|
||||
if otadata_info[0].seq >= otadata_info[1].seq:
|
||||
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_info_valid(otadata_info[0]):
|
||||
elif is_otadata_status_valid(otadata_status[0]):
|
||||
otadata_compute_base = 0
|
||||
elif is_otadata_info_valid(otadata_info[1]):
|
||||
elif is_otadata_status_valid(otadata_status[1]):
|
||||
otadata_compute_base = 1
|
||||
# Both are invalid (could be initial state - all 0xFF's)
|
||||
else:
|
||||
@@ -168,7 +216,7 @@ class OtatoolTarget():
|
||||
|
||||
# Find the next ota sequence number
|
||||
if otadata_compute_base == 0 or otadata_compute_base == 1:
|
||||
base_seq = otadata_info[otadata_compute_base].seq % (1 << 32)
|
||||
base_seq = otadata_status[otadata_compute_base].seq % (1 << 32)
|
||||
|
||||
i = 0
|
||||
while base_seq > target_seq % ota_partitions_num + i * ota_partitions_num:
|
||||
@@ -183,104 +231,70 @@ class OtatoolTarget():
|
||||
ota_seq_crc_next = binascii.crc32(ota_seq_next, 0xFFFFFFFF) % (1 << 32)
|
||||
ota_seq_crc_next = struct.pack("I", ota_seq_crc_next)
|
||||
|
||||
temp_file = tempfile.NamedTemporaryFile(delete=False)
|
||||
temp_file.close()
|
||||
with open(f_name, "wb") as otadata_next_file:
|
||||
start = (1 if otadata_compute_base == 0 else 0) * (SPI_FLASH_SEC_SIZE >> 1)
|
||||
|
||||
try:
|
||||
with open(temp_file.name, "wb") as otadata_next_file:
|
||||
start = (1 if otadata_compute_base == 0 else 0) * (self.spi_flash_sec_size >> 1)
|
||||
otadata_next_file.write(otadata_contents)
|
||||
|
||||
otadata_next_file.write(self.otadata)
|
||||
otadata_next_file.seek(start)
|
||||
otadata_next_file.write(ota_seq_next)
|
||||
|
||||
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.seek(start + 28)
|
||||
otadata_next_file.write(ota_seq_crc_next)
|
||||
otadata_next_file.flush()
|
||||
|
||||
otadata_next_file.flush()
|
||||
|
||||
self.target.write_partition(OtatoolTarget.OTADATA_PARTITION, temp_file.name)
|
||||
finally:
|
||||
os.unlink(temp_file.name)
|
||||
|
||||
def read_ota_partition(self, ota_id, output):
|
||||
self.target.read_partition(self._get_partition_id_from_ota_id(ota_id), output)
|
||||
|
||||
def write_ota_partition(self, ota_id, input):
|
||||
self.target.write_partition(self._get_partition_id_from_ota_id(ota_id), input)
|
||||
|
||||
def erase_ota_partition(self, ota_id):
|
||||
self.target.erase_partition(self._get_partition_id_from_ota_id(ota_id))
|
||||
_invoke_parttool(["write_partition", "--input", f_name], args)
|
||||
status("Updated ota_data partition")
|
||||
finally:
|
||||
os.unlink(f_name)
|
||||
|
||||
|
||||
def _read_otadata(target):
|
||||
target._check_otadata_partition()
|
||||
|
||||
otadata_info = target._get_otadata_info()
|
||||
|
||||
print(" {:8s} \t {:8s} | \t {:8s} \t {:8s}".format("OTA_SEQ", "CRC", "OTA_SEQ", "CRC"))
|
||||
print("Firmware: 0x{:8x} \t0x{:8x} | \t0x{:8x} \t 0x{:8x}".format(otadata_info[0].seq, otadata_info[0].crc,
|
||||
otadata_info[1].seq, otadata_info[1].crc))
|
||||
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 _erase_otadata(target):
|
||||
target.erase_otadata()
|
||||
status("Erased ota_data partition contents")
|
||||
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 _switch_ota_partition(target, ota_id):
|
||||
target.switch_ota_partition(ota_id)
|
||||
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 _read_ota_partition(target, ota_id, output):
|
||||
target.read_ota_partition(ota_id, output)
|
||||
status("Read ota partition contents to file {}".format(output))
|
||||
|
||||
|
||||
def _write_ota_partition(target, ota_id, input):
|
||||
target.write_ota_partition(ota_id, input)
|
||||
status("Written contents of file {} to ota partition".format(input))
|
||||
|
||||
|
||||
def _erase_ota_partition(target, ota_id):
|
||||
target.erase_ota_partition(ota_id)
|
||||
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.", file=sys.stderr)
|
||||
elif sys.version_info[0] == 3 and sys.version_info[1] < 6:
|
||||
print("WARNING: Python 3 versions older than 3.6 are not supported.", file=sys.stderr)
|
||||
global quiet
|
||||
|
||||
parser = argparse.ArgumentParser("ESP-IDF OTA Partitions Tool")
|
||||
|
||||
parser.add_argument("--quiet", "-q", help="suppress stderr messages", action="store_true")
|
||||
parser.add_argument("--esptool-args", help="additional main arguments for esptool", nargs="+")
|
||||
parser.add_argument("--esptool-write-args", help="additional subcommand arguments for esptool write_flash", nargs="+")
|
||||
parser.add_argument("--esptool-read-args", help="additional subcommand arguments for esptool read_flash", nargs="+")
|
||||
parser.add_argument("--esptool-erase-args", help="additional subcommand arguments for esptool erase_region", nargs="+")
|
||||
|
||||
# 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.
|
||||
parser.add_argument("--port", "-p", help="port where the device to read the partition table from is attached")
|
||||
partition_table_info_source_args = parser.add_mutually_exclusive_group()
|
||||
|
||||
parser.add_argument("--baud", "-b", help="baudrate to use", type=int)
|
||||
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", type=str)
|
||||
|
||||
parser.add_argument("--partition-table-file", "-f", help="file (CSV/binary) to read the partition table from; \
|
||||
overrides device attached to specified port as the partition table source when defined")
|
||||
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")
|
||||
|
||||
spi_flash_sec_size = argparse.ArgumentParser(add_help=False)
|
||||
spi_flash_sec_size.add_argument("--spi-flash-sec-size", help="value of SPI_FLASH_SEC_SIZE macro", type=str)
|
||||
|
||||
# Specify the supported operations
|
||||
subparsers.add_parser("read_otadata", help="read otadata partition", parents=[spi_flash_sec_size])
|
||||
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)
|
||||
@@ -288,7 +302,7 @@ def main():
|
||||
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_ota_partition", help="switch otadata partition", parents=[slot_or_name_parser, spi_flash_sec_size])
|
||||
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")
|
||||
@@ -308,84 +322,17 @@ def main():
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
target_args = {}
|
||||
|
||||
if args.port:
|
||||
target_args["port"] = args.port
|
||||
|
||||
if args.partition_table_file:
|
||||
target_args["partition_table_file"] = args.partition_table_file
|
||||
|
||||
if args.partition_table_offset:
|
||||
target_args["partition_table_offset"] = int(args.partition_table_offset, 0)
|
||||
|
||||
try:
|
||||
if args.spi_flash_sec_size:
|
||||
target_args["spi_flash_sec_size"] = int(args.spi_flash_sec_size, 0)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
if args.esptool_args:
|
||||
target_args["esptool_args"] = args.esptool_args
|
||||
|
||||
if args.esptool_write_args:
|
||||
target_args["esptool_write_args"] = args.esptool_write_args
|
||||
|
||||
if args.esptool_read_args:
|
||||
target_args["esptool_read_args"] = args.esptool_read_args
|
||||
|
||||
if args.esptool_erase_args:
|
||||
target_args["esptool_erase_args"] = args.esptool_erase_args
|
||||
|
||||
if args.baud:
|
||||
target_args["baud"] = args.baud
|
||||
|
||||
target = OtatoolTarget(**target_args)
|
||||
|
||||
# Create the operation table and execute the operation
|
||||
common_args = {'target':target}
|
||||
|
||||
ota_id = []
|
||||
|
||||
try:
|
||||
if args.name is not None:
|
||||
ota_id = ["name"]
|
||||
else:
|
||||
if args.slot is not None:
|
||||
ota_id = ["slot"]
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
otatool_ops = {
|
||||
'read_otadata':(_read_otadata, []),
|
||||
'erase_otadata':(_erase_otadata, []),
|
||||
'switch_ota_partition':(_switch_ota_partition, ota_id),
|
||||
'read_ota_partition':(_read_ota_partition, ["output"] + ota_id),
|
||||
'write_ota_partition':(_write_ota_partition, ["input"] + ota_id),
|
||||
'erase_ota_partition':(_erase_ota_partition, ota_id)
|
||||
}
|
||||
|
||||
(op, op_args) = otatool_ops[args.operation]
|
||||
|
||||
for op_arg in op_args:
|
||||
common_args.update({op_arg:vars(args)[op_arg]})
|
||||
|
||||
try:
|
||||
common_args['ota_id'] = common_args.pop('name')
|
||||
except KeyError:
|
||||
try:
|
||||
common_args['ota_id'] = common_args.pop('slot')
|
||||
except KeyError:
|
||||
pass
|
||||
# Else execute the operation
|
||||
operation_func = globals()[args.operation]
|
||||
|
||||
if quiet:
|
||||
# If exceptions occur, suppress and exit quietly
|
||||
try:
|
||||
op(**common_args)
|
||||
operation_func(args)
|
||||
except Exception:
|
||||
sys.exit(2)
|
||||
else:
|
||||
op(**common_args)
|
||||
operation_func(args)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
9
components/app_update/project_include.cmake
Normal file
9
components/app_update/project_include.cmake
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
# 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,3 +1,6 @@
|
||||
idf_component_register(SRC_DIRS "."
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES unity test_utils app_update bootloader_support nvs_flash)
|
||||
set(COMPONENT_SRCDIRS ".")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
set(COMPONENT_REQUIRES unity test_utils app_update bootloader_support nvs_flash)
|
||||
|
||||
register_component()
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
TEST_CASE("esp_ota_get_app_elf_sha256 test", "[esp_app_desc]")
|
||||
{
|
||||
const int sha256_hex_len = CONFIG_APP_RETRIEVE_LEN_ELF_SHA;
|
||||
const int sha256_hex_len = 64;
|
||||
char dst[sha256_hex_len + 2];
|
||||
const char fill = 0xcc;
|
||||
int res;
|
||||
|
||||
@@ -5,11 +5,10 @@
|
||||
#include <esp_types.h>
|
||||
#include <stdio.h>
|
||||
#include "string.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "esp32/rom/spi_flash.h"
|
||||
#include "esp32/rom/rtc.h"
|
||||
#include "esp32/rom/ets_sys.h"
|
||||
#include "rom/spi_flash.h"
|
||||
#include "rom/rtc.h"
|
||||
#include "rom/ets_sys.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
@@ -29,8 +28,8 @@
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_sleep.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
RTC_DATA_ATTR static int boot_count = 0;
|
||||
static const char *TAG = "ota_test";
|
||||
@@ -240,7 +239,7 @@ static void reset_output_pin(uint32_t num_pin)
|
||||
|
||||
static void mark_app_valid(void)
|
||||
{
|
||||
#ifdef CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
|
||||
#ifdef CONFIG_APP_ROLLBACK_ENABLE
|
||||
TEST_ESP_OK(esp_ota_mark_app_valid_cancel_rollback());
|
||||
#endif
|
||||
}
|
||||
@@ -387,7 +386,7 @@ 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_t handle = 0;
|
||||
nvs_handle handle = 0;
|
||||
int boot_count_nvs = 0;
|
||||
switch (boot_count) {
|
||||
case 2:
|
||||
@@ -444,7 +443,7 @@ static void test_flow4(void)
|
||||
// 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);
|
||||
TEST_CASE_MULTIPLE_STAGES("Switching between factory, OTA0, sets pin_factory_reset, factory", "[app_update][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow4, test_flow4, test_flow4);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BOOTLOADER_APP_TEST
|
||||
@@ -487,7 +486,7 @@ static void test_flow5(void)
|
||||
// 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);
|
||||
TEST_CASE_MULTIPLE_STAGES("Switching between factory, test, factory", "[app_update][timeout=90][reset=DEEPSLEEP_RESET, DEEPSLEEP_RESET, DEEPSLEEP_RESET]", start_test, test_flow5, test_flow5, test_flow5);
|
||||
#endif
|
||||
|
||||
static const esp_partition_t* app_update(void)
|
||||
@@ -519,7 +518,7 @@ static void test_rollback1(void)
|
||||
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_BOOTLOADER_APP_ROLLBACK_ENABLE
|
||||
#ifndef CONFIG_APP_ROLLBACK_ENABLE
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_UNDEFINED, ota_state);
|
||||
#else
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_NEW, ota_state);
|
||||
@@ -531,7 +530,7 @@ static void test_rollback1(void)
|
||||
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_BOOTLOADER_APP_ROLLBACK_ENABLE
|
||||
#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);
|
||||
@@ -598,7 +597,7 @@ static void test_rollback2(void)
|
||||
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_BOOTLOADER_APP_ROLLBACK_ENABLE
|
||||
#ifndef CONFIG_APP_ROLLBACK_ENABLE
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_UNDEFINED, ota_state);
|
||||
#else
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_NEW, ota_state);
|
||||
@@ -610,7 +609,7 @@ static void test_rollback2(void)
|
||||
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_BOOTLOADER_APP_ROLLBACK_ENABLE
|
||||
#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);
|
||||
@@ -621,7 +620,7 @@ static void test_rollback2(void)
|
||||
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_BOOTLOADER_APP_ROLLBACK_ENABLE
|
||||
#ifndef CONFIG_APP_ROLLBACK_ENABLE
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_UNDEFINED, ota_state);
|
||||
#else
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_NEW, ota_state);
|
||||
@@ -633,7 +632,7 @@ static void test_rollback2(void)
|
||||
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_BOOTLOADER_APP_ROLLBACK_ENABLE
|
||||
#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
|
||||
@@ -666,7 +665,7 @@ static void test_rollback2_1(void)
|
||||
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_BOOTLOADER_APP_ROLLBACK_ENABLE
|
||||
#ifndef CONFIG_APP_ROLLBACK_ENABLE
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_INVALID, ota_state);
|
||||
#else
|
||||
TEST_ASSERT_EQUAL(ESP_OTA_IMG_ABORTED, ota_state);
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
idf_component_register(SRCS "asio/asio/src/asio.cpp"
|
||||
INCLUDE_DIRS "asio/asio/include" "port/include"
|
||||
REQUIRES lwip)
|
||||
set(COMPONENT_ADD_INCLUDEDIRS asio/asio/include port/include)
|
||||
set(COMPONENT_SRCS "asio/asio/src/asio.cpp")
|
||||
|
||||
set(COMPONENT_REQUIRES lwip)
|
||||
|
||||
register_component()
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
// Enabling exceptions only when they are enabled in menuconfig
|
||||
//
|
||||
# include <sdkconfig.h>
|
||||
# ifndef CONFIG_COMPILER_CXX_EXCEPTIONS
|
||||
# ifndef CONFIG_CXX_EXCEPTIONS
|
||||
# define ASIO_NO_EXCEPTIONS
|
||||
# endif // CONFIG_COMPILER_CXX_EXCEPTIONS
|
||||
# endif // CONFIG_CXX_EXCEPTIONS
|
||||
|
||||
//
|
||||
// LWIP compatifility inet and address macros/functions
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
//
|
||||
// This exception stub is enabled only if exceptions are disabled in menuconfig
|
||||
//
|
||||
#if !defined(CONFIG_COMPILER_CXX_EXCEPTIONS) && defined (ASIO_NO_EXCEPTIONS)
|
||||
#if !defined(CONFIG_CXX_EXCEPTIONS) && defined (ASIO_NO_EXCEPTIONS)
|
||||
|
||||
#include "esp_log.h"
|
||||
|
||||
@@ -34,6 +34,6 @@ void throw_exception(const Exception& e)
|
||||
abort();
|
||||
}
|
||||
}}
|
||||
#endif // CONFIG_COMPILER_CXX_EXCEPTIONS==1 && defined (ASIO_NO_EXCEPTIONS)
|
||||
#endif // CONFIG_CXX_EXCEPTIONS==1 && defined (ASIO_NO_EXCEPTIONS)
|
||||
|
||||
#endif // _ESP_EXCEPTION_H_
|
||||
|
||||
30
components/aws_iot/CMakeLists.txt
Normal file
30
components/aws_iot/CMakeLists.txt
Normal file
@@ -0,0 +1,30 @@
|
||||
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()
|
||||
164
components/aws_iot/Kconfig
Normal file
164
components/aws_iot/Kconfig
Normal file
@@ -0,0 +1,164 @@
|
||||
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.
|
||||
|
||||
config AWS_IOT_MQTT_HOST
|
||||
string "AWS IoT Endpoint Hostname"
|
||||
depends on AWS_IOT_SDK
|
||||
default ""
|
||||
help
|
||||
Default endpoint host name to connect to AWS IoT MQTT/S gateway
|
||||
|
||||
This is the custom endpoint hostname and is specific to an AWS
|
||||
IoT account. You can find it by logging into your AWS IoT
|
||||
Console and clicking the Settings button. The endpoint hostname
|
||||
is shown under the "Custom Endpoint" heading on this page.
|
||||
|
||||
If you need per-device hostnames for different regions or
|
||||
accounts, you can override the default hostname in your app.
|
||||
|
||||
config AWS_IOT_MQTT_PORT
|
||||
int "AWS IoT MQTT Port"
|
||||
depends on AWS_IOT_SDK
|
||||
default 8883
|
||||
range 0 65535
|
||||
help
|
||||
Default port number to connect to AWS IoT MQTT/S gateway
|
||||
|
||||
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
|
||||
1
components/aws_iot/aws-iot-device-sdk-embedded-C
Submodule
1
components/aws_iot/aws-iot-device-sdk-embedded-C
Submodule
Submodule components/aws_iot/aws-iot-device-sdk-embedded-C added at 299183238f
20
components/aws_iot/component.mk
Normal file
20
components/aws_iot/component.mk
Normal file
@@ -0,0 +1,20 @@
|
||||
#
|
||||
# Component Makefile
|
||||
#
|
||||
|
||||
ifdef CONFIG_AWS_IOT_SDK
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := include aws-iot-device-sdk-embedded-C/include
|
||||
|
||||
COMPONENT_SRCDIRS := aws-iot-device-sdk-embedded-C/src port
|
||||
|
||||
# Check the submodule is initialised
|
||||
COMPONENT_SUBMODULES := aws-iot-device-sdk-embedded-C
|
||||
|
||||
|
||||
else
|
||||
# Disable AWS IoT support
|
||||
COMPONENT_ADD_INCLUDEDIRS :=
|
||||
COMPONENT_ADD_LDFLAGS :=
|
||||
COMPONENT_SRCDIRS :=
|
||||
endif
|
||||
65
components/aws_iot/include/aws_iot_config.h
Normal file
65
components/aws_iot/include/aws_iot_config.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://aws.amazon.com/apache2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file aws_iot_config.h
|
||||
* @brief AWS IoT specific configuration file
|
||||
*/
|
||||
|
||||
#ifndef _AWS_IOT_CONFIG_H_
|
||||
#define _AWS_IOT_CONFIG_H_
|
||||
|
||||
#include "aws_iot_log.h"
|
||||
|
||||
// This configuration macro needs to be available globally to enable threading
|
||||
#define _ENABLE_THREAD_SUPPORT_
|
||||
|
||||
// These values are defined in the menuconfig of the AWS IoT component.
|
||||
// However, you can override these constants from your own code.
|
||||
#define AWS_IOT_MQTT_HOST CONFIG_AWS_IOT_MQTT_HOST ///< Customer specific MQTT HOST. The same will be used for Thing Shadow
|
||||
#define AWS_IOT_MQTT_PORT CONFIG_AWS_IOT_MQTT_PORT ///< default port for MQTT/S
|
||||
|
||||
// These values are defaults and are used for ShadowConnectParametersDefault.
|
||||
// You should override them from your own code.
|
||||
#define AWS_IOT_MQTT_CLIENT_ID "ESP32" ///< MQTT client ID should be unique for every device
|
||||
#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
|
||||
|
||||
// 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 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_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.
|
||||
|
||||
#endif /* _AWS_IOT_CONFIG_H_ */
|
||||
44
components/aws_iot/include/aws_iot_log.h
Normal file
44
components/aws_iot/include/aws_iot_log.h
Normal file
@@ -0,0 +1,44 @@
|
||||
// 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.
|
||||
#pragma once
|
||||
|
||||
/* (these two headers aren't used here, but AWS IoT SDK code relies on them
|
||||
being included from here...) */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
|
||||
/* This is a stub replacement for the aws_iot_log.h header in the AWS IoT SDK,
|
||||
which redirects their logging framework into the esp-idf logging framework.
|
||||
|
||||
The current (2.1.1) upstream AWS IoT SDK doesn't allow this as some of its
|
||||
headers include aws_iot_log.h, but our modified fork does.
|
||||
*/
|
||||
|
||||
// redefine the AWS IoT log functions to call into the IDF log layer
|
||||
#define IOT_DEBUG(format, ...) ESP_LOGD("aws_iot", format, ##__VA_ARGS__)
|
||||
#define IOT_INFO(format, ...) ESP_LOGI("aws_iot", format, ##__VA_ARGS__)
|
||||
#define IOT_WARN(format, ...) ESP_LOGW("aws_iot", format, ##__VA_ARGS__)
|
||||
#define IOT_ERROR(format, ...) ESP_LOGE("aws_iot", format, ##__VA_ARGS__)
|
||||
|
||||
/* Function tracing macros used in AWS IoT SDK,
|
||||
mapped to "verbose" level output
|
||||
*/
|
||||
#define FUNC_ENTRY ESP_LOGV("aws_iot", "FUNC_ENTRY: %s L#%d \n", __func__, __LINE__)
|
||||
#define FUNC_EXIT_RC(x) \
|
||||
do { \
|
||||
ESP_LOGV("aws_iot", "FUNC_EXIT: %s L#%d Return Code : %d \n", __func__, __LINE__, x); \
|
||||
return x; \
|
||||
} while(0)
|
||||
64
components/aws_iot/include/network_platform.h
Normal file
64
components/aws_iot/include/network_platform.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Additions Copyright 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.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://aws.amazon.com/apache2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file 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 IOTSDKC_NETWORK_MBEDTLS_PLATFORM_H_H
|
||||
|
||||
#if !defined(MBEDTLS_CONFIG_FILE)
|
||||
#include "mbedtls/config.h"
|
||||
#else
|
||||
#include MBEDTLS_CONFIG_FILE
|
||||
#endif
|
||||
|
||||
#include "mbedtls/platform.h"
|
||||
#include "mbedtls/net_sockets.h"
|
||||
#include "mbedtls/ssl.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#include "mbedtls/certs.h"
|
||||
#include "mbedtls/x509.h"
|
||||
#include "mbedtls/error.h"
|
||||
#include "mbedtls/debug.h"
|
||||
#include "mbedtls/timing.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief TLS Connection Parameters
|
||||
*
|
||||
* Defines a type containing TLS specific parameters to be passed down to the
|
||||
* TLS networking layer to create a TLS secured socket.
|
||||
*/
|
||||
typedef struct _TLSDataParams {
|
||||
mbedtls_entropy_context entropy;
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
mbedtls_ssl_context ssl;
|
||||
mbedtls_ssl_config conf;
|
||||
uint32_t flags;
|
||||
mbedtls_x509_crt cacert;
|
||||
mbedtls_x509_crt clicert;
|
||||
mbedtls_pk_context pkey;
|
||||
mbedtls_net_context server_fd;
|
||||
}TLSDataParams;
|
||||
|
||||
#define IOTSDKC_NETWORK_MBEDTLS_PLATFORM_H_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //IOTSDKC_NETWORK_MBEDTLS_PLATFORM_H_H
|
||||
45
components/aws_iot/include/threads_platform.h
Normal file
45
components/aws_iot/include/threads_platform.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Additions Copyright 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.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://aws.amazon.com/apache2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file 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 "threads_interface.h"
|
||||
|
||||
#ifndef AWS_IOTSDK_THREADS_PLATFORM_H
|
||||
#define AWS_IOTSDK_THREADS_PLATFORM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
/**
|
||||
* @brief Mutex Type
|
||||
*
|
||||
* definition of the Mutex struct. Platform specific
|
||||
*
|
||||
*/
|
||||
struct _IoT_Mutex_t {
|
||||
SemaphoreHandle_t mutex;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* AWS_IOTSDK_THREADS_PLATFORM_H */
|
||||
|
||||
|
||||
40
components/aws_iot/include/timer_platform.h
Normal file
40
components/aws_iot/include/timer_platform.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Additions Copyright 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.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://aws.amazon.com/apache2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file 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 AWS_IOT_PLATFORM_H
|
||||
#define AWS_IOT_PLATFORM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include "timer_interface.h"
|
||||
|
||||
/**
|
||||
* definition of the Timer struct. Platform specific
|
||||
*/
|
||||
struct Timer {
|
||||
uint32_t start_ticks;
|
||||
uint32_t timeout_ticks;
|
||||
uint32_t last_polled_ticks;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* AWS_IOT_PLATFORM_H */
|
||||
419
components/aws_iot/port/network_mbedtls_wrapper.c
Normal file
419
components/aws_iot/port/network_mbedtls_wrapper.c
Normal file
@@ -0,0 +1,419 @@
|
||||
/*
|
||||
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Additions Copyright 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.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://aws.amazon.com/apache2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file 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 <sys/param.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <timer_platform.h>
|
||||
#include <network_interface.h>
|
||||
|
||||
#include "aws_iot_config.h"
|
||||
#include "aws_iot_error.h"
|
||||
#include "network_interface.h"
|
||||
#include "network_platform.h"
|
||||
|
||||
#include "mbedtls/esp_debug.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_vfs.h"
|
||||
|
||||
static const char *TAG = "aws_iot";
|
||||
|
||||
/* This is the value used for ssl read timeout */
|
||||
#define IOT_SSL_READ_TIMEOUT 10
|
||||
|
||||
/*
|
||||
* This is a function to do further verification if needed on the cert received.
|
||||
*
|
||||
* Currently used to print debug-level information about each cert.
|
||||
*/
|
||||
static int _iot_tls_verify_cert(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags) {
|
||||
char buf[256];
|
||||
((void) data);
|
||||
|
||||
if (LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG) {
|
||||
ESP_LOGD(TAG, "Verify requested for (Depth %d):", depth);
|
||||
mbedtls_x509_crt_info(buf, sizeof(buf) - 1, "", crt);
|
||||
ESP_LOGD(TAG, "%s", buf);
|
||||
|
||||
if((*flags) == 0) {
|
||||
ESP_LOGD(TAG, " This certificate has no flags");
|
||||
} else {
|
||||
ESP_LOGD(TAG, "Verify result:%s", buf);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _iot_tls_set_connect_params(Network *pNetwork, const char *pRootCALocation, const char *pDeviceCertLocation,
|
||||
const char *pDevicePrivateKeyLocation, const char *pDestinationURL,
|
||||
uint16_t destinationPort, uint32_t timeout_ms, bool ServerVerificationFlag) {
|
||||
pNetwork->tlsConnectParams.DestinationPort = destinationPort;
|
||||
pNetwork->tlsConnectParams.pDestinationURL = pDestinationURL;
|
||||
pNetwork->tlsConnectParams.pDeviceCertLocation = pDeviceCertLocation;
|
||||
pNetwork->tlsConnectParams.pDevicePrivateKeyLocation = pDevicePrivateKeyLocation;
|
||||
pNetwork->tlsConnectParams.pRootCALocation = pRootCALocation;
|
||||
pNetwork->tlsConnectParams.timeout_ms = timeout_ms;
|
||||
pNetwork->tlsConnectParams.ServerVerificationFlag = ServerVerificationFlag;
|
||||
}
|
||||
|
||||
IoT_Error_t iot_tls_init(Network *pNetwork, const char *pRootCALocation, const char *pDeviceCertLocation,
|
||||
const char *pDevicePrivateKeyLocation, const char *pDestinationURL,
|
||||
uint16_t destinationPort, uint32_t timeout_ms, bool ServerVerificationFlag) {
|
||||
_iot_tls_set_connect_params(pNetwork, pRootCALocation, pDeviceCertLocation, pDevicePrivateKeyLocation,
|
||||
pDestinationURL, destinationPort, timeout_ms, ServerVerificationFlag);
|
||||
|
||||
pNetwork->connect = iot_tls_connect;
|
||||
pNetwork->read = iot_tls_read;
|
||||
pNetwork->write = iot_tls_write;
|
||||
pNetwork->disconnect = iot_tls_disconnect;
|
||||
pNetwork->isConnected = iot_tls_is_connected;
|
||||
pNetwork->destroy = iot_tls_destroy;
|
||||
|
||||
pNetwork->tlsDataParams.flags = 0;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
IoT_Error_t iot_tls_is_connected(Network *pNetwork) {
|
||||
/* Use this to add implementation which can check for physical layer disconnect */
|
||||
return NETWORK_PHYSICAL_LAYER_CONNECTED;
|
||||
}
|
||||
|
||||
IoT_Error_t iot_tls_connect(Network *pNetwork, TLSConnectParams *params) {
|
||||
int ret = SUCCESS;
|
||||
TLSDataParams *tlsDataParams = NULL;
|
||||
char portBuffer[6];
|
||||
char info_buf[256];
|
||||
|
||||
if(NULL == pNetwork) {
|
||||
return NULL_VALUE_ERROR;
|
||||
}
|
||||
|
||||
if(NULL != params) {
|
||||
_iot_tls_set_connect_params(pNetwork, params->pRootCALocation, params->pDeviceCertLocation,
|
||||
params->pDevicePrivateKeyLocation, params->pDestinationURL,
|
||||
params->DestinationPort, params->timeout_ms, params->ServerVerificationFlag);
|
||||
}
|
||||
|
||||
tlsDataParams = &(pNetwork->tlsDataParams);
|
||||
|
||||
mbedtls_net_init(&(tlsDataParams->server_fd));
|
||||
mbedtls_ssl_init(&(tlsDataParams->ssl));
|
||||
mbedtls_ssl_config_init(&(tlsDataParams->conf));
|
||||
|
||||
#ifdef CONFIG_MBEDTLS_DEBUG
|
||||
mbedtls_esp_enable_debug_log(&(tlsDataParams->conf), 4);
|
||||
#endif
|
||||
|
||||
mbedtls_ctr_drbg_init(&(tlsDataParams->ctr_drbg));
|
||||
mbedtls_x509_crt_init(&(tlsDataParams->cacert));
|
||||
mbedtls_x509_crt_init(&(tlsDataParams->clicert));
|
||||
mbedtls_pk_init(&(tlsDataParams->pkey));
|
||||
|
||||
ESP_LOGD(TAG, "Seeding the random number generator...");
|
||||
mbedtls_entropy_init(&(tlsDataParams->entropy));
|
||||
if((ret = mbedtls_ctr_drbg_seed(&(tlsDataParams->ctr_drbg), mbedtls_entropy_func, &(tlsDataParams->entropy),
|
||||
(const unsigned char *) TAG, strlen(TAG))) != 0) {
|
||||
ESP_LOGE(TAG, "failed! mbedtls_ctr_drbg_seed returned -0x%x", -ret);
|
||||
return NETWORK_MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED;
|
||||
}
|
||||
|
||||
/* Load root CA...
|
||||
|
||||
Certs/keys can be paths or they can be raw data. These use a
|
||||
very basic heuristic: if the cert starts with '/' then it's a
|
||||
path, if it's longer than this then it's raw cert data (PEM or DER,
|
||||
neither of which can start with a slash. */
|
||||
if (pNetwork->tlsConnectParams.pRootCALocation[0] == '/') {
|
||||
ESP_LOGD(TAG, "Loading CA root certificate from file ...");
|
||||
ret = mbedtls_x509_crt_parse_file(&(tlsDataParams->cacert), pNetwork->tlsConnectParams.pRootCALocation);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "Loading embedded CA root certificate ...");
|
||||
ret = mbedtls_x509_crt_parse(&(tlsDataParams->cacert), (const unsigned char *)pNetwork->tlsConnectParams.pRootCALocation,
|
||||
strlen(pNetwork->tlsConnectParams.pRootCALocation)+1);
|
||||
}
|
||||
|
||||
if(ret < 0) {
|
||||
ESP_LOGE(TAG, "failed! mbedtls_x509_crt_parse returned -0x%x while parsing root cert", -ret);
|
||||
return NETWORK_X509_ROOT_CRT_PARSE_ERROR;
|
||||
}
|
||||
ESP_LOGD(TAG, "ok (%d skipped)", ret);
|
||||
|
||||
/* Load client certificate... */
|
||||
if (pNetwork->tlsConnectParams.pDeviceCertLocation[0] == '/') {
|
||||
ESP_LOGD(TAG, "Loading client cert from file...");
|
||||
ret = mbedtls_x509_crt_parse_file(&(tlsDataParams->clicert),
|
||||
pNetwork->tlsConnectParams.pDeviceCertLocation);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "Loading embedded client certificate...");
|
||||
ret = mbedtls_x509_crt_parse(&(tlsDataParams->clicert),
|
||||
(const unsigned char *)pNetwork->tlsConnectParams.pDeviceCertLocation,
|
||||
strlen(pNetwork->tlsConnectParams.pDeviceCertLocation)+1);
|
||||
}
|
||||
if(ret != 0) {
|
||||
ESP_LOGE(TAG, "failed! mbedtls_x509_crt_parse returned -0x%x while parsing device cert", -ret);
|
||||
return NETWORK_X509_DEVICE_CRT_PARSE_ERROR;
|
||||
}
|
||||
|
||||
/* Parse client private key... */
|
||||
if (pNetwork->tlsConnectParams.pDevicePrivateKeyLocation[0] == '/') {
|
||||
ESP_LOGD(TAG, "Loading client private key from file...");
|
||||
ret = mbedtls_pk_parse_keyfile(&(tlsDataParams->pkey),
|
||||
pNetwork->tlsConnectParams.pDevicePrivateKeyLocation,
|
||||
"");
|
||||
} else {
|
||||
ESP_LOGD(TAG, "Loading embedded client private key...");
|
||||
ret = mbedtls_pk_parse_key(&(tlsDataParams->pkey),
|
||||
(const unsigned char *)pNetwork->tlsConnectParams.pDevicePrivateKeyLocation,
|
||||
strlen(pNetwork->tlsConnectParams.pDevicePrivateKeyLocation)+1,
|
||||
(const unsigned char *)"", 0);
|
||||
}
|
||||
if(ret != 0) {
|
||||
ESP_LOGE(TAG, "failed! mbedtls_pk_parse_key returned -0x%x while parsing private key", -ret);
|
||||
return NETWORK_PK_PRIVATE_KEY_PARSE_ERROR;
|
||||
}
|
||||
|
||||
/* Done parsing certs */
|
||||
ESP_LOGD(TAG, "ok");
|
||||
snprintf(portBuffer, 6, "%d", pNetwork->tlsConnectParams.DestinationPort);
|
||||
ESP_LOGD(TAG, "Connecting to %s/%s...", pNetwork->tlsConnectParams.pDestinationURL, portBuffer);
|
||||
if((ret = mbedtls_net_connect(&(tlsDataParams->server_fd), pNetwork->tlsConnectParams.pDestinationURL,
|
||||
portBuffer, MBEDTLS_NET_PROTO_TCP)) != 0) {
|
||||
ESP_LOGE(TAG, "failed! mbedtls_net_connect returned -0x%x", -ret);
|
||||
switch(ret) {
|
||||
case MBEDTLS_ERR_NET_SOCKET_FAILED:
|
||||
return NETWORK_ERR_NET_SOCKET_FAILED;
|
||||
case MBEDTLS_ERR_NET_UNKNOWN_HOST:
|
||||
return NETWORK_ERR_NET_UNKNOWN_HOST;
|
||||
case MBEDTLS_ERR_NET_CONNECT_FAILED:
|
||||
default:
|
||||
return NETWORK_ERR_NET_CONNECT_FAILED;
|
||||
};
|
||||
}
|
||||
|
||||
ret = mbedtls_net_set_block(&(tlsDataParams->server_fd));
|
||||
if(ret != 0) {
|
||||
ESP_LOGE(TAG, "failed! net_set_(non)block() returned -0x%x", -ret);
|
||||
return SSL_CONNECTION_ERROR;
|
||||
} ESP_LOGD(TAG, "ok");
|
||||
|
||||
ESP_LOGD(TAG, "Setting up the SSL/TLS structure...");
|
||||
if((ret = mbedtls_ssl_config_defaults(&(tlsDataParams->conf), MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||
MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
|
||||
ESP_LOGE(TAG, "failed! mbedtls_ssl_config_defaults returned -0x%x", -ret);
|
||||
return SSL_CONNECTION_ERROR;
|
||||
}
|
||||
|
||||
mbedtls_ssl_conf_verify(&(tlsDataParams->conf), _iot_tls_verify_cert, NULL);
|
||||
|
||||
if(pNetwork->tlsConnectParams.ServerVerificationFlag == true) {
|
||||
mbedtls_ssl_conf_authmode(&(tlsDataParams->conf), MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||
} else {
|
||||
mbedtls_ssl_conf_authmode(&(tlsDataParams->conf), MBEDTLS_SSL_VERIFY_OPTIONAL);
|
||||
}
|
||||
mbedtls_ssl_conf_rng(&(tlsDataParams->conf), mbedtls_ctr_drbg_random, &(tlsDataParams->ctr_drbg));
|
||||
|
||||
mbedtls_ssl_conf_ca_chain(&(tlsDataParams->conf), &(tlsDataParams->cacert), NULL);
|
||||
ret = mbedtls_ssl_conf_own_cert(&(tlsDataParams->conf), &(tlsDataParams->clicert), &(tlsDataParams->pkey));
|
||||
if(ret != 0) {
|
||||
ESP_LOGE(TAG, "failed! mbedtls_ssl_conf_own_cert returned %d", ret);
|
||||
return SSL_CONNECTION_ERROR;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if((ret = mbedtls_ssl_set_hostname(&(tlsDataParams->ssl), pNetwork->tlsConnectParams.pDestinationURL)) != 0) {
|
||||
ESP_LOGE(TAG, "failed! mbedtls_ssl_set_hostname returned %d", ret);
|
||||
return SSL_CONNECTION_ERROR;
|
||||
}
|
||||
ESP_LOGD(TAG, "SSL state connect : %d ", tlsDataParams->ssl.state);
|
||||
mbedtls_ssl_set_bio(&(tlsDataParams->ssl), &(tlsDataParams->server_fd), mbedtls_net_send, NULL,
|
||||
mbedtls_net_recv_timeout);
|
||||
ESP_LOGD(TAG, "ok");
|
||||
|
||||
ESP_LOGD(TAG, "SSL state connect : %d ", tlsDataParams->ssl.state);
|
||||
ESP_LOGD(TAG, "Performing the SSL/TLS handshake...");
|
||||
while((ret = mbedtls_ssl_handshake(&(tlsDataParams->ssl))) != 0) {
|
||||
if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||
ESP_LOGE(TAG, "failed! mbedtls_ssl_handshake returned -0x%x", -ret);
|
||||
if(ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
|
||||
ESP_LOGE(TAG, " Unable to verify the server's certificate. ");
|
||||
}
|
||||
return SSL_CONNECTION_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "ok [ Protocol is %s ] [ Ciphersuite is %s ]", mbedtls_ssl_get_version(&(tlsDataParams->ssl)),
|
||||
mbedtls_ssl_get_ciphersuite(&(tlsDataParams->ssl)));
|
||||
if((ret = mbedtls_ssl_get_record_expansion(&(tlsDataParams->ssl))) >= 0) {
|
||||
ESP_LOGD(TAG, " [ Record expansion is %d ]", ret);
|
||||
} else {
|
||||
ESP_LOGD(TAG, " [ Record expansion is unknown (compression) ]");
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Verifying peer X.509 certificate...");
|
||||
|
||||
if(pNetwork->tlsConnectParams.ServerVerificationFlag == true) {
|
||||
if((tlsDataParams->flags = mbedtls_ssl_get_verify_result(&(tlsDataParams->ssl))) != 0) {
|
||||
ESP_LOGE(TAG, "failed");
|
||||
mbedtls_x509_crt_verify_info(info_buf, sizeof(info_buf), " ! ", tlsDataParams->flags);
|
||||
ESP_LOGE(TAG, "%s", info_buf);
|
||||
ret = SSL_CONNECTION_ERROR;
|
||||
} else {
|
||||
ESP_LOGD(TAG, "ok");
|
||||
ret = SUCCESS;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGW(TAG, " Server Verification skipped");
|
||||
ret = SUCCESS;
|
||||
}
|
||||
|
||||
if(LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG) {
|
||||
if (mbedtls_ssl_get_peer_cert(&(tlsDataParams->ssl)) != NULL) {
|
||||
ESP_LOGD(TAG, "Peer certificate information:");
|
||||
mbedtls_x509_crt_info((char *) info_buf, sizeof(info_buf) - 1, " ", mbedtls_ssl_get_peer_cert(&(tlsDataParams->ssl)));
|
||||
ESP_LOGD(TAG, "%s", info_buf);
|
||||
}
|
||||
}
|
||||
|
||||
return (IoT_Error_t) ret;
|
||||
}
|
||||
|
||||
IoT_Error_t iot_tls_write(Network *pNetwork, unsigned char *pMsg, size_t len, Timer *timer, size_t *written_len) {
|
||||
size_t written_so_far;
|
||||
bool isErrorFlag = false;
|
||||
int frags, ret = 0;
|
||||
TLSDataParams *tlsDataParams = &(pNetwork->tlsDataParams);
|
||||
|
||||
for(written_so_far = 0, frags = 0;
|
||||
written_so_far < len && !has_timer_expired(timer); written_so_far += ret, frags++) {
|
||||
while(!has_timer_expired(timer) &&
|
||||
(ret = mbedtls_ssl_write(&(tlsDataParams->ssl), pMsg + written_so_far, len - written_so_far)) <= 0) {
|
||||
if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||
ESP_LOGE(TAG, "failed! mbedtls_ssl_write returned -0x%x", -ret);
|
||||
/* All other negative return values indicate connection needs to be reset.
|
||||
* Will be caught in ping request so ignored here */
|
||||
isErrorFlag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(isErrorFlag) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*written_len = written_so_far;
|
||||
|
||||
if(isErrorFlag) {
|
||||
return NETWORK_SSL_WRITE_ERROR;
|
||||
} else if(has_timer_expired(timer) && written_so_far != len) {
|
||||
return NETWORK_SSL_WRITE_TIMEOUT_ERROR;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
IoT_Error_t iot_tls_read(Network *pNetwork, unsigned char *pMsg, size_t len, Timer *timer, size_t *read_len) {
|
||||
TLSDataParams *tlsDataParams = &(pNetwork->tlsDataParams);
|
||||
mbedtls_ssl_context *ssl = &(tlsDataParams->ssl);
|
||||
mbedtls_ssl_config *ssl_conf = &(tlsDataParams->conf);
|
||||
uint32_t read_timeout;
|
||||
size_t rxLen = 0;
|
||||
int ret;
|
||||
|
||||
read_timeout = ssl_conf->read_timeout;
|
||||
|
||||
while (len > 0) {
|
||||
|
||||
/* Make sure we never block on read for longer than timer has left,
|
||||
but also that we don't block indefinitely (ie read_timeout > 0) */
|
||||
mbedtls_ssl_conf_read_timeout(ssl_conf, MAX(1, MIN(read_timeout, left_ms(timer))));
|
||||
|
||||
ret = mbedtls_ssl_read(ssl, pMsg, len);
|
||||
|
||||
/* Restore the old timeout */
|
||||
mbedtls_ssl_conf_read_timeout(ssl_conf, read_timeout);
|
||||
|
||||
if (ret > 0) {
|
||||
rxLen += ret;
|
||||
pMsg += ret;
|
||||
len -= ret;
|
||||
} else if (ret == 0 || (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret != MBEDTLS_ERR_SSL_TIMEOUT)) {
|
||||
return NETWORK_SSL_READ_ERROR;
|
||||
}
|
||||
|
||||
// Evaluate timeout after the read to make sure read is done at least once
|
||||
if (has_timer_expired(timer)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
*read_len = rxLen;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
if (rxLen == 0) {
|
||||
return NETWORK_SSL_NOTHING_TO_READ;
|
||||
} else {
|
||||
return NETWORK_SSL_READ_TIMEOUT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
IoT_Error_t iot_tls_disconnect(Network *pNetwork) {
|
||||
mbedtls_ssl_context *ssl = &(pNetwork->tlsDataParams.ssl);
|
||||
int ret = 0;
|
||||
do {
|
||||
ret = mbedtls_ssl_close_notify(ssl);
|
||||
} while(ret == MBEDTLS_ERR_SSL_WANT_WRITE);
|
||||
|
||||
/* All other negative return values indicate connection needs to be reset.
|
||||
* No further action required since this is disconnect call */
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
IoT_Error_t iot_tls_destroy(Network *pNetwork) {
|
||||
TLSDataParams *tlsDataParams = &(pNetwork->tlsDataParams);
|
||||
|
||||
mbedtls_net_free(&(tlsDataParams->server_fd));
|
||||
|
||||
mbedtls_x509_crt_free(&(tlsDataParams->clicert));
|
||||
mbedtls_x509_crt_free(&(tlsDataParams->cacert));
|
||||
mbedtls_pk_free(&(tlsDataParams->pkey));
|
||||
mbedtls_ssl_free(&(tlsDataParams->ssl));
|
||||
mbedtls_ssl_config_free(&(tlsDataParams->conf));
|
||||
mbedtls_ctr_drbg_free(&(tlsDataParams->ctr_drbg));
|
||||
mbedtls_entropy_free(&(tlsDataParams->entropy));
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
104
components/aws_iot/port/threads_freertos.c
Normal file
104
components/aws_iot/port/threads_freertos.c
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Additions Copyright 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.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://aws.amazon.com/apache2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file 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 "threads_platform.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initialize the provided mutex
|
||||
*
|
||||
* Call this function to initialize the mutex
|
||||
*
|
||||
* @param IoT_Mutex_t - pointer to the mutex to be initialized
|
||||
* @return IoT_Error_t - error code indicating result of operation
|
||||
*/
|
||||
IoT_Error_t aws_iot_thread_mutex_init(IoT_Mutex_t *pMutex) {
|
||||
|
||||
pMutex->mutex = xSemaphoreCreateRecursiveMutex();
|
||||
return pMutex->mutex ? SUCCESS : MUTEX_INIT_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Lock the provided mutex
|
||||
*
|
||||
* Call this function to lock the mutex before performing a state change
|
||||
* Blocking, thread will block until lock request fails
|
||||
*
|
||||
* @param IoT_Mutex_t - pointer to the mutex to be locked
|
||||
* @return IoT_Error_t - error code indicating result of operation
|
||||
*/
|
||||
IoT_Error_t aws_iot_thread_mutex_lock(IoT_Mutex_t *pMutex) {
|
||||
xSemaphoreTakeRecursive(pMutex->mutex, portMAX_DELAY);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Try to lock the provided mutex
|
||||
*
|
||||
* Call this function to attempt to lock the mutex before performing a state change
|
||||
* Non-Blocking, immediately returns with failure if lock attempt fails
|
||||
*
|
||||
* @param IoT_Mutex_t - pointer to the mutex to be locked
|
||||
* @return IoT_Error_t - error code indicating result of operation
|
||||
*/
|
||||
IoT_Error_t aws_iot_thread_mutex_trylock(IoT_Mutex_t *pMutex) {
|
||||
if (xSemaphoreTakeRecursive(pMutex->mutex, 0)) {
|
||||
return SUCCESS;
|
||||
} else {
|
||||
return MUTEX_LOCK_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unlock the provided mutex
|
||||
*
|
||||
* Call this function to unlock the mutex before performing a state change
|
||||
*
|
||||
* @param IoT_Mutex_t - pointer to the mutex to be unlocked
|
||||
* @return IoT_Error_t - error code indicating result of operation
|
||||
*/
|
||||
IoT_Error_t aws_iot_thread_mutex_unlock(IoT_Mutex_t *pMutex) {
|
||||
if (xSemaphoreGiveRecursive(pMutex->mutex)) {
|
||||
return SUCCESS;
|
||||
} else {
|
||||
return MUTEX_UNLOCK_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destroy the provided mutex
|
||||
*
|
||||
* Call this function to destroy the mutex
|
||||
*
|
||||
* @param IoT_Mutex_t - pointer to the mutex to be destroyed
|
||||
* @return IoT_Error_t - error code indicating result of operation
|
||||
*/
|
||||
IoT_Error_t aws_iot_thread_mutex_destroy(IoT_Mutex_t *pMutex) {
|
||||
vSemaphoreDelete(pMutex->mutex);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
83
components/aws_iot/port/timer.c
Normal file
83
components/aws_iot/port/timer.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* Additions Copyright 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.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://aws.amazon.com/apache2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file timer.c
|
||||
* @brief FreeRTOS implementation of the timer interface uses ticks.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "timer_platform.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
const static char *TAG = "aws_timer";
|
||||
|
||||
bool has_timer_expired(Timer *timer) {
|
||||
uint32_t now = xTaskGetTickCount();
|
||||
bool expired = (now - timer->start_ticks) >= timer->timeout_ticks;
|
||||
|
||||
/* AWS IoT SDK isn't very RTOS friendly because it polls for "done
|
||||
timers" a lot without ever sleeping on them. So we hack in some
|
||||
amount of sleeping here: if it seems like the caller is polling
|
||||
an unexpired timer in a tight loop then we delay a tick to let
|
||||
things progress elsewhere.
|
||||
*/
|
||||
if(!expired && now == timer->last_polled_ticks) {
|
||||
vTaskDelay(1);
|
||||
}
|
||||
timer->last_polled_ticks = now;
|
||||
return expired;
|
||||
}
|
||||
|
||||
void countdown_ms(Timer *timer, uint32_t timeout) {
|
||||
timer->start_ticks = xTaskGetTickCount();
|
||||
timer->timeout_ticks = timeout / portTICK_PERIOD_MS;
|
||||
timer->last_polled_ticks = 0;
|
||||
}
|
||||
|
||||
uint32_t left_ms(Timer *timer) {
|
||||
uint32_t now = xTaskGetTickCount();
|
||||
uint32_t elapsed = now - timer->start_ticks;
|
||||
if (elapsed < timer->timeout_ticks) {
|
||||
return (timer->timeout_ticks - elapsed) * portTICK_PERIOD_MS;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void countdown_sec(Timer *timer, uint32_t timeout) {
|
||||
if (timeout > UINT32_MAX / 1000) {
|
||||
ESP_LOGE(TAG, "timeout is out of range: %ds", timeout);
|
||||
}
|
||||
countdown_ms(timer, timeout * 1000);
|
||||
}
|
||||
|
||||
void init_timer(Timer *timer) {
|
||||
timer->start_ticks = 0;
|
||||
timer->timeout_ticks = 0;
|
||||
timer->last_polled_ticks = 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,21 +1,7 @@
|
||||
idf_component_register(PRIV_REQUIRES partition_table)
|
||||
# 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
|
||||
|
||||
# Do not generate flash file when building bootloader or is in early expansion of the build
|
||||
if(BOOTLOADER_BUILD)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# When secure boot is enabled, do not flash bootloader along with invocation of `idf.py flash`
|
||||
if(NOT CONFIG_SECURE_BOOT_ENABLED)
|
||||
set(flash_bootloader FLASH_IN_PROJECT)
|
||||
endif()
|
||||
|
||||
# Set values used in flash_bootloader_args.in and generate flash file
|
||||
# for bootloader
|
||||
esptool_py_flash_project_args(bootloader 0x1000
|
||||
${BOOTLOADER_BUILD_DIR}/bootloader.bin
|
||||
${flash_bootloader}
|
||||
FLASH_FILE_TEMPLATE flash_bootloader_args.in)
|
||||
|
||||
esptool_py_custom_target(bootloader-flash bootloader "bootloader")
|
||||
add_dependencies(bootloader partition_table)
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
menu "Bootloader config"
|
||||
choice BOOTLOADER_LOG_LEVEL
|
||||
choice LOG_BOOTLOADER_LEVEL
|
||||
bool "Bootloader log verbosity"
|
||||
default BOOTLOADER_LOG_LEVEL_INFO
|
||||
default LOG_BOOTLOADER_LEVEL_INFO
|
||||
help
|
||||
Specify how much output to see in bootloader logs.
|
||||
|
||||
config BOOTLOADER_LOG_LEVEL_NONE
|
||||
config LOG_BOOTLOADER_LEVEL_NONE
|
||||
bool "No output"
|
||||
config BOOTLOADER_LOG_LEVEL_ERROR
|
||||
config LOG_BOOTLOADER_LEVEL_ERROR
|
||||
bool "Error"
|
||||
config BOOTLOADER_LOG_LEVEL_WARN
|
||||
config LOG_BOOTLOADER_LEVEL_WARN
|
||||
bool "Warning"
|
||||
config BOOTLOADER_LOG_LEVEL_INFO
|
||||
config LOG_BOOTLOADER_LEVEL_INFO
|
||||
bool "Info"
|
||||
config BOOTLOADER_LOG_LEVEL_DEBUG
|
||||
config LOG_BOOTLOADER_LEVEL_DEBUG
|
||||
bool "Debug"
|
||||
config BOOTLOADER_LOG_LEVEL_VERBOSE
|
||||
config LOG_BOOTLOADER_LEVEL_VERBOSE
|
||||
bool "Verbose"
|
||||
endchoice
|
||||
|
||||
config BOOTLOADER_LOG_LEVEL
|
||||
config LOG_BOOTLOADER_LEVEL
|
||||
int
|
||||
default 0 if BOOTLOADER_LOG_LEVEL_NONE
|
||||
default 1 if BOOTLOADER_LOG_LEVEL_ERROR
|
||||
default 2 if BOOTLOADER_LOG_LEVEL_WARN
|
||||
default 3 if BOOTLOADER_LOG_LEVEL_INFO
|
||||
default 4 if BOOTLOADER_LOG_LEVEL_DEBUG
|
||||
default 5 if BOOTLOADER_LOG_LEVEL_VERBOSE
|
||||
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 ESPTOOLPY_FLASHMODE_QIO || ESPTOOLPY_FLASHMODE_QOUT
|
||||
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.
|
||||
@@ -140,7 +140,7 @@ menu "Bootloader config"
|
||||
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_CLK_SRC (INTERNAL_RC or EXTERNAL_CRYSTAL).
|
||||
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"
|
||||
@@ -163,7 +163,7 @@ menu "Bootloader config"
|
||||
- these options can increase the execution time.
|
||||
Note: RTC_WDT will reset while encryption operations will be performed.
|
||||
|
||||
config BOOTLOADER_APP_ROLLBACK_ENABLE
|
||||
config APP_ROLLBACK_ENABLE
|
||||
bool "Enable app rollback support"
|
||||
default n
|
||||
help
|
||||
@@ -175,22 +175,22 @@ menu "Bootloader config"
|
||||
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 BOOTLOADER_APP_ANTI_ROLLBACK
|
||||
config APP_ANTI_ROLLBACK
|
||||
bool "Enable app anti-rollback support"
|
||||
depends on BOOTLOADER_APP_ROLLBACK_ENABLE
|
||||
depends on APP_ROLLBACK_ENABLE
|
||||
default n
|
||||
help
|
||||
This option prevents rollback to previous firmware/application image with lower security version.
|
||||
|
||||
config BOOTLOADER_APP_SECURE_VERSION
|
||||
config APP_SECURE_VERSION
|
||||
int "eFuse secure version of app"
|
||||
depends on BOOTLOADER_APP_ANTI_ROLLBACK
|
||||
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 BOOTLOADER_APP_SEC_VER_SIZE_EFUSE_FIELD option).
|
||||
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.
|
||||
@@ -201,33 +201,24 @@ menu "Bootloader config"
|
||||
|
||||
Your partition table should has a scheme with ota_0 + ota_1 (without factory).
|
||||
|
||||
config BOOTLOADER_APP_SEC_VER_SIZE_EFUSE_FIELD
|
||||
config APP_SECURE_VERSION_SIZE_EFUSE_FIELD
|
||||
int "Size of the efuse secure version field"
|
||||
depends on BOOTLOADER_APP_ANTI_ROLLBACK
|
||||
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 BOOTLOADER_EFUSE_SECURE_VERSION_EMULATE
|
||||
config EFUSE_SECURE_VERSION_EMULATE
|
||||
bool "Emulate operations with efuse secure version(only test)"
|
||||
default n
|
||||
depends on BOOTLOADER_APP_ANTI_ROLLBACK
|
||||
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`.
|
||||
|
||||
config BOOTLOADER_FLASH_XMC_SUPPORT
|
||||
bool "Enable the support for flash chips of XMC (READ HELP FIRST)"
|
||||
default y
|
||||
help
|
||||
Perform the startup flow recommended by XMC. Please consult XMC for the details of this flow.
|
||||
XMC chips will be forbidden to be used, when this option is disabled.
|
||||
|
||||
DON'T DISABLE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.
|
||||
|
||||
endmenu # Bootloader
|
||||
|
||||
|
||||
@@ -248,10 +239,6 @@ menu "Security features"
|
||||
config SECURE_SIGNED_APPS
|
||||
bool
|
||||
default y
|
||||
select MBEDTLS_ECP_DP_SECP256R1_ENABLED
|
||||
select MBEDTLS_ECP_C
|
||||
select MBEDTLS_ECDH_C
|
||||
select MBEDTLS_ECDSA_C
|
||||
depends on SECURE_SIGNED_ON_BOOT || SECURE_SIGNED_ON_UPDATE
|
||||
|
||||
|
||||
@@ -350,7 +337,7 @@ menu "Security features"
|
||||
config SECURE_BOOT_SIGNING_KEY
|
||||
string "Secure boot private signing key"
|
||||
depends on SECURE_BOOT_BUILD_SIGNED_BINARIES
|
||||
default "secure_boot_signing_key.pem"
|
||||
default secure_boot_signing_key.pem
|
||||
help
|
||||
Path to the key file used to sign app images.
|
||||
|
||||
@@ -366,7 +353,7 @@ menu "Security features"
|
||||
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"
|
||||
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.
|
||||
@@ -380,7 +367,7 @@ menu "Security features"
|
||||
choice SECURE_BOOTLOADER_KEY_ENCODING
|
||||
bool "Hardware Key Encoding"
|
||||
depends on SECURE_BOOTLOADER_REFLASHABLE
|
||||
default SECURE_BOOTLOADER_KEY_ENCODING_256BIT
|
||||
default SECURE_BOOTLOADER_NO_ENCODING
|
||||
help
|
||||
|
||||
In reflashable secure bootloader mode, a hardware key is derived from the signing key (with SHA-256) and
|
||||
@@ -412,54 +399,42 @@ menu "Security features"
|
||||
|
||||
Refer to https://docs.espressif.com/projects/esp-idf/en/latest/security/secure-boot.html before enabling.
|
||||
|
||||
config SECURE_FLASH_ENC_ENABLED
|
||||
config FLASH_ENCRYPTION_ENABLED
|
||||
bool "Enable flash encryption on boot (READ DOCS FIRST)"
|
||||
default N
|
||||
select SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE
|
||||
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.
|
||||
Read https://docs.espressif.com/projects/esp-idf/en/latest/security/flash-encryption.html before enabling.
|
||||
|
||||
choice SECURE_FLASH_ENCRYPTION_MODE
|
||||
bool "Enable usage mode"
|
||||
depends on SECURE_FLASH_ENC_ENABLED
|
||||
default SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT
|
||||
config FLASH_ENCRYPTION_INSECURE
|
||||
bool "Allow potentially insecure options"
|
||||
depends on FLASH_ENCRYPTION_ENABLED
|
||||
default N
|
||||
help
|
||||
By default Development mode is enabled which allows UART bootloader to perform flash encryption operations
|
||||
You can disable some of the default protections offered by flash encryption, in order to enable testing or
|
||||
a custom combination of security features.
|
||||
|
||||
Select Release mode only for production or manufacturing. Once enabled you can not reflash using UART
|
||||
bootloader
|
||||
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.
|
||||
|
||||
config SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT
|
||||
bool "Development(NOT SECURE)"
|
||||
select SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
|
||||
|
||||
config SECURE_FLASH_ENCRYPTION_MODE_RELEASE
|
||||
bool "Release"
|
||||
select PARTITION_TABLE_MD5 if !ESP32_COMPATIBLE_PRE_V3_1_BOOTLOADERS
|
||||
|
||||
endchoice
|
||||
|
||||
menu "Potentially insecure options"
|
||||
visible if SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT || SECURE_BOOT_INSECURE
|
||||
visible if FLASH_ENCRYPTION_INSECURE || SECURE_BOOT_INSECURE
|
||||
|
||||
# NOTE: Options in this menu NEED to have SECURE_BOOT_INSECURE
|
||||
# and/or SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT in "depends on", as the menu
|
||||
# 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 || SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT
|
||||
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
|
||||
@@ -473,7 +448,7 @@ menu "Security features"
|
||||
|
||||
config SECURE_BOOT_ALLOW_JTAG
|
||||
bool "Allow JTAG Debugging"
|
||||
depends on SECURE_BOOT_INSECURE || SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT
|
||||
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
|
||||
@@ -498,9 +473,9 @@ menu "Security features"
|
||||
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 SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
|
||||
config FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_ENCRYPT
|
||||
bool "Leave UART bootloader encryption enabled"
|
||||
depends on SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT
|
||||
depends on FLASH_ENCRYPTION_INSECURE
|
||||
default N
|
||||
help
|
||||
If not set (default), the bootloader will permanently disable UART bootloader encryption access on
|
||||
@@ -508,9 +483,9 @@ menu "Security features"
|
||||
|
||||
It is recommended to only set this option in testing environments.
|
||||
|
||||
config SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC
|
||||
config FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_DECRYPT
|
||||
bool "Leave UART bootloader decryption enabled"
|
||||
depends on SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT
|
||||
depends on FLASH_ENCRYPTION_INSECURE
|
||||
default N
|
||||
help
|
||||
If not set (default), the bootloader will permanently disable UART bootloader decryption access on
|
||||
@@ -519,9 +494,9 @@ menu "Security features"
|
||||
Only set this option in testing environments. Setting this option allows complete bypass of flash
|
||||
encryption.
|
||||
|
||||
config SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE
|
||||
config FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_CACHE
|
||||
bool "Leave UART bootloader flash cache enabled"
|
||||
depends on SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT
|
||||
depends on FLASH_ENCRYPTION_INSECURE
|
||||
default N
|
||||
help
|
||||
If not set (default), the bootloader will permanently disable UART bootloader flash cache access on
|
||||
@@ -529,38 +504,5 @@ menu "Security features"
|
||||
|
||||
Only set this option in testing environments.
|
||||
|
||||
config SECURE_FLASH_REQUIRE_ALREADY_ENABLED
|
||||
bool "Require flash encryption to be already enabled"
|
||||
depends on SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT
|
||||
default N
|
||||
help
|
||||
If not set (default), and flash encryption is not yet enabled in eFuses, the 2nd stage bootloader
|
||||
will enable flash encryption: generate the flash encryption key and program eFuses.
|
||||
If this option is set, and flash encryption is not yet enabled, the bootloader will error out and
|
||||
reboot.
|
||||
If flash encryption is enabled in eFuses, this option does not change the bootloader behavior.
|
||||
|
||||
Only use this option in testing environments, to avoid accidentally enabling flash encryption on
|
||||
the wrong device. The device needs to have flash encryption already enabled using espefuse.py.
|
||||
|
||||
endmenu # Potentially Insecure
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -1,123 +1,66 @@
|
||||
set(BOOTLOADER_OFFSET 0x1000)
|
||||
|
||||
# Do not generate flash file when building bootloader
|
||||
# This is for tracking the top level project path
|
||||
if(BOOTLOADER_BUILD)
|
||||
return()
|
||||
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
|
||||
#
|
||||
#
|
||||
idf_build_get_property(build_dir BUILD_DIR)
|
||||
set(BOOTLOADER_BUILD_DIR "${build_dir}/bootloader")
|
||||
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"
|
||||
"${bootloader_build_dir}/bootloader.elf"
|
||||
"${bootloader_build_dir}/bootloader.bin"
|
||||
"${bootloader_build_dir}/bootloader.map"
|
||||
)
|
||||
|
||||
idf_build_get_property(project_dir PROJECT_DIR)
|
||||
|
||||
# There are some additional processing when CONFIG_CONFIG_SECURE_SIGNED_APPS. This happens
|
||||
# when either CONFIG_SECURE_BOOT_ENABLED or SECURE_BOOT_BUILD_SIGNED_BINARIES.
|
||||
# For both cases, the user either sets binaries to be signed during build or not
|
||||
# using CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES.
|
||||
#
|
||||
# Regardless, pass the main project's keys (signing/verification) to the bootloader subproject
|
||||
# via config.
|
||||
if(CONFIG_SECURE_SIGNED_APPS)
|
||||
add_custom_target(gen_secure_boot_keys)
|
||||
|
||||
if(CONFIG_SECURE_BOOT_ENABLED)
|
||||
# Check that the configuration is sane
|
||||
if((CONFIG_SECURE_BOOTLOADER_REFLASHABLE AND CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH) OR
|
||||
(NOT CONFIG_SECURE_BOOTLOADER_REFLASHABLE AND NOT CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH))
|
||||
fail_at_build_time(bootloader "Invalid bootloader target: bad sdkconfig?")
|
||||
endif()
|
||||
|
||||
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()
|
||||
endif()
|
||||
|
||||
# Since keys are usually given relative to main project dir, get the absolute paths to the keys
|
||||
# for use by the bootloader subproject. Replace the values in config with these absolute paths,
|
||||
# so that bootloader subproject does not need to assume main project dir to obtain path to the keys.
|
||||
if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)
|
||||
get_filename_component(secure_boot_signing_key
|
||||
"${CONFIG_SECURE_BOOT_SIGNING_KEY}"
|
||||
ABSOLUTE BASE_DIR "${project_dir}")
|
||||
|
||||
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 causes 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()
|
||||
|
||||
set(SECURE_BOOT_SIGNING_KEY ${secure_boot_signing_key}) # needed by some other components
|
||||
set(sign_key_arg "-DSECURE_BOOT_SIGNING_KEY=${secure_boot_signing_key}")
|
||||
|
||||
add_dependencies(gen_secure_boot_keys gen_secure_boot_signing_key)
|
||||
else()
|
||||
|
||||
get_filename_component(secure_boot_verification_key
|
||||
${CONFIG_SECURE_BOOT_VERIFICATION_KEY}
|
||||
ABSOLUTE BASE_DIR "${project_dir}")
|
||||
|
||||
if(NOT EXISTS ${secure_boot_verification_key})
|
||||
# If the verification key is not found, create a phony gen_secure_boot_verification_key target that
|
||||
# fails the build. fail_at_build_time causes a cmake run next time
|
||||
# (to pick up a new verification key if one exists, etc.)
|
||||
fail_at_build_time(gen_secure_boot_verification_key
|
||||
"Secure Boot Verification Public Key ${CONFIG_SECURE_BOOT_VERIFICATION_KEY} does not exist."
|
||||
"\tThis can be extracted from the private signing key."
|
||||
"\tSee docs/security/secure-boot.rst for details.")
|
||||
else()
|
||||
add_custom_target(gen_secure_boot_verification_key)
|
||||
endif()
|
||||
|
||||
set(ver_key_arg "-DSECURE_BOOT_VERIFICATION_KEY=${secure_boot_verification_key}")
|
||||
|
||||
add_dependencies(gen_secure_boot_keys gen_secure_boot_verification_key)
|
||||
endif()
|
||||
# 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()
|
||||
|
||||
idf_build_get_property(idf_path IDF_PATH)
|
||||
idf_build_get_property(idf_target IDF_TARGET)
|
||||
idf_build_get_property(sdkconfig SDKCONFIG)
|
||||
idf_build_get_property(python PYTHON)
|
||||
idf_build_get_property(extra_cmake_args EXTRA_CMAKE_ARGS)
|
||||
|
||||
externalproject_add(bootloader
|
||||
SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/subproject"
|
||||
BINARY_DIR "${BOOTLOADER_BUILD_DIR}"
|
||||
CMAKE_ARGS -DSDKCONFIG=${sdkconfig} -DIDF_PATH=${idf_path} -DIDF_TARGET=${idf_target} -DPYTHON=${python}
|
||||
-DPYTHON_DEPS_CHECKED=1
|
||||
-DEXTRA_COMPONENT_DIRS=${CMAKE_CURRENT_LIST_DIR}
|
||||
${sign_key_arg} ${ver_key_arg}
|
||||
# LEGACY_INCLUDE_COMMON_HEADERS has to be passed in via cache variable since
|
||||
# the bootloader common component requirements depends on this and
|
||||
# config variables are not available before project() call.
|
||||
-DLEGACY_INCLUDE_COMMON_HEADERS=${CONFIG_LEGACY_INCLUDE_COMMON_HEADERS}
|
||||
${extra_cmake_args}
|
||||
INSTALL_COMMAND ""
|
||||
BUILD_ALWAYS 1 # no easy way around this...
|
||||
BUILD_BYPRODUCTS ${bootloader_binary_files}
|
||||
)
|
||||
|
||||
if(CONFIG_SECURE_SIGNED_APPS)
|
||||
add_dependencies(bootloader gen_secure_boot_keys)
|
||||
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
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
# sdkconfig replacement configurations for deprecated options formatted as
|
||||
# CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION
|
||||
|
||||
CONFIG_LOG_BOOTLOADER_LEVEL CONFIG_BOOTLOADER_LOG_LEVEL
|
||||
CONFIG_LOG_BOOTLOADER_LEVEL_NONE CONFIG_BOOTLOADER_LOG_LEVEL_NONE
|
||||
CONFIG_LOG_BOOTLOADER_LEVEL_ERROR CONFIG_BOOTLOADER_LOG_LEVEL_ERROR
|
||||
CONFIG_LOG_BOOTLOADER_LEVEL_WARN CONFIG_BOOTLOADER_LOG_LEVEL_WARN
|
||||
CONFIG_LOG_BOOTLOADER_LEVEL_INFO CONFIG_BOOTLOADER_LOG_LEVEL_INFO
|
||||
CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG
|
||||
CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE
|
||||
|
||||
CONFIG_APP_ROLLBACK_ENABLE CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
|
||||
CONFIG_APP_ANTI_ROLLBACK CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
|
||||
CONFIG_APP_SECURE_VERSION CONFIG_BOOTLOADER_APP_SECURE_VERSION
|
||||
CONFIG_APP_SECURE_VERSION_SIZE_EFUSE_FIELD CONFIG_BOOTLOADER_APP_SEC_VER_SIZE_EFUSE_FIELD
|
||||
CONFIG_EFUSE_SECURE_VERSION_EMULATE CONFIG_BOOTLOADER_EFUSE_SECURE_VERSION_EMULATE
|
||||
|
||||
CONFIG_FLASH_ENCRYPTION_ENABLED CONFIG_SECURE_FLASH_ENC_ENABLED
|
||||
CONFIG_FLASH_ENCRYPTION_INSECURE CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT
|
||||
CONFIG_FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_ENCRYPT CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
|
||||
CONFIG_FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_DECRYPT CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC
|
||||
CONFIG_FLASH_ENCRYPTION_UART_BOOTLOADER_ALLOW_CACHE CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE
|
||||
@@ -10,24 +10,32 @@ if(NOT IDF_PATH)
|
||||
"in by the parent build process.")
|
||||
endif()
|
||||
|
||||
if(NOT IDF_TARGET)
|
||||
message(FATAL_ERROR "Bootloader subproject expects the IDF_TARGET variable to be passed "
|
||||
"in by the parent build process.")
|
||||
endif()
|
||||
|
||||
set(COMPONENTS bootloader esptool_py partition_table soc bootloader_support log spi_flash micro-ecc main efuse)
|
||||
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")
|
||||
set(common_req log esp_rom esp_common xtensa)
|
||||
if(LEGACY_INCLUDE_COMMON_HEADERS)
|
||||
list(APPEND common_req soc)
|
||||
endif()
|
||||
idf_build_set_property(__COMPONENT_REQUIRES_COMMON "${common_req}")
|
||||
idf_build_set_property(__OUTPUT_SDKCONFIG 0)
|
||||
project(bootloader)
|
||||
|
||||
idf_build_set_property(COMPILE_DEFINITIONS "-DBOOTLOADER_BUILD=1" APPEND)
|
||||
idf_build_set_property(COMPILE_OPTIONS "-fno-stack-protector" APPEND)
|
||||
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}")
|
||||
@@ -51,7 +59,7 @@ if(CONFIG_SECURE_BOOTLOADER_REFLASHABLE)
|
||||
add_custom_command(OUTPUT "${secure_bootloader_key}"
|
||||
COMMAND ${ESPSECUREPY} digest_private_key
|
||||
--keylen "${key_digest_len}"
|
||||
--keyfile "${SECURE_BOOT_SIGNING_KEY}"
|
||||
--keyfile "${secure_boot_signing_key}"
|
||||
"${secure_bootloader_key}"
|
||||
VERBATIM)
|
||||
|
||||
@@ -65,7 +73,7 @@ if(CONFIG_SECURE_BOOTLOADER_REFLASHABLE)
|
||||
"\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 "
|
||||
"\n\t${ESPSECUREPY} digest_private_key "
|
||||
"--keylen (192/256) --keyfile KEYFILE "
|
||||
"${secure_bootloader_key}")
|
||||
endif()
|
||||
@@ -75,16 +83,15 @@ if(CONFIG_SECURE_BOOTLOADER_REFLASHABLE)
|
||||
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"
|
||||
MAIN_DEPENDENCY "${CMAKE_BINARY_DIR}/.bin_timestamp"
|
||||
DEPENDS gen_secure_bootloader_key gen_project_binary
|
||||
-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.elf POST_BUILD
|
||||
add_custom_command(TARGET bootloader POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"=============================================================================="
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
@@ -96,8 +103,9 @@ if(CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH)
|
||||
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.elf POST_BUILD
|
||||
add_custom_command(TARGET bootloader POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"=============================================================================="
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
|
||||
@@ -14,11 +14,8 @@ COMPONENTS := esptool_py bootloader_support log spi_flash micro-ecc soc main efu
|
||||
CFLAGS =
|
||||
CXXFLAGS =
|
||||
|
||||
#We cannot include the idf_target, esp_rom, esp_common component directly but we need their includes.
|
||||
CFLAGS += -I $(IDF_PATH)/components/$(IDF_TARGET)/include
|
||||
CFLAGS += -I $(IDF_PATH)/components/esp_rom/include
|
||||
CFLAGS += -I $(IDF_PATH)/components/esp_common/include
|
||||
CFLAGS += -I $(IDF_PATH)/components/xtensa/include -I $(IDF_PATH)/components/xtensa/$(IDF_TARGET)/include
|
||||
#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.
|
||||
#
|
||||
@@ -32,6 +29,4 @@ CFLAGS += -D BOOTLOADER_BUILD=1
|
||||
# include the top-level "project" include directory, for sdkconfig.h
|
||||
CFLAGS += -I$(BUILD_DIR_BASE)/../include
|
||||
|
||||
COMPONENT_ADD_LDFLAGS += -l$(COMPONENT_NAME) -Wl,--wrap=longjmp \
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# only compile the "micro-ecc/uECC.c" source file
|
||||
idf_component_register(SRCS "micro-ecc/uECC.c"
|
||||
INCLUDE_DIRS micro-ecc)
|
||||
@@ -1,8 +1,4 @@
|
||||
idf_component_register(SRCS "bootloader_start.c"
|
||||
REQUIRES bootloader bootloader_support)
|
||||
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
set(scripts "${target}.bootloader.ld"
|
||||
"${target}.bootloader.rom.ld")
|
||||
|
||||
target_linker_script(${COMPONENT_LIB} INTERFACE "${scripts}")
|
||||
set(COMPONENT_SRCS "bootloader_start.c")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS "")
|
||||
set(COMPONENT_REQUIRES "bootloader bootloader_support")
|
||||
register_component()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Submodules normally added in component.mk, but fully qualified
|
||||
# paths can be added at this level (we need binary librtc to be
|
||||
# available to link bootloader).
|
||||
COMPONENT_SUBMODULES += $(IDF_PATH)/components/esp_wifi/lib_esp32
|
||||
COMPONENT_SUBMODULES += $(IDF_PATH)/components/esp32/lib
|
||||
|
||||
@@ -16,15 +16,14 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp32/rom/gpio.h"
|
||||
#include "esp32/rom/spi_flash.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 "esp32/rom/rtc.h"
|
||||
|
||||
static const char* TAG = "boot";
|
||||
|
||||
@@ -75,8 +74,7 @@ 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) {
|
||||
} else {
|
||||
// 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) {
|
||||
@@ -113,9 +111,3 @@ static int selected_boot_partition(const bootloader_state_t *bs)
|
||||
}
|
||||
return boot_index;
|
||||
}
|
||||
|
||||
// Return global reent struct if any newlib functions are linked to bootloader
|
||||
struct _reent* __getreent() {
|
||||
return _GLOBAL_REENT;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
#
|
||||
|
||||
LINKER_SCRIPTS := \
|
||||
$(IDF_TARGET).bootloader.ld \
|
||||
$(IDF_TARGET).bootloader.rom.ld \
|
||||
$(IDF_PATH)/components/esp_rom/$(IDF_TARGET)/ld/$(IDF_TARGET).rom.ld \
|
||||
$(IDF_PATH)/components/esp_rom/$(IDF_TARGET)/ld/$(IDF_TARGET).rom.newlib-funcs.ld \
|
||||
$(IDF_PATH)/components/$(IDF_TARGET)/ld/$(IDF_TARGET).peripherals.ld
|
||||
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/esp_rom/$(IDF_TARGET)/ld/$(IDF_TARGET).rom.spiflash.ld
|
||||
LINKER_SCRIPTS += $(IDF_PATH)/components/esp32/ld/esp32.rom.spiflash.ld
|
||||
endif
|
||||
|
||||
COMPONENT_ADD_LDFLAGS += -L $(COMPONENT_PATH) $(addprefix -T ,$(LINKER_SCRIPTS))
|
||||
|
||||
@@ -40,7 +40,6 @@ SECTIONS
|
||||
*(.iram1 .iram1.*) /* catch stray IRAM_ATTR */
|
||||
*liblog.a:(.literal .text .literal.* .text.*)
|
||||
*libgcc.a:(.literal .text .literal.* .text.*)
|
||||
*libbootloader_support.a:bootloader_clock.*(.literal .text .literal.* .text.*)
|
||||
*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.*)
|
||||
@@ -54,7 +53,6 @@ SECTIONS
|
||||
*libmicro-ecc.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libspi_flash.a:*.*(.literal .text .literal.* .text.*)
|
||||
*libsoc.a:rtc_wdt.*(.literal .text .literal.* .text.*)
|
||||
*libsoc.a:rtc_clk.*(.literal .text .literal.* .text.*)
|
||||
*libefuse.a:*.*(.literal .text .literal.* .text.*)
|
||||
*(.fini.literal)
|
||||
*(.fini)
|
||||
@@ -151,6 +149,7 @@ SECTIONS
|
||||
*(.gnu.linkonce.lit4.*)
|
||||
_lit4_end = ABSOLUTE(.);
|
||||
. = ALIGN(4);
|
||||
_heap_start = ABSOLUTE(.);
|
||||
} >dram_seg
|
||||
|
||||
.iram.text :
|
||||
@@ -162,14 +161,6 @@ SECTIONS
|
||||
*(.fini.literal)
|
||||
*(.fini)
|
||||
*(.gnu.version)
|
||||
|
||||
/** CPU will try to prefetch up to 16 bytes of
|
||||
* of instructions. This means that any configuration (e.g. MMU, PMS) must allow
|
||||
* safe access to up to 16 bytes after the last real instruction, add
|
||||
* dummy bytes to ensure this
|
||||
*/
|
||||
. += 16;
|
||||
|
||||
_text_end = ABSOLUTE(.);
|
||||
_etext = .;
|
||||
} > iram_seg
|
||||
|
||||
@@ -2,8 +2,3 @@ PROVIDE ( ets_update_cpu_frequency = 0x40008550 ); /* Updates g_ticks_per_us on
|
||||
PROVIDE ( MD5Final = 0x4005db1c );
|
||||
PROVIDE ( MD5Init = 0x4005da7c );
|
||||
PROVIDE ( MD5Update = 0x4005da9c );
|
||||
|
||||
/* bootloader will use following functions from xtensa hal library */
|
||||
xthal_get_ccount = 0x4000c050;
|
||||
xthal_get_ccompare = 0x4000c078;
|
||||
xthal_set_ccompare = 0x4000c058;
|
||||
|
||||
@@ -1,96 +1,60 @@
|
||||
set(srcs
|
||||
"src/bootloader_clock.c"
|
||||
"src/bootloader_common.c"
|
||||
"src/bootloader_flash.c"
|
||||
"src/bootloader_flash_config.c"
|
||||
"src/bootloader_random.c"
|
||||
"src/bootloader_utility.c"
|
||||
"src/esp_image_format.c"
|
||||
"src/flash_encrypt.c"
|
||||
"src/flash_partitions.c"
|
||||
"src/flash_qio_mode.c")
|
||||
set(COMPONENT_SRCS "src/bootloader_clock.c"
|
||||
"src/bootloader_common.c"
|
||||
"src/bootloader_flash.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(include_dirs "include" "include_bootloader")
|
||||
set(requires soc) #unfortunately the header directly uses SOC registers
|
||||
set(priv_requires micro-ecc spi_flash efuse)
|
||||
list(APPEND srcs
|
||||
"src/bootloader_init.c"
|
||||
"src/${IDF_TARGET}/bootloader_sha.c"
|
||||
"src/${IDF_TARGET}/flash_encrypt.c"
|
||||
"src/${IDF_TARGET}/secure_boot_signatures.c"
|
||||
"src/${IDF_TARGET}/secure_boot.c")
|
||||
else()
|
||||
list(APPEND srcs
|
||||
"src/idf/bootloader_sha.c"
|
||||
"src/idf/secure_boot_signatures.c")
|
||||
set(include_dirs "include")
|
||||
set(priv_include_dirs "include_bootloader")
|
||||
set(requires soc) #unfortunately the header directly uses SOC registers
|
||||
set(priv_requires spi_flash mbedtls efuse)
|
||||
endif()
|
||||
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")
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS "${include_dirs}"
|
||||
PRIV_INCLUDE_DIRS "${priv_include_dirs}"
|
||||
REQUIRES "${requires}"
|
||||
PRIV_REQUIRES "${priv_requires}")
|
||||
|
||||
if(CONFIG_SECURE_SIGNED_APPS)
|
||||
if(BOOTLOADER_BUILD)
|
||||
# Whether CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES or not, we need verification key to embed
|
||||
# in the library.
|
||||
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)
|
||||
# We generate the key from the signing key. The signing key is passed from the main project.
|
||||
get_filename_component(secure_boot_signing_key
|
||||
"${SECURE_BOOT_SIGNING_KEY}"
|
||||
ABSOLUTE BASE_DIR "${project_dir}")
|
||||
get_filename_component(secure_boot_verification_key
|
||||
"signature_verification_key.bin"
|
||||
ABSOLUTE BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
add_custom_command(OUTPUT "${secure_boot_verification_key}"
|
||||
COMMAND ${ESPSECUREPY}
|
||||
extract_public_key --keyfile "${secure_boot_signing_key}"
|
||||
"${secure_boot_verification_key}"
|
||||
DEPENDS ${secure_boot_signing_key}
|
||||
extract_public_key --keyfile "${secure_boot_signing_key}"
|
||||
"${secure_boot_verification_key}"
|
||||
DEPENDS gen_secure_boot_signing_key
|
||||
VERBATIM)
|
||||
else()
|
||||
# We expect to 'inherit' the verification key passed from main project.
|
||||
get_filename_component(secure_boot_verification_key
|
||||
${SECURE_BOOT_VERIFICATION_KEY}
|
||||
ABSOLUTE BASE_DIR "${project_dir}")
|
||||
endif()
|
||||
else() # normal app build
|
||||
idf_build_get_property(project_dir PROJECT_DIR)
|
||||
|
||||
if(CONFIG_SECURE_BOOT_VERIFICATION_KEY)
|
||||
# verification-only build supplies verification key
|
||||
set(secure_boot_verification_key ${CONFIG_SECURE_BOOT_VERIFICATION_KEY})
|
||||
get_filename_component(secure_boot_verification_key
|
||||
${secure_boot_verification_key}
|
||||
ABSOLUTE BASE_DIR "${project_dir}")
|
||||
else()
|
||||
# sign at build time, extracts key from signing key
|
||||
set(secure_boot_verification_key "${CMAKE_BINARY_DIR}/signature_verification_key.bin")
|
||||
get_filename_component(secure_boot_signing_key
|
||||
${CONFIG_SECURE_BOOT_SIGNING_KEY}
|
||||
ABSOLUTE BASE_DIR "${project_dir}")
|
||||
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 ${ESPSECUREPY}
|
||||
extract_public_key --keyfile "${secure_boot_signing_key}"
|
||||
"${secure_boot_verification_key}"
|
||||
WORKING_DIRECTORY ${project_dir}
|
||||
DEPENDS ${secure_boot_signing_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()
|
||||
|
||||
# Embed the verification key in the binary (app & bootloader)
|
||||
#
|
||||
target_add_binary_data(${COMPONENT_LIB} "${secure_boot_verification_key}" "BINARY"
|
||||
RENAME_TO signature_verification_key_bin)
|
||||
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
|
||||
"${secure_boot_verification_key}")
|
||||
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()
|
||||
|
||||
@@ -9,12 +9,6 @@ endif
|
||||
|
||||
COMPONENT_SRCDIRS := src
|
||||
|
||||
ifndef IS_BOOTLOADER_BUILD
|
||||
COMPONENT_SRCDIRS += src/idf # idf sub-directory contains platform agnostic IDF versions
|
||||
else
|
||||
COMPONENT_SRCDIRS += src/$(IDF_TARGET) # one sub-dir per chip
|
||||
endif
|
||||
|
||||
ifndef IS_BOOTLOADER_BUILD
|
||||
COMPONENT_OBJEXCLUDE := src/bootloader_init.o
|
||||
endif
|
||||
|
||||
@@ -14,16 +14,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -13,13 +13,8 @@
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
#include "esp_flash_partitions.h"
|
||||
#include "esp_flash_data_types.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_app_format.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// Type of hold a GPIO in low state
|
||||
typedef enum {
|
||||
@@ -28,11 +23,6 @@ typedef enum {
|
||||
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.
|
||||
*
|
||||
@@ -135,7 +125,7 @@ int bootloader_common_select_otadata(const esp_ota_select_entry_t *two_otadata,
|
||||
|
||||
/**
|
||||
* @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.
|
||||
@@ -147,29 +137,15 @@ int bootloader_common_select_otadata(const esp_ota_select_entry_t *two_otadata,
|
||||
*/
|
||||
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();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* @brief Set the flash CS setup and hold time.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
void bootloader_common_set_flash_cs_timing();
|
||||
|
||||
@@ -1,79 +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 Update the flash size in g_rom_flashchip (global esp_rom_spiflash_chip_t structure).
|
||||
*
|
||||
* @param size The size to store, in bytes.
|
||||
* @return None
|
||||
*/
|
||||
void bootloader_flash_update_size(uint32_t size);
|
||||
|
||||
/**
|
||||
* @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
|
||||
@@ -16,10 +16,6 @@
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enable early entropy source for RNG
|
||||
*
|
||||
@@ -51,7 +47,3 @@ void bootloader_random_disable(void);
|
||||
* @param length This many bytes of random data will be copied to buffer
|
||||
*/
|
||||
void bootloader_fill_random(void *buffer, size_t length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -16,10 +16,6 @@
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Check if half-open intervals overlap
|
||||
*
|
||||
@@ -33,11 +29,6 @@ static inline bool bootloader_util_regions_overlap(
|
||||
const intptr_t start1, const intptr_t end1,
|
||||
const intptr_t start2, const intptr_t end2)
|
||||
{
|
||||
assert(end1>start1);
|
||||
assert(end2>start2);
|
||||
return (end1 > start2 && end2 > start1);
|
||||
return (end1 > start2 && end2 > start1) ||
|
||||
!(end1 <= start2 || end2 <= start1);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
// Copyright 2015-2019 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 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 */
|
||||
|
||||
/**
|
||||
* @brief SPI flash mode, used in esp_image_header_t
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_IMAGE_SPI_MODE_QIO, /*!< SPI mode QIO */
|
||||
ESP_IMAGE_SPI_MODE_QOUT, /*!< SPI mode QOUT */
|
||||
ESP_IMAGE_SPI_MODE_DIO, /*!< SPI mode DIO */
|
||||
ESP_IMAGE_SPI_MODE_DOUT, /*!< SPI mode DOUT */
|
||||
ESP_IMAGE_SPI_MODE_FAST_READ, /*!< SPI mode FAST_READ */
|
||||
ESP_IMAGE_SPI_MODE_SLOW_READ /*!< SPI mode SLOW_READ */
|
||||
} esp_image_spi_mode_t;
|
||||
|
||||
/**
|
||||
* @brief SPI flash clock frequency
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_IMAGE_SPI_SPEED_40M, /*!< SPI clock frequency 40 MHz */
|
||||
ESP_IMAGE_SPI_SPEED_26M, /*!< SPI clock frequency 26 MHz */
|
||||
ESP_IMAGE_SPI_SPEED_20M, /*!< SPI clock frequency 20 MHz */
|
||||
ESP_IMAGE_SPI_SPEED_80M = 0xF /*!< SPI clock frequency 80 MHz */
|
||||
} esp_image_spi_freq_t;
|
||||
|
||||
/**
|
||||
* @brief Supported SPI flash sizes
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_IMAGE_FLASH_SIZE_1MB = 0, /*!< SPI flash size 1 MB */
|
||||
ESP_IMAGE_FLASH_SIZE_2MB, /*!< SPI flash size 2 MB */
|
||||
ESP_IMAGE_FLASH_SIZE_4MB, /*!< SPI flash size 4 MB */
|
||||
ESP_IMAGE_FLASH_SIZE_8MB, /*!< SPI flash size 8 MB */
|
||||
ESP_IMAGE_FLASH_SIZE_16MB, /*!< SPI flash size 16 MB */
|
||||
ESP_IMAGE_FLASH_SIZE_MAX /*!< SPI flash size MAX */
|
||||
} esp_image_flash_size_t;
|
||||
|
||||
#define ESP_IMAGE_HEADER_MAGIC 0xE9 /*!< The magic word for the esp_image_header_t structure. */
|
||||
|
||||
/**
|
||||
* @brief Main header of binary image
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t magic; /*!< Magic word ESP_IMAGE_HEADER_MAGIC */
|
||||
uint8_t segment_count; /*!< Count of memory segments */
|
||||
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; /*!< Entry address */
|
||||
uint8_t wp_pin; /*!< 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 spi_pin_drv[3]; /*!< Drive settings for the SPI flash pins (read by ROM bootloader) */
|
||||
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 */
|
||||
uint8_t hash_appended; /*!< 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). */
|
||||
} __attribute__((packed)) esp_image_header_t;
|
||||
|
||||
/** @cond */
|
||||
_Static_assert(sizeof(esp_image_header_t) == 24, "binary image header should be 24 bytes");
|
||||
/** @endcond */
|
||||
|
||||
|
||||
/**
|
||||
* @brief Header of binary image segment
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t load_addr; /*!< Address of segment */
|
||||
uint32_t data_len; /*!< Length of data */
|
||||
} esp_image_segment_header_t;
|
||||
|
||||
#define ESP_IMAGE_MAX_SEGMENTS 16 /*!< Max count of segments in the image. */
|
||||
|
||||
#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]; /*!< reserv1 */
|
||||
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]; /*!< reserv2 */
|
||||
} esp_app_desc_t;
|
||||
|
||||
/** @cond */
|
||||
_Static_assert(sizeof(esp_app_desc_t) == 256, "esp_app_desc_t should be 256 bytes");
|
||||
/** @endcond */
|
||||
@@ -1,2 +0,0 @@
|
||||
#warning esp_flash_data_types.h has been merged into esp_flash_partitions.h, please include esp_flash_partitions.h instead
|
||||
#include "esp_flash_partitions.h"
|
||||
@@ -11,7 +11,8 @@
|
||||
// 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_FLASH_ENCRYPT_H
|
||||
#define __ESP32_FLASH_ENCRYPT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "esp_attr.h"
|
||||
@@ -19,19 +20,7 @@
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
#include "esp_spi_flash.h"
|
||||
#endif
|
||||
#include "soc/efuse_periph.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* @brief Flash encryption mode based on efuse values
|
||||
*/
|
||||
typedef enum {
|
||||
ESP_FLASH_ENC_MODE_DISABLED, // flash encryption is not enabled (flash crypt cnt=0)
|
||||
ESP_FLASH_ENC_MODE_DEVELOPMENT, // flash encryption is enabled but for Development (reflash over UART allowed)
|
||||
ESP_FLASH_ENC_MODE_RELEASE // flash encryption is enabled for Release (reflash over UART disabled)
|
||||
} esp_flash_enc_mode_t;
|
||||
#include "soc/efuse_reg.h"
|
||||
|
||||
/**
|
||||
* @file esp_partition.h
|
||||
@@ -121,37 +110,8 @@ esp_err_t esp_flash_encrypt_region(uint32_t src_addr, size_t data_length);
|
||||
* 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 On ESP32 V3 only, write protecting FLASH_CRYPT_CNT will also prevent
|
||||
* disabling UART Download Mode. If both are wanted, call
|
||||
* esp_efuse_disable_rom_download_mode() before calling this function.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
void esp_flash_write_protect_crypt_cnt();
|
||||
|
||||
/** @brief Return the flash encryption mode
|
||||
*
|
||||
* The API is called during boot process but can also be called by
|
||||
* application to check the current flash encryption mode of ESP32
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
esp_flash_enc_mode_t esp_get_flash_encryption_mode();
|
||||
|
||||
|
||||
/** @brief Check the flash encryption mode during startup
|
||||
*
|
||||
* @note This function is called automatically during app startup,
|
||||
* it doesn't need to be called from the app.
|
||||
*
|
||||
* Verifies the flash encryption config during startup:
|
||||
*
|
||||
* - Correct any insecure flash encryption settings if hardware
|
||||
* Secure Boot is enabled.
|
||||
* - Log warnings if the efuse config doesn't match the project
|
||||
* config in any way
|
||||
*/
|
||||
void esp_flash_encryption_init_checks(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -11,40 +11,14 @@
|
||||
// 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 __ESP_FLASH_PARTITIONS_H
|
||||
#define __ESP_FLASH_PARTITIONS_H
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_types.h"
|
||||
#include "esp_flash_data_types.h"
|
||||
#include <stdbool.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ESP_PARTITION_MAGIC 0x50AA
|
||||
#define ESP_PARTITION_MAGIC_MD5 0xEBEB
|
||||
|
||||
#define PART_TYPE_APP 0x00
|
||||
#define PART_SUBTYPE_FACTORY 0x00
|
||||
#define PART_SUBTYPE_OTA_FLAG 0x10
|
||||
#define PART_SUBTYPE_OTA_MASK 0x0f
|
||||
#define PART_SUBTYPE_TEST 0x20
|
||||
|
||||
#define PART_TYPE_DATA 0x01
|
||||
#define PART_SUBTYPE_DATA_OTA 0x00
|
||||
#define PART_SUBTYPE_DATA_RF 0x01
|
||||
#define PART_SUBTYPE_DATA_WIFI 0x02
|
||||
#define PART_SUBTYPE_DATA_NVS_KEYS 0x04
|
||||
#define PART_SUBTYPE_DATA_EFUSE_EM 0x05
|
||||
|
||||
#define PART_TYPE_END 0xff
|
||||
#define PART_SUBTYPE_END 0xff
|
||||
|
||||
#define PART_FLAG_ENCRYPTED (1<<0)
|
||||
|
||||
/* The md5sum value is found this many bytes after the ESP_PARTITION_MAGIC_MD5 offset */
|
||||
#define ESP_PARTITION_MD5_OFFSET 16
|
||||
|
||||
/* 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. */
|
||||
@@ -53,43 +27,6 @@ extern "C" {
|
||||
#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 */
|
||||
|
||||
/// OTA_DATA states for checking operability of the app.
|
||||
typedef enum {
|
||||
ESP_OTA_IMG_NEW = 0x0U, /*!< Monitor the first boot. In bootloader this state is changed to ESP_OTA_IMG_PENDING_VERIFY. */
|
||||
ESP_OTA_IMG_PENDING_VERIFY = 0x1U, /*!< First boot for this app was. If while the second boot this state is then it will be changed to ABORTED. */
|
||||
ESP_OTA_IMG_VALID = 0x2U, /*!< App was confirmed as workable. App can boot and work without limits. */
|
||||
ESP_OTA_IMG_INVALID = 0x3U, /*!< App was confirmed as non-workable. This app will not selected to boot at all. */
|
||||
ESP_OTA_IMG_ABORTED = 0x4U, /*!< App could not confirm the workable or non-workable. In bootloader IMG_PENDING_VERIFY state will be changed to IMG_ABORTED. This app will not selected to boot at all. */
|
||||
ESP_OTA_IMG_UNDEFINED = 0xFFFFFFFFU, /*!< Undefined. App can boot and work without limits. */
|
||||
} esp_ota_img_states_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[20];
|
||||
uint32_t ota_state;
|
||||
uint32_t crc; /* CRC32 of ota_seq field only */
|
||||
} esp_ota_select_entry_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t offset;
|
||||
uint32_t size;
|
||||
} esp_partition_pos_t;
|
||||
|
||||
/* Structure which describes the layout of partition table entry.
|
||||
* See docs/partition_tables.rst for more information about individual fields.
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t magic;
|
||||
uint8_t type;
|
||||
uint8_t subtype;
|
||||
esp_partition_pos_t pos;
|
||||
uint8_t label[16];
|
||||
uint32_t flags;
|
||||
} esp_partition_info_t;
|
||||
|
||||
/* @brief Verify the partition table
|
||||
*
|
||||
* @param partition_table Pointer to at least ESP_PARTITION_TABLE_MAX_ENTRIES of potential partition table data. (ESP_PARTITION_TABLE_MAX_LEN bytes.)
|
||||
@@ -101,16 +38,10 @@ typedef struct {
|
||||
esp_err_t esp_partition_table_verify(const esp_partition_info_t *partition_table, bool log_errors, int *num_partitions);
|
||||
|
||||
|
||||
/**
|
||||
* Check whether the region on the main flash is safe to write.
|
||||
*
|
||||
* @param addr Start address of the region
|
||||
* @param size Size of the region
|
||||
*
|
||||
* @return true if the region is safe to write, otherwise false.
|
||||
*/
|
||||
bool esp_partition_main_flash_region_safe(size_t addr, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
/* 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);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -16,11 +16,6 @@
|
||||
#include <stdbool.h>
|
||||
#include <esp_err.h>
|
||||
#include "esp_flash_partitions.h"
|
||||
#include "esp_app_format.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ESP_ERR_IMAGE_BASE 0x2000
|
||||
#define ESP_ERR_IMAGE_FLASH_FAIL (ESP_ERR_IMAGE_BASE + 1)
|
||||
@@ -30,8 +25,91 @@ extern "C" {
|
||||
Can be compiled as part of app or bootloader code.
|
||||
*/
|
||||
|
||||
/* SPI flash mode, used in esp_image_header_t */
|
||||
typedef enum {
|
||||
ESP_IMAGE_SPI_MODE_QIO,
|
||||
ESP_IMAGE_SPI_MODE_QOUT,
|
||||
ESP_IMAGE_SPI_MODE_DIO,
|
||||
ESP_IMAGE_SPI_MODE_DOUT,
|
||||
ESP_IMAGE_SPI_MODE_FAST_READ,
|
||||
ESP_IMAGE_SPI_MODE_SLOW_READ
|
||||
} esp_image_spi_mode_t;
|
||||
|
||||
/* SPI flash clock frequency */
|
||||
typedef enum {
|
||||
ESP_IMAGE_SPI_SPEED_40M,
|
||||
ESP_IMAGE_SPI_SPEED_26M,
|
||||
ESP_IMAGE_SPI_SPEED_20M,
|
||||
ESP_IMAGE_SPI_SPEED_80M = 0xF
|
||||
} esp_image_spi_freq_t;
|
||||
|
||||
/* Supported SPI flash sizes */
|
||||
typedef enum {
|
||||
ESP_IMAGE_FLASH_SIZE_1MB = 0,
|
||||
ESP_IMAGE_FLASH_SIZE_2MB,
|
||||
ESP_IMAGE_FLASH_SIZE_4MB,
|
||||
ESP_IMAGE_FLASH_SIZE_8MB,
|
||||
ESP_IMAGE_FLASH_SIZE_16MB,
|
||||
ESP_IMAGE_FLASH_SIZE_MAX
|
||||
} esp_image_flash_size_t;
|
||||
|
||||
#define ESP_IMAGE_HEADER_MAGIC 0xE9
|
||||
|
||||
/* 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;
|
||||
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];
|
||||
/* Reserved bytes in ESP32 additional header space, currently unused */
|
||||
uint8_t reserved[11];
|
||||
/* 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 */
|
||||
|
||||
/* Header of binary image segment */
|
||||
typedef struct {
|
||||
uint32_t load_addr;
|
||||
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 */
|
||||
@@ -51,6 +129,36 @@ typedef enum {
|
||||
#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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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 esp_image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data) __attribute__((deprecated));
|
||||
|
||||
/**
|
||||
* @brief Verify an app image.
|
||||
*
|
||||
@@ -123,14 +231,6 @@ esp_err_t esp_image_verify_bootloader(uint32_t *length);
|
||||
*/
|
||||
esp_err_t esp_image_verify_bootloader_data(esp_image_metadata_t *data);
|
||||
|
||||
/**
|
||||
* @brief Get the flash size of the image
|
||||
*
|
||||
* @param app_flash_size The value configured in the image header
|
||||
* @return Actual size, in bytes.
|
||||
*/
|
||||
int esp_image_get_flash_size(esp_image_flash_size_t app_flash_size);
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t drom_addr;
|
||||
@@ -140,7 +240,3 @@ typedef struct {
|
||||
uint32_t irom_load_addr;
|
||||
uint32_t irom_size;
|
||||
} esp_image_flash_mapping_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <esp_err.h>
|
||||
#include "soc/efuse_periph.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
@@ -131,6 +131,7 @@ typedef struct {
|
||||
uint8_t digest[64];
|
||||
} esp_secure_boot_iv_digest_t;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -21,7 +21,7 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "esp_flash_partitions.h"
|
||||
#include "esp_flash_data_types.h"
|
||||
#include "soc/soc.h"
|
||||
|
||||
#define SPI_SEC_SIZE 0x1000
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
#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.
|
||||
@@ -36,7 +35,7 @@
|
||||
*
|
||||
* @return Number of free pages
|
||||
*/
|
||||
uint32_t bootloader_mmap_get_free_pages(void);
|
||||
uint32_t bootloader_mmap_get_free_pages();
|
||||
|
||||
/**
|
||||
* @brief Map a region of flash to data memory
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
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 esp32/sha.h to calculate SHA256 in IDF apps.
|
||||
Use mbedTLS APIs or include hwcrypto/sha.h to calculate SHA256 in IDF apps.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
@@ -26,8 +26,31 @@
|
||||
|
||||
typedef void *bootloader_sha256_handle_t;
|
||||
|
||||
bootloader_sha256_handle_t bootloader_sha256_start(void);
|
||||
bootloader_sha256_handle_t bootloader_sha256_start();
|
||||
|
||||
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);
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
// limitations under the License.
|
||||
#pragma once
|
||||
|
||||
#include "bootloader_config.h"
|
||||
#include "esp_image_format.h"
|
||||
|
||||
/**
|
||||
@@ -63,40 +62,3 @@ __attribute__((noreturn)) void bootloader_utility_load_boot_image(const bootload
|
||||
* It is not recommended to call this function from an app (if called, the app will abort).
|
||||
*/
|
||||
__attribute__((noreturn)) void bootloader_reset(void);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/** @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);
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
/** @brief Enable Quad I/O mode in bootloader (if configured)
|
||||
*
|
||||
* Queries attached SPI flash ID and sends correct SPI flash
|
||||
@@ -34,30 +32,6 @@ void bootloader_enable_qio_mode(void);
|
||||
*/
|
||||
uint32_t bootloader_read_flash_id();
|
||||
|
||||
/**
|
||||
* @brief Unlock Flash write protect.
|
||||
* Please do not call this function in SDK.
|
||||
*
|
||||
* @note This can be overridden because it's attribute weak.
|
||||
*/
|
||||
esp_err_t bootloader_flash_unlock(void);
|
||||
|
||||
/**
|
||||
* @brief Read the SFDP of the flash
|
||||
*
|
||||
* @param sfdp_addr Address of the parameter to read
|
||||
* @param miso_byte_num Bytes to read
|
||||
* @return The read SFDP, little endian, 4 bytes at most
|
||||
*/
|
||||
uint32_t bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_num);
|
||||
|
||||
/**
|
||||
* @brief Startup flow recommended by XMC. Call at startup before any erase/write operation.
|
||||
*
|
||||
* @return ESP_OK When startup successfully, otherwise ESP_FAIL (indiciating you should reboot before erase/write).
|
||||
*/
|
||||
esp_err_t bootloader_flash_xmc_startup(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -11,12 +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.
|
||||
#include "esp32/rom/uart.h"
|
||||
#include "esp32/rom/rtc.h"
|
||||
#include "rom/uart.h"
|
||||
#include "rom/rtc.h"
|
||||
#include "soc/soc.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/efuse_periph.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
|
||||
void bootloader_clock_configure()
|
||||
{
|
||||
@@ -52,18 +53,9 @@ void bootloader_clock_configure()
|
||||
* 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_CLK_SRC_EXT_CRYS
|
||||
#ifdef CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
|
||||
if (!rtc_clk_32k_enabled()) {
|
||||
rtc_clk_32k_bootstrap(CONFIG_ESP32_RTC_XTAL_BOOTSTRAP_CYCLES);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
|
||||
int esp_clk_apb_freq(void)
|
||||
{
|
||||
return rtc_clk_apb_freq_get();
|
||||
}
|
||||
|
||||
#endif // BOOTLOADER_BUILD
|
||||
|
||||
@@ -17,17 +17,19 @@
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp32/rom/crc.h"
|
||||
#include "esp32/rom/gpio.h"
|
||||
#include "rom/spi_flash.h"
|
||||
#include "rom/crc.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "rom/gpio.h"
|
||||
#include "esp_flash_data_types.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_flash_partitions.h"
|
||||
#include "bootloader_flash.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "soc/apb_ctrl_reg.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/spi_reg.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "bootloader_sha.h"
|
||||
#include "sys/param.h"
|
||||
@@ -182,7 +184,22 @@ esp_err_t bootloader_common_get_sha256_of_partition (uint32_t address, uint32_t
|
||||
size = data.image_len;
|
||||
}
|
||||
// If image is type by data then hash is calculated for entire image.
|
||||
return bootloader_sha256_flash_contents(address, size, out_sha_256);
|
||||
const void *partition_bin = bootloader_mmap(address, size);
|
||||
if (partition_bin == NULL) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", address, size);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
bootloader_sha256_handle_t sha_handle = bootloader_sha256_start();
|
||||
if (sha_handle == NULL) {
|
||||
bootloader_munmap(partition_bin);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
bootloader_sha256_data(sha_handle, partition_bin, size);
|
||||
bootloader_sha256_finish(sha_handle, out_sha_256);
|
||||
|
||||
bootloader_munmap(partition_bin);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int bootloader_common_select_otadata(const esp_ota_select_entry_t *two_otadata, bool *valid_two_otadata, bool max)
|
||||
@@ -228,15 +245,13 @@ esp_err_t bootloader_common_get_partition_description(const esp_partition_pos_t
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
const uint32_t app_desc_offset = sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t);
|
||||
const uint32_t mmap_size = app_desc_offset + sizeof(esp_app_desc_t);
|
||||
const uint8_t *image = bootloader_mmap(partition->offset, mmap_size);
|
||||
const uint8_t *image = bootloader_mmap(partition->offset, partition->size);
|
||||
if (image == NULL) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", partition->offset, mmap_size);
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", partition->offset, partition->size);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
memcpy(app_desc, image + app_desc_offset, sizeof(esp_app_desc_t));
|
||||
memcpy(app_desc, image + sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t), sizeof(esp_app_desc_t));
|
||||
bootloader_munmap(image);
|
||||
|
||||
if (app_desc->magic_word != ESP_APP_DESC_MAGIC_WORD) {
|
||||
@@ -261,50 +276,12 @@ void bootloader_common_vddsdio_configure()
|
||||
#endif // CONFIG_BOOTLOADER_VDDSDIO_BOOST
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
uint8_t bootloader_common_get_chip_revision(void)
|
||||
void bootloader_common_set_flash_cs_timing()
|
||||
{
|
||||
uint8_t eco_bit0, eco_bit1, eco_bit2;
|
||||
eco_bit0 = (REG_READ(EFUSE_BLK0_RDATA3_REG) & 0xF000) >> 15;
|
||||
eco_bit1 = (REG_READ(EFUSE_BLK0_RDATA5_REG) & 0x100000) >> 20;
|
||||
eco_bit2 = (REG_READ(APB_CTRL_DATE_REG) & 0x80000000) >> 31;
|
||||
uint32_t combine_value = (eco_bit2 << 2) | (eco_bit1 << 1) | eco_bit0;
|
||||
uint8_t chip_ver = 0;
|
||||
switch (combine_value) {
|
||||
case 0:
|
||||
chip_ver = 0;
|
||||
break;
|
||||
case 1:
|
||||
chip_ver = 1;
|
||||
break;
|
||||
case 3:
|
||||
chip_ver = 2;
|
||||
break;
|
||||
case 7:
|
||||
chip_ver = 3;
|
||||
break;
|
||||
default:
|
||||
chip_ver = 0;
|
||||
break;
|
||||
}
|
||||
return chip_ver;
|
||||
}
|
||||
#endif
|
||||
|
||||
esp_err_t bootloader_common_check_chip_validity(const esp_image_header_t* img_hdr, esp_image_type type)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
esp_chip_id_t chip_id = CONFIG_IDF_FIRMWARE_CHIP_ID;
|
||||
if (chip_id != img_hdr->chip_id) {
|
||||
ESP_LOGE(TAG, "mismatch chip ID, expected %d, found %d", chip_id, img_hdr->chip_id);
|
||||
err = ESP_FAIL;
|
||||
}
|
||||
uint8_t revision = bootloader_common_get_chip_revision();
|
||||
if (revision < img_hdr->min_chip_rev) {
|
||||
ESP_LOGE(TAG, "can't run on lower chip revision, expected %d, found %d", revision, img_hdr->min_chip_rev);
|
||||
err = ESP_FAIL;
|
||||
} else if (revision != img_hdr->min_chip_rev) {
|
||||
ESP_LOGI(TAG, "chip revision: %d, min. %s chip revision: %d", revision, type == ESP_IMAGE_BOOTLOADER ? "bootloader" : "application", img_hdr->min_chip_rev);
|
||||
}
|
||||
return err;
|
||||
SET_PERI_REG_MASK(SPI_USER_REG(0), SPI_CS_HOLD_M | SPI_CS_SETUP_M);
|
||||
SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_HOLD_TIME_V, 1, SPI_HOLD_TIME_S);
|
||||
SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_SETUP_TIME_V, 0, SPI_SETUP_TIME_S);
|
||||
SET_PERI_REG_MASK(SPI_USER_REG(1), SPI_CS_HOLD_M | SPI_CS_SETUP_M);
|
||||
SET_PERI_REG_BITS(SPI_CTRL2_REG(1), SPI_HOLD_TIME_V, 1, SPI_HOLD_TIME_S);
|
||||
SET_PERI_REG_BITS(SPI_CTRL2_REG(1), SPI_SETUP_TIME_V, 0, SPI_SETUP_TIME_S);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include <esp_log.h>
|
||||
#include <esp_spi_flash.h> /* including in bootloader for error values */
|
||||
#include <esp_flash_encrypt.h>
|
||||
#include "flash_qio_mode.h"
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
/* Normal app version maps to esp_spi_flash.h operations...
|
||||
@@ -87,8 +86,8 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
|
||||
#else
|
||||
/* Bootloader version, uses ROM functions only */
|
||||
#include <soc/dport_reg.h>
|
||||
#include <esp32/rom/spi_flash.h>
|
||||
#include <esp32/rom/cache.h>
|
||||
#include <rom/spi_flash.h>
|
||||
#include <rom/cache.h>
|
||||
|
||||
static const char *TAG = "bootloader_flash";
|
||||
|
||||
@@ -250,7 +249,7 @@ esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
err = bootloader_flash_unlock();
|
||||
err = spi_to_esp_err(esp_rom_spiflash_unlock());
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -1,171 +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.
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include "string.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp32/rom/gpio.h"
|
||||
#include "esp32/rom/spi_flash.h"
|
||||
#include "esp32/rom/efuse.h"
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "soc/spi_reg.h"
|
||||
#include "soc/spi_caps.h"
|
||||
#include "flash_qio_mode.h"
|
||||
#include "bootloader_flash_config.h"
|
||||
|
||||
void bootloader_flash_update_id()
|
||||
{
|
||||
g_rom_flashchip.device_id = bootloader_read_flash_id();
|
||||
}
|
||||
|
||||
void bootloader_flash_update_size(uint32_t size)
|
||||
{
|
||||
g_rom_flashchip.chip_size = size;
|
||||
}
|
||||
|
||||
void IRAM_ATTR bootloader_flash_cs_timing_config()
|
||||
{
|
||||
SET_PERI_REG_MASK(SPI_USER_REG(0), SPI_CS_HOLD_M | SPI_CS_SETUP_M);
|
||||
SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_HOLD_TIME_V, 1, SPI_HOLD_TIME_S);
|
||||
SET_PERI_REG_BITS(SPI_CTRL2_REG(0), SPI_SETUP_TIME_V, 0, SPI_SETUP_TIME_S);
|
||||
SET_PERI_REG_MASK(SPI_USER_REG(1), SPI_CS_HOLD_M | SPI_CS_SETUP_M);
|
||||
SET_PERI_REG_BITS(SPI_CTRL2_REG(1), SPI_HOLD_TIME_V, 1, SPI_HOLD_TIME_S);
|
||||
SET_PERI_REG_BITS(SPI_CTRL2_REG(1), SPI_SETUP_TIME_V, 0, SPI_SETUP_TIME_S);
|
||||
}
|
||||
|
||||
void IRAM_ATTR bootloader_flash_clock_config(const esp_image_header_t* pfhdr)
|
||||
{
|
||||
uint32_t spi_clk_div = 0;
|
||||
switch (pfhdr->spi_speed) {
|
||||
case ESP_IMAGE_SPI_SPEED_80M:
|
||||
spi_clk_div = 1;
|
||||
break;
|
||||
case ESP_IMAGE_SPI_SPEED_40M:
|
||||
spi_clk_div = 2;
|
||||
break;
|
||||
case ESP_IMAGE_SPI_SPEED_26M:
|
||||
spi_clk_div = 3;
|
||||
break;
|
||||
case ESP_IMAGE_SPI_SPEED_20M:
|
||||
spi_clk_div = 4;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
esp_rom_spiflash_config_clk(spi_clk_div, 0);
|
||||
esp_rom_spiflash_config_clk(spi_clk_div, 1);
|
||||
}
|
||||
|
||||
void IRAM_ATTR bootloader_flash_gpio_config(const esp_image_header_t* pfhdr)
|
||||
{
|
||||
uint32_t drv = 2;
|
||||
if (pfhdr->spi_speed == ESP_IMAGE_SPI_SPEED_80M) {
|
||||
drv = 3;
|
||||
}
|
||||
|
||||
uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_PKG);
|
||||
uint32_t pkg_ver = chip_ver & 0x7;
|
||||
|
||||
if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5) {
|
||||
// For ESP32D2WD the SPI pins are already configured
|
||||
// flash clock signal should come from IO MUX.
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
|
||||
} else if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2) {
|
||||
// For ESP32PICOD2 the SPI pins are already configured
|
||||
// flash clock signal should come from IO MUX.
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
|
||||
} else if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4) {
|
||||
// For ESP32PICOD4 the SPI pins are already configured
|
||||
// flash clock signal should come from IO MUX.
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
|
||||
} else {
|
||||
const uint32_t spiconfig = ets_efuse_get_spiconfig();
|
||||
if (spiconfig == EFUSE_SPICONFIG_SPI_DEFAULTS) {
|
||||
gpio_matrix_out(SPI_IOMUX_PIN_NUM_CS, SPICS0_OUT_IDX, 0, 0);
|
||||
gpio_matrix_out(SPI_IOMUX_PIN_NUM_MISO, SPIQ_OUT_IDX, 0, 0);
|
||||
gpio_matrix_in(SPI_IOMUX_PIN_NUM_MISO, SPIQ_IN_IDX, 0);
|
||||
gpio_matrix_out(SPI_IOMUX_PIN_NUM_MOSI, SPID_OUT_IDX, 0, 0);
|
||||
gpio_matrix_in(SPI_IOMUX_PIN_NUM_MOSI, SPID_IN_IDX, 0);
|
||||
gpio_matrix_out(SPI_IOMUX_PIN_NUM_WP, SPIWP_OUT_IDX, 0, 0);
|
||||
gpio_matrix_in(SPI_IOMUX_PIN_NUM_WP, SPIWP_IN_IDX, 0);
|
||||
gpio_matrix_out(SPI_IOMUX_PIN_NUM_HD, SPIHD_OUT_IDX, 0, 0);
|
||||
gpio_matrix_in(SPI_IOMUX_PIN_NUM_HD, SPIHD_IN_IDX, 0);
|
||||
//select pin function gpio
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA2_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA3_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, PIN_FUNC_GPIO);
|
||||
// flash clock signal should come from IO MUX.
|
||||
// set drive ability for clock
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
|
||||
|
||||
uint32_t flash_id = g_rom_flashchip.device_id;
|
||||
if (flash_id == FLASH_ID_GD25LQ32C) {
|
||||
// Set drive ability for 1.8v flash in 80Mhz.
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA0_U, FUN_DRV, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA1_U, FUN_DRV, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA2_U, FUN_DRV, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA3_U, FUN_DRV, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CMD_U, FUN_DRV, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, 3, FUN_DRV_S);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR bootloader_flash_dummy_config(const esp_image_header_t* pfhdr)
|
||||
{
|
||||
int spi_cache_dummy = 0;
|
||||
uint32_t modebit = READ_PERI_REG(SPI_CTRL_REG(0));
|
||||
if (modebit & SPI_FASTRD_MODE) {
|
||||
if (modebit & SPI_FREAD_QIO) { //SPI mode is QIO
|
||||
spi_cache_dummy = SPI0_R_QIO_DUMMY_CYCLELEN;
|
||||
} else if (modebit & SPI_FREAD_DIO) { //SPI mode is DIO
|
||||
spi_cache_dummy = SPI0_R_DIO_DUMMY_CYCLELEN;
|
||||
SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_ADDR_BITLEN_V, SPI0_R_DIO_ADDR_BITSLEN, SPI_USR_ADDR_BITLEN_S);
|
||||
} else if(modebit & (SPI_FREAD_QUAD | SPI_FREAD_DUAL)) { //SPI mode is QOUT or DIO
|
||||
spi_cache_dummy = SPI0_R_FAST_DUMMY_CYCLELEN;
|
||||
}
|
||||
}
|
||||
|
||||
extern uint8_t g_rom_spiflash_dummy_len_plus[];
|
||||
switch (pfhdr->spi_speed) {
|
||||
case ESP_IMAGE_SPI_SPEED_80M:
|
||||
g_rom_spiflash_dummy_len_plus[0] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_80M;
|
||||
g_rom_spiflash_dummy_len_plus[1] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_80M;
|
||||
break;
|
||||
case ESP_IMAGE_SPI_SPEED_40M:
|
||||
g_rom_spiflash_dummy_len_plus[0] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_40M;
|
||||
g_rom_spiflash_dummy_len_plus[1] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_40M;
|
||||
break;
|
||||
case ESP_IMAGE_SPI_SPEED_26M:
|
||||
case ESP_IMAGE_SPI_SPEED_20M:
|
||||
g_rom_spiflash_dummy_len_plus[0] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_20M;
|
||||
g_rom_spiflash_dummy_len_plus[1] = ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_20M;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN_V, spi_cache_dummy + g_rom_spiflash_dummy_len_plus[0],
|
||||
SPI_USR_DUMMY_CYCLELEN_S);
|
||||
}
|
||||
@@ -19,26 +19,25 @@
|
||||
#include "esp_attr.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "esp32/rom/cache.h"
|
||||
#include "esp32/rom/efuse.h"
|
||||
#include "esp32/rom/ets_sys.h"
|
||||
#include "esp32/rom/spi_flash.h"
|
||||
#include "esp32/rom/crc.h"
|
||||
#include "esp32/rom/rtc.h"
|
||||
#include "esp32/rom/uart.h"
|
||||
#include "esp32/rom/gpio.h"
|
||||
#include "esp32/rom/secure_boot.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/efuse_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/timer_group_reg.h"
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "soc/efuse_periph.h"
|
||||
#include "soc/rtc_periph.h"
|
||||
#include "soc/timer_periph.h"
|
||||
#include "soc/rtc_wdt.h"
|
||||
#include "soc/spi_periph.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_image_format.h"
|
||||
@@ -50,7 +49,6 @@
|
||||
#include "bootloader_config.h"
|
||||
#include "bootloader_clock.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "bootloader_flash_config.h"
|
||||
|
||||
#include "flash_qio_mode.h"
|
||||
|
||||
@@ -64,7 +62,7 @@ static const char* TAG = "boot";
|
||||
static esp_err_t bootloader_main();
|
||||
static void print_flash_info(const esp_image_header_t* pfhdr);
|
||||
static void update_flash_config(const esp_image_header_t* pfhdr);
|
||||
static void bootloader_init_flash_configure(const esp_image_header_t* pfhdr);
|
||||
static void flash_gpio_configure(const esp_image_header_t* pfhdr);
|
||||
static void uart_console_configure(void);
|
||||
static void wdt_reset_check(void);
|
||||
|
||||
@@ -122,26 +120,12 @@ static esp_err_t bootloader_main()
|
||||
bootloader_common_vddsdio_configure();
|
||||
/* Read and keep flash ID, for further use. */
|
||||
g_rom_flashchip.device_id = bootloader_read_flash_id();
|
||||
/* Check and run XMC startup flow */
|
||||
if (bootloader_flash_xmc_startup() != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_image_header_t fhdr;
|
||||
if (bootloader_flash_read(ESP_BOOTLOADER_OFFSET, &fhdr, sizeof(esp_image_header_t), true) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed to load bootloader header!");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Check chip ID and minimum chip revision that supported by this image */
|
||||
uint8_t revision = bootloader_common_get_chip_revision();
|
||||
ESP_LOGI(TAG, "Chip Revision: %d", revision);
|
||||
if (bootloader_common_check_chip_validity(&fhdr, ESP_IMAGE_BOOTLOADER) != ESP_OK) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
bootloader_init_flash_configure(&fhdr);
|
||||
flash_gpio_configure(&fhdr);
|
||||
#if (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ == 240)
|
||||
//Check if ESP32 is rated for a CPU frequency of 160MHz only
|
||||
if (REG_GET_BIT(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_CPU_FREQ_RATED) &&
|
||||
@@ -183,12 +167,12 @@ static esp_err_t bootloader_main()
|
||||
}
|
||||
#endif
|
||||
|
||||
bootloader_flash_unlock();
|
||||
esp_rom_spiflash_unlock();
|
||||
|
||||
ESP_LOGI(TAG, "Enabling RNG early entropy source...");
|
||||
bootloader_random_enable();
|
||||
|
||||
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT
|
||||
#if CONFIG_FLASHMODE_QIO || CONFIG_FLASHMODE_QOUT
|
||||
bootloader_enable_qio_mode();
|
||||
#endif
|
||||
|
||||
@@ -301,24 +285,130 @@ static void print_flash_info(const esp_image_header_t* phdr)
|
||||
#endif
|
||||
}
|
||||
|
||||
#define FLASH_CLK_IO 6
|
||||
#define FLASH_CS_IO 11
|
||||
#define FLASH_SPIQ_IO 7
|
||||
#define FLASH_SPID_IO 8
|
||||
#define FLASH_SPIWP_IO 10
|
||||
#define FLASH_SPIHD_IO 9
|
||||
#define FLASH_IO_MATRIX_DUMMY_40M 1
|
||||
#define FLASH_IO_MATRIX_DUMMY_80M 2
|
||||
#define FLASH_IO_DRIVE_GD_WITH_1V8PSRAM 3
|
||||
|
||||
/*
|
||||
* Bootloader reads SPI configuration from bin header, so that
|
||||
* the burning configuration can be different with compiling configuration.
|
||||
*/
|
||||
static void IRAM_ATTR bootloader_init_flash_configure(const esp_image_header_t* pfhdr)
|
||||
static void IRAM_ATTR flash_gpio_configure(const esp_image_header_t* pfhdr)
|
||||
{
|
||||
bootloader_flash_gpio_config(pfhdr);
|
||||
bootloader_flash_dummy_config(pfhdr);
|
||||
bootloader_flash_cs_timing_config();
|
||||
int spi_cache_dummy = 0;
|
||||
int drv = 2;
|
||||
switch (pfhdr->spi_mode) {
|
||||
case ESP_IMAGE_SPI_MODE_QIO:
|
||||
spi_cache_dummy = SPI0_R_QIO_DUMMY_CYCLELEN;
|
||||
break;
|
||||
case ESP_IMAGE_SPI_MODE_DIO:
|
||||
spi_cache_dummy = SPI0_R_DIO_DUMMY_CYCLELEN;
|
||||
SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_ADDR_BITLEN_V, SPI0_R_DIO_ADDR_BITSLEN, SPI_USR_ADDR_BITLEN_S);
|
||||
break;
|
||||
case ESP_IMAGE_SPI_MODE_QOUT:
|
||||
case ESP_IMAGE_SPI_MODE_DOUT:
|
||||
default:
|
||||
spi_cache_dummy = SPI0_R_FAST_DUMMY_CYCLELEN;
|
||||
break;
|
||||
}
|
||||
|
||||
/* dummy_len_plus values defined in ROM for SPI flash configuration */
|
||||
extern uint8_t g_rom_spiflash_dummy_len_plus[];
|
||||
switch (pfhdr->spi_speed) {
|
||||
case ESP_IMAGE_SPI_SPEED_80M:
|
||||
g_rom_spiflash_dummy_len_plus[0] = FLASH_IO_MATRIX_DUMMY_80M;
|
||||
g_rom_spiflash_dummy_len_plus[1] = FLASH_IO_MATRIX_DUMMY_80M;
|
||||
SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN_V, spi_cache_dummy + FLASH_IO_MATRIX_DUMMY_80M,
|
||||
SPI_USR_DUMMY_CYCLELEN_S); //DUMMY
|
||||
drv = 3;
|
||||
break;
|
||||
case ESP_IMAGE_SPI_SPEED_40M:
|
||||
g_rom_spiflash_dummy_len_plus[0] = FLASH_IO_MATRIX_DUMMY_40M;
|
||||
g_rom_spiflash_dummy_len_plus[1] = FLASH_IO_MATRIX_DUMMY_40M;
|
||||
SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN_V, spi_cache_dummy + FLASH_IO_MATRIX_DUMMY_40M,
|
||||
SPI_USR_DUMMY_CYCLELEN_S); //DUMMY
|
||||
break;
|
||||
case ESP_IMAGE_SPI_SPEED_26M:
|
||||
case ESP_IMAGE_SPI_SPEED_20M:
|
||||
SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_DUMMY_CYCLELEN_V, spi_cache_dummy, SPI_USR_DUMMY_CYCLELEN_S); //DUMMY
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_PKG);
|
||||
uint32_t pkg_ver = chip_ver & 0x7;
|
||||
|
||||
if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5) {
|
||||
// For ESP32D2WD the SPI pins are already configured
|
||||
// flash clock signal should come from IO MUX.
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
|
||||
} else if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2) {
|
||||
// For ESP32PICOD2 the SPI pins are already configured
|
||||
// flash clock signal should come from IO MUX.
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
|
||||
} else if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4) {
|
||||
// For ESP32PICOD4 the SPI pins are already configured
|
||||
// flash clock signal should come from IO MUX.
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
|
||||
} else {
|
||||
const uint32_t spiconfig = ets_efuse_get_spiconfig();
|
||||
if (spiconfig == EFUSE_SPICONFIG_SPI_DEFAULTS) {
|
||||
gpio_matrix_out(FLASH_CS_IO, SPICS0_OUT_IDX, 0, 0);
|
||||
gpio_matrix_out(FLASH_SPIQ_IO, SPIQ_OUT_IDX, 0, 0);
|
||||
gpio_matrix_in(FLASH_SPIQ_IO, SPIQ_IN_IDX, 0);
|
||||
gpio_matrix_out(FLASH_SPID_IO, SPID_OUT_IDX, 0, 0);
|
||||
gpio_matrix_in(FLASH_SPID_IO, SPID_IN_IDX, 0);
|
||||
gpio_matrix_out(FLASH_SPIWP_IO, SPIWP_OUT_IDX, 0, 0);
|
||||
gpio_matrix_in(FLASH_SPIWP_IO, SPIWP_IN_IDX, 0);
|
||||
gpio_matrix_out(FLASH_SPIHD_IO, SPIHD_OUT_IDX, 0, 0);
|
||||
gpio_matrix_in(FLASH_SPIHD_IO, SPIHD_IN_IDX, 0);
|
||||
//select pin function gpio
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA2_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA3_U, PIN_FUNC_GPIO);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, PIN_FUNC_GPIO);
|
||||
// flash clock signal should come from IO MUX.
|
||||
// set drive ability for clock
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, FUNC_SD_CLK_SPICLK);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, drv, FUN_DRV_S);
|
||||
|
||||
#if CONFIG_SPIRAM_TYPE_ESPPSRAM32
|
||||
uint32_t flash_id = g_rom_flashchip.device_id;
|
||||
if (flash_id == FLASH_ID_GD25LQ32C) {
|
||||
// Set drive ability for 1.8v flash in 80Mhz.
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA0_U, FUN_DRV, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA1_U, FUN_DRV, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA2_U, FUN_DRV, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_DATA3_U, FUN_DRV, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CMD_U, FUN_DRV, 3, FUN_DRV_S);
|
||||
SET_PERI_REG_BITS(PERIPHS_IO_MUX_SD_CLK_U, FUN_DRV, 3, FUN_DRV_S);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// improve the flash cs timing.
|
||||
bootloader_common_set_flash_cs_timing();
|
||||
}
|
||||
|
||||
static void uart_console_configure(void)
|
||||
{
|
||||
#if CONFIG_ESP_CONSOLE_UART_NONE
|
||||
#if CONFIG_CONSOLE_UART_NONE
|
||||
ets_install_putc1(NULL);
|
||||
ets_install_putc2(NULL);
|
||||
#else // CONFIG_ESP_CONSOLE_UART_NONE
|
||||
const int uart_num = CONFIG_ESP_CONSOLE_UART_NUM;
|
||||
#else // CONFIG_CONSOLE_UART_NONE
|
||||
const int uart_num = CONFIG_CONSOLE_UART_NUM;
|
||||
|
||||
uartAttach();
|
||||
ets_install_uart_printf();
|
||||
@@ -326,10 +416,10 @@ static void uart_console_configure(void)
|
||||
// Wait for UART FIFO to be empty.
|
||||
uart_tx_wait_idle(0);
|
||||
|
||||
#if CONFIG_ESP_CONSOLE_UART_CUSTOM
|
||||
#if CONFIG_CONSOLE_UART_CUSTOM
|
||||
// Some constants to make the following code less upper-case
|
||||
const int uart_tx_gpio = CONFIG_ESP_CONSOLE_UART_TX_GPIO;
|
||||
const int uart_rx_gpio = CONFIG_ESP_CONSOLE_UART_RX_GPIO;
|
||||
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);
|
||||
@@ -356,13 +446,13 @@ static void uart_console_configure(void)
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, uart_reset[uart_num]);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, uart_reset[uart_num]);
|
||||
}
|
||||
#endif // CONFIG_ESP_CONSOLE_UART_CUSTOM
|
||||
#endif // CONFIG_CONSOLE_UART_CUSTOM
|
||||
|
||||
// Set configured UART console baud rate
|
||||
const int uart_baud = CONFIG_ESP_CONSOLE_UART_BAUDRATE;
|
||||
const int uart_baud = CONFIG_CONSOLE_UART_BAUDRATE;
|
||||
uart_div_modify(uart_num, (rtc_clk_apb_freq_get() << 4) / uart_baud);
|
||||
|
||||
#endif // CONFIG_ESP_CONSOLE_UART_NONE
|
||||
#endif // CONFIG_CONSOLE_UART_NONE
|
||||
}
|
||||
|
||||
static void wdt_reset_cpu0_info_enable(void)
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
#include "bootloader_random.h"
|
||||
#include "soc/cpu.h"
|
||||
#include "soc/wdev_reg.h"
|
||||
#include "soc/rtc_periph.h"
|
||||
#include "soc/sens_periph.h"
|
||||
#include "soc/syscon_periph.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/sens_reg.h"
|
||||
#include "soc/syscon_reg.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/i2s_periph.h"
|
||||
#include "soc/i2s_reg.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
@@ -114,18 +114,17 @@ void bootloader_random_enable(void)
|
||||
|
||||
void bootloader_random_disable(void)
|
||||
{
|
||||
/* Disable i2s clock */
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
|
||||
|
||||
|
||||
/* Reset some i2s configuration (possibly redundant as we reset entire
|
||||
I2S peripheral further down). */
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_START);
|
||||
SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF2_REG(0), I2S_CAMERA_EN);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF2_REG(0), I2S_LCD_EN);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF2_REG(0), I2S_DATA_ENABLE_TEST_EN);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF2_REG(0), I2S_DATA_ENABLE);
|
||||
|
||||
/* Disable i2s clock */
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
|
||||
CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_START);
|
||||
|
||||
/* Restore SYSCON mode registers */
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_READ_CTRL_REG, SENS_SAR1_DIG_FORCE);
|
||||
|
||||
@@ -16,18 +16,61 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <sys/param.h>
|
||||
#include "esp32/rom/sha.h"
|
||||
#include "soc/hwcrypto_periph.h"
|
||||
#include "esp32/rom/ets_sys.h" // TO REMOVE
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
// App version is a wrapper around mbedTLS SHA API
|
||||
#include <mbedtls/sha256.h>
|
||||
|
||||
bootloader_sha256_handle_t bootloader_sha256_start()
|
||||
{
|
||||
mbedtls_sha256_context *ctx = (mbedtls_sha256_context *)malloc(sizeof(mbedtls_sha256_context));
|
||||
if (!ctx) {
|
||||
return NULL;
|
||||
}
|
||||
mbedtls_sha256_init(ctx);
|
||||
int ret = mbedtls_sha256_starts_ret(ctx, false);
|
||||
if (ret != 0) {
|
||||
return NULL;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void bootloader_sha256_data(bootloader_sha256_handle_t handle, const void *data, size_t data_len)
|
||||
{
|
||||
assert(handle != NULL);
|
||||
mbedtls_sha256_context *ctx = (mbedtls_sha256_context *)handle;
|
||||
int ret = mbedtls_sha256_update_ret(ctx, data, data_len);
|
||||
assert(ret == 0);
|
||||
}
|
||||
|
||||
void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest)
|
||||
{
|
||||
assert(handle != NULL);
|
||||
mbedtls_sha256_context *ctx = (mbedtls_sha256_context *)handle;
|
||||
if (digest != NULL) {
|
||||
int ret = mbedtls_sha256_finish_ret(ctx, digest);
|
||||
assert(ret == 0);
|
||||
}
|
||||
mbedtls_sha256_free(ctx);
|
||||
free(handle);
|
||||
}
|
||||
|
||||
#else // Bootloader version
|
||||
|
||||
#include "rom/sha.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/hwcrypto_reg.h"
|
||||
|
||||
#include "rom/ets_sys.h" // TO REMOVE
|
||||
|
||||
static uint32_t words_hashed;
|
||||
|
||||
// Words per SHA256 block
|
||||
static const size_t BLOCK_WORDS = (64 / sizeof(uint32_t));
|
||||
static const size_t BLOCK_WORDS = (64/sizeof(uint32_t));
|
||||
// Words in final SHA256 digest
|
||||
static const size_t DIGEST_WORDS = (32 / sizeof(uint32_t));
|
||||
static const size_t DIGEST_WORDS = (32/sizeof(uint32_t));
|
||||
|
||||
bootloader_sha256_handle_t bootloader_sha256_start(void)
|
||||
bootloader_sha256_handle_t bootloader_sha256_start()
|
||||
{
|
||||
// Enable SHA hardware
|
||||
ets_sha_enable();
|
||||
@@ -52,7 +95,7 @@ void bootloader_sha256_data(bootloader_sha256_handle_t handle, const void *data,
|
||||
copy_words = MIN(word_len, copy_words);
|
||||
|
||||
// Wait for SHA engine idle
|
||||
while (REG_READ(SHA_256_BUSY_REG) != 0) { }
|
||||
while(REG_READ(SHA_256_BUSY_REG) != 0) { }
|
||||
|
||||
// Copy to memory block
|
||||
//ets_printf("block_count %d copy_words %d\n", block_count, copy_words);
|
||||
@@ -105,7 +148,7 @@ void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest
|
||||
|
||||
bootloader_sha256_data(handle, padding, pad_bytes);
|
||||
|
||||
assert(words_hashed % BLOCK_WORDS == 60 / 4); // 32-bits left in block
|
||||
assert(words_hashed % BLOCK_WORDS == 60/4); // 32-bits left in block
|
||||
|
||||
// Calculate 32-bit length for final 32 bits of data
|
||||
uint32_t bit_count = __builtin_bswap32( data_words * 32 );
|
||||
@@ -113,9 +156,9 @@ void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest
|
||||
|
||||
assert(words_hashed % BLOCK_WORDS == 0);
|
||||
|
||||
while (REG_READ(SHA_256_BUSY_REG) == 1) { }
|
||||
while(REG_READ(SHA_256_BUSY_REG) == 1) { }
|
||||
REG_WRITE(SHA_256_LOAD_REG, 1);
|
||||
while (REG_READ(SHA_256_BUSY_REG) == 1) { }
|
||||
while(REG_READ(SHA_256_BUSY_REG) == 1) { }
|
||||
|
||||
uint32_t *digest_words = (uint32_t *)digest;
|
||||
uint32_t *sha_text_reg = (uint32_t *)(SHA_TEXT_BASE);
|
||||
@@ -124,3 +167,23 @@ void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest
|
||||
}
|
||||
asm volatile ("memw");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
esp_err_t bootloader_sha256_hex_to_str(char *out_str, const uint8_t *in_array_hex, size_t len)
|
||||
{
|
||||
if (out_str == NULL || in_array_hex == NULL || len == 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
for (int i = 0; i < len; i++) {
|
||||
for (int shift = 0; shift < 2; shift++) {
|
||||
uint8_t nibble = (in_array_hex[i] >> (shift ? 0 : 4)) & 0x0F;
|
||||
if (nibble < 10) {
|
||||
out_str[i*2+shift] = '0' + nibble;
|
||||
} else {
|
||||
out_str[i*2+shift] = 'a' + nibble - 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -19,24 +19,26 @@
|
||||
#include "esp_attr.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "esp32/rom/cache.h"
|
||||
#include "esp32/rom/efuse.h"
|
||||
#include "esp32/rom/ets_sys.h"
|
||||
#include "esp32/rom/spi_flash.h"
|
||||
#include "esp32/rom/crc.h"
|
||||
#include "esp32/rom/rtc.h"
|
||||
#include "esp32/rom/uart.h"
|
||||
#include "esp32/rom/gpio.h"
|
||||
#include "esp32/rom/secure_boot.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/gpio_periph.h"
|
||||
#include "soc/efuse_periph.h"
|
||||
#include "soc/rtc_periph.h"
|
||||
#include "soc/timer_periph.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"
|
||||
@@ -167,7 +169,7 @@ bool bootloader_utility_load_partition_table(bootloader_state_t* bs)
|
||||
break;
|
||||
case PART_SUBTYPE_DATA_EFUSE_EM:
|
||||
partition_usage = "efuse";
|
||||
#ifdef CONFIG_BOOTLOADER_EFUSE_SECURE_VERSION_EMULATE
|
||||
#ifdef CONFIG_EFUSE_SECURE_VERSION_EMULATE
|
||||
esp_efuse_init(partition->pos.offset, partition->pos.size);
|
||||
#endif
|
||||
break;
|
||||
@@ -241,7 +243,7 @@ static esp_err_t write_otadata(esp_ota_select_entry_t *otadata, uint32_t offset,
|
||||
|
||||
static bool check_anti_rollback(const esp_partition_pos_t *partition)
|
||||
{
|
||||
#ifdef CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
|
||||
#ifdef CONFIG_APP_ANTI_ROLLBACK
|
||||
esp_app_desc_t app_desc;
|
||||
esp_err_t err = bootloader_common_get_partition_description(partition, &app_desc);
|
||||
return err == ESP_OK && esp_efuse_check_secure_version(app_desc.secure_version) == true;
|
||||
@@ -250,7 +252,7 @@ static bool check_anti_rollback(const esp_partition_pos_t *partition)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
|
||||
#ifdef CONFIG_APP_ANTI_ROLLBACK
|
||||
static void update_anti_rollback(const esp_partition_pos_t *partition)
|
||||
{
|
||||
esp_app_desc_t app_desc;
|
||||
@@ -304,7 +306,7 @@ int bootloader_utility_get_selected_boot_partition(const bootloader_state_t *bs)
|
||||
ESP_LOGD(TAG, "otadata[0]: sequence values 0x%08x", otadata[0].ota_seq);
|
||||
ESP_LOGD(TAG, "otadata[1]: sequence values 0x%08x", otadata[1].ota_seq);
|
||||
|
||||
#ifdef CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
|
||||
#ifdef CONFIG_APP_ROLLBACK_ENABLE
|
||||
bool write_encrypted = esp_flash_encryption_enabled();
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (otadata[i].ota_state == ESP_OTA_IMG_PENDING_VERIFY) {
|
||||
@@ -315,7 +317,7 @@ int bootloader_utility_get_selected_boot_partition(const bootloader_state_t *bs)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
|
||||
#ifndef CONFIG_APP_ANTI_ROLLBACK
|
||||
if ((bootloader_common_ota_select_invalid(&otadata[0]) &&
|
||||
bootloader_common_ota_select_invalid(&otadata[1])) ||
|
||||
bs->app_count == 0) {
|
||||
@@ -339,7 +341,7 @@ int bootloader_utility_get_selected_boot_partition(const bootloader_state_t *bs)
|
||||
#else
|
||||
ESP_LOGI(TAG, "Enabled a check secure version of app for anti rollback");
|
||||
ESP_LOGI(TAG, "Secure version (from eFuse) = %d", esp_efuse_read_secure_version());
|
||||
// When CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK is enabled factory partition should not be in partition table, only two ota_app are there.
|
||||
// When CONFIG_APP_ANTI_ROLLBACK is enabled factory partition should not be in partition table, only two ota_app are there.
|
||||
if ((otadata[0].ota_seq == UINT32_MAX || otadata[0].crc != bootloader_common_ota_select_crc(&otadata[0])) &&
|
||||
(otadata[1].ota_seq == UINT32_MAX || otadata[1].crc != bootloader_common_ota_select_crc(&otadata[1]))) {
|
||||
ESP_LOGI(TAG, "otadata[0..1] in initial state");
|
||||
@@ -354,19 +356,19 @@ int bootloader_utility_get_selected_boot_partition(const bootloader_state_t *bs)
|
||||
uint32_t ota_seq = otadata[active_otadata].ota_seq - 1; // Raw OTA sequence number. May be more than # of OTA slots
|
||||
boot_index = ota_seq % bs->app_count; // Actual OTA partition selection
|
||||
ESP_LOGD(TAG, "Mapping seq %d -> OTA slot %d", ota_seq, boot_index);
|
||||
#ifdef CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
|
||||
#ifdef CONFIG_APP_ROLLBACK_ENABLE
|
||||
if (otadata[active_otadata].ota_state == ESP_OTA_IMG_NEW) {
|
||||
ESP_LOGD(TAG, "otadata[%d] is selected as new and marked PENDING_VERIFY state", active_otadata);
|
||||
otadata[active_otadata].ota_state = ESP_OTA_IMG_PENDING_VERIFY;
|
||||
write_otadata(&otadata[active_otadata], bs->ota_info.offset + FLASH_SECTOR_SIZE * active_otadata, write_encrypted);
|
||||
}
|
||||
#endif // CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
|
||||
#endif // CONFIG_APP_ROLLBACK_ENABLE
|
||||
|
||||
#ifdef CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
|
||||
#ifdef CONFIG_APP_ANTI_ROLLBACK
|
||||
if(otadata[active_otadata].ota_state == ESP_OTA_IMG_VALID) {
|
||||
update_anti_rollback(&bs->ota[boot_index]);
|
||||
}
|
||||
#endif // CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
|
||||
#endif // CONFIG_APP_ANTI_ROLLBACK
|
||||
|
||||
} else if (bs->factory.offset != 0) {
|
||||
ESP_LOGE(TAG, "ota data partition invalid, falling back to factory");
|
||||
@@ -412,7 +414,7 @@ static void set_actual_ota_seq(const bootloader_state_t *bs, int index)
|
||||
bool write_encrypted = esp_flash_encryption_enabled();
|
||||
write_otadata(&otadata, bs->ota_info.offset + FLASH_SECTOR_SIZE * 0, write_encrypted);
|
||||
ESP_LOGI(TAG, "Set actual ota_seq=%d in otadata[0]", otadata.ota_seq);
|
||||
#ifdef CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK
|
||||
#ifdef CONFIG_APP_ANTI_ROLLBACK
|
||||
update_anti_rollback(&bs->ota[index]);
|
||||
#endif
|
||||
}
|
||||
@@ -519,7 +521,7 @@ static void load_image(const esp_image_metadata_t* image_data)
|
||||
* then Step 6 enables secure boot.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_SECURE_BOOT_ENABLED) || defined(CONFIG_SECURE_FLASH_ENC_ENABLED)
|
||||
#if defined(CONFIG_SECURE_BOOT_ENABLED) || defined(CONFIG_FLASH_ENCRYPTION_ENABLED)
|
||||
esp_err_t err;
|
||||
#endif
|
||||
|
||||
@@ -535,7 +537,7 @@ static void load_image(const esp_image_metadata_t* image_data)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
|
||||
#ifdef CONFIG_FLASH_ENCRYPTION_ENABLED
|
||||
/* Steps 3, 4 & 5 (see above for full description):
|
||||
* 3) Generate flash encryption EFUSE key
|
||||
* 4) Encrypt flash contents
|
||||
@@ -565,7 +567,7 @@ static void load_image(const esp_image_metadata_t* image_data)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
|
||||
#ifdef CONFIG_FLASH_ENCRYPTION_ENABLED
|
||||
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
|
||||
@@ -701,56 +703,3 @@ void bootloader_reset(void)
|
||||
abort(); /* This function should really not be called from application code */
|
||||
#endif
|
||||
}
|
||||
|
||||
esp_err_t bootloader_sha256_hex_to_str(char *out_str, const uint8_t *in_array_hex, size_t len)
|
||||
{
|
||||
if (out_str == NULL || in_array_hex == NULL || len == 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
for (int i = 0; i < len; i++) {
|
||||
for (int shift = 0; shift < 2; shift++) {
|
||||
uint8_t nibble = (in_array_hex[i] >> (shift ? 0 : 4)) & 0x0F;
|
||||
if (nibble < 10) {
|
||||
out_str[i * 2 + shift] = '0' + nibble;
|
||||
} else {
|
||||
out_str[i * 2 + shift] = 'a' + nibble - 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t bootloader_sha256_flash_contents(uint32_t flash_offset, uint32_t len, uint8_t *digest)
|
||||
{
|
||||
|
||||
if (digest == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/* Handling firmware images larger than MMU capacity */
|
||||
uint32_t mmu_free_pages_count = bootloader_mmap_get_free_pages();
|
||||
bootloader_sha256_handle_t sha_handle = NULL;
|
||||
|
||||
sha_handle = bootloader_sha256_start();
|
||||
if (sha_handle == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
uint32_t mmu_page_offset = ((flash_offset & MMAP_ALIGNED_MASK) != 0) ? 1 : 0; /* Skip 1st MMU Page if it is already populated */
|
||||
uint32_t partial_image_len = MIN(len, ((mmu_free_pages_count - mmu_page_offset) * SPI_FLASH_MMU_PAGE_SIZE)); /* Read the image that fits in the free MMU pages */
|
||||
|
||||
const void * image = bootloader_mmap(flash_offset, partial_image_len);
|
||||
if (image == NULL) {
|
||||
bootloader_sha256_finish(sha_handle, NULL);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
bootloader_sha256_data(sha_handle, image, partial_image_len);
|
||||
bootloader_munmap(image);
|
||||
|
||||
flash_offset += partial_image_len;
|
||||
len -= partial_image_len;
|
||||
}
|
||||
bootloader_sha256_finish(sha_handle, digest);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -1,362 +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 <strings.h>
|
||||
|
||||
#include "bootloader_flash.h"
|
||||
#include "esp_image_format.h"
|
||||
#include "esp_flash_encrypt.h"
|
||||
#include "esp_flash_partitions.h"
|
||||
#include "esp_secure_boot.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp32/rom/secure_boot.h"
|
||||
#include "soc/rtc_wdt.h"
|
||||
|
||||
#include "esp32/rom/cache.h"
|
||||
#include "esp32/rom/spi_flash.h" /* TODO: Remove this */
|
||||
|
||||
/* This file implements FLASH ENCRYPTION related APIs to perform
|
||||
* various operations such as programming necessary flash encryption
|
||||
* eFuses, detect whether flash encryption is enabled (by reading eFuse)
|
||||
* and if required encrypt the partitions in flash memory
|
||||
*/
|
||||
|
||||
static const char *TAG = "flash_encrypt";
|
||||
|
||||
/* Static functions for stages of flash encryption */
|
||||
static esp_err_t initialise_flash_encryption(void);
|
||||
static esp_err_t encrypt_flash_contents(uint32_t flash_crypt_cnt, bool flash_crypt_wr_dis) __attribute__((unused));
|
||||
static esp_err_t encrypt_bootloader();
|
||||
static esp_err_t encrypt_and_load_partition_table(esp_partition_info_t *partition_table, int *num_partitions);
|
||||
static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partition);
|
||||
|
||||
esp_err_t esp_flash_encrypt_check_and_update(void)
|
||||
{
|
||||
uint32_t efuse_blk0 = REG_READ(EFUSE_BLK0_RDATA0_REG);
|
||||
ESP_LOGV(TAG, "efuse_blk0 raw value %08x", efuse_blk0);
|
||||
uint32_t flash_crypt_cnt = (efuse_blk0 & EFUSE_RD_FLASH_CRYPT_CNT_M) >> EFUSE_RD_FLASH_CRYPT_CNT_S;
|
||||
bool flash_crypt_wr_dis = efuse_blk0 & EFUSE_WR_DIS_FLASH_CRYPT_CNT;
|
||||
ESP_LOGV(TAG, "efuse FLASH_CRYPT_CNT 0x%x WR_DIS_FLASH_CRYPT_CNT 0x%x", flash_crypt_cnt, flash_crypt_wr_dis);
|
||||
|
||||
if (__builtin_parity(flash_crypt_cnt) == 1) {
|
||||
/* Flash is already encrypted */
|
||||
int left = (7 - __builtin_popcount(flash_crypt_cnt)) / 2;
|
||||
if (flash_crypt_wr_dis) {
|
||||
left = 0; /* can't update FLASH_CRYPT_CNT, no more flashes */
|
||||
}
|
||||
ESP_LOGI(TAG, "flash encryption is enabled (%d plaintext flashes left)", left);
|
||||
return ESP_OK;
|
||||
}
|
||||
else {
|
||||
#ifndef CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED
|
||||
/* Flash is not encrypted, so encrypt it! */
|
||||
return encrypt_flash_contents(flash_crypt_cnt, flash_crypt_wr_dis);
|
||||
#else
|
||||
ESP_LOGE(TAG, "flash encryption is not enabled, and SECURE_FLASH_REQUIRE_ALREADY_ENABLED "
|
||||
"is set, refusing to boot.");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
#endif // CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t initialise_flash_encryption(void)
|
||||
{
|
||||
uint32_t coding_scheme = REG_GET_FIELD(EFUSE_BLK0_RDATA6_REG, EFUSE_CODING_SCHEME);
|
||||
if (coding_scheme != EFUSE_CODING_SCHEME_VAL_NONE && coding_scheme != EFUSE_CODING_SCHEME_VAL_34) {
|
||||
ESP_LOGE(TAG, "Unknown/unsupported CODING_SCHEME value 0x%x", coding_scheme);
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* Before first flash encryption pass, need to initialise key & crypto config */
|
||||
|
||||
/* Generate key */
|
||||
uint32_t dis_reg = REG_READ(EFUSE_BLK0_RDATA0_REG);
|
||||
bool efuse_key_read_protected = dis_reg & EFUSE_RD_DIS_BLK1;
|
||||
bool efuse_key_write_protected = dis_reg & EFUSE_WR_DIS_BLK1;
|
||||
if (efuse_key_read_protected == false
|
||||
&& efuse_key_write_protected == false
|
||||
&& REG_READ(EFUSE_BLK1_RDATA0_REG) == 0
|
||||
&& REG_READ(EFUSE_BLK1_RDATA1_REG) == 0
|
||||
&& REG_READ(EFUSE_BLK1_RDATA2_REG) == 0
|
||||
&& REG_READ(EFUSE_BLK1_RDATA3_REG) == 0
|
||||
&& REG_READ(EFUSE_BLK1_RDATA4_REG) == 0
|
||||
&& REG_READ(EFUSE_BLK1_RDATA5_REG) == 0
|
||||
&& REG_READ(EFUSE_BLK1_RDATA6_REG) == 0
|
||||
&& REG_READ(EFUSE_BLK1_RDATA7_REG) == 0) {
|
||||
ESP_LOGI(TAG, "Generating new flash encryption key...");
|
||||
esp_efuse_write_random_key(EFUSE_BLK1_WDATA0_REG);
|
||||
esp_efuse_burn_new_values();
|
||||
|
||||
ESP_LOGI(TAG, "Read & write protecting new key...");
|
||||
REG_WRITE(EFUSE_BLK0_WDATA0_REG, EFUSE_WR_DIS_BLK1 | EFUSE_RD_DIS_BLK1);
|
||||
esp_efuse_burn_new_values();
|
||||
} else {
|
||||
|
||||
if(!(efuse_key_read_protected && efuse_key_write_protected)) {
|
||||
ESP_LOGE(TAG, "Flash encryption key has to be either unset or both read and write protected");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
ESP_LOGW(TAG, "Using pre-loaded flash encryption key in EFUSE block 1");
|
||||
}
|
||||
/* CRYPT_CONFIG determines which bits of the AES block key are XORed
|
||||
with bits from the flash address, to provide the key tweak.
|
||||
|
||||
CRYPT_CONFIG == 0 is effectively AES ECB mode (NOT SUPPORTED)
|
||||
|
||||
For now this is hardcoded to XOR all 256 bits of the key.
|
||||
|
||||
If you need to override it, you can pre-burn this efuse to the
|
||||
desired value and then write-protect it, in which case this
|
||||
operation does nothing. Please note this is not recommended!
|
||||
*/
|
||||
ESP_LOGI(TAG, "Setting CRYPT_CONFIG efuse to 0xF");
|
||||
REG_WRITE(EFUSE_BLK0_WDATA5_REG, EFUSE_FLASH_CRYPT_CONFIG_M);
|
||||
esp_efuse_burn_new_values();
|
||||
|
||||
uint32_t new_wdata6 = 0;
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC
|
||||
ESP_LOGI(TAG, "Disable UART bootloader encryption...");
|
||||
new_wdata6 |= EFUSE_DISABLE_DL_ENCRYPT;
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader encryption");
|
||||
#endif
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC
|
||||
ESP_LOGI(TAG, "Disable UART bootloader decryption...");
|
||||
new_wdata6 |= EFUSE_DISABLE_DL_DECRYPT;
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader decryption - SECURITY COMPROMISED");
|
||||
#endif
|
||||
#ifndef CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE
|
||||
ESP_LOGI(TAG, "Disable UART bootloader MMU cache...");
|
||||
new_wdata6 |= EFUSE_DISABLE_DL_CACHE;
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling UART bootloader MMU cache - SECURITY COMPROMISED");
|
||||
#endif
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_JTAG
|
||||
ESP_LOGI(TAG, "Disable JTAG...");
|
||||
new_wdata6 |= EFUSE_RD_DISABLE_JTAG;
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling JTAG - SECURITY COMPROMISED");
|
||||
#endif
|
||||
#ifndef CONFIG_SECURE_BOOT_ALLOW_ROM_BASIC
|
||||
ESP_LOGI(TAG, "Disable ROM BASIC interpreter fallback...");
|
||||
new_wdata6 |= EFUSE_RD_CONSOLE_DEBUG_DISABLE;
|
||||
#else
|
||||
ESP_LOGW(TAG, "Not disabling ROM BASIC fallback - SECURITY COMPROMISED");
|
||||
#endif
|
||||
|
||||
if (new_wdata6 != 0) {
|
||||
REG_WRITE(EFUSE_BLK0_WDATA6_REG, new_wdata6);
|
||||
esp_efuse_burn_new_values();
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/* Encrypt all flash data that should be encrypted */
|
||||
static esp_err_t encrypt_flash_contents(uint32_t flash_crypt_cnt, bool flash_crypt_wr_dis)
|
||||
{
|
||||
esp_err_t err;
|
||||
esp_partition_info_t partition_table[ESP_PARTITION_TABLE_MAX_ENTRIES];
|
||||
int num_partitions;
|
||||
|
||||
/* If the last flash_crypt_cnt bit is burned or write-disabled, the
|
||||
device can't re-encrypt itself. */
|
||||
if (flash_crypt_wr_dis) {
|
||||
ESP_LOGE(TAG, "Cannot re-encrypt data (FLASH_CRYPT_CNT 0x%02x write disabled %d", flash_crypt_cnt, flash_crypt_wr_dis);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (flash_crypt_cnt == 0) {
|
||||
/* Very first flash of encrypted data: generate keys, etc. */
|
||||
err = initialise_flash_encryption();
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
err = encrypt_bootloader();
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = encrypt_and_load_partition_table(partition_table, &num_partitions);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Now iterate the just-loaded partition table, looking for entries to encrypt
|
||||
*/
|
||||
|
||||
/* Go through each partition and encrypt if necessary */
|
||||
for (int i = 0; i < num_partitions; i++) {
|
||||
err = encrypt_partition(i, &partition_table[i]);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "All flash regions checked for encryption pass");
|
||||
|
||||
uint32_t new_flash_crypt_cnt;
|
||||
#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE
|
||||
/* set flash_crypt_cnt to max to avoid needing to write protect it
|
||||
(which also write protects the download mode disable efuse) */
|
||||
new_flash_crypt_cnt = EFUSE_FLASH_CRYPT_CNT;
|
||||
#else
|
||||
/* Set least significant 0-bit in flash_crypt_cnt */
|
||||
int ffs_inv = __builtin_ffs((~flash_crypt_cnt) & EFUSE_RD_FLASH_CRYPT_CNT);
|
||||
/* ffs_inv shouldn't be zero, as zero implies flash_crypt_cnt == EFUSE_RD_FLASH_CRYPT_CNT (0x7F) */
|
||||
new_flash_crypt_cnt = flash_crypt_cnt + (1 << (ffs_inv - 1));
|
||||
#endif
|
||||
|
||||
ESP_LOGD(TAG, "FLASH_CRYPT_CNT 0x%x -> 0x%x", flash_crypt_cnt, new_flash_crypt_cnt);
|
||||
uint32_t wdata0_reg = ((new_flash_crypt_cnt & EFUSE_FLASH_CRYPT_CNT) << EFUSE_FLASH_CRYPT_CNT_S);
|
||||
|
||||
REG_WRITE(EFUSE_BLK0_WDATA0_REG, wdata0_reg);
|
||||
esp_efuse_burn_new_values();
|
||||
|
||||
ESP_LOGI(TAG, "Flash encryption completed");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t encrypt_bootloader()
|
||||
{
|
||||
esp_err_t err;
|
||||
uint32_t image_length;
|
||||
/* Check for plaintext bootloader (verification will fail if it's already encrypted) */
|
||||
if (esp_image_verify_bootloader(&image_length) == ESP_OK) {
|
||||
ESP_LOGD(TAG, "bootloader is plaintext. Encrypting...");
|
||||
err = esp_flash_encrypt_region(ESP_BOOTLOADER_OFFSET, image_length);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to encrypt bootloader in place: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_ENABLED
|
||||
/* If secure boot is enabled and bootloader was plaintext, also
|
||||
* need to encrypt secure boot IV+digest.
|
||||
*/
|
||||
ESP_LOGD(TAG, "Encrypting secure bootloader IV & digest...");
|
||||
err = esp_flash_encrypt_region(FLASH_OFFS_SECURE_BOOT_IV_DIGEST,
|
||||
FLASH_SECTOR_SIZE);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to encrypt bootloader IV & digest in place: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
ESP_LOGW(TAG, "no valid bootloader was found");
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t encrypt_and_load_partition_table(esp_partition_info_t *partition_table, int *num_partitions)
|
||||
{
|
||||
esp_err_t err;
|
||||
/* Check for plaintext partition table */
|
||||
err = bootloader_flash_read(ESP_PARTITION_TABLE_OFFSET, partition_table, ESP_PARTITION_TABLE_MAX_LEN, false);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to read partition table data");
|
||||
return err;
|
||||
}
|
||||
if (esp_partition_table_verify(partition_table, false, num_partitions) == ESP_OK) {
|
||||
ESP_LOGD(TAG, "partition table is plaintext. Encrypting...");
|
||||
esp_err_t err = esp_flash_encrypt_region(ESP_PARTITION_TABLE_OFFSET,
|
||||
FLASH_SECTOR_SIZE);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to encrypt partition table in place. %x", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ESP_LOGE(TAG, "Failed to read partition table data - not plaintext?");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
/* Valid partition table loded */
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partition)
|
||||
{
|
||||
esp_err_t err;
|
||||
bool should_encrypt = (partition->flags & PART_FLAG_ENCRYPTED);
|
||||
|
||||
if (partition->type == PART_TYPE_APP) {
|
||||
/* check if the partition holds a valid unencrypted app */
|
||||
esp_image_metadata_t data_ignored;
|
||||
err = esp_image_verify(ESP_IMAGE_VERIFY,
|
||||
&partition->pos,
|
||||
&data_ignored);
|
||||
should_encrypt = (err == ESP_OK);
|
||||
} else if ((partition->type == PART_TYPE_DATA && partition->subtype == PART_SUBTYPE_DATA_OTA)
|
||||
|| (partition->type == PART_TYPE_DATA && partition->subtype == PART_SUBTYPE_DATA_NVS_KEYS)) {
|
||||
/* check if we have ota data partition and the partition should be encrypted unconditionally */
|
||||
should_encrypt = true;
|
||||
}
|
||||
|
||||
if (!should_encrypt) {
|
||||
return ESP_OK;
|
||||
}
|
||||
else {
|
||||
/* should_encrypt */
|
||||
ESP_LOGI(TAG, "Encrypting partition %d at offset 0x%x...", index, partition->pos.offset);
|
||||
|
||||
err = esp_flash_encrypt_region(partition->pos.offset, partition->pos.size);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to encrypt partition %d", index);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
esp_err_t esp_flash_encrypt_region(uint32_t src_addr, size_t data_length)
|
||||
{
|
||||
esp_err_t err;
|
||||
uint32_t buf[FLASH_SECTOR_SIZE / sizeof(uint32_t)];
|
||||
|
||||
if (src_addr % FLASH_SECTOR_SIZE != 0) {
|
||||
ESP_LOGE(TAG, "esp_flash_encrypt_region bad src_addr 0x%x",src_addr);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < data_length; i += FLASH_SECTOR_SIZE) {
|
||||
rtc_wdt_feed();
|
||||
uint32_t sec_start = i + src_addr;
|
||||
err = bootloader_flash_read(sec_start, buf, FLASH_SECTOR_SIZE, false);
|
||||
if (err != ESP_OK) {
|
||||
goto flash_failed;
|
||||
}
|
||||
err = bootloader_flash_erase_sector(sec_start / FLASH_SECTOR_SIZE);
|
||||
if (err != ESP_OK) {
|
||||
goto flash_failed;
|
||||
}
|
||||
err = bootloader_flash_write(sec_start, buf, FLASH_SECTOR_SIZE, true);
|
||||
if (err != ESP_OK) {
|
||||
goto flash_failed;
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
|
||||
flash_failed:
|
||||
ESP_LOGE(TAG, "flash operation failed: 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user