diff --git a/.bumpversion.cfg b/.bumpversion.cfg
index 1958733e..b67ccfcd 100644
--- a/.bumpversion.cfg
+++ b/.bumpversion.cfg
@@ -1,5 +1,5 @@
[bumpversion]
-current_version = 1.10.1
+current_version = 1.11.0
parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\.(?P.*))?
serialize =
{major}.{minor}.{patch}.{suffix}
diff --git a/.pylintrc b/.pylintrc
index cbdec543..4f4158bb 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -326,8 +326,8 @@ min-public-methods=1
[EXCEPTIONS]
# Exceptions that will emit a warning when caught.
-overgeneral-exceptions=BaseException,
- Exception
+overgeneral-exceptions=builtins.BaseException,
+ builtins.Exception
[FORMAT]
diff --git a/MANIFEST.in b/MANIFEST.in
index 64db16cb..a87d0afa 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -2,5 +2,6 @@ include LICENSE
include SW_Content_Register_SPSDK.txt
include requirements*
include spsdk/py.typed
+include SW_Content_Register_SPSDK.txt
recursive-include spsdk/data *
recursive-include spsdk *.pyi
diff --git a/SW_Content_Register_SPSDK.txt b/SW_Content_Register_SPSDK.txt
index bb13063d..c9f8d5da 100644
--- a/SW_Content_Register_SPSDK.txt
+++ b/SW_Content_Register_SPSDK.txt
@@ -1,7 +1,7 @@
NXP Software Content Register
Package: NXP SPSDK
-Version: 1.10.1
+Version: 1.11.0
Outgoing License: BSD-3-Clause
License Files: LICENSE
Type of content: Source code
diff --git a/codecheck.py b/codecheck.py
index a33c91b3..51f2eed6 100644
--- a/codecheck.py
+++ b/codecheck.py
@@ -31,9 +31,7 @@
"PYTEST",
"GITCOV",
"PYLINT",
- # "PYLINT_TOOLS", # This is covered by PYLINT
"PYLINT_DOCS",
- "PYLINT_ALL",
"MYPY",
"MYPY_TOOLS",
"DEPENDENCIES",
@@ -175,7 +173,7 @@ def check_mypy(args: List[str], output_log: str) -> TaskResult:
return TaskResult(error_count=res, output_log=output_log)
-def check_pylint(args: str, output_log: str) -> TaskResult:
+def check_pylint_all(args: str, output_log: str) -> TaskResult:
"""Call pylint with given configuration and output log."""
cmd = f"pylint {args} -j {CPU_CNT//2 or 1}"
with open(output_log, "w", encoding="utf-8") as f:
@@ -187,32 +185,47 @@ def check_pylint(args: str, output_log: str) -> TaskResult:
return TaskResult(error_count=len(err_cnt), output_log=output_log)
-def check_pylint_errors(input_log: str, output_log: str) -> TaskResult:
+def check_pylint(
+ args: str,
+ output_log: str,
+ disable: Optional[List[str]] = None,
+ enable: Optional[List[str]] = None,
+) -> TaskResult:
"""Check Pylint log for errors."""
- with open(input_log, "r", encoding="utf-8") as f:
- errors = re.findall(r".*: [EF]\d{4}:.*", f.read())
+ cmd = f"pylint {args} -j {CPU_CNT//2 or 1}"
+ if disable:
+ cmd += f" --disable {','.join(disable)}"
+ if enable:
+ cmd += f" --enable {','.join(enable)}"
with open(output_log, "w", encoding="utf-8") as f:
- f.write("\n".join(errors))
+ subprocess.call(cmd.split(), stdout=f, stderr=f)
- return TaskResult(error_count=len(errors), output_log=output_log)
+ with open(output_log, "r", encoding="utf-8") as f:
+ err_cnt = re.findall(r": [IRCWEF]\d{4}:", f.read())
+
+ return TaskResult(error_count=len(err_cnt), output_log=output_log)
-def check_radon(output_log: str) -> TaskResult:
+def check_radon(
+ paths: List[str],
+ output_log: str,
+ min_rank: Optional[str] = None,
+ max_rank: Optional[str] = None,
+) -> TaskResult:
"""Check the project against radon rules."""
+ cmd = "radon cc --show-complexity"
+ if min_rank:
+ cmd += f" --min {min_rank}"
+ if max_rank:
+ cmd += f" --max {max_rank}"
+ cmd += f" {' '.join(paths)}"
with open(output_log, "w", encoding="utf-8") as f:
- res = subprocess.call("radon cc --show-complexity spsdk".split(), stdout=f, stderr=f)
-
- return TaskResult(error_count=res, output_log=output_log)
-
+ subprocess.call(cmd.split(), stdout=f, stderr=f)
-def check_radon_errors(input_log: str, radon_type: str, output_log: str) -> TaskResult:
- """Check radon log for records with given radon_type."""
- with open(input_log, "r", encoding="utf-8") as f:
- errors = re.findall(rf".* - {radon_type} .*", f.read())
- with open(output_log, "w", encoding="utf-8") as f:
- f.write("\n".join(errors))
+ with open(output_log, "r", encoding="utf-8") as f:
+ err_cnt = re.findall(r"[ABCDEF] \(\d{1,3}\)", f.read())
- return TaskResult(error_count=len(errors), output_log=output_log)
+ return TaskResult(error_count=len(err_cnt), output_log=output_log)
def check_black(output: str = OUTPUT_FOLDER) -> TaskResult:
@@ -387,7 +400,7 @@ def main(
logging.basicConfig(level=logging.INFO)
output_dir = str(output) if output else OUTPUT_FOLDER
ret = 1
- # the baseline PYLINT_ALL, RADON_ALL, and RADON_C checkers are always just informative
+ # the baseline RADON_ALL, and RADON_C checkers are always just informative
info_check = [x.upper() for x in list(info_check)]
try:
available_checks = TaskList(
@@ -403,31 +416,27 @@ def main(
info_only="GITCOV" in info_check,
),
TaskInfo(
- "PYLINT_ALL",
+ "PYLINT",
check_pylint,
args="spsdk examples tools codecheck.py",
- output_log=os.path.join(output_dir, "pylint_all.txt"),
- info_only=True,
- ),
- TaskInfo(
- "PYLINT",
- check_pylint_errors,
- input_log=os.path.join(output_dir, "pylint_all.txt"),
output_log=os.path.join(output_dir, "pylint.txt"),
- dependencies=["PYLINT_ALL"],
- inherit_failure=False,
+ disable=[
+ "R",
+ "C",
+ "W0511",
+ "W0212",
+ "W0237",
+ "W0718",
+ "W0613",
+ "W0223",
+ "W1401",
+ ],
+ enable=[],
info_only="PYLINT" in info_check,
),
- # This is already covered by PYLINT
- # TaskInfo(
- # "PYLINT_TOOLS",
- # check_pylint,
- # args="tools codecheck.py -E",
- # output_log=os.path.join(output, "pylint_tools.txt"),
- # ),
TaskInfo(
"PYLINT_DOCS",
- check_pylint,
+ check_pylint_all,
args="spsdk --rcfile pylint-doc-rules.ini",
output_log=os.path.join(output_dir, "pylint_docs.txt"),
info_only="PYLINT_DOCS" in info_check,
@@ -458,28 +467,20 @@ def main(
output=output_dir,
info_only="PYDOCSTYLE" in info_check,
),
- TaskInfo(
- "RADON_ALL",
- check_radon,
- output_log=os.path.join(output_dir, "radon_all.txt"),
- info_only=True,
- ),
TaskInfo(
"RADON_C",
- check_radon_errors,
- radon_type="C",
- input_log=os.path.join(output_dir, "radon_all.txt"),
+ check_radon,
+ paths=["spsdk"],
+ min_rank="C",
output_log=os.path.join(output_dir, "radon_c.txt"),
- dependencies=["RADON_ALL"],
info_only=True,
),
TaskInfo(
"RADON_D",
- check_radon_errors,
- radon_type="D",
- input_log=os.path.join(output_dir, "radon_all.txt"),
+ check_radon,
+ paths=["spsdk"],
+ min_rank="D",
output_log=os.path.join(output_dir, "radon_d.txt"),
- dependencies=["RADON_ALL"],
info_only="RADON_D" in info_check,
),
TaskInfo(
diff --git a/devices.txt b/devices.txt
index cd378dea..fae9ad18 100644
--- a/devices.txt
+++ b/devices.txt
@@ -1,11 +1,12 @@
List of devices and chip versions tested
- MIMXRT1160-EVK A1
-- MIMXRT1064-EVK REV A
+- MIMXRT1160-EVK A0
+- MIMXRT1064-EVK REV A0
- MIMXRT1060-EVK REV A / A2
- MIMXRT1050-EVKB REV A
- MIMXRT1020-EVK REV A / A3
-- MIMXRT1010-EVK A
+- MIMXRT1010-EVK A0
- MIMXRT685-EVK B1
- MIMXRT595-EVK B2X2 / sch. D / chip rev. C
- LPC55S69-EVK A1
@@ -15,4 +16,7 @@ List of devices and chip versions tested
- K32W1480-EVK A1
- KW45B41Z-EVK A1
- MIMXRT106X-EVK A1
-- MIMXRT1024-EVK
+- MIMXRT1180-EVK A0
+- RD-RW61X B0
+- MIMXRT1040-EVK A0
+- MCXN9XX-EVK B0
diff --git a/docs/_static/images/elftosb/address_or_range.png b/docs/_static/images/elftosb/address_or_range.png
deleted file mode 100644
index e35ce797..00000000
Binary files a/docs/_static/images/elftosb/address_or_range.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/basic_stmt.png b/docs/_static/images/elftosb/basic_stmt.png
deleted file mode 100644
index bbb6e393..00000000
Binary files a/docs/_static/images/elftosb/basic_stmt.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/bool_expr.png b/docs/_static/images/elftosb/bool_expr.png
deleted file mode 100644
index 00cd97e9..00000000
Binary files a/docs/_static/images/elftosb/bool_expr.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/call_arg.png b/docs/_static/images/elftosb/call_arg.png
deleted file mode 100644
index 4dc6e6c6..00000000
Binary files a/docs/_static/images/elftosb/call_arg.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/call_stmt.png b/docs/_static/images/elftosb/call_stmt.png
deleted file mode 100644
index 679d461c..00000000
Binary files a/docs/_static/images/elftosb/call_stmt.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/call_target.png b/docs/_static/images/elftosb/call_target.png
deleted file mode 100644
index bba3e5d7..00000000
Binary files a/docs/_static/images/elftosb/call_target.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/call_type.png b/docs/_static/images/elftosb/call_type.png
deleted file mode 100644
index 06f0bf66..00000000
Binary files a/docs/_static/images/elftosb/call_type.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/command_file.png b/docs/_static/images/elftosb/command_file.png
deleted file mode 100644
index 135d97e1..00000000
Binary files a/docs/_static/images/elftosb/command_file.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/const_expr.png b/docs/_static/images/elftosb/const_expr.png
deleted file mode 100644
index 1abf9690..00000000
Binary files a/docs/_static/images/elftosb/const_expr.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/constant_def.png b/docs/_static/images/elftosb/constant_def.png
deleted file mode 100644
index c433f975..00000000
Binary files a/docs/_static/images/elftosb/constant_def.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/constants_block.png b/docs/_static/images/elftosb/constants_block.png
deleted file mode 100644
index 05dae926..00000000
Binary files a/docs/_static/images/elftosb/constants_block.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/else_stmt.png b/docs/_static/images/elftosb/else_stmt.png
deleted file mode 100644
index 1e72091c..00000000
Binary files a/docs/_static/images/elftosb/else_stmt.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/enable_stmt.png b/docs/_static/images/elftosb/enable_stmt.png
deleted file mode 100644
index 6e7462db..00000000
Binary files a/docs/_static/images/elftosb/enable_stmt.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/encrypt_stmt.png b/docs/_static/images/elftosb/encrypt_stmt.png
deleted file mode 100644
index e76fc8fe..00000000
Binary files a/docs/_static/images/elftosb/encrypt_stmt.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/erase_stmt.png b/docs/_static/images/elftosb/erase_stmt.png
deleted file mode 100644
index e78b6481..00000000
Binary files a/docs/_static/images/elftosb/erase_stmt.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/expr.png b/docs/_static/images/elftosb/expr.png
deleted file mode 100644
index d9718f0d..00000000
Binary files a/docs/_static/images/elftosb/expr.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/from_stmt.png b/docs/_static/images/elftosb/from_stmt.png
deleted file mode 100644
index 4f033e33..00000000
Binary files a/docs/_static/images/elftosb/from_stmt.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/if_stmt.png b/docs/_static/images/elftosb/if_stmt.png
deleted file mode 100644
index efce5b4e..00000000
Binary files a/docs/_static/images/elftosb/if_stmt.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/in_from_stmt.png b/docs/_static/images/elftosb/in_from_stmt.png
deleted file mode 100644
index edbf9ef5..00000000
Binary files a/docs/_static/images/elftosb/in_from_stmt.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/int_const_expr.png b/docs/_static/images/elftosb/int_const_expr.png
deleted file mode 100644
index ed439c2b..00000000
Binary files a/docs/_static/images/elftosb/int_const_expr.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/jump_sp_stmt.png b/docs/_static/images/elftosb/jump_sp_stmt.png
deleted file mode 100644
index 0de32cf8..00000000
Binary files a/docs/_static/images/elftosb/jump_sp_stmt.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/keyblob_block.png b/docs/_static/images/elftosb/keyblob_block.png
deleted file mode 100644
index 08fd625f..00000000
Binary files a/docs/_static/images/elftosb/keyblob_block.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/keyblob_contents.png b/docs/_static/images/elftosb/keyblob_contents.png
deleted file mode 100644
index 588b0fef..00000000
Binary files a/docs/_static/images/elftosb/keyblob_contents.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/load_data.png b/docs/_static/images/elftosb/load_data.png
deleted file mode 100644
index 68d1fe07..00000000
Binary files a/docs/_static/images/elftosb/load_data.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/load_ifr_stmt.png b/docs/_static/images/elftosb/load_ifr_stmt.png
deleted file mode 100644
index 715876d7..00000000
Binary files a/docs/_static/images/elftosb/load_ifr_stmt.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/load_stmt.png b/docs/_static/images/elftosb/load_stmt.png
deleted file mode 100644
index 4d39c353..00000000
Binary files a/docs/_static/images/elftosb/load_stmt.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/load_target.png b/docs/_static/images/elftosb/load_target.png
deleted file mode 100644
index 920ad208..00000000
Binary files a/docs/_static/images/elftosb/load_target.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/message_stmt.png b/docs/_static/images/elftosb/message_stmt.png
deleted file mode 100644
index 360e0eef..00000000
Binary files a/docs/_static/images/elftosb/message_stmt.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/message_type.png b/docs/_static/images/elftosb/message_type.png
deleted file mode 100644
index d626c778..00000000
Binary files a/docs/_static/images/elftosb/message_type.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/mode_stmt.png b/docs/_static/images/elftosb/mode_stmt.png
deleted file mode 100644
index 38f4665f..00000000
Binary files a/docs/_static/images/elftosb/mode_stmt.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/option_def.png b/docs/_static/images/elftosb/option_def.png
deleted file mode 100644
index 829d7f4a..00000000
Binary files a/docs/_static/images/elftosb/option_def.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/option_list.png b/docs/_static/images/elftosb/option_list.png
deleted file mode 100644
index c6ce7306..00000000
Binary files a/docs/_static/images/elftosb/option_list.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/options_block.png b/docs/_static/images/elftosb/options_block.png
deleted file mode 100644
index 64320caf..00000000
Binary files a/docs/_static/images/elftosb/options_block.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/pre_section_block.png b/docs/_static/images/elftosb/pre_section_block.png
deleted file mode 100644
index 5f96e854..00000000
Binary files a/docs/_static/images/elftosb/pre_section_block.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/reset_stmt.png b/docs/_static/images/elftosb/reset_stmt.png
deleted file mode 100644
index c5f1345c..00000000
Binary files a/docs/_static/images/elftosb/reset_stmt.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/rr-1.63.png b/docs/_static/images/elftosb/rr-1.63.png
deleted file mode 100644
index d7fc4c9c..00000000
Binary files a/docs/_static/images/elftosb/rr-1.63.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/section_block.png b/docs/_static/images/elftosb/section_block.png
deleted file mode 100644
index b35ffff5..00000000
Binary files a/docs/_static/images/elftosb/section_block.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/section_contents.png b/docs/_static/images/elftosb/section_contents.png
deleted file mode 100644
index abe8fd23..00000000
Binary files a/docs/_static/images/elftosb/section_contents.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/section_list.png b/docs/_static/images/elftosb/section_list.png
deleted file mode 100644
index d7156561..00000000
Binary files a/docs/_static/images/elftosb/section_list.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/section_options.png b/docs/_static/images/elftosb/section_options.png
deleted file mode 100644
index feddb11d..00000000
Binary files a/docs/_static/images/elftosb/section_options.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/section_ref.png b/docs/_static/images/elftosb/section_ref.png
deleted file mode 100644
index e2ba83d7..00000000
Binary files a/docs/_static/images/elftosb/section_ref.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/source_def.png b/docs/_static/images/elftosb/source_def.png
deleted file mode 100644
index e998a906..00000000
Binary files a/docs/_static/images/elftosb/source_def.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/source_value.png b/docs/_static/images/elftosb/source_value.png
deleted file mode 100644
index 28a3e04a..00000000
Binary files a/docs/_static/images/elftosb/source_value.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/sources_block.png b/docs/_static/images/elftosb/sources_block.png
deleted file mode 100644
index 0ac3bd31..00000000
Binary files a/docs/_static/images/elftosb/sources_block.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/statement.png b/docs/_static/images/elftosb/statement.png
deleted file mode 100644
index cb2791f5..00000000
Binary files a/docs/_static/images/elftosb/statement.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/symbol_ref.png b/docs/_static/images/elftosb/symbol_ref.png
deleted file mode 100644
index 29ac1494..00000000
Binary files a/docs/_static/images/elftosb/symbol_ref.png and /dev/null differ
diff --git a/docs/_static/images/elftosb/unary_expr.png b/docs/_static/images/elftosb/unary_expr.png
deleted file mode 100644
index ca3a9560..00000000
Binary files a/docs/_static/images/elftosb/unary_expr.png and /dev/null differ
diff --git a/docs/_static/images/spsdk-architecture-apis.png b/docs/_static/images/spsdk-architecture-apis.png
index b6b12377..4af46ca6 100644
Binary files a/docs/_static/images/spsdk-architecture-apis.png and b/docs/_static/images/spsdk-architecture-apis.png differ
diff --git a/docs/_static/images/spsdk-architecture-apps.png b/docs/_static/images/spsdk-architecture-apps.png
index 7240f8af..fc85697f 100644
Binary files a/docs/_static/images/spsdk-architecture-apps.png and b/docs/_static/images/spsdk-architecture-apps.png differ
diff --git a/docs/_static/images/spsdk-architecture.png b/docs/_static/images/spsdk-architecture.png
index 2707a0d5..67c0cd8b 100644
Binary files a/docs/_static/images/spsdk-architecture.png and b/docs/_static/images/spsdk-architecture.png differ
diff --git a/docs/api/dk6.rst b/docs/api/dk6.rst
new file mode 100644
index 00000000..c14d23b1
--- /dev/null
+++ b/docs/api/dk6.rst
@@ -0,0 +1,39 @@
+DK6 API
+====================================
+
+This module contains support for programming DK6 devices.
+
+Module with the DK6 commands
+----------------------------------------------------------
+.. automodule:: spsdk.dk6.commands
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Module representing DK6 device and memories
+-----------------------------------------------------------
+.. automodule:: spsdk.dk6.dk6device
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Module representing drivers for communication
+----------------------------------------------------------
+.. automodule:: spsdk.dk6.driver
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Module representing communication interface
+----------------------------------------------------------
+.. automodule:: spsdk.dk6.interface
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Module representing communication protocol
+----------------------------------------------------------
+.. automodule:: spsdk.dk6.protocol
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/api/tp.rst b/docs/api/tp.rst
new file mode 100644
index 00000000..e991f047
--- /dev/null
+++ b/docs/api/tp.rst
@@ -0,0 +1,69 @@
+Trust Provisioning API
+========================
+
+Provides support for trust provisioning containers and OEM trust provisioning.
+
+TP Data Containers
+-----------------------------------
+
+.. automodule:: spsdk.tp.data_container
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Data Container
+-----------------------------------
+
+.. automodule:: spsdk.tp.data_container.data_container
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Audit log
+-----------------------------------
+
+.. automodule:: spsdk.tp.data_container.audit_log
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Data Container Authentication
+-----------------------------------
+
+.. automodule:: spsdk.tp.data_container.data_container_auth
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+TP Adapters
+-----------------------------------
+
+.. automodule:: spsdk.tp.adapters
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+TP Config
+-----------------------------------
+
+.. automodule:: spsdk.tp.tpconfig
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+TP Host
+-----------------------------------
+
+.. automodule:: spsdk.tp.tphost
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+TP Utils
+-----------------------------------
+
+.. automodule:: spsdk.tp.utils
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/apps/dk6prog.rst b/docs/apps/dk6prog.rst
new file mode 100644
index 00000000..1dfefc20
--- /dev/null
+++ b/docs/apps/dk6prog.rst
@@ -0,0 +1,30 @@
+====================
+User Guide - dk6prog
+====================
+
+.. warning:: *dk6prog* is a prototype application and it is not tested. To be used at the user's own risk.
+
+This user’s guide describes how to use *dk6prog* application.
+DK6 Programmer Tools allows reading and programming flash memory of DK6 target devices (JN51xx, QN9090, K32W0xx).
+It's a Python port of JN51xx Flash Programmer (https://www.nxp.com/docs/en/user-guide/JN-UG-3099.pdf).
+
+Supported devices
+==================
+DK6 Board and all compatible modules https://www.nxp.com/products/wireless/multiprotocol-mcus/advanced-development-kit-for-k32w061-and-jn5189-88:IOTZTB-DK006
+
+Backends
+=========
+*dk6prog* tools support four backends (drivers). PYFTDI backend, pure Python implementation of libFTDI. PYLIBFTDI backend, ctypes wrapper for libFTDI. FTD2XX backend, ctypes wrapper for D2XX. PYSERIAL backend for simple UART communication.
+
+
+Jupyter example
+================
+Visit Jupyter example :ref:`DK6 Programming tool` for more information and examples of usage.
+
+----------------------
+Command line interface
+----------------------
+
+.. click:: spsdk.apps.dk6prog:main
+ :prog: dk6prog
+ :nested: full
diff --git a/docs/apps/elftosb.rst b/docs/apps/elftosb.rst
index 3cd766b3..079e1429 100644
--- a/docs/apps/elftosb.rst
+++ b/docs/apps/elftosb.rst
@@ -25,3 +25,5 @@ Command line interface
.. click:: spsdk.apps.elftosb:main
:prog: elftosb
:nested: full
+
+
diff --git a/docs/examples/dat.rst b/docs/examples/dat.rst
deleted file mode 100644
index f22832db..00000000
--- a/docs/examples/dat.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-Debug Credential with remote signing example
-============================================
-
-This example demonstrates how to use custom remote signing service to sign Debug Credential file.
-The steps how to run example are located in 'examples/dat/README.md'.
-
diff --git a/docs/examples/dk6.nblink b/docs/examples/dk6.nblink
new file mode 100644
index 00000000..22ff2399
--- /dev/null
+++ b/docs/examples/dk6.nblink
@@ -0,0 +1,3 @@
+{
+ "path": "../../examples/jupyter_examples/dk6/dk6prog_intro.ipynb"
+}
diff --git a/docs/examples/jupyter.rst b/docs/examples/jupyter.rst
index b023d4f9..ce8ba989 100644
--- a/docs/examples/jupyter.rst
+++ b/docs/examples/jupyter.rst
@@ -6,5 +6,5 @@ For those unfamiliar with the jupyter environment we recommend this tutorial fir
.. note::
- You should install additional development requirements using **pip install -r requirements-develop.txt** in order to run jupyter notebooks.
+ You should install additional development requirements using **pip install spsdk[examples]** in order to run jupyter notebooks.
Users using Windows 32bit need to install rust and add MSVC target: **rustup target add i686-pc-windows-msvc**
diff --git a/docs/examples/rt5xx_dat.nblink b/docs/examples/rt5xx_dat.nblink
new file mode 100644
index 00000000..3bf9237e
--- /dev/null
+++ b/docs/examples/rt5xx_dat.nblink
@@ -0,0 +1,3 @@
+{
+ "path": "../../examples/jupyter_examples/rt5xx_signature_provider/rt5xx_dat.ipynb"
+}
diff --git a/docs/examples/rt5xx_mbimg.nblink b/docs/examples/rt5xx_mbimg.nblink
new file mode 100644
index 00000000..2e544bd2
--- /dev/null
+++ b/docs/examples/rt5xx_mbimg.nblink
@@ -0,0 +1,3 @@
+{
+ "path": "../../examples/jupyter_examples/rt5xx_signature_provider/rt5xx_mbimg.ipynb"
+}
diff --git a/docs/examples/sahsm.nblink b/docs/examples/sahsm.nblink
new file mode 100644
index 00000000..23512e69
--- /dev/null
+++ b/docs/examples/sahsm.nblink
@@ -0,0 +1,3 @@
+{
+ "path": "../../examples/jupyter_examples/rt5xx_signature_provider/sahsm.ipynb"
+}
diff --git a/docs/examples/signature_prov.rst b/docs/examples/signature_prov.rst
new file mode 100644
index 00000000..e2573b31
--- /dev/null
+++ b/docs/examples/signature_prov.rst
@@ -0,0 +1,10 @@
+===================
+Signature Provider
+===================
+.. toctree::
+ :maxdepth: 1
+
+ rt5xx_mbimg
+ rt5xx_dat
+ signature_provider
+ sahsm
diff --git a/docs/examples/signature_provider.nblink b/docs/examples/signature_provider.nblink
new file mode 100644
index 00000000..dea54776
--- /dev/null
+++ b/docs/examples/signature_provider.nblink
@@ -0,0 +1,3 @@
+{
+ "path": "../../examples/jupyter_examples/rt5xx_signature_provider/signature_provider.ipynb"
+}
diff --git a/docs/exts/generate_apps_img.py b/docs/exts/generate_apps_img.py
index 14908a58..4b9ecf38 100644
--- a/docs/exts/generate_apps_img.py
+++ b/docs/exts/generate_apps_img.py
@@ -241,6 +241,7 @@ def main():
"SDP(S) Protocol",
"Debuggers",
"Trust Provisioning",
+ "DK6",
]
tools_list = ["MCUXpresso SEC tool", "Mass production tools", "3rd party tools"]
diff --git a/docs/exts/generate_schemas.py b/docs/exts/generate_schemas.py
index b697c19a..a12ea2f0 100644
--- a/docs/exts/generate_schemas.py
+++ b/docs/exts/generate_schemas.py
@@ -6,6 +6,7 @@
# SPDX-License-Identifier: BSD-3-Clause
# Script for the automated generation of schemas documentation for elftosb/nxpimage
import os
+
from typing import Any, Dict, List, Sequence
import yaml
diff --git a/docs/images/mbi.rst b/docs/images/mbi.rst
index bc5391bc..60d517f7 100644
--- a/docs/images/mbi.rst
+++ b/docs/images/mbi.rst
@@ -6,11 +6,11 @@ Master Boot Image (MBI)
Master Boot Image can be used directly (e.g. by using *blhost write-memory* command) or it can be used for further processing (e.g. used as input to Secure Binary image container).
Image is created based on a supplied configuration file, either JSON or YAML is supported.
-We can divide divide into two categories based on layout.
+We can divide into two categories based on layout.
* eXecute-In-Place (XIP) images
* Plain
- * CRC
+ * CRC
* Signed
* Load-to-RAM images
@@ -72,7 +72,7 @@ Sample configuration for LPC55s6x plain signed XIP image. Other sample configura
Supported devices for MBI
==========================
-NXPIMAGE support devices from LPC55xx family (*LPC55S0x, LPC55S1x, LPC55S2x, LPC552x, LPC55S6x*), *RT5xx*, *RT6xx* and *LPC55S3x*.
+NXPIMAGE support devices from LPC55xx family (*LPC55S0x, LPC55S1x, LPC55S2x, LPC552x, LPC55S6x*), *RT5xx*, *RT6xx*, *LPC55S3x*, *MCXN9xx* and *RW61x*.
Supported execution targets are: *Internal flash (XIP), External Flash (XIP) and Load to RAM* and image authentication types: *Plain, CRC, Signed, Encrypted and NXP Signed*.
The following table shows the supported image types for each device,
diff --git a/docs/index.rst b/docs/index.rst
index 20dfb2a4..18423856 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -36,6 +36,7 @@ Secure Provisioning SDK (SPSDK)
:maxdepth: 1
apps/blhost
+ apps/dk6prog
apps/elftosb
apps/ifr
apps/nxpcertgen
@@ -60,12 +61,14 @@ Secure Provisioning SDK (SPSDK)
api/crypto
api/dat
api/debuggers
+ api/dk6
api/image
api/mboot
api/pfr
api/sbfile
api/sdp
api/shadowregs
+ api/tp
api/utils
.. toctree::
@@ -74,7 +77,6 @@ Secure Provisioning SDK (SPSDK)
examples/crypto
examples/general
- examples/dat
.. toctree::
:caption: Jupyter Examples
@@ -84,6 +86,9 @@ Secure Provisioning SDK (SPSDK)
examples/lpc55sxx_secure_boot
examples/lpc55sxx_secure_fw_update
examples/kw45xx_k32w1xx
+ examples/dk6
+ examples/signature_prov
+
Indices and tables
==================
diff --git a/docs/release_notes.rst b/docs/release_notes.rst
index c3760da5..f11c6519 100644
--- a/docs/release_notes.rst
+++ b/docs/release_notes.rst
@@ -8,6 +8,41 @@
Release Notes
=============
+---------------------
+1.11.0 (7-July-2023)
+---------------------
+
+**ANNOUNCEMENT**
+
+Next version of spsdk (2.0) will introduce breaking changes:
+
+* elftosb will be replaced by nxpimage
+* nxpcertgen and nxpkeygen will be replaced by nxpcrypto
+* select appropriate family will be done using: -f/--family parameter
+* move towards options for all parameters with an exception to BLHost
+* removal of crypto backends
+* extend dedicated spsdk.crypto module - serve as the de-facto backend of SPSDK
+* module level imports via init files
+
+**New features**
+
+* :ref:`nxpimage`:
+ - enable signature providers for AHAB image and signed messages
+ - add support for rt104x in bootable-image
+* :ref:`tphost`/:ref:`tpconfig`:
+ - add possibility to check TP_RESPONSE only with NXP_PROD raw binary key
+* add support for mcxn9xx
+* add API for FuseLockedStatus
+* possibility to declare private keys with passphrase in signature provider config
+* add checking of written data length in usb interface
+* add support for dk6 tools
+
+**Bugfixes**
+
+* :ref:`nxpimage`:
+ - fix offset on NAND memory in AHAB image
+* fix plugin error for signature Provider for sb21
+
---------------------
1.10.1 (26-May-2023)
---------------------
@@ -39,7 +74,7 @@ Release Notes
- add new command: ele_message
* :ref:`nxpdebugmbox`:
- add command: read UUID from device
- - update PyOCD to latest version to support CMSIS DAP FW v3
+ - update PyOCD to latest version to support MCU LINK FW v3, implementing CMSIS-DAP v2.1
* :ref:`nxpdevhsm`:
- USER_PCK rename to CUST_MK_SK
* :ref:`nxpimage`:
diff --git a/docs/requirements.txt b/docs/requirements.txt
index c02c5f98..90128fd2 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -9,7 +9,7 @@ myst-parser
sphinx-click>=4.2.0
jsonschema2md
pytablewriter
-Pillow
+Pillow<10.0.0
docutils==0.17
# pyscard package is a requirement for TP
pyscard
diff --git a/docs/spsdk.rst b/docs/spsdk.rst
index 494e98cd..a315bd33 100644
--- a/docs/spsdk.rst
+++ b/docs/spsdk.rst
@@ -99,8 +99,8 @@ CLI/API stability notice
``SPSDK`` is still in alpha (as noted in `PyPI `_) and should be treated as such
-* Major releases are not planed in the foreseeable future
+* Major releases (2.0) is planed in the near future
* **Minor release may break compatibility!!!**
-* Patch release will not break backward compatibility (any occurrence is threated as a bug)
+* Patch release will not break backward compatibility (any occurrence is treated as a bug)
New features might be implemented in both patch and minor releases.
diff --git a/docs/usage/apis.rst b/docs/usage/apis.rst
index 7d006822..67f4372c 100644
--- a/docs/usage/apis.rst
+++ b/docs/usage/apis.rst
@@ -28,7 +28,6 @@ Please check *SPSDK* examples:
- :ref:`General examples`
- :ref:`Crypto examples`
-- :ref:`Debug Credential with remote signing example`
Development guides for various SPSDK modules are bellow:
diff --git a/docs/usage/elf2sb.md b/docs/usage/elf2sb.md
index 49e2d0bd..54ba6358 100644
--- a/docs/usage/elf2sb.md
+++ b/docs/usage/elf2sb.md
@@ -6,241 +6,14 @@ This is a user guide describing how to generate a secure binary rev. 2.1 based o
The syntax is written in EBNF (Extended Backus Naur Form), however, the `elftosb` application uses (namely SLY - python implementation of Lex/Yacc) only BNF. From this perspective the graphs visualize the EBNF form with the grammar and the conversion into BNF as well as remarks what is supported.
-
+**command_file:**
-
-
+![command_file](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAY8AAAA5CAYAAADOfqc7AAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAEfxJREFUeNrtnQdYVEfXx%2F9LUVGaIFYi9o4KRETFBkqMvWHXF1vUIHaNGs1nEv0Syxt7iYXYojG2GGtsUWPE3mIliqCoKDaaoJR95wzuCrhLL8tyfs8Dl2UuM3fu%2FZ8558wMuwDDMAzDZBCFPnTCqSaU%2FCgZTVy4qR8aZztgXeoaRvryMM7%2F5cuKZJLxcdNBBa7PbAesy9zCgB8lo%2B%2FROEfkDOuSnQfDMAzDzoNhGIZh58EwDMOw82AYhmEYdh4MwzAMOw%2BGYRiGnQfDMAzDzoPRF15Hv0Ho83Ct5Y9DXuJtbFyW2njw8Bni4xP4ZjMZgnRJ%2BtTEm7exCHnyMkv1R71OXfvsPJh8wb6DF5IJ2f%2FOI3QfMAdxcTk76B44fAne43%2FUWt6133e48s%2B9TNefkKCEi%2FskPH8ZwQ85nw7gpM2krFp7EAuX787xtn0mrvygbRUXrwRI%2B8gKew6cw9jJa%2Fghs%2FPI38ycuxUBgSHq19bWZujZpQkMDBR8c5g8gzRJ2kyKY73KaNigOt8cPcaooHV4he8BNG5YAzt%2B98OdgBC0aeWAfj1bJEYql%2B%2FisUhzq1UphyPHr6C8rQ3aejjh7r0QrNlwWB4d6laE95C2MDMzSbOtiIhorFx3ELf%2FfQhL82Jo2rgWOnzaQJYF3n%2BKNesP4%2Fadh6hvXxGfD%2F4UlpbFZBlF4KvXHcL9B6GwKWGOrh0b4cnTVwiLiMKW7Sfxt99NuAjDrFnNFiHi9yrnER3zFqtEe2fP%2F4uypa0weEArVK9aTpYdPXEVRoaGuB8cioNHL6NsGStMGt0VVsVN033v9ooIj%2B6bqWkRjBnRARXtSmk8b9e%2BM9i9%2FxwMFAp079wEHm711WX3gp5g3eY%2FERoaJu9vr%2B6u%2BKiczQfTDavWHoJ7c3vUrP4RW2kOcOVaIDZvO4EXLyNhW9YafTyboUqlMurnvGvvGcTGxqFtayd4igBFxZkL%2Fti5%2B7TUdp1adujdrSm27vxbavOHJbvkOYP7t0LMm7fiOcYly5LXrD%2BEh49fwNmpKoZ6ecCkSCFZtujHPfBo6YAtO0%2Filn8w2rg74D993NLdl8jIGMxb%2FBsuiUyD6ib7NDI2%2FOC88PDXWC7s%2F7LIkqtULIPPBnoI7ZVIltkf%2BvOyyOTj4eJcHZ6dm3xQx7Wb93H85DV5%2FYWMjQq0hgpc5rF89QGMmrQK5cpYo1WLepizYCe2iwFROo%2BrAZg%2BaxNGTvgRT8Tg9uJVpIyqenjNRb06FTB%2BZCe8FMY2dPTSdLX1%2BfgVePjoOQb2dUN94XT2H7oof38%2F%2BBm69Z8tBkZbTPDpjKjXMRjkvVjtcDp4zkREZLQ0Wmsrc%2Fy08QiKW5rCyMAQpWwspeDNzYviZVgkFgvDUzF8zHJcux6E4YM%2BQY3q5dBtwGwEPXgqy44cv4ohPktwN%2FAJOrRpIB3n9Jk%2Fp%2Fu%2B0aBx4NAFtG5ZD8ZGhug1aJ7GdQ7fjYcxf%2Bnv6NHFFZ3bu%2BArcT9V95fuZYdes2Bd3AzdOjVCXHw8tu%2FyS%2Fb3VOeQkUuk46whnCOT%2FZAmew%2F%2BL5xEdtBLDP4WQksnTl1PnG4SQcuyVfvQXwRUXn3c5WC7edtfsuyPI5cwbNQyGey0Fxq6efsB%2FM7dFgGOhdQm6ZK%2BDIU%2BTooAhwIWIkgELN36f49qIpAhbV67EYTPRD0qFq%2FYi%2BFjl0knRo7ju%2FnbcUwM0OmFpscMDQzkNe3adxZzFu384ByaGqU%2Bhz4Lw6hh7WRQ1lFokZwnsWTlPnwv2qUxwV187f3jvNRgUq7fuo%2F%2FDF8Ie%2BE0C7rjKJCZB7H0v8NQu0Z5%2BTNFSBRNdxPRPVG5Ymn84jsBhoaJfnXyjPUY0KsFenZ1TUzH61ZCVccRMjugQTA1rt96gBmTm6CRcw35RdGdHGA3HJL1qV471a%2BMWs4j8UhEZQeOXJRZwcxpfWVZC9c6UviUXRQrVgQtmtVBQ6dq6sFYxb93H8Pv7C1c9VuIIoULwbVRLWHcwVi%2F%2BRimT%2BohzxnYzx1TxnWXP5cUTmjyjHXpvmfU5uK5n8mfKSL7uPl4%2BJ25jeautZM75zUH8MOsQTLLSjTaBCxYvkfe35VrD6Ljp87wEcZLuDWrK%2FumIi42HsNGLxP9t8b3M%2FpDoeDpuJyAAofChYzwiRioKQhxa2avHmAXrtiNvb9Og91HJeXvxkZ0xMZfj6N396ZYsGw3pk7wFIFBYkT%2BaWtH%2BTdWVqYiUzmbLENJysZfjons00FmJMTHjlVQr%2FEYmZGrMuM1S3yk7RHnLt6RWQRpPz18Ka6pe%2BfG8udSJS0wYdpaTB3fPdk5p87clGszu7%2FxkrZE9kjtbN91SgR37jII27J2onSMROd2DWXfLly%2BK1%2FTtQ78fDEWfDdYrW12HjqCQ23UM1CiK5SgUbyq%2BLJDLnzeSKUKpbH1t7%2FVr62tzNSOQw7KIt3e98cFdfSVKFBLkSpHp%2Bk8xvt0wvgvf8KchTvh5FAZg%2Fq1khnMbVEnRV87fn8fdVNmQTs7yLDtxTnJ0sN0rGmQI%2FnI1kY6DhU0%2FUYO5X097%2FtF0WasSM8zA90fmrIKefryg%2BkmcoCqAUF1DQH3Ep3cHeHgVEaetG8qBzJmyhq5c4sGkux2HOl4B1MqD6JHLlTnl6DAjkvXcUUf7aBRw%2BqoW7sC6ruORe1a5dFMDIbDB7XBa6E%2Fyqx7es1Ldn7VymXfBSiPxN%2FZZVibNFXp7FhV%2FZo0SlOWASILVmklaT00JZwhbSa5BHJAT0PDkgUlidfwFFUrlUnWTvWqZUUmHoLHQsdke5RRaOrbo5AX6DVwHrz6umW748gvutRJ5yECgGpxCixVJKCOuEubxa1aZJiAGxX8EbQViM%2BmB6CVFyKDKG6p3QlQtD%2FGu4Mc%2BDNKX8%2Fm6NqhEf65HoT9hy8Ko5yLSyfnw0zU6T20rTTYlJiKsmeZ2BpoZmoip7qSEhHxWtaXE1BblhbFkv3O2MhIpvPhot2SNhbqaTi6Ntk3cQwLf621zqYiW6J55xnfbcY3X%2FbJ1utN68N3PIVPDKwGu3gD0OjgJgbwA441cc1ICW%2Fhf%2F31yQ7oGa1bMVquo1FkTVNT9PP%2FTe4lnfbebdM1Bkb0HF9peH4KurVKZao2FJ5Sm5GkC83azErgEBEZI51PSqem%2BRpiYC7ONS1aRFy%2BUq6JFNewBkgOdcLozpg1b5tcL22QxBHquy5TI0%2FXPBxqwT1egdPi7h0Pi0WFizcx7uIt7Dnnj4D0GkxmCH9nADSwrdv0J9p5OGk9t00rR%2FhuOKLeL04iowGOpljSYsfu09JQaRFvxOA2cm0jJvotPNwdsPbno3LuWQUtYtMUmnuLutLR0II6QXvYDx9LDDQsLYqKzOSx5ntZr5I89%2BiJf9TG%2BdveM3BrXjdb7tmbN7Gy7wRlM8GPn6OxGPFSRmotm9lj45Zj6t9t%2BPWYuIbEaRF3cS20SPvqVZR8%2FexFOE6deZ8Z9ezmio2rx8o%2B0LpJbkJ6I92R%2FkiHpEfSJemTdKpPdvCPyHpv%2BT%2BUGTRtCPnEzUHO%2FZNzaOJSE3Pm71Bv%2FyYb%2BfOvRE2RNmkLrkr7NFVK6x7mZkXllBCdqwn3ZnXltJYquKH1jIioaDjWr5wt%2FYmJeauedqP1QVo3SYmr6Net28G4ej1Qvn76LAx%2FCDujKTtyGHQty9bsV59%2F%2Bry%2FPIeoXbO8DATnfuuFgd6LcUP0uSDoUmczD4q04pXYKsajAXRjcrPtcVN9ZaD08lWknNtMbWcHzfXSDqUW7abBytIUYZGv5ZSNR8v6abazbtNRTJv5M6qJtP%2BeSNG%2FmtRTCrV7p8YIehAK945fyTrDhSHZiTS%2BWZNacm1h7IgOaOv5LSyFUb4SUTwtuNNC3qD%2BrTD16w1ygZHmnTu3b6hui3auLJs3DKO%2FWA1b2xIIEml6x3bO6NTWOVvuGaX3zm4TZXbxKjwKS%2BZ%2BpnHH2azp%2FeA1YiFatp%2BGWDHIlLA2h%2B9Sn8RMrEdz3PQPRiOPL1DcvJi8l19P7p3s7yni3ew7Hp16%2F7%2FMbGidJi%2B4cwf0n2czHWvgsoiwtgq9uuREpJcXdkBBxrBR8%2BV6B%2BmGpmxWL%2FaWZYtmD4HPpFWo22S01N9L8ayHeX2Clk3tMX1iD4ycuBL1mo6BhWlRxLyNhe8SH9SzrwCXBtXg0noSjA0NseuXqcnaox2GtL7QpPVk2NmVRHDwM6HV4ShqUjhb%2BrNwxR4sW7Vf9qN8eRusWz76g3MoE5470wv9hsxHpYql8W%2FAIwzp31qufRCL5wyV623bdp2S07vFihbGtvVfJKuDgkwaM%2FoO%2FgG%2FbZ6iXhfSR11mcLYwdxEp9kFxOCHStpnZMW%2BY3o%2FfpIW6Tb7jULaUlYyULVJMvWiDdgFRam8lBjcSVnqhlDdSZBy0uyPpegQR%2BzYOIaGv5HpHyuklVXulbSxhXOi9j4%2BMipERXpnSxTW2R1EhzeGaFTNRb%2F3NLsg4aZpPU19SQmsftDZC0a22emh3TU4uiif9uM%2BsfGa00Nc0cWgm6vDQFzsggh8%2BlzZAGzRSQtkhZQeanhFpmvSZ8tnSWkORwsbSKWkiLCxKTh2l1HR2QFkCaV9TX5JlKSK7D30WLgMT1XRqynpIt2mtZ%2Bq7LnU286BFQSTA3iwaHfPKeRXPwP83qOaJk%2B4Jp73iKf8xKim0JZGyBWpHW1tkQEnrTK09FeRkUlvHoP3t2urUBA0SQ0Zp33pMO2pUu2TIaabXcaZmxBmpRxcQOp0XYQJv0m12LlbmtR3YlrPWWkaBh7bgQ5ueVetc2qBALb3BGrFzz2n8%2FOsJreWzvx6g3qFVsoRFuuqkoCc1%2B0hvPfqsS512HgYJ6Cb87aZjgYjJ7ba%2FndYH5UpbZ7ke2tK3bf0k5HdogNCHfuQkpFOnWtgkdYvsM9K8tIP8QJf2LvKLyV1dplu%2FedFpJdBIfDuaF213bOuc7dM5TAFA6FXqVk%2FsgGFd5kvnoYBcJLzOT57JL5BeSbdsB4y%2B61KnnYfAxiQST%2FjRM%2FmFd3q1YTtgCoAuddp5FPEL5nleJv%2FwTq9F2A6YAqBLnXYetD1NyY%2BeyUcokf1b29kOGF3UpU47D4ZhGCYfw86DYRiGYefBMAzDsPNgGIZhdBC9%2BTCopO8XwzAFFbYDhjOPDEBvLpaVNxhjGLYDhimAzoNhGIbJXfTqM8w56mIYtgOGMw%2BGYRiGnQfDMAzDzoNhGIZh58EwDMMwuu48%2BM3gmPxGTryJIdsBo4u61Gnn8aZFhbx5G2GGyQyNbKVeY9gOmAKgS512Hs%2BjTPPmA0wYJjNEm6KUOISyHTAFQJc67TwC4hLy5qMTGSYzGCpQWwn4sx0wBUCXuus8RGfPKxLgyo%2BeyTco4KYA%2FNgOGH3XZYacR8M6MvXRSlrlGTYaBfYqFOgB8H%2FCMrqPXJdQok%2BCAbazHTD5XZdZHc9Vf29I30pZI7ysDeqUL40TD58iKuXJaZVnlJBQBJUtiZHlbBDyKBQ3WAaMLmNdBpPFweTiDczLznrZDpi80GVmx3PnmuhSuiQOJSRgyuNnmGWUmPnIDMQzPh5dnGpip5EhfM5cw5P3mVHq5ZkgQdQ5TqnET%2FVr4PzlWwhkKTC6iGMNtBeHcYZKuORA9WwHTK7rMqPjOTmNeAUWxSthm3RTsMw8hBea8e41VVpbiHlMGRvYqzxTWuWZ6byItO6UKYlCBkosE8fzj0NxnyXB6ApVqqBwxVKYolBgjhjhPS%2FcxPmcaIftgMltXaZ3PFdlGsJfDBUvzZPWITKPr%2BVcq%2FA%2BSi0eKk4U7CQvlVp5VjIRpxroIypaIBcPldiSYIhzFlEIOBaYN3uXmYKJELhhYDXYxRug1rtFyN5Ck9eMlPA%2Beyvnd7OwHTC5pcu0xnsjBfbHAd%2BAMg0t0Ds3p%2Bo8SMjCNVUXR7NUy5UwEi2b8KNmGIbJn8jABcJJASbimKB8NzOlzXkYafFAp8QfPhTHVgnAanEcm1q5sRFmZ3ENhGEYhskFUiYLScdzcfyxiDF8Y2IxSCQGQ5QKhGnLQIw0VaJMrOSMsSFqklMQjY1NrZwfB8MwTP4ijfF8XMM6mB0bjy%2B0OZGkzmNrGk5hKzsNhmEYvSDN8fzd77Q6EZXziBaVBKfiFNIqZxiGYfIHGRrPUzoRkbEM51vIMAzDZIr%2FAYhM3fV%2BbCVtAAAAAElFTkSuQmCC)
-
-
-
-
-
-
-
-
-
- command_file:
-
-
-
-
-
-
-
-
-
-
-no references
+```
+command_file
+ ::= pre_section_block* section_block*
+```
Comments:
@@ -279,119 +52,30 @@ section (2) {
}
```
-
- pre_section_block:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- options_block:
-
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
+**pre_section_block:**
+
+![pre_section_block](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAN0AAACpCAYAAACvdzjNAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAIABJREFUeNrtnQdYFFfXx%2F%2FLLr2riGIjEVDQqIgIqKiANYrGghFL7IkdW9QvMTHmjSbmTdPYxagYJVETNbF31Nh7AQSDDURUpHcWvnsv7AoIsvgiC%2Bz5PY%2FuMHfmzr0z53%2FPOXdmdwCCICoUSXXohJM9culSVi0uhVQP23sdZNWlIxdP%2FkKWXEVo4z5ao%2FuvRSZAqCs60dQIhURHECQ6giDREQRBoiMIEh1BECQ6giDREQRBoqvapKRm4GlsYonl0Y%2FjkJmV%2FT8d42HUM%2BTk0AM%2F5S46l%2BawfNVGpZVrioH%2F8deZQuv4358v3KK2Nu09cBF%2Bc9aWWN7HdyFuBT947fqzMrPh6jUb8QkppJRy0IFifyG6LDkeOdlja0mVllauCTx7noiP520otM6hSX14dHyHrFFDeF0dtLVHPycHPMyW4y7%2FWzx7KckTn49czgrtsUMmxZRzNxGj2Km08qpEcko61qw%2FgItX76BRg9r4cGQ3vNUo7xzuP3wZxkb6uHbzHk6fC4VD0wbwm%2BANQwNdbNvxD%2BQ5cvywbJfYdlC%2FDshgniApKU1Zd2RULNZuPIjbd6Lg%2BM7bGD%2B6O0xNDUXZ%2Bl%2BPoG0bW%2BzefxFXb9xFexd7TBzbE1paEuTm5mIrqz%2Fo1C1oa0thz8Q8Yogn9PV0VOrT3%2FsuYMfuszAxMcD0id6iX8Xx599nsYd5R6lUi7W%2FPbp0bqksi7j3GAGBx%2FD0WSIaNrCA78COqFvbrND%2B6RmZWLvhELp6tEJTu3oaJ7qy6oCLTS7BUnku6hd84K1QTpebJ0JeaWRxii6tvCowcsJS3L0fg8njesG6YW30HbwIj2PiRNk%2BJrpxfiuQkJiCPu%2B2xenzoZg7f6Moq13LlJ11CRrUqyX%2B6epp4zoT566950V5fHwK%2Bg5ZBHMzI%2FiN743Y50l4f9R3kMtzRPkvTHSjJv4MUyaM3j3aYP3mI0xop5RlG7cchU%2B%2Fdujm2QohtyPxKPq5Sv05ff42Dh27Kvbjj%2B0PZsfkYWFR1m44iGVr9mDwgA7o28sFn3z5K2v7OVEW%2Fm80vAcvhAXrY%2F8%2Bbshk%2B%2B%2F4u3AonZGZhdGTfsajx8%2FRxNZKoz1eaTpQeDY5G%2BfABVcEWSmVCkWXVl5VPN%2FV63dxOzwSv62bCRnzKO1cmgqvE7j9JKZP6iO2mTimJyZ%2F%2BK5YbtHMGj0GLsD3i0ajk3tzSCVaTBjti637D2akTW3rYRrzNBxX5yZo13UOTp0JQacOzcS6H1k97V3txfLdezG4fDWCicAdwaEPmedgoap7Xqjaq3sblfvUrm0TLP12nFge2Lc9WrtPx%2FnL4crjKFixbh9WfP8R3No2zQuVsrKx0n8%2F%2Br7rgjUbDmCAtxsmjcvrt1enFmLyRM7iIcW246b4s0HKEgs%2FG8rGHgmIYnQgwT423H1Z1LOpJDoFbIy%2Bylxhj9xSyrOzcZcdVL%2Byn6QI5uHetq4jBKegiU09%2FHs3%2BkUIUcCeGltbCq8RG5tUat3ce9raWBWoRwLbxlYibFOIjoeSCkyMDfA8LlksjxrmhbGTl6G521S0aWWD93q74D3mjcqKTKYFa%2BvaiM733AUngZ48TYCdbb0C%2Fc5rm8LTDRvUqfAMG2urPH95yuy1bP94bFzlV%2B6Cqw7fNOA6YGelV3YuBrLPUud6ZSXErqfZjlHsswur0J99Tn9VubYMixWezgeQ3rNDI7kWHNiGnmwbX7btTVkuJrFoLexNdFrVC2dkqIek5LRC6%2FjfRkbFjxfP45NF%2FmNqaoBnTHg893pV3c%2BKTN%2BLutn6khIEBc3tG%2BLM4cUICYvEuQth%2BL8Fm1CDhakd2zcre86anC5C3ILo6miLgYbnnzXNjcW6xAL9NjbSQ3xiyTOUnTs0x87d5%2FDlt1sxf8775XrtKsuXWVkAYJctwXLWmObsKgcyizoqzUGwdRjub0Pe%2BFPUzgrqgH2uZhnHL%2BksCmeOaGyuBAnFhZYv5XS8EvaxjVVgz%2F5FsrDR%2FnIIZpRWXjC05A1kdhNxORS7eVlCFqzZfkEsoTzr6AAvdZ5Y1zZ2Ilc6dylP%2B3HM0%2Bw%2BcAGeBWYgE5NS80YvNl4tX7tXGJyBvi5MjfWRxcKtB5HPiq3bs2MLHDxyVXgUzs2QB7gZ%2FADu7RxKbdeBI1eEIByaNBATKI3qWwjBq0J6WpZy%2BeTpYMQwj%2BTC%2BlnUA3Zq1wybfjueFxaxwWPz70EijFS0fcu2E0jIvzXA7%2F2dYSOkAh4Cb143AwcOX8HS1burXZjI7ZLbJ7dTbq%2Fcbrn9cjtWCE4VnZy%2Bjpv8UyqFLTvF29h2SWzjyFd5Ol4JV%2Bw5PoFWTI5WWnmx3LmDDPbxVeumIhTdxkYU1zfl8UqDz%2B4tWTwWH05ZgUaNLERexQ2Kz8YVnOHbvuuMmDjgs5r%2BSyeJ9XwWkk9CdOs3H4YGeljO8qNCI6WTLcaO6AoP73mwfdtKhKyLvxyBOpbmpbaLz5b6zfFH47fqCNE4sRCzV1cnlfoUHvEIzh6zoC2TISEpBcv%2B%2B2Gx3vXr%2BcPFJJKn92fIyMiCpYUZflk%2BRZR94OuB0PAouLIc1NzEEIkpafjykyGF9reoaYLA9TPx3uBFMDc1wvDBnauF4LiHYznYNiaSD7jQVNilVB3kr5vh0hyLs%2BSYU9TzSfLdZiqrZBWrZHFxlZRWXoYwcB776MhCim7lHV6W5eca%2BFMaMU%2FimfcyEEJU4DfXH3YsDxs9vAsSE1NhWWTKnMPv12lJtFDD3KjYunlIyW8mW9QygZ6ujsptSkvPFOGpsaE%2BzMwMy3wbJI55RlWOyT09D5mL6xvP%2FZ7HJaG%2BVc03OllS8Oca1B1eMts5yD5OsHZ8pcK2r6UDPrvJxcc6Op4dx0B4OuYe33pVJaWVq4pxGr5L0sckx2ZoeeUWrqnrROuwJJRP%2B5cEvz9W0j2yWjVMXt1HlicZG5V9Tokfr2CbYpnxf%2BS3ssTte3dvg5FDPZX5ZIm5YxGs6tYosYzfj%2BT%2FNAVuh8jBO8wu%2B6g0UfWaOijo%2BZThZWkVldftgOP3kO7kgC1aORjAo6rKdhGG%2BnSCiXHlmITlEx7bA2aDeHMIO5RgC7fLMojntVHsX%2FG%2FBpaLo8xFT6uU8T3LywjNgdmhmyQXP1W42Cv6gCxpvcViWzu65IS64XbI7bHai04%2FWbhYC7rkRCXAIt8eq7fozkSK%2BFmPrjdRCdDLt8fqLbq8UBr08B5RSSLMin8Mjb45ThAkOoIg0REEQaIjiKpLtXlVlqa%2FfokgT1eh8IdmNfklgwSJjiAITQgvFR6PLilBno4gCBIdQZDoCIJERxAEiY4gSHQEQZDoCIJERxBEUarFzfHq8Hv4hGpUhwcgqs0TKWX5sVmialJdHmqn8JKoclFNVY9sSHQEQaIjCBIdQRDVRHT0NRwCmmh%2FahOdW336wVlCfajT%2FtQmujQjWNKlJzTR%2FtQmOqkEzejSE5pof%2BrL6STwpEuvHvgbV%2FkbZUuCv601KzP7tevn7zR%2FGPVMvLe9Emd0nponulwM6WxdvfO6myEPcPnqv%2BVW3%2Fadp5GalvE%2F17NrzznM%2BL%2BSn%2BDp5fMfhN6Jev3QLT0Trl6zkZKSXimvi7A7Zn%2BaJzrgRpI%2BZlVn0e07dAnbdp0ut%2FpmfrYez58nk6v%2BH8m3uxvqOr7anr2U5mKyXIKzrZvi6uVQ7K6o4%2FKwKeD348IDGRnpw6tTC3TzbCXKArefxMGjV6Cvp4vBAzqgY%2Fu8sP9W6AOEhkXBzNQQv%2F1xEjKZFNMmeKOJbT1Rfvd%2BDNb%2FegSPn8TD0sIM%2Fb1dUbOmCc5dCBOj%2Fg%2FLdsGU7TtmeBfs3n8BR0%2FcQHxCCixrm7HjuKNlc2tRz%2BHj16Cnq42IezFiuZ5VTcye2g%2Fm5kb4468zyGXhmn%2FAQZgYG6Ara3Nz%2B4asPadw4vQt8R71Zk0b4IMhHqwOHZXOxU7m8f7aex6mJgaYPqkvGtavVaKH3Xf4MrS1pRjUrz08O7ZQlt2JiEZA4DHEPk%2BCdaPa8B3QETVqGBXan3tn%2F42H0KNLa9jZWKlVcMzeerOPGcz%2BXJn93dYoT3c%2BFGE5EvhIJAhwssc8GxtUyBvmx05djmPM6Af0bSeMdIX%2FPrGeC2PjlqMYPtiDGYcj%2FOb640jQ9TzRhTzEzHnr8ceuM%2Bjm0UoIY8zkZcpQqu%2FgRWjYwALDBnViQqmBw0FMPHraMDbWh6GhHhrUq4W6luZi%2B%2BiYeDi2eBtjP%2Bgq1g0a8a0yvzp07Jqo9%2F7Dp%2FDu4Yyw8Ch88c1vosyCiZhTt04NUZ8Rq3fNhoPYvC0I7%2FfvIAaOG8H3EfM0QaXzcOJMMI6dvIHuXo4i9%2FId%2FR2ys3Ne2o6fn1XrD8B3oDt6d2%2BD2Z9vxJ6Dl0QZH4j6Dlkk2tS%2FjxsTV6YQckHSMzIxcsJSPH2WqFbBcfvidsbtjdsdtz%2BN83ScK8E40rYpXLMlWG6qjUmt7RHI30kuzUGwdRjubwPk5Xm867fu4fzlcFw%2B8QPzZnneYNj7nSGX5wgD3r5pjvAenITEVKxct194Qo5rGzus%2BOEjsdyVCa%2BZ6xTExSUjPjEFiSlpeLerE6zq1lB6R44DE%2FVzto0P8w4Kxo3oKoTKPYRzaxvhbUNCI%2BHezkGUj2FinO3XTyzXrGmMzxcGimVer0RLgl7d2qB%2BvZpiXXDoQzjYNUDnDs3zcjEmClXp6OaAJd%2BMFcsDvN3Q0n0aLl27Axcnu0ITIqvYOVi3fDJra9772NPTs9h52cfa4cTEuB%2Fv9%2BuACWN6iDJ%2BrriAudA4GVlZmDBjFZqyiODLTys2hfJhwdQ9OzSSa8GBT5pIAN9clmbLmIe7FKI%2BwalddAqPx%2B3YsRlaauWiP1uemiOFbYQ9GjmV81MD4f9Gw7ZxXaXghKtnhvyYeZ%2Bk5LRCIzEPHXnYqAyHtV4EBSYsHBOhqlyOtxpZwod5zfbd5op93FyaYsLoHqhtYVpsG75dsgObfw9CCxZS1mKi4gYqz3nhYaTSAsdhYWR2dsnjzqhhXvjQbwVauPnBybExC2vd4N3TuexGwMLGRvUt2HmIK7Q%2BkQ08sXFJaGJTT7nOztZKhL955%2FMRG0S6FQ6dtF5csokzVouw89e108vdbkr7pkFE3sse77PWhDMrOsO8W48rt3CtMuSUleb7dPkn5NqbuAAKeEiWkJD60noeAkpY3MGFV9PcOC%2FZZst8e1X4739G4tOZPrh49Q4LUY9h8sdrsHXDx0pvoSDk9kOsCziEUwe%2FUYaLXfvOf%2B1z1uqdt3DuyLcICYvE2Qu38fFnG4SQ3Vj4UObJheR0mJkUzsX0DXRZ%2FqqFxKQ05UCTxJaNjfLOizHz0gksNy0J7vm27vgHi77fjk9mDixXe6nKX2bVqAeeeYjIR%2FNDx66Kv3koxCc2uPHwUO%2FX346L9Tzc3Lw1CJ6dWpRa5%2F3Ipzh3KQxmZobo0rklfN5rJ0JKjpmJIf69%2B1i5bWaWXISIOjKp%2BPvqjbuIeRKvcvvNjA1x52608u%2F9hy8jmYnFoUkDjBzixcLOWspjl0Z6RpZymed28QnJcHayKbQNn5xp72qPX7ceV56vX%2Fl5yZ9I8WKfm5jX5kLkPGH55NmLLyK3IQM7Yov%2FDPy977wI1YlK5ukqAj6DuOqnCZjxyS%2FQ1w0UuZgj8xa9ezjjh0WjMWL8Evy9%2FyJS2Pq3rC0xc3LfUuvkM4p%2Bs%2F2Zq81FrRomePIsQZkr8Xr9Nx2CU6eZrMwY%2B%2F%2BcDw%2F3d%2BDiNVtMsrxtXQd6%2Bjoqt%2F%2FDUd3w4dTlYjbTb7w37j14gmlz16Hx23VEiMwHle6ejirVFXo7Es4es6AtkyExORUrvvsIBvovz2UtXjACIycsEQNVWlqWyFu%2FmT88P7ztgjAWYrb1%2BhjmbIBJYudt4WfDgGaNlPvzGdot62biPd%2Bvxewvn5DRdNTionk4WJ7hAa%2BvrD%2FXEBkVy0RoILxc0fU6ujLUrmVapvq4B81i%2BVd9q5oiVFXAvUNUdKzI8XR1tJXbarHcrazHEBM8LJzLyMpW7ssnZZ7FJsKE9YMPKmUhOSUdcfHJhdpWElGPYqHNPF9xuaqiHj6r%2BiYp%2BHMN5WE%2F5W2H5OlKQTEDqOr60qiTf0vgpfidhZNFjbGkbVX11oXyLj2dQvXzEG%2FizNUl7t%2F33bYYPrizMsdVNW%2Fl9wxflSurWg%2BhwaKrrnBPtD1gNp0ImkghCIJERxAkOoIg0REEQaIjCBIdQRAkOoIg0REEQaIjCPVRbZ5IqS6vUSLI01UJ%2BEOr1eFlgQSJjiAICi9L93h0SQnydARBkOgIgkRHECQ6giBIdARBoiMIgkRHECQ6giCKUi1ujqv6s%2BpE5UMTH2ioNk%2BklPXHZgn1o6kPqVN4Sag9StG0SIVERxAkOoIg0REEUU1ER1%2FDIaCJ9qc20bnVB73mhYAm2p%2FaRJdmBEu69IQm2p%2FaRCeVoBldekIT7U99OZ0EnnTpy4eU1Aw8jU0ssTz6cRyyMrNfu%2F7c3Fw8jHom3ipbjTI6T80TXS6GdLamvK482L3%2FAqbPXVdiee%2F3v8Kt2w9fu%2F7MrGy4es1GYmJqtThfwu6Y%2FWme6IAbSfqYRZIhKpp8u7uhruOr7dlLaS4myyU427oprl4Oxe6KOu61m%2FcQuP0Ensclo75VTQzx6Qibt%2BuKssDtJ3Hw6BXo6%2Bli8IAO6Ng%2BL%2By%2Fev2uCK%2B8ezorR%2F5lq%2Fdgyoe9oK0jw5ZtJ9DWyRYPIp%2BKbd%2Fr7YK3retg%2F%2BHLrL6ryGLbuzg3gc977aCro43rt%2B5h02%2FHERUdi7at7TB%2BTHfo6eqIMO73P08h6J9b0NGWwaFpA4wY4iHKVOGvveexc885mJoYYNqkPmhU36LY7f746wz2HrwEmUyKQf3aw6tTC2XZv3cfIyDwGJ6xcLVRw9rwHeguXqlcaBIiPRNrNx5Ed09HNLGtV6UEx%2BytN%2FuYwezPldnfbY3ydOdDEZYjgY9EggAne8yzsYHumz5m1KNY%2BI75Hk4tGzNRuQvjPHH6lij7YdkubNxyFMMHe6BHF0f4zfXHkaDrouzK9Qj8ve%2B8sp6MjCx8z7bPzJaLv7cwEQ8b9yPb%2FxiSUtKRzspXrz%2BAr%2F67DZ4d30EXj5bYf%2Bgy7t6LwZVrERgzeRk6uNlj2oQ%2BCA59gDmfB4h6%2FAMOCzFyIXTzbIVbIQ9EPqYKp86FiPZ293IUDzL6jvwO2Vnyl7bj7Vrhv1cMKn3YIPJ%2FCzaxvl0QZWF3HqGP70JY1jZD%2Fz5uSGfi2rH7bKH9MzKzMGriUjyOiYedjVWVERu3L25n3N643XH70zhPJ4w5GEfaNoVrtgTLTbUxqbU9ApnFHJXmINg6DPe3AfLyPN6diMfM08iEYZowwXFBcOTyHKzZcBDbN81Bc%2FuGYl0Cy19WrttfyAu8iolje%2BIDXw9lfQOGL8am1dPQxtFGrOv7rouYiBg3dTlmTOor%2Fua8ZW2Jtp1n4fuFo4UAm9rVh4d7Xrt6dW%2Bjct86uNhjyeKxYnlAn3ZwdJ%2BGC1fC4cZOcEFW%2Bu%2FDqiUT4drGLl9E2ayf%2B4QX54L06dtO9IXD%2B87bnJWdNwmTyT6nTF4rIoOv5g2t1CLzYcHUPTs0kmvBgU%2BaSNg4xAajmzLm4S6FqE9wahedwuOxj66OzdBSKxf92fLUHClsI%2BzRyKmcnxpwc2mCFs2s0arDdDRzaIiO7RwwfnQPpDDvlJScVmjk5mHT3fsxKtddMAR78jRBTDq0aG5dOKzQYvFMeBQuX%2F0XS1b%2BrVzPPUt6RiZGDfMSonzHbSqcWtmgn7eLUpxluqgyLREaRjNvVCiXYX3ks5xNGhfspxUi7uX1MzziEUb4er7UZgWTZ60RYWfAar9yt4Py%2FqZBBER991nrw5kVnWHerceVW7hWGQaESvN9uvwTcu1NXjCeJ21c5YeYJ%2FG4xAx%2F5S%2F7xfL8uYMhYXEHN8qa5sZKAzUyfDG5mpWtutM1NNAV9cUnpKB2rcL5kLGRPuZO74%2FePZxf2o8PCGcPf4uQsEicuxCGOfMDRHs6uDmU%2BZwks%2FabmRoWWqfH8kmZthSJKWkwNzcS6xKTWD%2BN8vppbKjPPHxKiXVyD%2Fwnywd52PzZ7EHlev016cusGvXA843g%2BwgNixKe5d1uTmIigE%2BocCE4t7bBryyfUoSHm7cGwTM%2FtOReLPj2Q6SmZYhwa%2Bfuc688Dg9deX08PFV69EvhLA%2BKE6HtChbixcfnGXd2dg72HLwklg8cucLEkg6HJnwCxRMN61mI9qkCz78UBJ26hWfPk%2BCSH0Iq4JM%2BHZmAFf3kEzebfw%2BCV8e8fvL%2B8n4rbg1wr3jmwou5Bl%2BWB29eNwP7WHuXrdlL06BV3dNVBFw0H039UYhCX09H3FT2%2F3lS3kTKotEYMX4J%2Ft5%2FkYWbaSLXmjm5b15u07kFlq%2FdC6dOM6EtlaInE2xp%2FMTyq%2FF%2BK%2BHIQlnuXfgM5NYNH2PyuHfx%2BEkcXLvMRg0zI8Qxz9KGhZK9WJ185tNvjj8av1WHbRMvZkR7dmmtUt9u34mCs8csaMtkSEhKwfLvPhIetyhfz%2F8AIycuFZMufEKoDhuA1i2bIspGMqGHsfDXhbXN3MRQeMSiuRv33IHrZ6Lv4EUwMzPEsEGdSEVlRC0unYeD5RlO8PrK8nMNkVGxIlexqluj2DIdXdlLYSH3CpGPYmHCvKJpkbDtVXBvwSJN1KphUmg9n3bn%2BZFFLZNCtwQU63mox426TCEly03j4pNfqrM4HkU%2Fh1SqJbx%2BSfU0qFfrjdpBwZ9rUEd4Wd52SJ7uFdSvV7PMZTxHex0jtKhpUux67mmLq6%2Foei7aCdNXlVi%2Fd482IhTl8By0YB76KoobcBSUpR6CRFft4KLdHjCbTgRNpBAEQaIjCBIdQRAkOoIg0REEiY4gCBIdQZDoCIIg0RFE1aHaPJGiqa9dIsjTqQX%2B0KomvlyQINERBKFJ4aXC49ElJcjTEQRBoiMIEh1BkOgIgiDREQSJjiAIEh1BkOgIgihKtbg5Xt6%2Fg09UHJr4QEO1eSKlLD82S1QONPUhdQovCbVHKZoWqZDoCIJERxAkOoIgqoHoeAxPX8Mh1Ikk3w41RnTpbvVBr4Uh1Ea%2B%2FaVrkuiephnBki49oS7y7e%2BpxoiO%2BfQwqQTN6NIT6oLbH7dDjREdC6bPsP881XFs%2Ft7vzKzscq2Tvz88ISGl2DL%2BjvKHUc%2FEm1xLg7%2FrO07Fd4wXhb899dnzxBLL%2BZtXszJfv9%2B8%2Far2o4pkdJ7CDjVFdDla%2BIO5uyGdrSs%2Br%2Bs%2F9Bvxbu%2Fy5KeVf2HZ2uJffM%2FF6Oo1G1nZ8lLrWb3hAL5duuO12rBz91l8PG9DieU9%2Bi9A%2BN3o1%2B4jFzXvR2paZpXXm7A7Zn%2FCDjVFdFdu4Rr7uJGkj1kU6BAVTb7d3ci3wwpHbc9eSnMxWS7B2dZNcfVyKHarJbdkodL6zUdgb1cfbm2bilBw89YgHDt5AzKZFL4D3eHh%2Fg7uRz7Fnv0XMXFsT%2BW%2B9x48weHj1zD2g67ib%2B7J%2FAMOIejUTTR%2Bqw6mT%2BwDU1PDl46ZncW223QI%2F5wNRa2axhg51Astm1u%2FiALkOdj023EcOnYVDRtYYNpEb9SqYaJyn3Ywj%2FfX3vMwNzPC9El9SnxP%2BrYd%2F2Df4cvQ0ZHh%2Ff4dRD8VhP8bzdpwDLHPk2DdqDaGDOwIExODQvunpmXAf%2BMh9OzqBNvGdauM4Ji99WYfM5j9uaqrDWq7OX4%2BFGE5EvhIJAhwssc8GxvoVrTg5n6xCUeDbqB1q8Zi3SdfbsKRoOv4cFR39OvtipmfrsfZi2GoU9sMK9ftw7lLL%2FLulev2izxJQeC2E4h8FIs%2BPdsiJCwKU2avLfa4Mz9bj5OngzFuRFc4t7bFkLHfI%2Fj2Q2X5H3%2BdQWh4JLx7OOPBw6f4aOoKlft0%2FORNBP1zCz26tEY2GwSGjPkBcibiovy8eg%2FWbDiIoYM6oXf3NpjFwtJ9hy6LshDWlveGLoJV3Rro5%2B2KlNQM7GIiLkh6RiY%2B%2BGiJEGVVERy3L25n3N643XH7U1db1PotgyvBOMIcjGu2BMtNtTGptT0CWax9VJqDYOsw3N8GyN%2FUsT9fGMhEE4tfVkyBjrYMT54mYOeec7h66kfo6eqIbW6HR2EXW%2Bfaxo55vY4I2HIMLk52SEpKE%2BsP7lygrO8DXw98OstHLHOv6dpl9kuTIspjnPgR5uZGYt3d%2BzFYF3AY3y8cJf726dceCz8bJpa9OrdEqw7TEBkVi%2Fr1apaeq7g3x09fj8nLXdmg0YLte%2BV6BNo42hQabHjuGLDSTznYcGGt%2BmU%2F81qtxWDCPdv40T1EWRfWBh4BpKTm3dLKyMjC5I9Xo7lDQ3wxd3ClFRm7EtJ7dmgk14JD%2FqSJby5wU8Y83KUQ9QlO7aJTeDz20dWxGVpq5aI%2FW56aI4VthD0aOb2hp1a%2B%2B3knrt%2B6hwtHvxOC49yJiEZaeiY6vzuv0LZdPFqKz%2BGDO4uyp7GJInxzdW6ChvWLD924QHR1tBHzNB6WFmaFQlIeKioEx2liUw%2BbtwUVW08Ntp25qRGiY56rJLqCaLOwsSELLaMfxxVaHxefIgYDWxurF22wrYeIe4%2BV54ELrVA4pPXiMoyfvlLsv8V%2FZrlek%2FL%2BpkFE3tMm91nLw5kVnWHerYe6crhKJ7oikyvXKuKC2TGDM9DXxdQ5a%2BH%2F82RIpVowMtKDsZE%2BzhxeDInkZa3z3Mi9nYMII7fvOo2v5g0tsf6MzCyW42XD1KRwTsePkZKSLryN4hiJyakwMtQvth7uYXjuZGZq9NozjmZF8koDAx3R3%2BTkdNFfMbHAPLeRYd5EsiH7TExKLbHOrkyQv%2F15Eot%2F%2FBNzpvcvt%2BuvSV9m1cgHnnneteqn8UhISMWMT38RInBo0hDGzOBW%2BO97EQ4%2BS8CZC7eVf48c6omlq3aLkZ8LsCDcSyrYsPkomts3RN065oW24V7N1NQAO3afU%2BZG23dKxyltAAACPklEQVSehlenFsXWE%2FjHCVGHzdt1VOpXwX15bsrF5OxkU2gbHjrz8HfT78eVwv51axA889vAvVxA4HEkJaeJv2OexIu8VsEQlgduXjsDf%2B4%2Bg9XrD9BUaFX2dBUNN74NK6ei%2F%2FDF%2BOLr37DgE1%2BsXzGV5StrsWb9QRga6CKBeaEFc30B57x9OrVvJmbxRg31eskb7j14CQeOXBHrpUyUAaunvzxjyzzMiu%2FG46PpK1ged0hMxHTs0EyErgqCTt6Es8csVocWsuVy1ka%2FYj1vcQSHPBT7astkwoOu%2BmG8Mj8tyLf%2FGYFRE5aK9qalZYrQ9b9fjhBlY4Z3RdidR2jr%2BTHMmadOSknD1%2FOHc1%2Bv3L%2BOpTkC181EvyHfCE%2FKZz8J1akWLp2Hl%2BX5cw08b%2BNT%2B0U91b93H6P3%2B1%2Fh4vHvhSiLwnOd5NR0WNWpIQRWEnxG8dHj56wOPZG3FYXfUE9knqauZQ3IZGULRriHimf717YwFXnlq4h6FAttltPybYsLTePik0u85VAeFPy5Bk0KL2U07ryMRc3i74vxafZB77UvVnAcPkFibl56%2FsUF%2BSpj5vf3Ct7j44%2BucQ9cEv28XTDUp5NY5nmaIlcrjXpWJU%2FO8BxPkecRJDq10cHVHm2dbCv8uDyc2x4wmy4AiU7z8O7pTCeB%2BJ%2Bhn2sgCBIdQZDoCIIg0REEiY4gCBIdQZDoCIIg0RFExVNtbo5r6muXiKqHtDp0IvoZFvB%2FVhb4gi5p1b2GFF4SBEEQRHXg%2FwExG%2BbPNkzHHgAAAABJRU5ErkJggg%3D%3D)
+
+```
+pre_section_block
+ ::= options_block
+ | constants_block
+ | sources_block
+ | keyblob_block
+```
+
+referenced by:
+
+* command_file
+
+**options_block:**
+
+![options_block](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAXsAAABHCAYAAADm8edpAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAFM1JREFUeNrtnQl8Tccex393yc2ekAVNaBCJJNZIROxLra2lsZSqUnm2olVL0VevRZWiKEpVPdtrldhqrS5aKpYQERIJEUmQ2LLv6733zZzIlRCy3SXJ%2FX99jnPPmXNmJjPz%2F89%2F%2FmfOHIAgCIKo9YioCAh9x8MVSioFzXI5nHSNrpFSERAEEHhmKxWChvDs6kuFUA0QUxEQBKGN0RONoEjZEwRBEKTsCYIgCFL2BEEQBCl7giAIgpQ9QRAEKXuCIAiClD1BEARByp4giOpIRmYOEpPTy319eno27sUlCHuClD1BEC8hMysX%2Bw%2BfL3GOH3%2F25S6t52XfL%2Bcw%2F%2FOd5bqW57F9rznwnboe%2F9tziiqyBkPLJRCEFkhISsPHC7Zj2OCOqnNuzRvCqq5Ztc73NxuPYPM3U9GtcwuqRFL2BKE%2FcBfI5m2%2FITA4Eg6N6mHSe33RxKG%2BEHbizyCYmxnjamgMzgXcgJtLI8x4fxBMTQyx9%2BBZyBVyrP72kHDtWz5dkJtXUMI1EhuXiB92%2FI6bkXFwb9UUU3z7wdLSVAjb9uNJeHk64eiJQASHRKNzB1dMnTAAYnH51hc78uslHDhyXogvn6VbnPjENOFvCgm7g2ZNX8GU8f3R0N4ah44HIO5%2BIk6evobAK5GYNL4fzEyNqBHUUMiNQxAV4L331yH6ziNMn%2FgGGr9aD0NGLcXDR8lC2K9M2U%2BcsRGpaZkY%2FLoXzl28gfmf7xDC6tlYAiIRGtnbCJuhkQGusU7h0PGLQnhKSiaGjF6KunXMMGPKQCQmpWPk%2BK8hlyuE8K1M2Y%2Bfuh6WFiYY2N8T2346Cb%2BD%2FuXK8497TuGLlX7svvbo3b11CX8972z438DTnTVtCOrZWmL42OVCh2BjZcGyLIItyzvPs0RC6oIse4LQA4KvRePmrVjs%2Fu9sSA0k6NTBRbCyf953BjOnDRaumfqvAZg%2B6XXhd%2BsWjdF%2F%2BCKsWuqL7l1bQiISY4RP51Lj3s%2Bsbhcne3w0dZBw7N2%2BOTr1mQf%2F8%2BHo3qXQhbKGxdPZ21X4HR3zCEHBURg1rGuZ%2BV73%2FTGsWDwOPbq0FI4TEtNxNiBc%2BL330Fm4t24ijBI4Xh5OOHQsQBi58LQM2N%2FZv7e7YPETpOwJQue4t0AbsRJDoQR3ijuxzQFq%2Fl5DFLPomzZuICj6Ipo3s8ft6AeqY1GxFB0b1xcs5MTEsme%2B8NGCUzO7YvGI4ORoh6iYhyplX9xlY2FugqTkjDLjTc%2FIFlwxvOMpjYjI%2B%2FjrTAi8X5tb4nxObr5G6qkcK1%2Fy8Dtsu8Vq77xChANXruMqtXBS9oSe4%2BUC5wIRNogUaMm0xM9MVayTKBDWOAJ39gJyNSkgAe6v5srzWWVqZmZc6vVJKRmC68PS0kSwppVK5UvjTkhMez7uF%2FnIy9mNyWRSoZNIz8wu9WEwj3%2FI6174auFYrdRXWR8xGQFIYpzhIBfDjR32Yh34iXauCJUqMe3iDURQi6885IQjaq4174bX5CJcYNrjdGo%2BGgeFY1bQDRy9FIGo8ir6iuDt6Yz7D5IQcLlQ5yQzy%2Frob5fQq1sr1TVp6VnCXqFQYsMPxwXXiYmxISzNjZFfIMfd2IRS4%2B7VrTV%2BPxmMx%2FGpwnFo%2BF2Eht1F105uVcqzocwArVs2ht%2BBQv9%2BWloWzj1x4XD6veYuPDe4fuOu6tyloFt48DBZJ3XK643XH69HXp%2B8Xnn98nrm9U2tnix7Qg8terkSe5mxPJYrBm2kaWFhgrXLJ2DSBxvh4GAr%2BM25z7xPz7aqaw4cuYB9h84jNy9fmKWzZd004TyfBTNqWBf09fkcpiZG2LBqcsm%2Fx8MJE8b1Qc9BC%2BDU1E5wDS1fPA4N6tetcr6%2FXDAGYyavwa69%2F0BeoECbVk1gZGQghLVv54RP54zAW%2B%2BthKWZCbKyc4W%2Fc9eW2dWiniMjkct2S9q5IJhZpntZvXuThV856LuQRI3EwxW%2Fs90%2Fl8OxRA1xKSvyWcK8%2FAI8epzCrHUTQTEWMWP%2BFjg72sH33d6CBV2%2FXp3n7uXz7cUi8Qvn13PXTUpqJmxtLGBkKFNbefHOh48a%2BGwbbu0%2FCx%2BJxD1IhIWZsWq6p7oo%2FlnCqnyLltXTArbrxuLoSxJAlj2hD%2B6bFmgDBVqZZ2OwLtKXGUiFqYgvwthIJmylwaczvgw%2BT9%2F8Bc8ASuO0%2F3Ws33zsheHzPvIRrHeu4F%2BWZ%2B7Xf1l4dYDV99fpxpjG658e2pKyJ%2FQAsQLDmH2461QMcqpTvt4Z0R0W5sZaTZPP1CmarVPb4fXt4YZdQv2DlD0pe6LWowQ6ipT4prrli%2FvdCY1X%2Fl%2Bs%2Fj%2BigqiEkURFQNQ0RBAezl6nktA%2FeL3z%2BqeSIGVP6Ae2xhl4RMWgfzypd1sqCVL2hH5gdD62evnrCe3wpN5pNTZS9oSewKfvKakY9BIlaMo4KXuCIAiClD1BEAQpe4IgCIKUPUEQBFGDoZeqCAIl128hCLLsCaIWwhfnqsoCXQRBlv0LKO%2FHIoiSCkmT8SsDJxnsO39hRlhE8tibt1OdklLzDOOTcspM07quYYGpsUGKjZXh6ci72cv%2BDsi6TLVF1HRqozzozI1TkSVlycWgWRfDH9s93v9o7S8rI6LTTAf2aoQ3p7yKBvVMUM%2B67HdXHifmSB8%2BzrLxD3w87E7c3SGDe5gExiVkjbkcitvUoRI1kdoqDxJdJGpni4WTfIdQqyonm7cdEsqMbw8SsEht1otyodjNKtFv%2Ffbwj%2Fv1aChbMrsdvN1tUd%2FWGKYm5bMD%2BHX8%2BvZtbDByYBOxQomGIeHJk%2BrZiILuP1ZGaqr9qLMciJqFpuq%2FpspDeSGfvR7jt27%2Fnq17bg1ftaA9xvo4QmZQtebA7%2BfxbFjsbWQiEx3xdAM99SRIHqqJPJCy1%2BOh6pbdEcNX%2FtsTrZrXVWvcPL5vF3lLpFLxFndS%2BATJQ7WQB1L2egh%2F%2BHT05L2VY5jVoe6GXbyBjx7SVCSF6Htm0QygUidIHnQrD6Ts9RA%2ByyDyTrrpqIFNNJrO5LebQyYTSxVK7PFoCUd1yifVot6i9kXwaoE8kLInSifsVvK4%2Ft3tq%2ByTLAsev1cbWy6dUsjxtRqjzu3RmJa51Uc6NhTqPYfkgZQ9UQ5uRqU5dvGsr5W0%2Bnaz4zv%2BYdYuwofC1UNiphl9wEIfyTYDb7jxJA%2Bk7InyaMqkXCP7BiZaScutWZ2iwffjJx%2BKVgdRBQr6NJ0%2BIhGhhRKIIHkgZU%2BUg6S0XJG1pWGl7r3%2FOAf3HmQhK0derusb1lcJkRnb%2Bqgj%2F0zYA0UKdKGa1ENE6CUCzutKHh4mFLb%2FjKyCSqWlCXkoL8KbAh1aon5A6Iu%2F6VlWuKb5658Q%2FLDjd0THPIKJiSH69mqL6ZPegJmpkSp845Zfhd9GhgZo5eYA37G9ERXzECvX%2FvLCeFd%2BMQ4f%2F2eH6njOh2%2FC27PQYAwKvo0NLM7r4Xchk0nRtZMbZrw%2FCPVsLIXwUHZ%2B4bLdaN3CAZ%2FNG%2Fk0znUH4d66KXr3KByh%2FX0mBJu3F%2BbdyMgALs4N8ZZPF%2FTq1kpn8qKQKyGWVOxl0YiYDLw7%2ByKi7mYKx5uWtMOwfvZlWxNP0lEqYSVS0xvbShGOMStlHfu5GPSwVm%2Fgz2nSlRitEKO%2FruRh5IcBCLuVBim73ndEE3w5u0XFrOtKyENV9W%2FR%2FYJlny%2FHfQ9X%2BPGTpV1cVrgm2ffLOUydvQlvvtEBe3fOxeqlvrh2PQYj31uJvPzC3jU%2BIRVJyemYPX0wxo3uiYjb9zF45BLYN7AWzvHtzYEdBAVedMw3u1essGaZLy5duYVpEwegTcvGQnxnL4Rj5Piv0cHDCXu2z8HmtVORmprF4vwSKSmFyi4tLQsxdx9h9wF%2FhITdUeX35q04PIpPEX6f9r%2BO92dtwtCB3vDbMRcbVk2GK1P2h44H1DhBW70lQlD0owY2wi%2BbOqF7e5sKGmSCJaOW9nMlDH%2BzCMWebtodBhO6Jd0Yc9gu5Mp1XNVVHtYuaIMfV3vB0sIAm3dHITwyrZIDlPLLQ2X1r5crfDzccK9AjmiVZS8qdOeMkMtZoCsOSiX4oHhPUla4psjPK8CSlX5Y%2Btm7GDrIWzjXyN4G2zZ%2BiO4DPsX%2BQ%2Bfx9vCuhWMiMyN09HIRfvfs2hotO36A29EP0b1LYc9rYmIEiUSsuqYIHh%2BnQb06MDaSCb8XL9%2BDDya%2FgUnj%2B6muW79yIt4cvQyb2Qhj7gwf4ZylhQnGvt0Ty1bvw64ts5%2FL%2Fx%2BngtGHWfgjfDqrzrVweRUFBYoaJ2iPk3KF%2FaRRTdCquWVlo1HX8hwK1iZnMetoW1sXBAbfQAypwtpNOxcMZLtZEiW8dZmPtm6FPvdu7W1x8Hdm2CXmwrUZNCoPFdW%2FXMnLRVjHBiwNi497S%2FjslYXKn0caW1pPUla4url%2B4x5S0rMwqJ9nifOGMgO83tcDp8%2BGlt5JFBSwjkIOQyODCqeZkJQmuGh8BpVsUyKRSBhdnPYvmeaEsX0QfjMW5y%2FeeC4uFyd7%2FHM2DH%2BeuoqMzKezxaTSmveopMhHaWFmUC3yExiGX5WsQTNpOdPODV1JHdZOmjWDIdM1C5j47WQ9%2FAgmZhHVIV%2FmZtIScqENytK%2FRZa8HDgAruifQVpGpEJPUla4piz9xwmpsKpjBgPZ89nklvjVkOinyigjR1C4mVm52LHrL7g426O9e8W73ISEwmFZA9s6z6dZvy7iE0sO20yMDTFjyiAsXb0fR3Z%2FWiJs1LBuuHMvHjPmbxHcP45NGjzn%2B6%2FOyJlpEB2biX8uJeDajVR0ameNV%2B1Mqk3%2BgsKw1MMFMSIl9rdzRSDb71FIcMkyE1GnYtQ7F5vQDiOYtRvjDAe5GG5PHsa%2BzfRNqJRZ9JfDq4ei5%2FDnVT8fvocNO2%2FDpq4hnBubMV0l07bSL9S%2FIvzKupzFz1ry5VL2qrEyEMxs0P7KMsKZIR3NEjVW9x%2FFH8BmMotYycbr3LIu4b9j501Nn75Xc%2F9BElZ9exgymQQdPJzxL2Zxc7dNReHuHk5aZjasZeYl08zIVj0ULs6Yt7pj87bfcOLPoJKFyyz4T%2BeMELaIyPvCiGHbTyfx7sQ1%2BO3gwkqViTa%2FBcCHqB2H%2F104bPWywU%2BrvSCq4iLAmso%2Fy9YA9t8AsULw7fJ0iBpI1NP6LF63DeQi3KxOdcoNn5%2FXemH0zIsYNPEsRgxoiI2L3bUqD1z%2FsrJ5o0CJ4WyvKCsi6QsE5xy7MY7te7MIt7D9zJeFG0ixvCKWfXn%2FwJauryIvrwBBwVHwcC%2F5dvGZc2Ho2bWl6tjZyQ77ds6tciU2srcWrG4eP3fbFMf%2FfBjatWn6fCEaSDBnhg9WrD0Ih0alv%2Bvj3MxO2JwcX0H%2FoYuEh8syg4pPTlHHmuvlLX8bZqn8d5kHzl5OxNZ9MZi3IhRr%2F1O190BozXiiulEZhctnp036NAj1rY0wfawjOrSx0pg8PJu%2F4vqX7b83MsDWnHz4MtN2glKE1NJcOBzxs5Gw3V4WgSvbYqUSuAaFY1ZZ4Zp6WGthYYJ3R%2FXA3M%2B3IzYusbA3Y%2F3Xuk1HERn9AKOZRa12C5GZrlMnDMAXK%2FwQfvOe6vzeg2dx7LfLmDiub6n38Y5BLBazDiFcdY7Hcfj4RdWsIf7A%2BcCRC8Ksn8ooem0jk4kxuLcdls9rBVdHc%2Bw6fFeYZ08Q%2Bs42ZvwkpeTh31Nd4Du8MVo4WWg8zRfp33PXEMr3EgmclErsZdels4tjX2bZ80h4TxHADFXXUhR4WeEa4bO5I7Hkaz%2F0HLgA1lbmSM%2FMFqZU7t46B7bWVSvgh4%2BShRk28gIF3pm4Bqu%2BHM9GC60w8b2%2ByMnNh887X8HS0gQ52fnCbJ%2Ft332I5k6lzy0Xi0WYP3Moxk1ZW8Ka%2F2rNAcz8ZCtsbSyQkpYpvAPw%2FdqpNa5x21gZArfTkZKaB7t6tCwNod8kM0XPsdaSn748%2BvfJuVkdWmJ5vhzznrX0i5R9Nu8pXqLEywrXGNxFsvCTtzFv5jAkJKbB0NDguYebI4d2EbaXwa3pW1e%2BK3GOP3C9cHJFqdfzqZdTxvfDw%2FgUSJjFzufkF6dTBxecPPxFiXP8Raq4G1ufy1dicjqysnJhbmqMOnVMa2TjNjctbConzjxC86bmkEjIG0PoJw%2FicxAYmlzofTDTygi9Qvr3WaXPJHWKStmz4UCTl0VSVrg24HPgi%2BbEaws%2BC0gdaVrXNRe2mszEkU1w6kI8ln13Q9jK%2BwYtQdQmuo8%2BLbxBy%2BGTFtzd6mje4K2k%2Fi2u9FXKvqyIdK3oCfXCX9mu6JIJXTxtcOVob4RHpgvHzZuYleu%2BjMx8KnCi1sgDf4M2M1sOU2OJ6gWrilAZeaiq%2Fi26X0pVrX%2FUMZcVJKbmSm2tKuZ7t7KUobOHdYXuuRWTRgVO1Bp5aFtFS16X8kCrXuoh5qYGKXEPs7SS1sWrCcJepAQfEsip9AmSB93IAyl7PcS6ruFp%2F0DteOb%2B8L8v7JUiPGY7cgcSJA86kgdS9npI5N3sZcf%2Bii3Iy9fsgmzRsemIic0oamn85ci7VPoEyYNu5IGUvR7yd0DWZZmBOHD30WiNpjN%2F%2BeWnB0rwtaH%2FoNInSB50Iw%2Bk7PWUuISsMVt2R%2BSE3EzWSPwrNofi9p30ooYdxTYPhRj7qeQJkgfdyAMpez3lMmt7efnKYdM%2FvyBXdwPnDduvuJUkgr8IuKTLj04QhL7LAyl7PSYgRH48I7tg4uRPzinX7wxHVX2W3Cc58oNTJRu2Ej%2Bx%2F%2FspJZhLJU6QPOhOHmievZ4TFIZtnq4K8f%2F23960%2B3C01LutDfp3bwhnRws42L38xamsnALcjErDxeB4%2FOl%2FnzXujJIX8IbN1yQXYXwgs5yotAmSB93Jg04WONHmmuy1bripoSWC27VAfyiEFfP4p9Kq9m0C7pNkQ1W2788smHFB13GCao6oSdRGeZDoItEHCVjENztbLKRmVfGy00i88Yi0awA%2F1iAd2WbLrI8o1tBzWSPlo7%2BylvbLYNfGiZW4qBQhhPXkDmIR4tmdo1jDvkS1RtQ4OauF8kBuHOLpqKFwaOnj3gJtxAoMY7%2F7MutGxP6VtVSnmVKJFNaw%2BbvkF5n1siiQHsYSJA8kDwRBEIR2%2BT%2FMdrJkSWUBvAAAAABJRU5ErkJggg%3D%3D)
+
+```
+options_block
+ ::= OPTIONS '{' option_def* '}'
+```
Comments:
@@ -406,254 +90,77 @@ options {
}
```
-
- option_def:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- constants_block:
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
+referenced by:
+
+* pre_section_block
+
+**option_def:**
+
+![option_def](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAUEAAAAlCAYAAADcHFvJAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAADlhJREFUeNrtXQdYVMcaPQtLr9JFrKgIahRRIc%2BCXWJDFCOxhxiVF4yFaDSmaOw1Ro2xYMP4xBaNJbbYIjYESywIqIgCIqB0UGHZNzMrKyqwQLaw6xy%2F6907c%2B%2FM3Ttnz%2F%2F%2FM3MHgIODg%2BM9hkAVlbo5Q%2Fy%2BPODIKMU%2BY3HEGJ3dFy5OuB2TPiL6XmajZ5kv9VKfPa9wnZY19AqNDHQyrCz0ztx9mD%2F%2F1KW8SN7%2BnH%2Fy5p8qeFZRCFVVccTZjRpPwNYd%2FBVa%2FvHNbgETf963OCYuy6hPl9roP64O7GwMYWOpX%2BEyUp4%2BFyan5FmFRaQMjE986N2vk2FEYlresMibuMfbn%2FNPXvxTFc8qAm1VVGpvjZlj%2FL01noTrNv3BvivdHqdhltysr3imlovF050rN0dN6dnJQXdOUCt4uFrD1toARoaVs2v0fHpdmxZWGNynvlaRGA43otLH2FgJriSliO%2Fy9uf8kwf%2FVMGzikKLU0X9sHPFnh0bd8T6Lv22DUb4OEJXRz7NSMuh5f3yo4e%2Boa7gQGsX%2BPOnzSFv%2FlU3nnERVDPQECQ4NMZ38Tet0dyphkLqoOWumuWhLRRqBbtyIeRQEP%2BqC8%2B4CKoRaCf0wROPFg8jVlRRAliSoEO8GwiEEKwllvoj%2FvQ5FMG%2F6sAzLoJqBDoKdzc%2B28ivT32l1Df2Eyfo6moJi8TY4dYMjrwFOP8UwT9V84yLoBrhdmz6SC%2FPWnLrA5QFWk%2FbFtZ0joUQIizhLcD5pwj%2BqZpnXATVCNH3sxzbt7ZVap09OtrTnQHZ2rs2RQveCpx%2FmsYzLoJqhKfPXujXsjNUap0uDc0lHwRI0SrCQN4KnH%2BaxjMugmqEZ1kvBJZmekqt08FWSnpjsnXnrcD5p2k8YzMb3ZvB9tJNPCnrJFn5ikJc%2FBNM%2BW6L9HjWN35o2qQOZsz%2BDdGxSSzNooYxGje0x4C%2BHmhQz0567rZdZ7D3wKV3ypz3%2FTB2%2FvAxyyEqEmHt8v%2FCxNiA5Z0Ou4nzl%2B7Af1hXBE5ZX%2BZ9Fd%2BHslEkEkNLW7lvOhbXJxbDQqDCN4yUgZtRD%2FHyRQFateRjQMrmX1V49m91qfh6VlmBCEluztgj1Mb40gqVla8wL6SmJeZ8OxRd%2B32Hgzu%2BRcMGNVn6jdvxcHdrjC4dmxMXPRsnzvyDnj6zsGTuKHj3cmfnPHyUCj1dIQLH9HqjzJp2kqH9y1diUcveAms3HcVX4%2FuztLS0LERFJ8Dc3AhBgf1YWmFhEfz8l2DVkjGws5G47LXtrd67H4BAYqENNPk7Hj4eiWfpOVwE1YRnVdWlts7wEQmwolAES3IoecdFIAmLB4lE8CGF7n27UFn5ioIOETEqVMXipaerI82jgvhh2ybscx%2BvNuj7UVuM%2BfIXtHFtBPuakmusrc2k55SGKV%2F6YOL0DRg1tAusLEyl6fp6utLrCl4Wsn2rFg1Qt7aN2pApPjEPCcn5pbv%2FxOq6t7SoSrFKf82SPv%2BQHadx5do9GBOPvavnB%2BjRpSXL2777LI6dvAoDfT34DWyPju2asvRbdx7iTkwizM2MELrnLISEsBMD%2BsKpUS1phLHptxNITsmArbU5iyIsLU1x6XIM8p%2B%2FxLJVf8CMXPvZ8G4y7%2B8JKWP9lmPEMD%2BEE4kwxvl7Mf7RiOJ29COMHvE6sgsOOY62bo3wQdN6WB18GO0%2FJL%2FgPy7g%2FoNkeHVvhaGDPNl5kVfvITk1A40Ix6mBr1%2FXBl7dWqmVmAXvjMP1qEx4dbRD7852CuFZZXWpWPyIQ%2BtQcgmPN9xOseS4zEJl5asS1Ct0blIbh45G4PNRPVhaamomLoTfeeO8Zi51peFvk8YO6NnFFSvXHCIh7icaZVG3%2FB6PlSGlv5JpTGxf3Bn1mP88mhg2kagI%2FkSQEhLTmHhQEaRCdezkNUydOAA5OfmYMC0YS%2BZ8ykTyVtQjTP1hC3p1c0OPzi1xnnDgs8BVCDs6n4mct988fBnQB906tWBC9deZ6xg5pAtMTAxIWKaF2rWsYGQkexGKjIxceH8yj4llj0BXnLsYhY9HLcbpQ3PRzLkOvpqxCQKBgOVTAdx%2FOBwj%2FTqza1dvOIxd%2B85hiG9H1KtjgwXL9sDIUB%2F9e7sj8tpdrCERio0VMeLuTWBqqn4O%2BLmIpzh46jFq2RpURQQrBVm6VJb4lSqCZRVa2UpVhXq1rZGQ9FR6fPvOIyxdtf%2BdPkGThq9JFURC4e7e3%2BPzkT00SgS9u9mjcX3j0j1BoXqMh%2F1z6wHCr8Tiyt%2FLiLeny9KGDe7ERHHd5mPYvfVrJjYUmVl5%2BHXDESaCFB6tG2P1srHsc3cihE09xiOdhLoZWbnIys1Hr%2B5uzGMr9h4pXIgRpeHwIJ92Fbq%2FHXvDSMTgJDW61Mv7%2FcBFXL8RBzdXR6xb%2BQV8RyyEro6QeYv7t89g0U0xfl02jhliirz8F8wrpCJIQfutt62fDG1t9Ry7dGpggvSsl6hjrzwBf0eXBDhM4rgfyxK%2FckVQ2hEKXCNN4CWWkV9YiDhSqcrNVUZmLhzr15Qee3ZohuXzPyv3mjoOVoz0S1ftQzt3Z4Xdm7LX0KtbyxAW5jqlhxECgVp8j9h7j9HIsaZUACm0tARIfpKBbOL9UaGQ%2FuhIqEvDXGk8pfVaPExNDV%2F1IYlIaGmLQd7%2FQbse09g11NMKICGsjbVZpe8v5m4SjhJv1KPr1DfSn794KYk6iEAHfeGNaTNDsHXdJNi%2B6lMuDXRQb9%2FB1wN5ljVM5CqAyubftHFOKrtfqkuE4b0LxfAl%2ByJZBQnLiLXPkwsTyb4bKTCY7CeVl08M3cLKeIKKaJCkx89I6BuN6UG%2Blb52QkBfdPCaDitLU4WRQh6LW1bmua3Yclch4bAyv4cxCUkzM%2FPeSaehKhVyKoRULCjoZ2Ojiq2juHj2KMwIGoQIEnZu%2Bd8pBE5Zh52bp0i8CXHFqUnr8%2B33IX6cMaTM%2Fsz9Ry6juUtdhGw%2Fhc7EKJdlgJ5lZMPCwkRj%2BJeU8hxxj3JhYiTEB03MFHK%2Fb99PSV0i%2B7X6Otj4vAD%2BxJSMFguQCeoRyhLB4kLEkkIu6WjDmYobqWxSefmq9P6ys%2FNx4XI0Zi0IxTC%2FTnBxql3pMqyJ%2BPkP64b1JMTyaOMETYCnuxXxoErvX9bREajFd6AhbfKTdBw%2FdY2FtEXEpv95LIINhLVp1RC%2FhZ5mBoyGx9t2nkGXV6FweYhPSGVl0tkFtE8wL%2B8FVqw9xPLMTY0QHhlb4fvz6ubK%2BiyHDPIkYa1k0OViRAwaEG%2BTepbfz9%2FOPi%2BaPRK9fGdj1bo%2FMX5sb%2Bn1mdkSgc8iofyWbadIqO%2BpMd0xSzfEIOT3eEwPaFIlEawMZOjSZPdmWFggwtdliWFJEdwlQ9x2KVv8omMTMXzscva5r99crP0pQDp9YfI3G9lmaKAHJ0JASi6%2FgR3evOG959hWEgdCZ5Q6BYKGRCGhpzSGhJ5trdmmzqAjtGuWB7B2NtDbzvryXJvXZyK4bJ4%2FRo77GQeORCCXpNevZ4ugQNkLtYqJkE6YGkx%2BB2I2IyAlLRM%2FLxjN8mi5wVuPw80ziOSZ4OjemeWWRWcQTBnvgwHDF8DcxBC5RFAtLIyxfUMQdu87zwZKDu%2F5gc1qWEO423fwHDbLoJ2HpNtl0tcbSKwmRnpGDgYQj5L2d2oKzl5OYxGHv289RVclU5depZUphsUimE8KSShH3GTlKwS0zyb85OJ30mkHsyxMn%2BzLtrJwJ%2BKXN47pyODNCyve9Zp0hUi8w5eCVxU6d2iOq2d%2FQkLiUyKKhtKRfdq39%2FfheSxdV0%2FIRlKL8bFPO7aV7Ecs2YYXTyxi3mBBoQgO9pbSEJVOw7pwfBESHz%2BtcB8hnV41nEQgScnPYEaEsLj%2F0bf%2Ff9hWDNq3%2BTbnNq4ez6bo0Pujgl%2BMMZ%2F2VOs2o1OzaCj8xXBH4l3rKLKqSunS22JIWn2cVASF2qhfXiGy8jk4FA2HWpaVSpcFO9vS18OjgkSnyFDQaTV01Lk0uDg5SPsCtV9Nq6kKatQw1ri2CotIo0tjIWBoA4XWU1VdKimGUhGUVRAXwOoB%2BmqRsl%2Bdy8kteG%2Bf94ZVgQore%2B53Q1HTtoZG8u8jTzt08rCGbSX%2B4FdVePZvdan4er6AghrB3ES38GnmC6XWGfsgiz94BYC%2B3lkyBNYk%2FpmZ6MDOSl9teMZFUI1gYqSTkZicp9Q6w6%2Bnsb1AjGyyE%2FFW4PzTNJ5xEVQjWNbQOxMWodyeieNhktV6xAKkkB3vFuH80ziecRFUI9x9mD%2F%2F0MmEwpcFRUqpLy4hGw8ScoqZcp%2F8%2F5C3AuefvPmnap5xEVQjnLqUF6mroxURejBOKfVNWxj5%2BkCMXGqweStw%2Fsmbf6rmGRdBNUNiWt6w4NCY5zei0xVaz6J1N3EvPruYmPfJ5lakhT28BTj%2F5Mm%2F6sAzLoJqhkjCmZcF4oGBP1wUKUoIKTF3lrT2AoQJgMtXb%2BE6bwHOP3nxr7rwjIugGuLSDdGfOfmFn4%2Bdfl68MiQK8uqjoX0zg8effpOYYmwj%2F%2FcUa2Mqf%2FIc8uBfdeOZkDepeuLKbWxq7VyktXXPvTWh%2B%2BOEHi2t4OXpgMaOpqhrX7G3EPKeF9I%2Fo4jwa6n4KyyJkDPnzRMoMQXoIhDg0wjiAfCnzlEV%2FlV3nqlkORFlr21WLcKIKMU861ZN4YUi7BJIliSXz5qOtG%2BGhCZk70Us88grt3CEtz%2Fnn9z5p2CeVRTaqqj0cRpm0c3eGjPfFxLS76uQclNx194OOwmRHMlmTazpfULIF4Rc1MvXrWAxOeSaRC0xwsUC3CAKVVdLgFRSgh8h5mXe%2Fpx%2FcuKfUnnGw%2BH3ycpLQggf16Zo8eoPV%2Fcg1llA%2FlX0vSxjsRgZhJh06eNwYpVnRfBBEA7584%2FzjIODg6O64f8rmKvsck0WfAAAAABJRU5ErkJggg%3D%3D)
+
+```
+option_def
+ ::= IDENT '=' const_expr ';'
+```
+
+referenced by:
+
+* options_block
+
+**constants_block:**
+
+![constants_block](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZsAAABHCAYAAADRE%2BoYAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAF49JREFUeNrtnQdcVMf2x3%2B7LL1KsSBWUAELzYIm1liITyUEiSVG%2F5LEaKIxkUSTpy%2FPRBONvueLGk1ibNHYW6K%2BxKeJ2GJBQGyAiIgKFhDpTbb8ZwZZQdHdhV2Knq%2Bf6907M3fuZe6cOXPOzJ0LEARBEISBkVAREIR%2B8POAikqhbhIVR21dbSOjIiAI%2FRF5dDUVQh2jc89QKoQ6gJSKgCCI58HqJMuTlA1BEARByoYgCIIgSNkQBEEQpGwIgiAIUjYEQRAEQcqGIAiCIGVDEARBEKRsCIKoS%2BTmFSIjM1fr9Dk5BbiRehe5uYVUeKRsCIKoq1yIu47omCt6y2%2F7L8dRUFhc5fM37ziGWXM2aJV2y85j6PrSxwh9dyk2bT9CD7MeQ8vVEMQzzu8HonAvMw%2B%2B3q56yS%2FsH2vg36UdLJqaGvzev1m%2BG2uWTUH3ru70IEnZEAShKyX35Vi35ZCwOKyszPFS704Y2M9bxG3afhT7D56BuZkpRga%2FiF4vtBfhF%2BOvIz4hFXa2lsw6OAqZzAgfTBqKdm2aivir1%2B5gzc9%2F4nZaFho52eHVof5wcLDBqdMJKCy6j0Xf%2Fgpbdu6bb%2FTH3n2ncfDIeWRl56NRQzt2nZ7w6tBS5PPHobMwMzVGUvId8bupswOmvx%2BEBg2ssGP3CaiUKqxctx821hYYwO65o2cLjX%2Fvrr0nsfu3CHHv%2FF4kkofrYqalZ2PF2v%2FhfOx1tHNzxsTQADg3sRfn3LyTif3hZ3Ei4hImvhkAC3NTqjz1FHKjEUQt8Nb7yxDOGvvgwB5o794My1f%2BLsK5Qvhp40G8MbIvAvr7YOonK%2FHn4XOlyibuBsJmrcGOX09gYF9voRDenPytiOMNeODIr9C8mRPGvNabKQh7%2FHGYKQ0zY1hbm8PS0gzNmjqiSaMGIv2tO1nw6dQab40dIMJeG7cAd%2B%2FliLgDrHHn%2BV67kY6hAV2QcDkVs%2BdvFnFOTHlxmjS2F%2FlZsXw1wRXggm92YtjgrujXqxMy7j0cr8lmyi5w1Jdo6GiLsMmBsG9gjRB2L%2FISBRztbYRS4nH8WkZG1FyRZUMQhNacu5iMiOjLiD6yiFkvJiJszIg%2BUCiUrIe%2FH9vXz0AHj%2BaljXFOAb5btU9YPhz%2Fzm2xfNE74vcApnDa%2B09BZmYesnLykZNfiMED%2FIRVUGYNcTyZMuNutJCgF9Rhb48bIBRUYtItdPF1E9ZVXHwKevbwFPFvMiU0fWqQ%2BO3gYI3PvtwkfvN8JVIJ%2FjawM1yaOmj8W1UqFZb8sBffLpyAF%2Fw9RBi3vKLPlo4hiTEZ9jdNGD9IHHf1a4Ode07gzPkkcS9GEikGD%2FRFi2YNqeKQsiGIZwef9vCSqvAqVOjODtuwjfuI9PotlMtXbqGNaxO1ohEuBtaA32bWBp%2Bp1dbNWR3OXWTcPVaGkfRh797GxkLsSxQKtGrRCCHMSnph4CfinO7d3DEpNAANnWwrvYcFi3dhw5bD6NShJRyZMikqvg%2BFUvnwOuWsCO4uk8sVVfpbs7LyhZusU%2FuWlcYnXLmJ%2FQdj4P%2FS9ArhxcUlBnm%2BWqz8zOOv8cfEnvoJpQQ7z1zEWZIMUjYEoRe6uqOtXIJlEiU6sNZmE2tylhgpEdsyAde2AVq1tNouYc9dT9nZBY%2BFc1cXdxtxhePQwFqE8d%2FauKo4C%2Bf8H2aGhSAyJhE%2FbQzH5I9XYOvaj9UWRhlxl25g1boDOLZ%2FvtotNiDwnwYpVxNTY%2FXfxN15lZXF8GE9MGfW6Bp5zpo%2BohbC9GxyW7RQSMFNvH6s47HP1wMXZCq8FxGPBJKUqkNOUIKsGU%2B8pJDgJGuFDmeXoGV0HKZFx2Pv6QQkaatodIG7wm7fycSB8BhxrFSqxIC9tZW5cGn9vPmQCOdutQ1bD6PfAxfa07iWko5TUQmws7NE%2Fz5eCHmlh3CdcexsLHHl6m112vslCuEKM5EZieOY81dxJy1L6%2Fu3s7ZE4tVbWqW1tDAVY1Jbd%2F0ljvkYzQnWapcxqL8vduw5gfiEFHUY%2Fzt0uR99wp83f%2B78%2BfN6wOsDrxe8fvB6QtJClg1BVNmiUaiwjXX8x%2FIGpiauyWeEff%2FNJEz7%2B2qYm24SYy0%2BHVthSEAXLPoqFOMmLsaefZHIZ%2BGtWjYSA%2Bea4DPEpk5fyUwrlRhYT7ubjcXz3xJxPN%2BV6w%2FAr3cYi7PGvp3%2FRN%2BeHdHtpenC2mjdsjHMzE20vv8J4wdiwvvLxOy0qROHYnRIr6em%2F%2FKzMRg3aTHWbQ6HQq5Ex%2FYtYMosHk73Lu0wY2oQgsd%2BDVsrC%2BQXFLN8LbFp1Ud1on4kJoK%2FUDTX1x0xrGe%2BjdUXf7JwqgZ9l5t4rvHzwH62OxIVh7l6yEul62ehU1IzmPKxEFbNo%2BEmpjIxE0sXuMVUIlfAxdmhwvRibj2l3soQYzimJsbqtFIjqc7XKLNQikvkWp%2FLx4TS7%2BaIadYmxo%2F3cbkVd%2FP2PdhaW6jHovRF%2Bc9Ca3KjaXi%2Bs9iuF8tjIEkOWTYEoTV8MgBYR9u6EMNq6x6eNKNLm5leldH4wdTmR%2BETEPj0YW3SamudcQ4eOYflK%2Fc9Md3MsOHw8WoNM1OTx65fHj4h4WnxdQFWT%2F6Va473eL2hSQOkbAhCa6RKBLN%2B7sZDySii0qga%2FL0Zvj0P8Hri54mNot6AlI3O8kZFQDyvqIDu7L%2BDVBKEDpXmoKg3BCkbgtAWCcTkgItUEoS28PrC6w2VBCkbgtAFJ%2FM83KFiILTlQX1xopIgZUMQumB2IoXGawjteVBfzKgkSNkQhC7wabAqKgZCB1SgV0ZI2RAEQRCkbAiCIAhSNgRBEARByoYgCIKop9AKAgShR8qvw0UQBFk2BKF3%2BCKP1VnokSDIstEz2n5kijBMg2jI%2FFWRE4y3nzg5NTYhc%2BylK9lt7mXfN02%2FV6Txmg4NTOWW5sZZjvamhxOvF84LP1UQRU%2BLeF55FuWo1txoui7FTlQfQ7t4Dqz1m%2FTB4l8WJlzNsRzSrxlemdgcjRtaoKGD5nfg0jKKZLfTChyPRaYFX0u9Hjisj0Vk6t2CMVEXcIUUOvE88azKkVFtXNTZCbMnhAZSraphVqz5VZQ9327dxed664WpZks97TO2Ll0b9%2FGgPi4mc8N84e%2FjhEZO5rC00K4%2Fw9Px9F28HDFiSCupUgWX83GZExo6SqJvpqkSDVUP9VkOxPOBoepNfZUjbaExG6LabF2yY8vqLZeH%2F3tWF4wNcoWJcfWqFT%2Bf57PsC38zCxPJns6eoFF3guSonssRKRui2ib%2Fys0Jwxf%2BvTM6tmug17x5ft9%2B7m8kk0lX%2BpDCIUiO6rUckbIhqm72R04w3vvnjYVjWO9J3wJSXlBGB7aWyCD5gfXMXqZSJ0iO6qcckbIhqgyfLZN4Lddy5JBWBr3OO6PawcREKlOqsMWvA1z1Kef0FAkd0fvirc%2BAHJGyIQxL7OXMcQG9m1bbt6wJnn9XLycu5TIo8C89Zl3cpyUtF09oT3cXUV%2BKSI5I2RA1yKWkHNcXOzeqkWsN7OXMd%2BZse9GnPbz0lG1GvhV9CIvQnkIr8AqfTnJEyoaoQTLuFZs1bWxRI9fydLMrc2KkSZUI1lO2SXIlfeKX0B4jCdqrgASSI1I2RA1yL6dY4mBrWqVzb6YV4catAhQUKbRK79JILYxWbBugj%2FtnjUakRIkX6UkSWiNBPwlworbk6PbdUrnJK5BX6VqGkCNtEW8KdeuARqcuPPlb7JriDU3MuatYsXY%2FYs5fhaWFKdq4OmP4K93Rr1cnEX%2Frdia%2B%2BW4Pjp%2BKR0mJHJ06tMSUd%2F6Gjp4t1HkMH7sAFuYm%2BHHpezA1MRZhv%2B2PQkLiTXzw7lBxfOXqbfxn2W6cOZcEpVIJt9bO6NurA0LH9EfIuAVQPWFYcGLoIPTvU2qRHgiPwQ9r9uOd8QMxoK%2F3Q1P5cipmztkAz3Yu%2BGLmaHX4N8v3oK2bM6RSCVau%2B6PS%2FI2NjbBpVRju3svBv5f%2BihMR8SgqKkEzF0d079IO7779MsxMTWr8uSgVKkiNdHtZPiE5D2%2BERSDper44%2Fn6uL4IHNdXcK3pwHfYM7CV6WvlCJcF%2FWW9rCfv5BWiyAKEBPr6Xq8JopRQBtSVHI94%2FhdjLOZCx9KEhrfBlWHvdrIsqyFF12%2F%2By88XFShS46eeBHTIjTKksU03xhuR%2Ff57B%2B9N%2FxMdTgzD9gyCmTBQ4eOQc5izYKpRNekYOhoyYi749O2AlVySmxti7LxKvvj4fm1aHobOPGytYlWig3ds2xU8bDmLC%2BEGlvYS0TFy%2BclP85g35sFFfYtyofpg6aSgk7ElERF3Ghq2HhbKZNjkQZdpm0off453QAHh3bCmOXVs1Ud%2FvTxvDkZWdL%2FbllU1uXiGuJN1iSicFgYO7wc%2BndDIIv76NjTkGD%2FBD2ORhIuz0mUSs2xSOpQveLu1MSaVQKJQIYQqTK9DliybC0tKMKeEkrN90CMGv9EALl%2Fox9LBoZYJQNCOHNBNbu1ZWOnYsRY%2FMXB%2F3ciYW4X6ekHb2RHBkLLZTc0o8jVxzfMR2589cxNnauofFs7xwJ6MYU%2BfEYMXmJIwJbAYPN5sqGGjay1FV2%2F%2BuHghSSLBEroADOyxdA0FS6k4LUSgQxDLd9WimmuINhVyuZNbAz%2FjHjBEY81pvdXgb1yYY%2BWqp92PZj7%2BJ43%2FNHa%2BOnzxhMPLyCzF34Tb8svFTdfiMD4IRNnM1RrO8rCwrTkI6FXlZWAfTmVIrw611E7wWVHodbkGUYWpmDA9moXTv6l4hj7T0bJZPAvZunYVBwZ%2BL44ZOtup4C2aVjRvVF%2FMWbcf29TMqnNu4UQOxcfLyi8S9lM%2BfW13cCvtlw6ewtbUUYVzBcMXFy6m%2BkHavWOwnjGyFju1sq5qNvpZZUrK6PY31IdZ4uyMyJh7J1KQSleHrjiFsN81IBf%2FavA9vz9Ixl15dnLBrf6pQPB5uMKgc6dr%2BlykZZrC5lPcXVBizUZWaVTzTFJbpVm7%2B6BKvby7GXxeWy%2FDA7o%2FFlTW4R%2F66iKAhjz9%2FHhYVkyga7jK4NeHn7YbvV%2B97LH1bV2ek383GqvV%2FCCtH7WeUaT%2Bs9cvek%2BjDLKx2bZqim19bcfwo417vh2sp6Qg%2Fel6nsnBuYg9ra3P857s9uJ5yt6IvVFZ%2Fht7KfM02VsZ14n6YRfO7igkGk7qjvp7oSc0qUR43N5iytm6WRIJ1rGcSEhGv38kBVcXaSlZBnmoCTe0%2FVzJ%2BnrihAHaCK5pHkGnIVGgyTfGGsnTS0rNgb2f11PGINKYgGjW0eyy8MQtTKlXIYIrD0uKhi%2BmTD4PxyutfYfyYlyqk59bRoq9CsWjpr%2Fjsy41wcrBB927umBgaAK8OLbW63%2B2%2FnlCP%2F7w61B%2Br1v2hdtmprSITY0x7LxDzF%2B1Anxc7aF0W5mYmWLNsCmbP24wf1%2B6HjY0F%2FLxcEfpGf%2FTr1bFOC6yCdXGupuTjyOm7OBefjR6%2BDmjubFFn7i86Fl%2F5uSNZosIOXw9Esv0WpRFO2%2BYj6VCyft%2BpIOo2Iay3n9wWLRRSeD6YDDCKtXcXZMyiiYqrG4qGw8c5N%2B2%2BgWXrrsCxgSnatrRibWXNjNs%2B1v5L8DtTeV88aslopWzUPgYghvWZA1Qa4uVyXGUXNdf3H8VdXXl5RUJp8AH0StNY8DSFj4Xn5pW2EZaPuMv4uM2gfj5Y8t1etGhecZxjeGAPsd1Jy8K5i8nY%2FVsEgsfMx%2FEDX1dwh1VGfEIq4i%2Bn4F5mLrbt%2BktYVNwy4%2BH8muV5LegFYV3t%2Bf20TuXB3Wr%2F2zUbWVn5OB97DYeOXcC4id9gx%2FpP0NWvjU551eQ3hbip3314eKn539URGxZ1FWNi1cFQ989u62X238tSpfDR8%2BsQzxFJD%2BtB%2BTrRWCHBpbpUF3iHbdPirhj9YQSGvv0XQl52wfIvfGpUjnj7z8rmb3IVhrO9UlNGsicI3HF2Yirb92cZrmT7D58WbyzD17pYNtr%2BgR08W0AuV%2BCvk3Ho2cOz0jQ%2BXq1x9HgshgR0qRB%2B9EQsWjRrCEd7GzFBoDxhU17BgMDP8Hq5caDycEtpQENvMcPMo%2BtkxF66oVHZ7Nh9HO5tXBAV8%2FCzEdydxsNnfhRSIa2RkVSMDc1j1o2nezOdH7KdnaUoD75FnkkUs%2Bd0VTb6%2BOaKts%2FRkfW4Vs3zw19RGVi9PRkzFlzA4n9U730y%2BmYM8axQlQafz%2BqcMDMajRzMMHmsK7p52RtMjh69v%2FLtP9v%2FYGaM1UUlCGWGx1sqCbIrc6FxpI9mwnbbWAYebEuRGcEjOg7TNMUbarKAtZU53hzbH9M%2FWysa%2FPJWxOSPVojf3M217Zfjwgopg%2Ff6uZuKTxSojOYujghh1sX6zYfUYdwa4ZMNMjPz1GG%2FHYiGQq5Ee4%2FmT9fwTKfv2nsSsz8dif%2FMe1O9zfjgVRGurETnDx7oB1sbC4Qf0W7s5nT0ZeHeS72ZoQ47eyFZTKnu7O1Wp4XJxESKYf2d8fWMjvBwtcbG3dfFezYEQVSNNazTdi%2FrPv7%2BrjtCh7dE%2BzY2Br%2Fmk9r%2F4%2Bdwge%2BNjNCG9eu3sXS5LHHK0ywbngnXVKeMWSaVKBBN8Qbh02nDxXRmPpXZyspMTAFWscZ7VEgvEc%2FHU1YseRez5mwQjbEJS8unGU97dxhGP0hTGXx689adx9THrq0aY8O2I8LacHF2QFHRfeGCW71sihi%2FeRrc8uLGk3%2B5GWucfj07oqDwvog3N6%2FoT5VIJGL8aGSodksUNWlkj6TkO%2Bgx6BNxP%2Fz8%2B8VyoeDKplHXBxztTYErucjKvg%2FnhrQsGUFUhUymaDgOdjX2fp3G9v9B2LRuHfB1iQIzHrV0ypRNIddUT1EimuINBnc5ffx%2BkBhUv3n7HoykUjEzqzzc3cU33utXsla%2FScMGkBkbVWjYU%2BMrfoaaN9gJ0d%2Bpj329XcU0aT7WkpmVBxNjWaUTD0Sh%2FrmwwjF3Z0Ud%2Fvdj6YxNZIg9tfShUto%2F%2F7HzHr0vDn8%2Fp%2Fw7OhyXpg74%2BccPcb9ELsaUOM2aOtY7IbG2LK1y%2B47eQbvW1uz5kjeMIHThVnoRIi9kit82VrKauKRO7f%2BjSodJ%2BES1smHmUKunZaIpvqaUjqbGtamzQ7WvwyclPPoOTp1ySTElWB%2BVTBlvj2iFQyfTMe%2B7eLFpu4IAQRBA79GHxQoCHD7ZxsfTzuDXrGr7X17pqJWNpoxqW9EQdRO%2B9IWuS9a82NkRZ%2Fb2R1xirjjWdgWBvPwSKnDiuZcjvoJAfqECluZG6hc8daEqclTd9r%2FsfBk9aqKq2FmbyDOyi2VO9rpZgva2JnjBTzcr9HJyDhU48dzLkXc1LZnalCNa9ZmoMtaWxlmptwtq5FoRZ0tXTZCowE0iBZU%2BQXJUv%2BSIlA1RZRwamB4%2BFlkzHtYDx0oXTFVJkMZ25NYlSI7qmRyRsiGqTOL1wnn%2FPZgiv19i2IVAr6bkIjklr6zG8pe8r1PpEyRH9UuOSNkQVSb8VEGUibE0cvPeqwa9zidfRz08UIF%2FCOcAlT5BclS%2F5IiUDVEtUu8WjFm5OaHo%2FKVMg%2BS%2FYMUFXLmWWyYgSWzzU0qxg0qeIDmqX3JEyoaoFlGsDt8vUQVP%2FudJhb4FhQvI1vK9PQmOSfi35Wrx41UEQXJEyoaoJU6dV%2FyWVyh%2F%2B51Pj6uWrotDdX3P3Lc8YsqhigKiwgb2%2FyCVEaZTiRMkR%2FVPjug9G0IvRMdiTWcPpXT9jivfb959Vebv7YiA3i5o62qDFs5Pf3GzoEiOS0k5iIhJxx%2FHbjIhyauYgAsI%2F7aIBOMjWQ%2BQSpsgOap%2FclQrC1PV5LdUiCeY7QZaot%2B3PQKgFCu%2F8sXpqveNI%2B5bZiY%2F2wewnti46IvYR0%2BOeB54FuXIqDYueusuPuebsxNmU7WqHXj5GyTfdCQ6N8ZWVrFd2ebEelFJTGCKWWXnVrSmJWrzWNpUqQoRKgnOsx5JC6kE6ezMkUxATtNTI54b%2BXwG5YjcaIT%2BraZSEz3Ipz28pEoEs98DWS9Nwv5ZajjVSqVCFhMQviZHBOuFfR5JkwEIkiOSI4IgCILQhv8HHEvHZ5c1t1EAAAAASUVORK5CYII%3D)
+
+```
+constants_block
+ ::= CONSTANTS '{' constant_def* '}'
+```
+
+referenced by:
+
+* pre_section_block
Comments:
Only numbers can be assigned to identifiers in the constants block.
-
- constant_def:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- sources_block:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- source_def:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
+**constant_def:**
+
+![constant_def](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAATsAAAAlCAYAAAA9d06YAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAADaNJREFUeNrtXQdYFEcbfu84ehEpgoAFUBA1KqCCvwWiiFgJ0TxixBj5FTSxRI2xG0nUxJbY%2F9iVJIrdKJpmYjREBEFjNCKCIgqoVCnS4f6ZPe8EBY5D7s7FeXmWLbP7ze7Me%2B9838wWgIGBgeE1gEAdmbo6Qfy6FHBsnHLLWBwTpHk48uKMG7dy3ou%2Fnds%2BO7dUOyO7uN55mjbXLtfX1XxsZqJ9LvFe0RdnowpjWf0znjWUZ%2BrgU30hUlfGMX%2FuavIE7N43UKn2f93jOuWj9cdX30rK0x%2FWvxXemtwali300MJUp9420rOKRQ%2FTC80iYtJHJqfe8x3hqReTmlkYEHsdt1n9M54pyjN18ak%2B0FBHplbmWBoU6NvkSbht9w%2FctdLpQSZCGq2VFS8VdjTJOrhxT9ycQZ42Wstmu8Dd2RwW5rrQ11Os%2FaL70%2BN6dDXD6GG2wkoxbK7F5QS1MBNcTksXJ7L6ZzxThGfq4FN9IWRU4R8ObjhyYNeBhFFrF%2FXAe3720NJsnGqkdqi9zZ%2B56%2BhpCU5274hAVtqMZw3l2avGJyZ2PAMNKXaE3Rq1ekF3vOHYXCl5ULubQtw1RCLhDmcmeIxnL8mzV4VPTOx4BNpJHP7b%2FdUBpLVUltBVJei7vnYCEQRbSYs8mJU%2B4xnf%2BcTEjkego2GJyfn6%2FsNsVZJf8BhHaGkJRZViHHDtDHtWA4xnfOYTEzse4UZCzngfD%2BtG66OTB5pPz67m9J4GESqwhtUA4xmf%2BcTEjkeIv5Nn36e7hUrz9O5nRWe6ZOrj3AldWS0wnvGVT0zseISs7BIda0s9lebZsZ2xZEGAdGElRrJaYDzjK5%2BY2PEI2XklAtNm2irN08ZCRnoDMg1U9TWnPchGWWl5o9t9%2BCgHpWXljFQq5pk6%2BcTdGejWGRZR1%2FGotp3kpSsLScmPMGfxXtl6yAJ%2FdOrQGgs%2F%2Fw7xCWncNpPmBnBoZ4W3h7vDrq2lbN%2FvD53DsZNRL9hcsSSA239c0DpUVFZg67oPYGigy6X9EXEdF6JuIjBgAKbO2V7reUnPQ9WorBBDqKHaJ%2Fyk%2BYnFMBGo4YmbwSM%2Fw75dsxq9vEeOW4m1KwLh3t2BqZsKedYQPr2s%2FkiP5zIrq0CaqxOOiDQwrSaj8tKV5lW0NMWyRWMxYMRihB9YhHZ2Lbnt124kw83VAf37vUFc7nz8du4fDPILwZrl78N3iBu3z737GdDWEmFq0JBqNltaSobSL11OgLWVCbbu%2FhkfT3uL25aZmYe4%2BBQYG%2Btj9tQR3Lby8kr4B67BpjVBsGwhccFbWZm9dj8AgaQl1mVSwKBqPjVUf3o6wa9CgA3lFTAlq5JnPgSScPadigr4EaPHnjcqL11Z0CRiRQVJKlLaWpqyNCp8vXp24JaH%2BfTA8ME9ETR9M3o4t4dVS8kx5ubNZPvUhDnT%2FfDR%2FJ14f2x%2FmJkYybbraGvJjpOGUC5d7dCmVQvekCk5tRApD4tqdudJ6%2BrWzaQhZtXyeOGDhzk4cCSC8%2FR9Brpg7DsesrSIyBvYf%2FhPFBaVwOvNrnh3VD8IBBLv4V5KJrbv%2BQWJSQ%2Fg3MUOUwJ9YGiouF4Xl5RiZ%2BgZXLx0i4skJowdgG5dbHH3XjqJHi5i4viBsujg9C%2BxEAoF8PFywfFTUbC0aI6oS%2FGIjk2AM%2BHQtOChHI%2FpNYX%2FHIO3R7jjh1OSCCQwwIt3orXjYBKuxuXCp58lhr5pqRQ%2BKao%2FUpEjDqpN1VdOVHMjxZL1Wo3KS1cnqJfn1KEVThECTXrfm9uWkZGLyOib1fbr3LGNjJgdHGwwqL8zNn5zioSmY5pUy7n3aDI2htb8KKIBaeOSzvHnPuHPVx0kAtcP9raWWPnVUejpasNvmDt%2BP38NsxfswtIF%2FqRO9bBmwzGuj482Ylk5%2BfAdsxwTAgZgiLcLDh2%2FgDET1%2BLE%2FoWcGCmCwA83kijDjBOqeykZCAj%2BGqcOLSaNnzmuXr%2BLT5bsxf%2B%2BmoyYK4lYvHwfToYt5I47Hh6FK1fvYNwYT9IY98AOIpiPc59w0Qo9z9XrjxKhPo%2F%2FuHWAkaEeL3n2V0wWws8%2BgLWFbkPETiHI05%2FaRK5GsavNqKKZqgttCflS0rJk6zdu3sfaTSde6LMzbPesdZ9NQtiBvkswabx3kxI7Xy8rONga1OzZifg1LrXlq2BZn11%2BQTEOE%2BGiYrdtz8%2BYMWW4rOuipYUxEbgVmDllBLdPl05tMT14mKTfprsjevb%2FmHhn8Zy41BexV24jJTUL32%2BfxXmMPV3bI%2BJiHH769TKCJwzChpUT4fN2CDZuPYX9h85z3R3SyIKLHma8hYDRntyybVsLTPhgIyd20gjih30LGuRtvipwtDNETl4pWlup7hpe0B8BfiTx12e1iVydYifrqAT%2BJj8LH7Gc9PJyJJFM1V5jtNW0t20pW%2Ffo2xnrvvhvnce0tjHDO369iSgeR283J6Wdm6rf4dbGWg8mxpo1hwUCAW%2Bu43lQ7%2B5YeCS3fOfuIzi2t5KlObSzxpPCEjzKePw0zVqWRr259vZWZPtDhcTu1u00pKZlo5fX3Oo%2F8nYS20ZGeti8NhjDRi%2FjhLdXD8fnC1u2SAfQcglHachNoaun1ehCp%2Br6mTfZUW3nS%2FWHlO7QcjFGkXmlPEOiWmLkC%2BTAVDL3IgZ3kPnMutI1RVipiGenjAqhYUFkdDzmzx6l8LGUpH195sPM1EhppGiMlysqUm4b9iYqJYxV9XU8j4KCIhgb6XPLhgY6yMt%2F1i%2BZT5apkBvo63BTXn5htWPpuoGBYuJC7VBBPX14Sa37HD5xAW90bIPjJy9iMvH2qADWhOzsfC4E19XRajI8S0svRtL9JzDUF6FLh2ZKOd%2Fnz6eq%2FpD5Vh1N7CouQyBxvCaKBcgF9fDkiZ3UiFhiJEpTA05UxEhmM%2BtKV2dLTwkeSUKTkC%2FDEODviY6OrRS2YU5EjnYO085s9x6OaArwcDMjP6qa%2B381NQW8upbiojLJvKQU%2Bw6fx2AvF269f78u3OCEl2dXaGgIEXrgLFy62aFZM30M8OiCD2dv5bopaP3%2BfS0JCYlp6O2umPdO95%2BzeA%2FCf7rEDYRR0IEJKpw0TD5yIpILjWkf3txPQzF97g7s3jJN5j3n5UkEl47qb9n5I4Z4u76UZ%2F2qYe3OWwg9moz5Uzo0SOwUgRz9meXWGSvLKjC3NtGrKnaH5IjYIVWLXHxCKsYFr%2BOWh%2Fsvx9avpxAyS54fnrVgFzfRltLRwZrrPPYf2bf6CR%2F7i5uqgnYeS21UBR2pCw0722RI6NHTnJuaAqbN2caFgzm5BfDs01k2avnRByMQPGMLenvP4wadikvKsPeb6VwaDVVp4%2Bc5dCHa25HwNekh1iybwAmfIqCjrzs3TcXHi3ZjyYr90CJhTElpGTasnIS4%2BPsI%2BSIMR76bx%2FW%2FrVgyDoNHhmDTttMcHylC95%2FFzm%2FPoKi4FJ2dWnMcbkr481ImFykEjmqr7Kzk6s%2FTbbWKnlTsioiRlDpETF66cjo%2F21sj%2BvfVL2ynI2ryMH%2FWKG6qDTdjNldbp30n1yM3vOgFaYmQepO9QlxduHpB0tilpmVxddHC7Jn3oK%2Bnje%2B2z0R6Zi5KS8phY21a7djZU30RNN4bj%2FOeoIV5s2q3Lv31y5cKeXeRZ1Zxt4uIyI%2BgqmD%2BE7m%2B2vmc%2F3FFtWOnEtGjgylPCournbursz2iflvN67qhtzbREPbDcfYwNtJUZlYK6c%2Fzokc8wskysRNpwLYuI%2FLSGRiUDWsr01rTqorI86CNWF2DAKvWH%2BPugasJdFDj4J45snXpDemKgoognZoaImIy6SubMGWsnVLzaaj%2BVBU9mdjJM8SE7tUAfdRG1Y%2BMFTwpa9Jl%2BskMP6XZnvieV7XbUJoazwZ7WMLT3RwWCnzgqSF8eln9kR4vYhLCHxgbapVn5ZaIzE10VJZnwt08VvANRJ9eHZs0z5oZanITX%2FjE3nrCIxjqaz5OfVio0jyjr2Zyc4EY%2BWRWwWqB8YyvfGJixyOYNtc%2BFxGj2h6FXyMkb5cRC5BOZqw7g%2FGMt3xiYscj0C%2Bsn%2Fo9pby0rFIl%2BSWl5ONuSoGUKXfI%2F3usFhjP%2BMonJnY8wtmowlgtTWFMWHiSSvKbtzL22YoYT2jDzGqB8YyvfGJixzOkZhYG7Ai7VXwtPkep%2Bazadh23k%2FOlxLxDJtdKIY6wGmA84yufmNjxDLGEM6Vl4pFTP71YoSzBo8Q8WLVVFyBCAFy68i%2BushpgPOMrn5jY8RBR1ypOFxSVTwqef0G8MTQOjdW3QvtURk%2F7ozoxxfie%2FB8k1sAnrOQZz%2FjMJ3afHU9x%2BQZ2d3eqFH575PY3YSeSRO7dzODjYQMHeyO0sTKol43C4nL62TxE%2F52BMxFphJwF1XegxBSgv0CACTGkpWelznhWF89edT6p5fUL6n4nmlrCgjjllLVLJ%2FigEocEkldcN87L0WifCgk1yNyHtMDjL%2F%2BLn1j9M541mGdK5lN9oZ5vCmQihE5W5lj6upCQXq9S7GYg0coSBwmR7MlkTlrNO4SQJYRc1Guv74vTCsgxqUIxosUCXCNK1EYoQAax4E%2BIeYnVP%2BOZgjxTKZ9YGPs6teaSkMCPfmH96YeHvUkrLCB%2F%2BvU0YSAW4zEhJv18WjRpfUNi2GAEQ8N5xvjEwMDAoC78H%2F7hb365CQltAAAAAElFTkSuQmCC)
+
+```
+constant_def
+ ::= IDENT '=' bool_expr ';'
+```
+
+referenced by:
+
+* constants_block
+
+**sources_block:**
+
+![sources_block](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAYEAAABHCAYAAADhn%2Fs5AAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAFaBJREFUeNrtnQl8TNcex38zmWyyyoYkCEIkQSQhwlMULVq1FM%2BufVqq1tL19XldladKa1%2BaUmpfijaWoho7kcQWCUESkQRZZN9neeecME1sM1km2%2Fy%2Fn8%2FNndx759w755z%2Feu65FyAIgiD0FglVAUGUxtcdKqqFqiE0knRQdSOjKiCIJwk5sZYqQcd0eGE8VUINQEpVQBBEdUZdFHmRESAIgiDICBAEQRBkBAiCIAgyAgRBEAQZAYIgCIKMAEEQBEFGgCAIgiAjQBBE5ZOdk4%2FUtCytj8%2FMzMWdhBRkZeVR5dViaMYwQRCC7btP4uz5KKxZPFnjsTv3nMbsbzahsaMdhgzsjEnj%2B1IFkhEgCEJf%2BH7FbwhYMgVdO3tQZZARIAj95VJ4LLbsPI4HadlwdrTFqGHd4Nq8kdi3ZecJHDp6AaYmxhgxpCu6%2FcNTbL94OUakUV7r11H8X1gkx7LV%2BzBt4qswNJJh847j8PNtibj4ZHHsoP6d0NylIQ4eCWPlXUQRO75TRzcMG9QFxkaGuHw1Fr9sDULC3VT4%2BbTCpLf6wMTYSKvr37v%2FHPYEnoO1lRkKCuSl9iWlZODHnw%2Bx8m%2BjZYtGeJd5%2B07sN%2B7Zdw6Jdx%2FgSNAlBIfewDtsu1k9Y%2BoMtRQaEyCIcpKQmIqRby2Er1cLpuRfgJVlPRw%2FfVXsW7RsL9ZvPoqxI15E397emPFJAP48dlnsu3A5Gr8fCFaXU1BQhIXs%2BEK5Qvy%2FmRmVMRO%2BZ9%2F%2FC1k5%2Bchn%2B1ev%2BwNzFuxAz25t0ftFLxw8HIaY2Pu4cCkab01dxjxyd7z37gBEXIvDx59t0Or6N2z5C3MX7mTGyA%2B9urcrNR7A8%2F2DRsyFrY0F3p86EA52Vhg27lsUFcphx7ZJJBLYs22NnexgYEAPAqVIgCD0kJvR95gnLkOfXt6wZAaAK2iOQqHEGuZB7%2FzlY7RxbyK2ZTCluvKng0LZasPkt%2Fth3MgX1eUNGTsfv6x%2BDx28XcW2ga90glKpwoTpyzFrykDxP6eZSwP49fgAC78ZD5ns%2BT7ektWBWMSOexShcM%2Bfjwlwtu85BV%2FvFupcP49MdgeeRSgzYDwFxMvu95KPiFAIMgIEUePw9oSXVIXXoUJn9m9LtjRFJb8%2Fo3MnN7TzdEH7rjPh6dEE3bp4CKWZw7z3rOw8tHJ1VB%2Fr1tIJMbfva122g73V32mZ5Azhmbdr41I6jJdKcP1GAsIu3sLilb%2BrtzdwsGbRQyHMZSbPLJ%2BXd%2Fdemrj%2Bp3HjZiKOsMjFv9dHpbYX5BfppL20eJIo33%2BbXxprxTNKCX69cBWXqKeTESCIUvi1Riu5BMslSrRhWmMLUx1LDJSIcInC7R3Mqa4khSQwMpRh%2FaoZuJ%2BUjlCmiFeuPSg%2Bf%2F7JCJEu4YbAtr6FOJZ%2FNjf7WykXyRVa%2Fyaeb%2BflpWfkiLRMSSzMTfHJzNfRv2%2FHMtWTkbGs%2BBpz8mBtbfbkOdm1Du7vj7mfjamSdtP0cplhgEFsKzRVSMFHonsyA3%2FQxx3hMhWmBF9DFPX88kNjAkTd8f490EshwVmmTY5lFMElLBKzwq4h8HwUorU1AGXhSsRtXItKEJ73Ky%2F7ok9PbzFAzBVzRx9XbNwapE7nbNp%2BDD0fpoK4lx9x%2FQ5y8wpESocPzD4Pnmri5fF00iP4gOy9%2B2kiFbUi4ADS03PEdrlciX2HQjVeOx84bufZFNt3n1JHBqfPXVPv79vbRwwAR7LrfPyc1QFvP96OvD15u%2FL25e3M25u3O%2FV%2BigQIigBaKVTYoVJhHFcUVXFOrsTfmf69UNKmJkbIyS1AwNIpYt%2BiuePxxqTF%2BP1gCHKYt81z9XyAldOrRzss%2F3E%2FfLu%2FD0MDA%2FRjBkQTP8x%2FG5NmrIR315mQGRoIJb795w8xdcIruJeUBv%2FeH8HG2hxpmTno0N4Vr2pR5pzZozF20g%2FYuC0ICmY8vNq6wNS0%2BC4fPgbw75lDMPSNb2FlXk%2F8VisrM2wOmFUj2vvmTRTwn%2BDTGheZJ7uDtb8%2FRQTlg4b1iTqBrzsOsdXx0EjMqYSyVGV5vWR8QqrIzzs2snnqPp56eTyNo2LWKj4xFZYsauDKVVuSUzMhYVJrZ2NZantefiFS2D57O0utbw%2Fl8LGD5JRMEc3w9Nbj8EiF33pa1uvUhpKvl6zIu4ZZe81mq26sjJdJEigSIPQxDeQJLyjR1iIPA6rj%2FM5OtmXex%2FPx%2FPbKsmJva%2FnU7TwSKVle0MlwLFuz%2F5nlcC%2Bf3%2F3DDcbzroMbt%2FJcZ1XC2v27LFNM4f2ABovJCBB6iFSJIcyP3BwUi3yqjWJ6dG0jFn2At7uvBzaLfgAyAmWWH6oCorajAjqzP0epJvS6ExwV%2FYAgI0DoHxKIQeGrVBP6C29%2F3g%2BoJsgIEPqJvWk27lM16C8P29%2BeaoKMAKGfmJyJp%2FEAfeZh%2B5tQTZARIPQTfnuhiqpBr1GBbnknI0AQBEGQESAIgiDICBAEQRBkBAiCIIhnQjOGCeIplHyuDUFQJEAQegR%2FmFlFHmhGEBQJaEDbl3YQz1dUuixfFTLRcOeZszMiotLGXb%2BV0fJBRqFx8oN8jee0rW8sNzM1TLezMT52My5v3l%2FnckOptYi6Ql2Ui2pLB5XlUb1EaXSdqjj8s%2B%2B77y3esyAqJtOsf8%2FGGDSpCRo61IODrea5OEmp%2BbJ7Sbl2J0OShtxOiBs4oEe9kISU3DGh4bhFhpaozdRVuTCojpM62uOLieMHUq8qJ2vW7RV1yJe7Kfiy0rwc1RdSD5vU7Ut%2FjvywTw9noznv%2B8Df2x4N7E1hVk87f4Efx4%2Fv6GWH4f2bSZUqOF%2BJTJvoYCcJS0xS3dRVf6rMeiBqJ7rqB7VVLrSFxgQINduX7Nq2dtuNoQtnd8S4wS1gZFix7sG%2Fz8tZ%2FpW%2FST0jye8dPECjrQTJRQ2TCzIChDrUDdgaNXTBpx3Q1q1%2BpZbNy1v2pb%2BBTCYN8CZDQJBc1Ci5ICNAiMGuwD%2FvLBjDvJPK7uglO%2Fyogc0lMkhWM8%2BnH9U6QXJRM%2BSCjAABfrfDzdtZZiP6N9Pped4Z6QYjI6lMqcI23zZoUZnySq2o91T6QwTrgFyQESC0I%2BJG2ht9uztVONepCV6%2Bn5c9l1YZFPiuEosu6OFCjxHWZzo7i%2FbPJ7kgI0CUg%2BvRmS26dmhQJed6uZsjX5mypat4QXzlkJpjTi8U0WfyzME7cDLJBRkBojwa9EGBiVPDelVyLg9X60fBe9LDF4NXBtFyJb1aUJ8xkMBTBUSRXJARIMrBg8wCia2Vcbm%2Bm5iUjzt3c5Gbr9DqeOcGaqEyZ8tLlXH9TPhDJEp0pZbUYyToKQHOVJdc3EsploPsXHm5zqULudAWMdOhUxs0OBf%2B7He0atqvUwWVlo1Fy%2Ffi1NlI5OUVwtnRFv5%2Bbnj3rX4wq1fcQJHX72Dp6v0Iu3QLBgZSdOnUGjMmvQZnJ1ux%2F3zYDfyyNQhLvp1QquzZczahZ7e2bGmHI0GXsGrtH8WVIpPCzdUJb47uiWZNS4eDgQfPY%2Buuk7gZfRe2thZo494Ub456Ee5ujfHd0j04e%2F5JZ2TdimmwMDdFBLvOJasCcflKLOu0ErRs0Qh9enlj1LBu1So%2FSoUKUoOyTY6Nis3G2PeDER2XI%2F5fNccHQ%2Fo4afY6Hp5HpYKNpJJmrKsk2Me8mSXs41egQWK9g48HZakwSilF3%2BqSi%2BHTzyHiRiZk7Pjxw5rhm%2Fc9y%2BaNl0MuKqqXH31fnKxIgURfd%2BySGWDa0wrVtF9XqFiNDH9zAVOWjli6YCIsLerh0pUYbNx%2BDANfeSCU6OWrsRg6dj4mv%2F0KPpg%2BEHK5Eus2%2FYlXh32Ng79%2BjkYN6yMtPQcXLsc8UX54RBw8WzcRn%2B8npyM9Iwdf%2F2ckcpmxOXA4FP2Hz8GJA%2FNgU99cHDP%2Fh1%2BxY88pfPHJCHi1bcbKzcbuwHNYzBT7qu%2FfRdSNBLg0sceQAZ1LncfUxBh3ElLw%2Buj%2FYfKEfvhw%2BmAolSqcPheJXXtPV7sRKA%2BLAqKEARjRv7FY3JqZl9FxEx6PaWVcy4UI%2FOXrAWkHDwwJicBOUov6RZYpPmCrKxeu4lJ1XcPi2V64n1qAGV9fxJqt0RgzsDHcXS3LEdBoLxfl1ct%2B7hiskGCJXAHuJRfPeZYUp4WGKRQYzArd%2FXihmvbrivjEVOE9b%2FppFhzsrMS2Js52eK1fR6HsOXMX7sSof3bHe5NfU39v3udjkXj3AVPOv%2BN%2FX4zT%2BnyWzFvv7NdafO7VvR0C%2FwjBxSvRIlKIjUvCioD9OLDrc3gwr5%2FT2MkO7TxdkJGRoy6jibO9uoyS8EimYQNrTH%2Bnv3obN2Kj%2F9mjVgpe0oMCsZ44ohnaulmVt5jKemyJkvXRWcxnWNe%2BNUIuXkMsqUb9wKc1uEDNMlDBvzqvo71HcU6%2FW0d77D6UIAyCuyt0Khdl1cuPlD8LcJxLxsulxgRUxWEILzSeFbqdhwtl2V%2FZNHCwRn3mhfMUyu07SaXzWDIpCovkOHP%2BOgb3f7L9Xx%2Fgj%2BMnr1YoDVWQX8QUffFNJ0ePX0Ybj6ZqA1ASKysz9ee4%2BGScCb5WauEGq3VLZ8Tcvi%2BimDRWdsnfURt5lPu0NDesEdfDIoADKtbBmfSc8PHAC6Qe6zaurjBmOmi2RIINzAMYxsQsqiZcl4W5rJR8VEnGRINe5sqfRcp3FMCv4AbgMWQaChUWRtN%2BXUUGRoYyrF02DZ%2FP3YJ1G%2F%2BEhYUpfLya41%2Bje%2BGlF9sLZSpnMVFDB%2BunGJD6SErJKNP5Eu6lYtGyvcJI7j8UirffeEl46yJdlJQOp4Y2GsvgHn9sXOk71fiYQPt2zTBn9hhh0D7%2BbD2LCuqji58bpkx4Fa1bOdUKwVMwFyImPgfHz6fg8rUMdPGxRRPHejXm%2BsIiMNe3NWIlKuzycUcIW29TGuC8VQ6ig2Ir9x5yomoZxrzj2FZoqpDC4%2BEg8Egmp%2BEyFgGERtYMA8Dh42JbfruD5Rtuwa6%2BMVq5mMPG2qiqjUGxXpbgADNFXz3u%2BWtlBNQxNnCR%2Bal9VRr2y%2BWIYSc11cUP8%2FNtiQO7PkN6eg7CI2%2FjxJkIvDV1GTYHzBJ5eQlzBbKy80TUUMpTZdvMzYrnD7FDxPjCE5XGtkmlTw788HEHXu4H0wept5mxstIzczVe78ih3TB9Uv%2Bn7hs7oodYEhJT2W%2BJw869pzFo9FwE%2F7kAlpblU6ZV%2BW4GHuJ2HvpXcdjrZ4dNi%2FxE3VYEXV0%2Fu6x%2B7E8%2FqVLkjPl5iFpM9N%2FtWrKNGyokuF6T2pY7RlsW%2B2HUzGC8NuEUhvVzxoqvvKtULrheZnXzqlyFoWyt1FSQ7BkCdJp9MYGte7MCA9h65vP2M4d9flkigfL8QGtrM3Tt7CGWsEvRCLscLT5zT%2F346atwbd6o1PEnTkfA17s4KWdjbYG0jGwxGFtS6SenZKoHfTlODW0xa%2BpAFBXKMWL8d5j%2BUQBWfT9JGISOrKwlKwNFmqjkd8qDk6OtWHp190Jzr4niTiOf9uWbLV4Zz7zXtj3smEfz0zxfnApNxdqdsfj423As%2Fm%2FF5rXQM%2FuJmkp59BS%2Fa27if8LQwNYEU8e1QCcvG53JxePXV1Ivs%2FVqE0OszS%2FCeOaov62SIONpqSCO9PFC2GoHK8CdLfEyA7iHRWKWpv26GiS%2ByDzyT7%2FaKO6secTVa3FsuSOUMmfKhFewcNlehF74%2B90MB4%2BEYeO2Y3j3reI7xtp4NoFMasC2BamP2fdHCFJSM%2BDn0%2FKJ8xoayfDj0qm4Eh6LeYt2iW3%2BHd3EIPCkmSuRnJqpPvbYyauYs2C7xt%2ByfvNR%2FLj%2BMLKy8tTbdu49JSKMlq6OtUIojIykGNDbEfM%2Fbgv3FhbY%2FFucmCdAEEQx65hz9CC9EJ9Obo3xQ13g2dJS5%2Bd8ll4%2BfRnhfG1ggJYqFXaw47LYwfHPiwR4IdyCnDNkhTxFsWvaX%2BnwXH88MwAv9PsUtvUtxByAvLwCfDpriPoOnKEDuyA7Ox9vTF4ME2NDKORKyNgFLvtuIjo8NBTGRoZYvWQypn6wGt%2Bv%2BE2UU1SowIpFk0oN6paEe%2FvrV7%2BHASO%2FgUsTB3Eb59rl08Tcgk4vfggHeytk5eSJ65o5ZYD6e%2Fw2Ur6UJPzMEhGp8DuZvv52Gxwb2iA3twA2NubYsGqGmENQ27CzMQZuZSE9oxCODvTYHoLgpDEDwLGtonEAbfTyw22zOrXB%2FCIFPn48MnhkBPK4BXmOcte0XzdGoEF9bGCKmKdn7iWni238tszH4ZO6eK498d4DZugk6kliJfHv0AohQQvVUYVTI9tSqaHRw7qLpSQ81RQZvKxUSoobl7z8QhZFZMLU1Igpw78t%2FZolU575W%2F7h7459O%2F4rIoH0zBwYM4P16LbX2oiFWXHXOXjiPtyacwNNWR1Cv7mbnI%2BQ8DTx2dK8St7cWya9%2FLgxYBI7SW0EWPjQ7HmFaNqva3h65mnKvyTcu9d0zLOMSFkxNTEqdzn8Die%2B1HYmDG%2BGoLPJmLfymli0nTFMEHWR7qOOiRnDHH7ThLeHtc7PWV69XNIYqI2ApoKq0wAQuodPWS%2FroyO6drDDhcDeiLyZJf7XdsZwdk4RVThR5%2BSCzxjOyVPAzNRAPXGsLJRHLiqqlx99X0ZNTVhbGMlTMwpk9jZly%2B3bWBnhH762ZfrOjdhMqnCizslF%2Bwp6%2FtUpF%2FQUUQIWZobpCfdyq%2BRcwZeKx2QkKvAQQkG1T5BcVK9ckBEgYFvf%2BNjJkKrJ%2BB0%2BmSjWKgn4c0AozUiQXFSzXJARIHAzLm%2FevqPx8sIipU7PExOfhdj47Ec9j08CjaPaJ0guqlcuyAgQ%2BOtcbqiRoTRka2CMTs%2FzyfzQv%2F9RgT969TDVPkFyUb1yQUaAECSk5I4J2BqVf%2BV6mk7K%2F3ZNOG7dznrU0aPZ4quUYhfVPEFyUb1yQUaAEISyvlhYpBoy9fOzisru8Lyjby%2FpTUlwUgKcr86XgBAEyQUZAeIxzl1R7M%2FOk09459%2BnVUs3RKKiuVCe6xw%2BLah0R1dhE%2FvbR2WAj6jGCZKL6pcLmidAlCIsAus6uCulv%2By6tWrrbzEy%2F%2FZ26NvdGa1aWKKp4%2FMnhOXmy3E9OhPBF5Nx5GQi6%2BzZpQ%2FgHZ0%2FC16Cf4UwD4tqmyC5qH65qJYHvlTlM%2FDrfLiqo0cx%2B3iiL5TiyYP8VXcVe84Fz3WyUJet%2BzJP542wqzhILUfURuqiXBhUx0nvpuBLvjja4wvqVhWvS52Um4ybjg2xnXXQFmyxZ15KNOv4BazT8uhR0yMSs9mxCVIVglUSXGEWv6lUgmT2zRGso5%2BnViNqrbzVQbmgdBDx7CijODQd7O0JL6kSQ9jnl5kXxB%2FUaqbhq%2BYqFdJZR%2Bdz6YOZl%2FNlCA0CEyQXJBcEQRBEzeL%2FryE%2BHB%2BO3SUAAAAASUVORK5CYII%3D)
+
+```
+sources_block
+ ::= SOURCES '{' source_def* '}'
+```
+
+referenced by:
+
+* pre_section_block
+
+**source_def:**
+
+![source_def](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAmUAAABlCAYAAAAMEJQOAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAIABJREFUeNrtnQd4FcX6xt9z0huBVEiCBBIgCZ2EEJGOQFCKiFxRseUqoCBgQdDLVbnX8veKXhWwgdiuiiA2sAuKorSEIiUkgYRAQknv%2FZz9z2yKQRNSOCUn5%2F09z8luzu6Z2Z3v2%2F3enZmdAQghhBBCiNnRmCPT8FAo1lLAcfHGLWMldo7dx7t2LzqWmHtbwsn8njn5FQ6ZOWXNztOzk0OVi5NdnpeHw44Tp0uf%2BXFPSRztT4ztt4QQYq54aI6411xszZVx7C%2Fr272DRIyIMWr6378dfs%2Filz57LjGlwGXy2K64bt4V6OzjDB9Px2ankZFdZns%2Bo8RrZ2zGjNT009OmjnaOTc8qmR13BCdpf%2BvE2H5LCCHmjIfminvNwcYcmfp544k5MdPavZO88dbn6rnKz7ksrDDY04DyhDbMI3vjqrfjl0wcHWD%2F5IODETXIG77eTnBxbpnOlvvL3w0Z4IUbJ3fX6hUEHI7PnePjpdl%2FNkM5QftbH8byW0IIMTStiYfmiHvNRUuTWh4bX9780fqPkm54fvkQ3DY9CPZ2hjGjTEemt%2BZfUY7O9potEWFglQkhhJB2Gw%2FbWtyjKLMwZBXtug2JNzz3aAT69e5klDxkuqtXRNnY2mrXDaIwI4QQ0s7jYVuJexRlFoTsxLh125nnZgtVbyxBVt9Bb57WQ2MLzeviyWESS58QQkh7jodtIe5RlFkQ8q2SE6mFLrMmdzdJfnNv6g17e62tXsFH4X0RRAsQQghpz%2FHQ3HGPosyCOJaUe3v0KH%2BD9SFrCplP5ABvOTaCLXRYSQsQQghpz%2FHQ3HGPosyCSEguCBoe4WvSPCeM9JMLJ%2FEZPqgPBtAKhBBC2nM8NGfcoyizILJzyh39OzubNM%2Bw4I7VKxpkaPWYQSsQQghpz%2FHQnHGPosyCyCko13i6O5g0zwDfOqd3FZ%2FxtILxKS2rQEZmPguCEELMEA%2FNGffUkdWG9oXvniO40NhOTW03FimpF7Dkn%2B%2FU%2Fb%2Fi0VnoE3IF%2FvHv%2FyEh6az6nUcnV%2FQK9sP1U6LQI7Bz3b7vb9qBT7fs%2BUuaTz82W93%2F1jkvQqfX4fUX74Wbq5O67aedR%2FDbnuOImT0OC5asbfS4ao%2FD1Oh1CrQ2pp39pjY%2FRYGHxowzQFgTO4Qfrl77FbZ%2BtJyFQQghJo6HrYl7l6uTan%2BvZlapw9nwUGy2tcF9DSXa1HZjEdDFE08uvwXjpv5TDVDBPbqo3x8%2Bloqh4b0wdmQ%2FZOcUYtuO3zFx%2BgqsfOoOTLtmqLrP6TOZcLC3xYI511yUZpfO1a%2FO7tufBH8%2FD7z%2B1rd46L7r1O%2BysgoQn5CGjh1d8OCCqep3VVV6zIpZidUr56CzT3WVZlc%2FL6u7ADTVTwxOvBUQQghh3DOMTooMxXSdBi9X6eAp%2Fq2eg0BT3Yw5U6fDdJHop39OtKntxsJOiCopnGrFlIO9Xd02KdCujAxR1ydHD8GUSZGYs3ANhgzqCb8u1b%2Fx9nav26chliycjsWPvIk7bhkLL48Odd87OtjX%2Fa6yokpdDh7QA926%2BliMM6WmlyDtfGmD22zFU8DQgR6tSdbk03IdOnIKH378M3JyixDg54mbZ46sE%2BcffvwLvtt%2BAE6ODpg1YzhGXtVH%2Ff7g7yk4k54lfGKI%2Bn9FZRVWv%2F4l7ptzrepTH2z6GZHhPXE6LVPd97rJQ9Va1m9%2B2C%2FSO4hKsf%2FQIb0x87phqs%2F9fvQU3tvwE9LPZSNycC%2FM%2B%2FtE1UcuRVp6Nj77cs9FDwXyuy%2B%2Fi8XcOyeqDxby%2BDMy8%2BDi4ohxI%2Ftj6jWRf0lHNmW%2Buu5rLL53KrTa6qe3T7fuVsugX1g39f8Dh5Lxv407cP5CLoZGyOOLhr0dKzUJIUSybmMKDsXnI3pkZ1w7prNR4l5LdVKtGNMpCIBSLz7X30mp%2Fr%2FRRJvabk5krVloSFd8%2BW0s7r5jgvpdZmY%2Bdu09ftF%2BfUUgq22uDOkVgIljB2HVa19ixaM3tSsnfOeTVKx6t%2BEpvFyFFk%2FZ0fbHg00%2Fm42b%2Fv48ViybBU%2FPDjgsxNHPvx1VBckLqz9XBdTDi69HUVEpFi1bh5VP3olxo%2FrjwO%2FJqt1rRVl5eSWeF%2FvPjYmuFmVC5L382lb07umPHt07o0xslzWmUngtu%2F966PR6bPr0N0QMDEJpaQXmLH4Fy5fMRBdfD6x75zssfexdvPTsXZc8dl%2FxQLD27e8wJDxYrdWVvLvhR%2BTnF1f7ZlYBuvp74erR%2FZGbV4zHn%2F4QdkJITRo%2F%2BKJ0SkrL1WNfOHeyEGXV94ZPvtiNayaEq6JsT1wi7luyFo89%2FDf4eHfEq29%2BjUdXvKeWBSGEEODX2Gxs%2FfEc%2FH2dWiPKWkRTOqkxMdagKGss0ZZmai4Cu3ojTQTyWo4dPyMC2hcX7SP7lLkF%2F1Eb%2BeB912H8tMdw9%2B0T2pUTTrvaD726uzZcU2ZrGe93nEg%2BrzZBTxw3CB06OKvCW6LT6fGGEDwfv7cUfUOr%2B%2FblF5QIQfKNKsqaw713TcJtN42pS2%2FGrc%2FivdcXI2JQcHX5XTMUer2CuxeuwQPzp9U1i3cP9EXk6Ifw%2FFMxlyxHKf7%2Bdv1Vam2YFGWyGXzTZ7%2FiXZFH7UPEmBF91XN0crTHoAE9sP%2FQyb%2BIsqaQNYBLhTCVtcUS%2Fy4eGH3tcooyQgipoXcPN%2BQWVOAKP9P1wPmLTtLg6yrgX42JsUuKslr0wEERdqKVJrZXVSFFZGr2%2FkZ5%2BcUI6t6l7v9RIui9%2BMzfL%2FmbKwK8MHP6VUK8fYarhoYa7dhE%2BSimLItu%2Fs7w6GjX4DaNRmMR53Hl0N7o3ycQA4ffjz5hV2DksDDMi4lGcXEZCotK1Rc26i66nv7qiyHNxcfbvW5dvulYIERd%2F76BF%2B0jmwsTktKx%2F%2BBJvPTqlrrvfX06oqy8Aq62jpfM45a%2FjRKC%2F3H8%2B9GbsWtfAvw6e9Q1OX7%2F40Ese%2BI9tXk%2BKLAzUs9kIPCKljePJ548iyef24jnXvrj2cnTw01tsjVEE6ap%2FZYQQgzNsnm9zXYflDpJRNxrqxTcIJb6phJq8K4tfvib%2BGG6WF4tElwnlvdfaru49z%2FbkpoyY9zoz57Lwa69CXjkwRta%2FNtF90zBiOhH4OXZwWhOERePy35NpCXl9vI7J4zSfGnK85Ci4p3XFuFCRh7ihDB6df036vrjy2apwlIKM89Obuq%2Bct3V5Q%2BRVFmla%2FbxuDg7qOlJUe%2Fj5X7RNtnULZs0a2uiWoIUWYMHBql9y3785TBm3zi6btvD%2F3wHzzxxK6Kvrq4Z%2B%2Fd%2FNkJRlAauxerirhSPW7Z2f%2B3aIM956T9mYMLYgWbx25mAzale6KbTIkzsOVbsfJM4iyO2CubvPY5EhgNCyJ%2BJDEGvKg3WiPtFX3G%2F%2BFBEhO02ehwLTETqJqBZN%2B%2BWxMOzGWVIOVMMNxdb9A9xN0rc%2B%2FPx1NdJYvm6ox3Wl1UiRgvcpWiQD1lj1pQoq01EqU5kj4gBoVJsiczuv9R2cxq3sLBUrYVY8X8bMHvWaIT17triNLyFGIuZfbXaByhqSO924fSjhnrBybHh%2Fol2dhqLOAfZGd7O1hYhvfzVPlTJpy6oTXxSKA0ZHIz%2FbfhJFdSy%2BfH9jTswtqbpUtaCHUs4o%2FbHkh3yP9u655L5yKZRmZ5s%2Fnx86Y3qd3vjktRaVNl0%2Bsq6rzE8Kkx9K1c2Q367%2FQCuFcfTHG69cRT%2B89KnyM0rwprn59Z9X15ZBQeH6prMzOwCtbP%2BwP5%2FncOtgzhXeQ6x%2B09gxLAw9aWDpJNyOJjq%2FCeOG4zVa79EVEQv9TyqKnX47seDanmZAvUGmohksSo%2FW4OD8Yi7HZboNNg9KAwzDxzDNoYgQkgt4r4wTqdgk4hCL%2BRXYvKJEyiv3bbPSHk%2B%2F2Yi3v0kFY%2FcE9IqUdYSmtBJDwzti2fFbXppY%2BKsvijb1ITY2mRqMSabjm6d%2B6K6PmXWU3j9v%2FeoNQ%2FqmT26Xv04Ozmgtwja9829FrNmjLj4gD%2F9Vf3UZ8uGf9SlUZ97YqLVjtjthVGR3urHkpGiau7C%2F6piQ%2Fa7Ki4px7pV89VtLzwdg9vnvYQt38SiuLhU7ev14IJp6rZxo%2FtjzdqvED7qQdjZ2GBSMwTKi8%2FehXmLXsWg4ferNVJSCG18ewkW3H0NzmfkIurqh%2BHR0RW5BcWIGBjcbFEWLUTT8n%2B%2Fr75ZKc%2BhlmWLr8ddC9bA26uDKs68PNwa%2FL08loXzrsWt815UHx78u3jWvagiWXzvFPUNzsixS%2BqOb5h4DDWVKPszNTfYJweHqF0bNolDiWKNGSGktoZMCjJFwW37j2OrqfL9ZV%2BW2kIUc0Og0Z9Tm9JJNd81Ks40NdVuJSKR10QiDTZDNrW9pchqvthf1rd7B4wYEVO3bqhmv9gvppj%2BPKZuMfx5tMD%2BcigJ2b%2BrdqiTP2%2Bzd7D9S7OjbAqUL33ImiZ3d5dm5yVrrWSXu%2FpDpEjk0BRZYpsUUU0Nh9Fc8vKKUSgEpXwLsymycgpQWaGrG2evIQErx%2ByTtYT1h44xp98KO8vRb0eKNCaAEGL1iHvCd2Lxs7gnPGmqeCiHhho05QfMvzUITywMM1rca61OkoPGSnEmMpgn8qkep8zWBt0vlUhT2wkxJgH%2Bni3eJvuINUfs%2FBnvRvoVylqu%2BunJ2R9Wv%2FFVo%2Bk8cv8MhA8KumResjlUfprDn0Xin5E1xs7%2BDm3Kbm6lWFnohPlyQt8DR3GInkyI9aJO7K1HP3FfmGrKfHfGZsHeXot7bulh1Hxaq5Pq15yp6dT7sqkfETMjp34w9VRLRcWVLPgGGD28r%2FohjfPTKZSFh%2BGDmgl9KcoIseb4Je8DGnwg7wumjIeTRnXG6Chv%2BHo6GjXuXa5Oqv09JyS3IDq62Vdl55ebNM%2BkUwUseNJ6FGxXgCtZEIRY%2B61A3AfE%2FcDU8dDdzQ6dvRxblLY54x5FmQXh5mKXl36%2BxKR57j2UpS41CgrRzFeVCalFPMgeFc%2BxvVgShFg38j4g7weWEA%2FNGfcoyiwIz04OO3bGmrYl%2BfudZ6ufcjTIEAs2Y5MW4VSk%2Bow3S4IQq8e75n7Q5uOhOeMeRZkFceJ06TNfbk%2BrqqjUmyS%2FlLRCnEorqvUUOQ7VaVqBtIRdaWr%2FEUeWBCFWj2PN%2FaBNx0Nzxz2KMgvixz0lcfZ22tgNW1NMkt%2ByZ%2BP%2B%2BEeBnEn7e1qBtBA5yrWGxUCI1aOpuR%2B06Xho7rhHUWZhpGeVzF63IbHscEKuUfP5zxtHcDK1sNYxk8UnXK%2FFZlqAEEJIe4yHbSHuUZRZGHHCZyoqlRkLHt%2BtM5Ywk465sf7ThwY7xSPOPo41RQghpD3Gw7YS9yjKLJA9h3VfFZVW3T33kd%2BUVe%2FGw1Bt6rIt%2Fcb7frrYMRW8L%2F5OVGzwMEueEEJIe4qHbS3u2dKklsn%2BY3grIlSvfW%2Fzydc2fJFiGzXQC9GjAtArqAO6%2Bbk2K42SsiokJBdg78FM%2FLDzrHDOoot3kI6pwViNBnfGiicSljohhBBLjodtPe6ZTZTVn1%2BPtI7YeLw5uI%2BSrqvQbdqx94KN%2BDgZJGHZlq7BTrEWrWhxe9xRfEP7k7aMEjvH7uNduxcdS8y9LeFkfs%2Bc%2FAqHzJyyRl8w8OzkUOXiZJfn5eGwQ77FJTsNsxQJ%2Fd%2BK46EJ4l5zMOtbUXJCUWu5aAwxkXej5dgXQdBhpSjNEULdnxNfuSsaeIj%2FmzsTd5E4uEyNgkS9BiWKgkitBntk1W2cEZ8UrMn%2B1uy30s7G9P%2Fv3w6%2FZ%2Bu2M88lphS4TB7bFcMjfNDZxxk%2Bl5hWJSO7DOczSrAzNgOf%2F3C6ytHeJlZ2Go5jjTCxMCzF%2F419H2hFPDRL3GsKG3M6k583nrCWC%2BdcFlYYLe0M5Ir0P%2Brsi2%2BFg0mn9xEOaCfWOjQzCXv56q9wXDnh1y7hlMv3H8PLMl3a37oxhN9KOxvD%2FxXlCW2YR%2FbGVW%2FHL5k4OsD%2ByQcHI2qQN3y9neDifOlGALld7jdkgBdunNxdq1cQcDg%2Bd46Pl2b%2F2QzlBC1P2jqW5v%2FGug9cRjw0S9xrCo4fRAgx7pOrkZ6QP3qp36b1HyXd8NyjEejXu9Nlpyff3pJvcZWUVs2JPYb1tBxpy1ia%2F5uqpszS4duXhBCLQzbZrNuQaLCAJJHprF4RZWNrq103KAzs9Ejo%2F4SijBBCLoXs1Cz70MyeHmSwgFQ%2FMN08rYfGFprXI8IwiaVN6P%2BEoowQ0q7iCAzYVUK%2BZXYitdBl1uTuRjnYuTf1hr291lav4CO10zAhbQgL9X%2BDTrFEUUYIIa2n7MoAw01Kfiwp9%2FboUf6wtzPO7UumGznAW0YRW%2FUtLkLaEJbo%2FzXXfxmtR1FGCDE%2FmaWu8DVUYgnJBUHDI3yNesATRvrJhRznaPigPhhAE5K2giX6f831n0nrUZQRQsyMAiTaaNDHUOll55Q7%2Bnd2NuoxhwV3rF7RIEOrxwxakbQVLNH%2F5fUv7wO0HkUZIcTMaIBdctoSQ6WXU1Cu8XR3aNFvsnLKceZcCfIKKpu1f4BvXdCTc7SMpxVJW6G5%2Fq8IFSR9Xn4qKlo2H6TB%2FV9OWyTvA4SijBBiXvRabIaCm0cHGqZfmV6nQGvT%2FPcGklKLED5tG8bc8rMaoJp1Y6xJXwQ2D7G4glYkbeZ6aqb%2Fa8Qu%2F30rCYOnbsP9Tx1qmTAwoP%2Br1724%2FtX7AKEoI4SYlwNHISPC4UInPGSO%2FBf96xBKynRYuaw%2F%2BvV2b%2BEDvlpT4EsrEkvkuaX90T%2FEHRu%2FSsP3v15o8e8N4f811%2F3hmvsAoSgjhJgbGwULxOKBwSGYbMp8f96bhX2%2F5yBqoAeum%2BDX6sOnBYlFXnc2Gjz9YF91%2FYV1SSb3%2F5rr%2FYGa659QlBFC2gJ7j6uT%2Fs7UaPBueCiWBwfDwRT5fr3jvLq8eSpbIIl1MlQ8kPS4wgVxR3NxPss0o1LI61te5%2FJ6l9e9vP5pieZhyyIghJiCA8ewLTIEUVUarHG3w%2FzBofgQCrbb6HEsMBGpmwCdofP8PSFfXQ7p34kGIFbLkH6dkHy6GEcSCtDZy9Hg6c8EbE71QjedFmE1nfpvUoAjtgqi4uIpyCjKCCFtkpon5vFy7COtguvF%2BkK9DXomh6JbOAw%2FWXFuXoW69Ox0eRVzcjJlWo9YKl4e1f6fk19hFP9Prh6tP1VcwEniKt6l1yCafcgoygghFkLNDbtVN%2B2WCCRX1%2BpbXGmZDp062LX6eMXTvqaVNQXz2XRDaokMQS9ZUyz8o6%2Fwj1bVFLfmAaGkpDppFydbo%2Fg%2FoSgjhJAmCfR3EQIwD0cS8%2BHn42i0fNSAmigrDNTP1uBgPOJuhyU6DXYPCsNM2XRLa1g3wg%2FG6RRsEurmhfxKTD5xAuW12%2FYZOW%2Fp%2F5IeXZ1piDYOO%2FoTQtotY6%2F0Vpebv043ab4y4MbF40lFwW1aEYhlDQmtYb1I%2B0s%2FkP4g%2FaK%2BIDM2qekliD2Sqz6UhAR1oDEoygghxDxMn%2BCvdmzesv0c4k8UmDz%2F%2FcexVSxe0GmwmtawXmrs%2F0KNP5iU59YmqKP7z7s5SB1QllCUEUKIWXCw1%2BLph%2FqiskqPex8%2FgMLiKpMfg1spVopFP05sbp3U2L1fjR%2BYlE%2B%2FS1cHjg3r2QExMwNpDAuAfcoIIZb1JGmjadFUS1PGdcG7K4cgv7ASaedKEBrcdBNOUXGlwY73p1MoCw%2FDBzUTO%2FONNGvzV2l3DT6QfmBK%2F5e1Y3rxefmxgRg22FN9QGkuhvR%2FQlFGCGnHdHSzr8rOL7f19mh%2Bx%2F1Jozq3KI%2BkUwZu6lSwXcTHxbSe9SHsfqVGwYum9n%2FZVDljon%2Br8jC4%2F5Pmi24WASHEknBzsctLP19i1Dz2HsqqDmwKCmGAQW11Co6KGMnO%2FlaItLu0vzX7P6EoI4S0Uzw7OezYGXvBqHl8v%2FOsulQ0yBCLy87MqUhNw5vWs0q8a%2Bxvtf5PKMoIIe2UE6dLn%2Flye1pVRaXeKOmnpBXiVFpR7R1Sjjt2%2BnLT3JWm9idypPWsEsca%2B1ut%2FxOKMkJIO%2BXHPSVx9nba2A1bU4yS%2FrJn4%2F74R0GxrDgwQLJyFHYOSGCdaGrsb83%2BTyjKCCHtlfSsktnrNiSWHU7INWi6%2F3njCE6mFtYGpGTxCddrsZklTuj%2FhKKMEEIaIE7EjopKZcaCx3frDBWYZEDaWL%2F2QYOdGmAfJ1Ym9H9iKmxYBIQQi6wtyFCSPDvpz3y9PW1qSblOMyjMEzY2LW8hlH1o5v1jF3buq9efWcH7IihNEHfIm85lwCBRz88bT5zLwgpazrowlt0tzf9J8%2BA4ZYQQi2X%2FMbwVEarXvrf55GsbvkixjRrohehRAegV1AHd%2FFwb%2FE1JWRUSkguw92Amfth5VgSloot3qA5IYzUa3Bl7BCdZyoT%2BTyjKCCGkGcTG483BfZR0XYVu0469F2zEx6lVCck%2BNBrsFGvRiha3xx3FN235vMNDDdd5nFxMXLzlvJRhrf5PUUYIIW21xkAEkPC%2BGAgdVorgMkI85Z8TX7srGniI%2F10a%2BVmRiLyZGgWJeg1KhMKJ1AKuii2G7beQGoLYX9bT%2BAYmYkQM%2FZ81ZBRlhBByOcRVB5LpcgLomnkmJ0Avnv01jQYlV0VBnghcHcX6XsUGK2LZqZngj1pIS6oxo%2F9TlBFCSJuj5m0x%2BXmMpUHo%2F8SS4JAYhBBCCCEUZYQQQgghhKKMEEJMB6dasj4MOsUSoSgjhBBiGMquDOCk5NZEjb3LWBKEoowQQtoWmaWu8GUxWA819s5kSRCKMkIIaUMoQKKNBn1YEtaDtLe0O0uCUJQRQkgbQgPsktPXsCSaR25uEQoLSy3d6GNVuxNCUUYIIW0HvRaboeDm0YGW06%2BsuKQcm7%2B4WFPI%2Fx976gOj5%2F3kyk146%2F1t6vq2Hb9j0dJ1Tf5m%2B8%2BHcSY9q02UnWpnYW%2FV7oRQlBFCSNuhZlDPw4VOeMhSjjkrpwBLlr990XdhvQMwZmQ%2Fkx5Hj0BfRF89uMn9Vr2%2BFYcOp7SJsqux8%2BEDHCWftACO6E8IISbCRsECnQa7B4fg4P7j2GqqfIuKy%2FDGW98i9uAJdOvqgzl3TED3btXvHHzzw364uTrh0JFT%2BG3PcYSFdMWie6bAxdkBmz79FTq9Di%2Bs%2Flzd92%2FTh6O8ouqiZsW09Gysfec7JJxIx6B%2BPTAvZiLc3atn9nnrf9sQGdETW7%2BJxUEhlq4aGop775oErbZlI4NUVemRl19c9%2F8vvx3D51%2FtUc9Lnsdts8YgJfUC0s%2FlYIvIK%2FHEWfTr0w3jxww0i52FfSeLxQPC3lH0etISWFNGCCEmYu9xdfLnmRoN3g0PxfLgYDiYIt877nlZFS0L7r4WgVf4YNqsp3H%2BQq667Wshyu5e9AryC4ox9ZpI%2FCYOctnj76jbfLzcAXGwXf291I%2BDox1%2BF%2BLt86%2F2qtvz8oox7ean0amjKxbNm4zsnELceOdK6HR6dft6IcruvHcV3Ds4Y3J0hNocufHTnS0%2B%2FqSTZ%2FHh5p%2FV9bgDJ7Hw4bUYM6IfZky9Ugg2HfYfOokOIg8Hezt4eripxyqPydRIe0q7SvtKO0t70%2BtJS2BNGSGEmJADx7AtMgRRVRqscbfD%2FMGh%2BBAKttvocSwwEambAJ0h8zv4ewoSktKw4c0HYWtng2FDQ9Raqw8%2F%2FgX3z5%2Bq7nPv3ydhwZxr1PX%2BfQIRfcMKPP90DEaN6AsbjRYzp1%2FVYNqbt%2BxCSE9%2FLL53ivp%2F1JDeGDZ%2BKXbuiseo4dUvmv5XpHNVVKi6nnLqAvYfTMasGSNafT7x4lx8vN1x9ZgBqgirXxvm5emGYZG9hQAcYhJbzgRsTvVCN50WYTWd%2Bm9SgCO2CqLi4inICEUZIYS0eWpqUMYP6oMBWgXXi%2FWFehv0TA5Ft3ADj%2FqfnHoBPQI7q4Kslt7B%2FjiZcq7uf029HIMCfVFZUYXs7MIm05a1bz2D%2Feqlo0HPID8knzpfJ8rqN1V2cHNGTm7RZZ3PtePD8dEnO9EvaiH69%2B2OsSP74e7bxsPO3vDhLDz00qPxJ1eP1p8qzjBJWG2XXoNo9iEjFGWEEGKB1ATwVgXxpgRDLa4ujigsunhoCfm%2Fq6tTg%2Fvn5BXBxkYLd3dnZAlhpijKJdPOyi74a9oujbxgagC52amTK7Zs%2BAdS0zKx%2F%2BBJvPjKFlRWVqn94CSKASc1iovntFjEtLBPGSGEtGOiInrh7Lkc7Imrbk2T439t%2FXafWsNUS0FhibrU6xWsWfsVRg%2FvC2cnB7i7OaGySofTaQ0PMzF2ZH98t%2B0gMjLz1f%2BPxJ%2FGkWOnMWJYmNHOZ9e%2BBHXYi24B3pg%2BOUptMq2tfZM1cSeSz9HoxGJhTRkhhLRjZAf4l569C3PuewXdunmr%2Fbpkn676fbE%2B2bIbH3%2B%2BC%2BUVlerbjOtenq9%2BL9%2BinDVjOCZMfxwuzo5Y8%2Fzci9KODO%2BJu24fjzFTlqNnDz%2B1SfTZf92Ozr6djHY%2B2dkFiJm%2FCv5dPKHT6eDoYI%2B3XrlP3XbHLWMxb%2FGravPm2FH98fRjs%2BkAxKJg1SwhhFggsvky9pf1zd6%2ForIKFzLy4O7mrAq1WhYtW4deQX6IufVqFBSUwNen419%2BK8cr02q08OjU8BuNsslSDlnh7dVBFUnGRr7defZ8jtrRX3b6r09pWYXaHy7A37NVaUeMiKlbZ%2FMlMTWsKSOEECvA3s5WHSqiMZwc7dVPQ3h5dLhk2nKcM7dG%2Bqg1xI6dR7HqjS8b3b508XQMGdyz0e2yz1tj5yLPobWCjBCKMkIIIWbjlpmj0MHNyaR5yjcza9%2FOJIRQlBFCCEF1vzBCSNuAb18SQgghhFCUEUIIIYQQijJCCCGEEIoyQgghhBBCUUYIIYQQQlFGCCGEEEIoygghhBBCKMoIIYQQQsif4eCxhBBiodSfp5EQYvnYsAgIIcTyOJeFFfLj540nWBrGK2OWAjElbL4khBBCCCGEEEIIIUTy%2Fyr0xHnKKM%2BPAAAAAElFTkSuQmCC)
+
+```
+source_def
+ ::= IDENT '=' source_value ( '(' option_list? ')' )? ';'
+```
+
+referenced by:
+
+* sources_block
Comments:
@@ -663,59 +170,20 @@ as `source_name`, however, the grammar can't be defined using this type of token
no rule to distinguish between an identifier token and a source name token. So the grammar uses
the `IDENT` token instead and documents this fact in description, that it's a `source_name` identifier.
-
- source_value:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
+
+**source_value:**
+
+![source_value](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAYkAAABRCAYAAAAnx1pLAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAGh5JREFUeNrtnQdcFEcbh%2F8HRxcUAQv2LooFsPdoLFiI3WiMGnvsJbHFxBKjH5YYuzGWxN57iwaNFVFQEdRQBFGwoRTp5e6%2BmTnuAAU5lHbwPv7W5bbM7s6%2B87aZ3QUIgiAIIhMkheEiHGygoFtZtPB4WDhklyAKOtLCciHuV7bS3SwiNGo9nCqBIPIIHaoCQlujR4ogCYKMBEEQBEFGgiAIgiAjQRAEQZCRIAiCIMhIEARBEGQkCIIgCDISBEEQBEFGgiAIgtAU8cR1U1uUdvPGy8w2ymq9NhEWHo1f1x3DtRsPEReXiPLWFmjWpBa%2BHeGIhc778CjwRYb7dfqsAdq0tMXcRbvUy6pVKYP%2BPVvCwa6a%2BH3%2FvyeYt3ivev3yRcNQuWIpTJm9BcEhb7DaeSSsy5YU67weBOHPXRew4pdv1Nv7%2BIXg921%2F47bnI8hkClQsb4kWTWtjUN82MDcvluW1fTNuNWZO6Y3aNcunW75hy1m4XLon%2Fq5QzgI9uzXDmk2nMi1n75bp%2BOHnnXj0OP0tNzLUx45NU%2BD36DlmL9iRWg%2BVS6NvzxZobF%2FjvbL4tYeFRWHb%2BknQ1U31SX5de4xdn5XYjyCInOdT9bZqf2EkkmR45mCDQ1JdTMyo0KzWawsKhQIDhi1DjWrWWLNsNMxMjeHpFYid%2By%2Fhi65h%2BKp%2FG8TExCsV%2FOqjqMqMQO8ezcTv0qVK4A1Tdt5MuW9bPxGJiTLccPdBn6HOOLlvLmxtKqJ61bKYPbUPnAb%2BgosnF6FcGaVB4MfQ0ZFgBVOMKqPw9m0sPL0fq8%2Ft4hUvfDt1IyaO6Ybxo7pCT0%2BKu%2FcCsH3PRZgWM8KQgZ9leX237vjjbVTce8u%2F7N2KGccoYcRmsfPTYcp6%2BgSnFMP2lBnN49iyZrx6e12pDu7dD0K71rZo06JO6nJdXTGPjo4T17T998lIYsLh5uGLfqxej%2B2egwa2ldXb%2Bwc8x%2FmLd2FsZIArrg%2FQrpVtqkH0f8bqhAJZgsgtPlZvN7FBL5kEq5NlsGA%2FjYWRkCjTTv1kMvRihR55t9Cs1msLwc%2Fe4IHPU%2BzaMg2lLIuLZdxb7%2BHYGMnJckilqUqrZElTVGDrmjeprV7GjQRXoKplbVvVxTW3h7hy%2FYEwEgb6eihbxlysK8ciFD391FdjTRrbHTN%2F2s4ili7CmKQlmd3N7%2Bb%2Bibkz%2BmNw%2F7bq5fzcnLo2EdHPp8CjkOJmJiwSMBDGjmNlYaZer89uaNrrVMGNaUbLlQYjtR7atKwLVzcfXL52P52ROHTMFd07NULx4ibs7%2BvpjARBELlLdvW2yjjIFCif9oU36Vw5hTL9xAsNZoXu5%2BFGdtYXdLiC5Apz9caTCHr6Kn3eTZp9r5Yr99ehb1GxglWW23KjNHTQZ1j62%2BH31t3xCkBERAwG9GyZ4b4lNUg15QZ%2Bj57B9eZ%2F6ummh1%2FG9cAMbOgbXg%2BW6aK2wydd0fuL5iIaO%2FvPHcTEJlDLJYi8zqBkobe5cXCog6cy4DC4gXgHaRaFCguU1XptiSz09aTYunYi5i3eg207XWBqagT7BlXxzVcd0PGzhhqVER%2BXJPLpnBvuvrCpXQGd29tptO%2F4kV3RvNNM3PUKTLf85asIlLIyU0ceSYnJOHrKTb3ejp3ju9FHXnDmvAdu3fZX%2F1b1SXASElLr4eZtP1StXBrdOjZSb3vjlg%2FzZCRoYl8DEokElSqWwum%2F3dGvV0tqtQSRv8ZCqbclOJMMLHw3ctDISKiQA3eZf91FkcX65GQEsoMaaUNFNXGogTOHfhKeu%2FfDIJErHzFhLXZvnoZWzetoXM7TkNd46PMULid%2B1jgKMTMzxrgRjvjfykOYOLqbenmxYkYIj4wR3jdXqMlyOa4zz51z6dp9TB7bPV%2BMxKSxPdR9MpkR8jxMdMK7HFsIqZ6uevnBY64iXXfw6HXx27qMOQ4ed81xI0FvgiWI7MH1tgTolqxAXzaXZ9WAMjQSbMfrbMcQNv%2BcFbiZzad%2BaD1z0J1VkUQ%2FQPdxTVSS6aAO27A922Yg29ZbqsB4pvd8c%2BOiP0ZRlChhIowCn257BuD2vQCNjIShkR6mTfhC%2FD1tzlYMG7sKh3bOEl62Jgz%2F%2BnNs2fGPME7qSKFeFSTEJ4m%2BDZ7f52WtXDJCrBs4YkWBFDQDg9R6kOrqYCirh8O7ZsPE2ADxCYk4dc4dn7dtoDZ2vI%2FnyAlXPH8Rru63yQno40NEUaRJbdRMlmAdE35bpvz2MA14QVeOB5V9EXQAkGWkF9PqbTb%2F3VAPW5naGc5c3JEKCSIzSjVxdN4thM0OsAJs2BQs1YXN7YeYltX6tKkmfoK3fBFw%2Bz%2Bc5Osik1CZ7XdJJsENuzrokJ8Vy9M8cxbuFFGACj7ih4%2FwaWxXPdvlOc8fIkbujJ%2F%2BO%2BRyzewUNwBTxzlhy%2FZ%2F1Mt4x%2B6Y4Z0xlRkd9zup6R2ubKNTRlsVZH75cbC4hm%2BnboBMJsc5l7uoYG2JtctHC2PHp9%2FY1Ni%2BJo6cvEEtnCA%2BAa5HuT7lepXrV65nub7leldlIDTR69fvwZvPdXVRQ6HAAbZdFNs4%2BEORBC%2BEWxg3PVZIBn0MWa3PEH9%2F8N7KRfa1RWrqALOAzXIrosiKMqVKIJgZiNaOc2BhbipG6MTFJWDOtD6ZjuL5ELwP4Y%2FV49F9wCIsXLoPTl0aYwxTlJz2PeZix%2B9TUbO69Xv7DezTGhu3nk23bMbk3mIE0sgJa0XKiXvqEZEx7LxqiRSZpvT6akm6319%2F2U4Mod114DISE5IwaOQK7N48XaOyJn6%2FSUzqtJiJIXw81r8fjjKB%2BGPVOFYPv2Dekj148jQUPbs3fW87vmzbzn8wbqSj%2BL1s9RExqahauQyunF1MWoAgPhBByJhCZ0p9CDcMGuySpd5OWTatqS2ck2SY%2BW5kIUkJS2JZIRtZIc4ZFZLV%2BmykheayWRuPh%2BiU0%2Bmm7Hy%2BlHcMvwiNEH9XKGdZ4ATh2fMwyORylLIqLobVEulJ%2B%2FlSSjcRRQmm686x2WUm94s02Paj9DYf%2FcSNBWtYY9lxlM9JsPCjyocKyWq9ppjGYXmUEcbb1UWDO%2FfhmV8VzSOAgmgcVKieyk7LfOahez98mnG9FjMUTzQTBFGI00xMb0KOekyPOmmy%2Fcfq7bSRhSgnzcKsdvpk%2Fn2MeIc62K0jRx%2F205Nuu%2BbMnz2QKoEgijBCb0qwm%2BvRbCj7j0a1f96%2FF0GBCywEak63nCAIIjuqk%2BlNpj%2Fz3Djl9QFlCtyXADXplhMEQWgO15tcfxZ6I2EULUIYK7rlBEEQ2cIqRX8WbiPhGizyaYZ0vwmCILKFYYr%2BLNxGAiK1RsMWCYIgsokkRX8WeiNBEARBaAlkJAiCIAgyEgRBEAQZCYIgCCIHkRaWC0n7Ph%2BCIAiCIgk1%2FCVv9KI3giAIMhIEQRBEHiItTBdD0QRBEARFEgRBEAQZCYIgCIKMBEEQBEFGgiAIgiAjQRAEQZCRIAiCIMhIEARBEGQkCIIgCCIjCsXDdA42ef8hjoJObj9YqHAfrXfQ9cbkB77hQ3weRdYIi0w0CA2Lz%2FSYFuYGySZGehGWJQ0u%2BT%2BJW3LRLdaD5IIgeSYjkWe4X9lKLSmF3H7Z4fk%2FHb6dsuroMt%2FAtybd21dAz7EVUaaUMUpZZP5V2ldv4qUvXsVaXnV%2F1Sco5MkXTu2M3UNexw728MYjkguC5JmMBJFP0VVOemAKxXyd%2FasP7Vu60bvv4N7VsHR2Y%2BjraZax5A2OT%2FVtSmLklzWle08GNtu819e7UT1Fb3cv2Rm6YwTJc8GE%2BiQIjeENaus%2Bv74r5jbGkF7VNG5Q78L34%2FuvW9jM0FhfcqJRHdB73gmSZzIShDbDQ3LmKfVdNqcR6tUyz5EyeTlrFzTTlUp1NtuRoSBInslIENoJ79Q76fJ02WDmLeVUg0rbsAZ9UVUiheR35oE5Um0TJM9kJMR9YhO91ltL4KM%2B%2FIOiTL7sXiVXyh8zsBb09XWkcgX2OdiiGtU4QfL8HpIUvVlkjER88%2FIwJHHVDh74hQ%2Ft0rbcR%2Bdss4KX26SBFW8FUsiwnGqcIHlOT4q%2BjC9KRiI0rhhKk7hqBz4Bb6u1apS7t6tTG2s%2BM2JTK7u6aEC1TpA8p5KiL0OLjJFgMZOvrgR1SVy1gzdhCYblyhjn6jHqVC%2BhCqpf6cjRh2qdIHlOhetLrjeLjJFgYZgr%2B689iat2EPY2QWJR3CBb%2B7wOS8DT57GIeJuk0fblS6sbbTE2daRaJ%2FJbnhVMK3MZ5lNiojxbx8hxeWb6UujNfCBfHqaT6%2BAQs65n21XGD%2F8%2Bzts827Q5W%2FEk%2BHW6ZWamRti6biL%2Bt%2FIQTIsZYfyormmU3VtMmvEHxgzrgjWbTmVarvOCITj7z21cvOL93rr1v45BieImGDTiV%2FWysqVLoGunRnDsaJ9axsrDuHXHH3Om9YF9Q2V%2FV%2Bibt5gyczN2bZ6Wb41KLlNAR1fzcQZ%2BQdH4fPBl6Onp4MiG5ihhVjxrbyWlfNYwS0ryQS4HjliB2aze69etnOW2B45cQ4%2BujWFooF%2FgFOCr0Ejc9nyELp%2FbkzX4RHmWsE1WbvPDjiNP0L9reaxbYKe5952D8sz0pGGUAoOY3uxSZIzEnfvwdLCBV5QRvmM%2FF%2BXlsT29A9GNKefmTWqlVoJUV8wH9G6FLr0XoEWT2rBrUFUsmzVvO2pWL4dG9tUxfYKTWBYVHY9vxq3GlrUTUNxM6TGULlUC%2FgHPUdqqOAYPaJvumHwbmUwO15v%2FYcOvY2FlaQav%2B0GYOmcLYmLi0bdnC7Hdf37BCI%2BIwuIVB3Fwx0yxLCE%2BCW7uvlrVCCcv9ERsvAx%2F%2FNgQ9WoVz9a%2BEqXnZZTX59zHqTm7dyU08C4VmDJ7C9q2soWhVcEzEr7%2BIXD%2B7TAZiRxi2cz68HwYif2ng9GzkzU6tiyd5%2FKcoie9uN4sMkaCo6vABJkEN%2Bxr4%2B7t%2F3AyL49dq0Y5ZiRqv7e8SqXSmDm1t1De544uwIkztxDw%2BCXWrRgDA3099T7h4dFizg2HZUmzdGWUs7bIsOy4%2BEQxt29QDeXLKbd5%2FDSURR5eaiPB%2BXrAZ1i%2F5QwuXPZC%2Bzb1tK5RXb75GrfuhaFZw5KiUX2seOT1eb8Ji2Keo9L7%2B9vljogoffxCxH2oVNEK30%2FsieIsGjxw9LrYZuPWsyhmYoguLBKsU6tCluWfOX8b5y%2FeRVJSMpo2roV%2B7J5zmbru9h92H7iMaOYsfN6uPr7q31acR2RkDP7acxGd2tvhj7%2FOIfR1JL7%2Bsh06ftZQqTii4rCJLefnWMLMBG1a1kG3zo1w4Nh1vHkThV%2FXHhPbjRrWSVzLh0hITMLWHS7CieEOzbBBHeBgVw1BwaE4xK531FBWhqmyDB4ty%2BUKFgU74Pjpm7BiTtGt235wu%2BWLhvWrYOKYbiLCevkqAsdOuTHZbinmMrkcI4doXxZRl0UEi6fbovuoa%2Fh1s1%2B2jcSnyjPTj915AoTpy2b5VQf59jAdk0dfuQT9WHvYzqKKudWrwyCvjs0bFm8QqokLuYpvvuqAUsyjnD1%2FB3523oc1y0aJxqwpIc%2FepCubT7wRZsTzF2GoWN4q3TIDAz1MG%2B8E55WHhNeqbZy59ELMBzlV1Krz5kr%2FxatwtZEYPn4NnrH74%2BTYWER9Py%2FbL9bxKJBjXbYkKpSzhIlx1mK7YctZER1yo9%2BhXQOcOeeBx0GvcOX6A4ybtpEtq4%2Bhgz7D3sNXRcqTE%2FE2BktXHcGcBTtEVNvYvgZGTV4v5IszbvpGPHsexuS1vVDO3AiJ87Mwg1RPV5wbn1RR8ocYOWGdiIInjO6Gdq3rYdi4VQgMeolKTDYf%2BDzF9B%2BUL0m8ey8QcxbuVKfkjp%2B5idGT1iEhIQlOXZvg%2FAVPzF%2ByVynbL8PF%2Bfcb6gz%2FwOfCcGkrTZnDU7WiCTzuh%2BPF67zJjnN9yPUi149cT3J9mV%2FXn68v%2BLvzAC7MoW6WLMG64noYb2%2BDPVDggq4cDyr7IugAIMuN45782x3Xb%2Fqof%2FM%2BCd4IlXlICZbM%2BxptHOdgGGuAdWtnT9nxPoWXoZHplvE%2BCZU3t3n7OXY8YxGhBIe8wYpf3n96vx%2Fzvrhi4Y3QoUF1rWpQ93yU1964vjm0mbHDu2DKuB7ib%2B5Fc4XHadfKVsydHJswZyLrVFpyshyrNp7A7j%2BmqfuZenZrKrzxRczwjGeKuVd3pZNY3toSjn0WYDqLWjj6elIc2jlTHeEcPXUD95jB4tGq98MnWNirlYhI%2BTSoXxv1%2Bblcuod%2BvVpqdJ13vQLxKPAF%2Fto4GTo6EjRxqIEbt3xwmhky3je3cvEIOPZdiFUbTmDf4WtYs3SUiIRVTJ%2FQU7QTodiqlMWgkSuw%2BKevlQ6PoR6O7JwNMzNjaDuN65kj4EkMvH3eooxlzj%2Fi1Y9FG49ropJMB3VSOqkHMhfRW8oiCI%2BHyNd8c76%2FBTbFQnbkY4l1FOjN%2Fp4k10WNABtUcsilp7KnT%2FhChOaZ8dfuC8Jo8HB68tgeGikDFVwBzJneN9N0Eyc2LgGnmKE6uH0mSpoXyyDE1cGMKb2xePkB7N7yaR3Wef1NhfAI5XVamBto1Xm%2FF2Kn6djkKZikpI%2FzV16y6ISnht7tEOcK%2BVHgS5HKUVGjWlkkJiWLCFPlsKgMhNKZ4X1byvPghoQPwuDGy75hVQwf%2FDka2FbO9vn5%2BT8TqaEWHWemW66KcLmB3LByrOirmzC6K1o2s0m3XZrTQ9XKpUXajPezcXjaKacNRH7JhWVJpTyHRSbmynkHKJ%2BmDmLV6ce0niuLHrrkVx9EgTMS6qhCWSGe%2BS04l6%2Fdx1mXO3A5thBLWOj%2F3dxt2P77lBy7zpFDOglPrFxZC4ycuBYn9s1N55mp6NrRHuv%2FOI09B6980vFy4tXK2anfYsWkKUZRBnMzPa0579yC91twRR8RFfNe%2F5VpMUNERcepf3MFywc4mLB9VIo2Mwb3bys623kq7PR5DwwYtgx3rq4U67KTpuTHqlalDM4dnZ%2FpNoeOXUe9OpVw7NRNfDvcESVKmGTsIERGC8NgbJx7meP8kovYWKVxNjGS5tt555vDBEJNREQMpv2wFct%2FHiY8qB%2B%2B6wdf5ml9qqLOiG8Gd4BjJwcMGfub8DTfhSuWWVP7YMv2f7SqDiuXUyoQb9%2FIQikj%2FL5w75jn8DWBd3Y3sqvODH7qJwbcPHyF996%2BbX0hWzwlxdmx918RDbxrTDJU3MddRTqKp4fGjXBETGy8GAnHz%2B0FKzsmNkGj82vZtDaehITi6Ck39bKgp6%2Fg6f1Y%2FH3stBv%2BveqNw7tmiShi4oxNIlWmIjIqVsy5cVvHrrFzBzsRCRc2VPJctYIxihpF8qNDoyevT%2Febp3y8XFdj1oLtYvRIm5bKh8F5p%2BTyRcMwctI6tGpuIzoCs2Id8%2F75lJYbLkthafF%2Bw%2F%2F5h0EYPHolRk1eh52b3k8rtW5RR%2BSxPe74a03dtm9uhSPnQnDoTAg6tSqcb14ZM6wzhn27CuZMbr6f2Cvd6LSMWOU8AmMmb4Bdq6nQlerAyNAAB%2F76HpPGdmfL16Nl55kobmoiFP2fGyZrdA5%2F7bmAH3%2FZjZrVrBH4%2BCV%2BmjFAePjcSDSwrYKmHb6HrkQHZw%2FPQ9ky5h80YtvWT8L02Vux0HmfMDy8I3rl%2F0aIAR5zf97FznUmjI0MsOjHr9A1pX9i6njlcPBd%2By%2Fhr90XRTqVj%2FLatGpcobvfQSGxcPcOh3UpQ9SuZlbk9GWheBMrDx%2FpM5WppP3cY06F5%2B7He2i0bUKiHI2%2BcMGbiES47GgNm%2BqaN6pGTidy%2FrxzSS541JmYnIxSlpr3V716HSm8bAtz03TL%2BQOT8UzJauKEpEvvhEcjmhkWPuLq3Qf7eKTCFbtq6KomvHgZDh12fppeE0%2BXtm5eR3SS81RZdupCW%2BSZM2H%2BHew7FYyFU%2Bri26%2Bq5ps8UyRBFAoM9HWw%2BDtbDJ%2FljnHz7uD4ppYwNSl8YqbKy5%2B7cBeb%2FjyX6XY%2Fzeyv7rTOTIlaWXycd8ojGfMMBj5w%2BMOdnBVrj8E1zUi%2Bdzm4fYb67zKlP25EGjdGfCqM8KiYP0hXp4YZhverXCTbNBkJIkv4SJ%2FsvJqjR4ey2L68MSKjkhD8PFajaCI6Jkkr66ZT%2B4ZiKqjwkXy5BR9RlZ2Rf9omz7z%2Fn3e%2FrP6pIVrYWwgHSFO0VZ7JSBAf5zWb6ie%2FiUyQWpXUfHy4Y9sy2TqG3%2BO3VNFaRoumtQu1PPPhvX06l%2FuoYxQmeabRTUSWmJroRYS8iM3VY9z0VL50UaIAfzRXRrVOkDyTkSC0BAtzg0tX3V%2Fm6jHOX32mDPEleMVmL6nWCZJnMhKEluD%2FJG7JqQvByYlJ8lwpPzA4Co%2BDo1USGcD%2Bf0K1TpA8k5EgtISLbrEe%2Bno67ntPBuZK%2BbOcPVJ%2FKBDDHTGqdYLkmYwEoUWEvI4dvHmvb7yXT3iOlrt0kzceBUWpGlQAmxz4R6moxgmSZzIShBbhwWQ%2FMUnRZ8K8G7Kcali8Qe1P681JcFXCX6RbQF5sRpA8kzyTkSCygZuX7HR0XPKoMbOvK9Zsf4iPzenynO2Aif%2Bmb1AK7GL%2Fd1boYgbVNEHyXHCg5ySIbHH7AbY1spHr7Dj0aOPe44HSZg0t0aVtedSsZoZK1hk%2F%2FRsbnwyfgLe4eTcU%2F1x9xhpVdPoNeIPi79CX4Bt35uFRLRMkzwWHQvPuJhL3TMLqXHpnjH1ddIEcByTKTzN%2B3Dd8ec6WheRs3oV5XENv38dZkguC5LlgoVsYLuL5ayzgk7UV5lMzer9ucqXcUPhbl8F%2B1iCqscmKeU0BrIElsEbCo1P9THaLZtuE6ChwUyGBF9PglXQkCGV7fMka1C2SC4LkueBB6Sbi4706ZSjdS3xVUI4%2B7O9OzBuTsH8mmexSTKFABGtQ%2FO1zN5m3tcCdOqkJkmeCIAiC0E7%2BD6pQ%2BNrzVL%2BcAAAAAElFTkSuQmCC)
+
+```
+source_value
+ ::= STRING_LITERAL
+ | EXTERN '(' int_const_expr ')'
+```
+
+referenced by:
+
+* source_def
Comments:
@@ -732,113 +200,33 @@ Command line usage:
```
elf2sb -c.. -o.. "some/path/to/file1.bin" "./file2.bin"
```
+**option_list:**
+
+![option_list](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAT0AAABRCAYAAACg2nEIAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAE%2BBJREFUeNrtnQlcFVX7x39zF3ZQdkUMDQVBzQVUfLUoU6Jyye0fmalZaf7TrEzLbLPNSvNfar1qmGmZuGW5pGZuf8kFL2qvCLIooGAIguz7vfOeMyyiIRfwLnDv8%2BUzzL2znLkz5zm%2FeZ5zzpwBCIIgzAjBVE9MVE1Tbj1%2BYnZswo1J8RfzuubklVtm5ZT%2B43ydHS0rba2VuS5OlkeSLpcsOnSyOJrMgiBI9FoV%2B78PmLHrwJXFCcn5tsOHdMTgQDe0c7OBm7PVP7bNzC5FRmYxIlWZ%2BPWPy5VWFnJV%2BvXiidExuEjmQRAkei3buxPfl21etm1T%2BMaEcRPHeCNseGdYKGWN3r%2B8QoOIXckIj0goLakQx6jOqfeQiRCEaSE3pZPxd8re%2FN2mxHFLFvRDyGAPyOVN03S%2BfS8%2FJwTe56LYfzQ9zNVRk3Y1C2fITAiCRK9FhrTL18XN5YLX09fxrtJyd7FGYE8X2e5DaSNdncUrGSR8BEGi16LCWtU05bKNUQceCfa04B6eLuDCV1KmFmLibjzu4QoV8%2FiSyFwIovUjM4WT4K20SakFtrwOT5dMf8oXFhYyhUbEpoAe8CZzIQgSvRZBbOKNyaHBHZrUaNEYeHr9e7ny1h4F1FhC5kIQJHotgvhL%2Bd6DA931knbIA1K4bM2mwX26oxeZDEGQ6Bmd7Jwyqw7tbPSStn%2BXtlUfBGTKNBhLJkMQJHpGJye%2FTHBuY6mXtD3da8XUjk3DyGQIonWjMIWT0KhFyOT66Wddk64owkkwketFECR6hFaEKk%2FPmq4EQVB4a07I6RIQBIkeQRAEiR5BEERLpMXU6fE%2BcDIRYyBiIPvalU1eaIGjwAT4sV9IEIQ2eDlJZVMiK8XHNQJ%2BPnMef5HoMfp3g0%2BlgK8FDXqwq7SRXaplcg1iOyUgdQug1rUQxV0sQE5uOTzbWcOrQ9P79kXHme7AqwShK8YD8hQfeKll8GdfhzCHZm9fP8QoRLwUdQEJZit6ffzxsFrEFqYiS%2FMqMDwpCWU1607p6ZhT31AhKbUQO78d1CzRIwhCO5LDkoBL7COfdnXpgvltlJirFnCClfvxZ2JxwFi%2FzWh1etzDY%2Bq%2FRRQxiXlPH9UVPH3xd1apJHj9ezkhqLcTWSZBGAhevnk55%2BWdl3te%2Fs1O9Jjir2CzpacvYJehjhmpui7NZ0%2FpQlZIEEagurwvrS7%2F5iN61Q%2Fu97QvMezIJUdPXYd%2FVwcMG%2BRO1kcQRqK63Pc01gAeRqnTkx7cF%2FDT4RSU6iQ9udCoR9HefskPSqUMQhOaIgqLKshKCUKH8HIf4I%2BfqgfwMHiLrlE8PREYyP4d1FV6be0tKrPztFcJujlbwtFB2aS0E1PyyUoJQvcicFDSAXMJb5mj5cMcs%2FM6c5dtlbnpGcV6%2Ba1Rf1XVAwoiCtDILjQEQTQML%2F9cB8xG9Biu1oW4pqvEnB0tj0Sqrunlh%2B6PvFp1YxKQyWbXyFwJ4u6pLv%2Bu5iR6VsfTdFOfx0m6XLJo98G0Sv7eWl2SnFaAlLTCmivF%2BxtdJnMliLunuvxbmZPoCYDuHuc6dLI42kIpU%2FEXdeuSNz%2BLrlsHUcQdPzJXgtAJIoz0mKnJDDiQfr14YnhEQum5%2BBs6Se%2Fz1TG4mFpQkz2X2BSgkWEb2SpBtG5MRvSimUaVV4hjZ753Qn23wscFb3Ndr1FAJLslnWopD0wTBEGiJ3HynPq3wpLKF6bPPyYuXx%2BHptbx8Tq8J2cdvlXwRGxg%2Fx8R5ZhH5kIQrR%2BTGy7%2BdCzWBvppZD9su7gyYkeyIqi3C0KDPeHj7QAvD7tbti0ureSvj0TU2Sz8EXmViV7h7bUOG5iXN0QQ8KyKeZJkLgRBotciUcVhTd%2FuYrq6XL3lSNQ1OZua9m4LXofHQlr2KVSUYXL0eewlUyEICm9btsfHhEqQozf7uI%2BJWLYAxLDpChOzono2L2TrkmUi2xbYLgKW0ouAFPjXaRI8giBPr7UQXRWSjpZGZa56zi8EGiZ7Amxv29ROFJErCuBv9o4S5ViookYLgiDRa61Ut7ry6V3KcoKg8JYgCIJEjyAIgkSPIAiCRI8gCIJEjyAIgkSPIAiCRI8gCIJEjyAIQj%2BYROfkAD%2FdDUja0omO0%2B%2FAi6JqmnLr8ROzYxNuTIq%2FmNc1J6%2FcMiuntNHHdHa0rLS1Vua6OFke4SNa8wFeKf%2FJ%2Fkj09IDq6Hcmb3CB90%2FVa%2Fr7vw%2BY8cpXvyxOSM63HT6kI5548R60c7OBm3PjR%2FXOzC5VZGQWu0SqMsempl8eNfJBGxUf4DVaz6PUmEP%2Bm7r9kegRDXo1urzjiuL7ss3Ltm36fGXMuIljvPH5%2FH6wUDav5oMLJJ%2Fu83PC82E%2BiohdyUHhEQkxgT3FMapz6j2Ug2R%2Fxobq9AhwwftuU%2BK4L97uh0mjvZsteLfD0%2BHpff1BkJWNhbAz0B9T6WoTJHqEUeEhLfPExi1%2BKxA9fR31cgye7oqFQXKFQhbeh4SPINEjjAVvtNh14Mriicwb05fg1RW%2BCaPuFRQQVjGP71G6%2BoS5iR61trUAeCttUmqBbdjwzgY53vSnfGFhIVNoRGwK6AFvygGzRjCWDhhL9Moe7GScF%2F0SN4lNvDE5NLiDzurwtMGP07%2BXK7d2BdRYQjlgvgz0lMp%2FqTmJXnaRHVwp641L%2FKV878GB7gY9ZsgDHnzG31kymI9oTblgnpTYgRteljmJ3qVKDXwo641Ldk6ZVYd2NgY9pn%2BXtjXBTWb1EP6EGSIX0J3FtglmI3rsZFWCBoMp641LTn6Z4NzG0qDH9HSvFVn%2BPs5hlAtmCn%2B1KnDcGIeWOicP6AH3kzG4dqeNtK1vsugJ2M3Udhn7%2BAEMWJmZnHoNc99ZV%2Ft94Vth6N7tHiz48EfEJ16Vljk52sGniwfGjAjCvZ3a1W67YcsRbN958h9pfvLuRGn7Z6Z9CbVGjVVf%2Fi%2Fs7areOHk4MgbHTl7A1IkPY%2Bbcb%2B%2F4u2p%2Bh6HRqEXI5IbtY1pzPFGEk2DineNj4i6jvKwCfXtTm01deH1%2BgYgJGhlCm7Lf3epQzf6S0VWocTXAD9sUcsyqL1Ft65vKmVgcCvCHLNAfY1Wx2GowL6O9Mz56%2B2k8PPId7Nr0Nrrc215afi42FQMCfDDkgZ4s5CvAgSP%2FwSOjF2LJx1Mw6rEB0jaXr2TB0kKBmdMeuyXN9u2qunqcOp2IDh5OWLV2H16f9YS07Pr1fMTFp6FtW1vMmTlSWlbJ4vqwqUuwYsk0tHOrCvU6eriY4Y1e8vSsTfkc9%2ByPRs6NQhK92yiwxuu82J1p4hsHm6tD%2Ff0wWi1gWaUazuyrjaLaAHmYO16txmiW6PbbE9W2vjlOBkvzNXa3X9u7G1RnLyDFEBdbyUSLC1ONWFlaKGvXcQEc2L%2Bb9Hl4aD%2BMeLQ%2Fpr38Nfr16QqP9lX7uLq2qd2mPua%2BPBqvzF%2BDKU8PgYuTQ%2B1yK0uL2v0qyiuled9e98Kro1urMdTU9GKkZZTUHy4w721Ab6dmVe0Y%2Bjz49V%2B%2F6TBOn70IO%2BaRPxx8H0KG9JbWbdx6FL8fPANrK0uEjR2MBwZ1l5afv3AZFxLS0baNLSK2HYWCFYBXZoyAb9cOtRHE2h8PICMzF%2B6ubaUowdnZASdPJaCktBxLV%2FyKNmzf554ZqvX3XWNpfLvud3YjvgxfFkG8ODVUsj8eMcTGX8Hzk27WCISv34%2F%2BAV1xX%2FdO%2BCZ8DwYPZIrw63FcSslA6LC%2BeHp8sLRd9JmLyMjKRVdm4%2FyG3tnLDaFD%2BxrFjvp2w3A2e00uIqgZN8om6VCN2LGAxrNuPKm4ra5N0VCi2tY3Bebh7enrj2Xs5I%2By%2BYTTsTjakgo59%2Fr8unXE7n0qvDAlRFqWlZWH41EXbtmuh79XbTjbzccTjwzpg%2BUrd7OQ9SmTujuv%2BzkVy9cn1bvOjt07k4%2B0jv7Gz7MbmVqtwVQmQGnp1yWx4KLHhen3g2cx75UxKCwswew3w7Hko2clUTwfdwXz3luHx4YGIOSh3jjGbOC5mSsQuW%2BRJGqjwj7ByzOGY%2BiDvSRh%2BuPIX5g8YQjs7a1ZOC9Dxw4usLXV3kMrN7cIo576RBLHkJl98OeJOPzPlMU4vPtj9PC7B68vWAtBEKT1XPB27InC5LCHpH2%2FWbMHW375ExPGPYBO97jh06XbYGtjhSceH4Dos0lYySIQNxd20x7QDQ4Ohnewu3SBZRsl5nLBYx7P%2BOi45jdiaNOhO4ldvaJ3p0SbetDGwoTuk4BuSBFEbOvrBxWbb9LIcapNES4dTjFOH566dOroirSr2bXfYy9cwRcrdvyjTs%2B%2By00jmsNC22Gj3sULk0NMSvRGDfWAT2e7%2Bj09Ret4sOc%2F51MQdToRp%2F9%2FKfPmLKRlE598UBLB1d%2F%2Fjq0%2FvCGJCycvvxj%2FXrNXEj1OUKAPvlk6Xfo8jAlf96BZuMFC19z8IuQXleCxYQGSR1bjHXL82U2Th7fjRw9q1O%2FbtD2SRQS%2BtTdZ7sX9vPME%2FjqXjIA%2B3li9%2FCWMm%2FQZLJQKyRvcsXGBFL3U8O%2BlL0o3Xk5xSZnk9XHR4%2FB65w3fvga53DB5NZ558Sk%2B8FLL4F%2FdaPEU040YBfPw7kbwGtQhAXtYHPXBncSuQdGrjUGBs%2BwShYpa1ldWIpkd9K5uH%2ByiPMr%2BPSrTSDE%2FH83B6OTmFcG7c%2Fva78H398CXi55rcJ97PF0kI%2F9ixS8YNEB%2FJ2HoMeS8OtjAqa2y%2FrwThFZxHokX%2F0ZX7%2Fa1gseRyQRkXMtFAfPuuDDUwENXHrbWxuGym2Lh4GBTXcekZqGiO8aP%2BhcGhbwp7cM9qRksJHVzbdPk35eQdBX7mLcZ9PC8W5aXlpVXRRVMkOe8NApvvr8eP6x%2BFe7VdcL1wRvhftl1s%2BHN2dFep4KnLd8u3SzXdct4O%2BaBxeu6bHMdYmk%2FXiliHJtrtBmU4g4CdIztmM7mQ1mC4Wz%2BakPr2Y3nM1227raEgnP17xwWysZj%2FpxxTd539owRuD90PlycHfR2zroY2qcp123ZuiS9hLeGPA87FmLm5RX%2FYzkPPblwc%2BHj4sDhn%2B1sG%2FfQ0OIPp2DBnPFQsTBy3U%2BHMHPuamz%2Bfm6VNyI23jT58caNHIgPFky4Y33kjr2n0NPfC%2Bs3HsJD7CZ8pxtOTm4BnJzsW7T93W0%2B19UhNl9lpcR3pRWYyqT9eVFAHrjHp030ahIRqxI5qZTDj4sZO9irDa03pTCuoKAEx0%2FFY%2BGnEZgY9iD8fTs2OQ1XJnZTJw7FtyxkCurnaxLXJXiAC%2FOQ6m93UCpbx9BqPETNuHYD%2Bw%2BdlUJUDfMJfvtdJTVc9evbBT9GHJZuWDzc3bD5CIZUh7YNkZqWJaXJW%2F95nV5xcRmWrdotrWvrYIuo6MRG%2F77QoX2kOscJ44NZmFrVSHJClYB7mTfJPcd3F22UPn%2F%2B4WQ8Nu5DrFj9G2ZNf7x2%2F7yCKkHPZ6H5ug2HWOgeDFNEiw69NqAHPqtQ4407iV9d0duiRcy2tHaxi09MxzPTv5Q%2Bjwj7GKv%2Bb0Ztd4LX3vpOmmysLeHLDI4bU9jY%2B2%2B9ANv%2FlKa67IxYUG%2BXBB7irI84ZDKGFtzfVZpaM7wFdeWXM6R8trbcKNXF9enZWRK9pZ9MxeQXv8LOvSoUseWdO7ljzsxR2uuVmHDOnhfOypUotdhnXs%2FDV58%2BL63j6Yb%2FsB8BwXPYOnvs2%2F5%2Bg2nxFv65s0ZjzDOfoq29DYqYgDo52WHjmjnY%2BssxqWFjz7b3pF4HK5ntjnjyI6kXwKCgqnjx1TfWsNhOxI3cQoxhHiOvrzRBtOpQ9bI7ip9Q7TYWs0RWskTqDVO1rTc23O01t%2BHidRUWqnaMMPx5jNyp%2B%2FNoYv6npWczEbSpbXmvu9zCUiG1dDYF7u1VVKrh6eF8S8jJvcn0v7MlT61uF6mG4J7m1YwctGHCV1N%2FqI0eA1%2FG1nXzpC4zvJ6SC3xLt79m5HOzdIh3Subix37wi%2Bx3V%2FXTU8jRuaFEtK0niNaGZwfnJi3XRjv3%2Bscj5ALEu6xweDcX3ipcH%2F6%2BnrV1efLqbi7NwdHRzmTzrLk6VNfzqw1vtSVEgmea8EfCDP0oWmFRhdle7zUrZuot7Y%2FfeRrt3R1N%2BvrdrQ7V7E8jJ5sxbe0tKrPzygx6zMSUfLrweoA%2FLqmPkNYkb%2FZ0CcwXe1tlbnpGsUGPGfXXdWkuiChgMzXlAkGiRxgMZ0fLI5Eqw9Zc7I%2BsGs1GFJDJZlRtQpDoEYYj6XLJot0H0yrLKzQGOV5yWgFS0gprLI932r9MuUCQ6BEG49DJ4mgLpUwVsSvZIMd787Pom19EFHHHj3KBINEjDEr69eKJ4REJpefib%2Bj1OJ%2BvjsHF1IIawbvEpgCNDNsoBwgSPcKgRDMtKq8Qx85874RaX8LHBW9zXW9SQKQAnGrqIJIEQaJH6IST59S%2FFZZUvjB9%2FjFx%2Bfo46KqOj9fhPTnr8K2CJ2ID%2B%2F%2BIKMc8uvKEMVDQJSA4p2OxNtBPI%2Fth28WVETuSFUG9XRAa7Akfbwd4eTSul39xaSV%2FrSSizmbhj8irTPQKb92ACx4fW03AsyrmYdJVJ4yBYAonYeix5VpEWKqnZx%2F7dkcoNNgiVA3lrpshdnkdHgtp2TyUeXiTT5%2FHXsp%2Fsj9jITeFDPj7OhbyycMV75uL0fHz1Uu6WUjyaIfNTEa82eTKvLJLzLrLmInzqMCikckUsn3SZSKiRAHnmCJ5yQRksRTCmOCdovwn%2B6PwlmhZd%2FGq0HN0n%2B7oVf1C7hDm%2FQnsr7HPOdmJInKZ4PGhfaOYd7dQRY0WBEEQBGF4%2FgurbXeo4uzwzAAAAABJRU5ErkJggg%3D%3D)
+
+```
+option_list
+ ::= IDENT '=' const_expr ( ',' IDENT '=' const_expr )*
+```
+
+referenced by:
+
+* keyblob_contents
+* section_options
+* source_def
+
+**keyblob_block:**
-
- option_list:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- keyblob_block:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
+![keyblob_block](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAmEAAAAlCAYAAAAKoz4YAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAGvFJREFUeNrtXQV8U9cbPUmVuiLF3aW0xYq7y3CHDhvD%2B8fZhm2s6BguQ4c7wwYbrqXF3Yq0SEu9lHr%2B97shIS0tSbsmbdp79stC8967776X79x7PrkvgICAgICAgICAgM4hyYqTupSHTNz69MH3vna%2FK5nPEKPdly6PvvcotN%2FDp%2BGlQ8LjTIJCYtI8p72tSYJ5HqMwBzuTM09efpxz6kq0r7AbAWHPuu234KOA4HX25IemMMyqE%2FucWycsVkO41vPQavsnNrh8N2bx%2FnmP%2FCLM2zYujI7DiiB%2FXjPktTdN85jA4BjDt4HRDud9Aju%2FCHjZoX1DM5%2BA99F9fO%2FgqbAbAWHPuum34KOA4HX25YcmMMiKkzo5YvoQjw7CajXE6vUH%2BD2j15v3mJFpXoVsurSCXfDOJRvuj2%2FRsJDxbM%2FqqOXsiHyOeWBu9nV9TttpP7eqDujetrg0SYZCt%2B%2BHDsnrILn2OlD2RNiNgLBn7fdb8FFA8Dp78kNTSIXp5F7s%2FH3PjnU7HndZMM0N%2FTqVhLFRxsyBjqPjl82sZWpmLPnLtQI8xN0VEPas234LPgoIXusfP4QIy6Wg0O7a7Y%2B6zJviisplbTOlTWpn6YxaBoaG0rXOYuAXEPacJf0WfBQQvNYffggRlgtBxY2H%2Fn01rw%2FzBrRh2L06lJAYQrKKeRitxN0WEPas%2B34LPgoIXusHP4QIy4Wg1SVPXkSa92hbXCvtD%2B1ZFsbGUsMkGXa4VEJJcccFhD3rvt%2BCjwKC19mfH0KE5ULcexzav2WDgv85t54WqN0aVR1prbIhEjFf3HEBYc%2B677fgo4DgdfbnhxBhuRAPn0WUrOuaT6vnaF7fid7ysFdd54qoKu66gLBn3fdb8FFA8Dp780OIsFyI4JBY04L5zbR6jgqlbOT%2FkCBQmoTO4q4LCHvWfb8FHwUEr7M3P4QIy4UIiYiV2FubpOuY9yGxePUmGmER8RrtXyifkjwW7NVM3HWBrLZnmQzchukVF5eUrnNow54zwkMFXgfG8OuIjknUCz6%2BfReKuPiETG0zLOwDwsM%2FpLotKUmGVwHv2Xeu%2FqH%2BERHRCA2NEkTS43nq7Xs5H6KiM2ZjWckP%2FqSzmpWQ78odvEtrJ3XbtYmJP21Cm%2BYuqO9eUfnZrLk7YWZmAs8RHbB9zznsPnDpi%2BNmTe2JVRuOo1mjavx4BZ49f4sff96GFYuGYf%2BhKzhwxFu5rXjRvPimXS3UrlGO%2F%2B3t%2Bxhbdp3B4l8Hpdq3uw9eYsmqw7hxyw%2BGhgaow44b%2FV1bFHSy59ufvwzE%2F6ZtUO5vY20G95rl0bd7QxgaGWSZcSclyiA10PzXJR6%2FiELTPmdhZCTFvhW1YWNlrV7df2qfjYF2kiz4ZYae3y7A5HGdUaViMbX77tp3Ae1au8HUxDjbDUSBQeG4dvMpWjatLkbl%2F2jPErbLovWPsXnfS3RrXQjLZjhr7q1qwZ7Ty0PCo%2BdR6OvpjWcv5eJj5ezq6NyiYLbn4ze9f8VvXoNQw6V0prX524qDbEwyxNT%2Fdf1iG4mzWk0mwO%2F2ahgbff1yV234GyFMhM35qW%2F24Pz7cPhef4pWzTKH8yfP3kLZUgWV81JO4zWh%2B6gruPc4AoZsf4%2BuxfGzZ8V0nSsj%2FPivukhxPI%2BExSfitUt57KQPU9tZ3XZt4vbd5wgKjlD%2BPXveTlz2eYihA1vwv1%2F6v2cCSMoEWftkr0JODmjFJq6pMzZzT0eBSdM3o4ZraVha5MGLV4HIY2qkPMbRwRo9POZz8cSVeGgkF1ip4cZtP3TqNQcVyhbGtnWeWLdsJB%2Fk23abjXeBYXyfqA8x8LnxRNl%2B6%2BauWLb2CJavO6pXZBg98yb3uOdPqoLKZa3TdaxE7lno3G46t6%2BNfI42GkRHZBgz%2BQ9mIx%2Bz5b1%2F9CQAXr%2FtFUorkzBvYhVUKWeNnUf8ceJC%2BsfPrLJnBRaufcQFWI%2B2hbF%2FZR00cHPQq%2F4LqMfTZ28wZ%2BHuTGtv0fK%2FcOvuixx9zxZPq4o%2FF9aAtZURVm9%2FhvtPIjLUTnr4kVFdVKM8OrlUwKuERPgpI2ESeVqya2Ii21ge%2BwwNMFJV4anbrissXX0Ep8%2Ffxe6NE2Bh%2Fvn3ohztrZTRK1W0aOLMI2Vei%2Ffi5x%2F6YO9fl%2FGeCbrhHp8fB5KXTdSKY%2Bl99fq%2F8ZaJqGJF8n61Lz%2FP34W%2BPRph1LC2ys%2B8ZvbH67ch%2BH3VIX4%2BrrDZ3VPt2yXvB3j9JkRvjPus93tcvRWCWtXs0LG5U0ab0XnYLzgkkoliuXfz97%2FXueh%2B%2BDiAeYW3UbSII8aP7Ahra3Ps2n9RHlFYd4zbVEvmfZKwVoejJ67hxKkbiI9PQE23sujasQ5MjI1w8coDbN11lgvwpg2roHe3Brwf5Jlv3HYKzRs7Y83G4whi3m7fHg15pJYQGfkRq9nn1EcbK3PUd6%2BANi1csevARQQHR2Lh0gN8v8EDmvNr%2BRpi4%2BKxbvO%2F3NasrcwwoFcTuDiXxAv%2FIOxh1zu4P2vDUt7GsX%2Bu8dRN6%2BYuOHjEG46O1rh67TGuXH2EalWKY%2BTQNjxCSI7FgcNX0KWjO39PTErCoH76l2U2YB7vL56V0HbwBSZoHqOZez69sGdllCQklr8P6VE83Q5Rdui%2FwvFZv%2BVflC9TiI%2BNZH9bdp7BqXO3eUahZ5d6aFSvMrfXw8d8MHzQ5%2FGaHOR%2FTt9U2l48m8nWbjqBM%2BfvoGTx%2FBg7vD3ndUoksBlz7eYTuHD5ARzsLTGgdxNUrVRMJeqShM3bT3NOFynsiDHD28HBzkqj67n38BXvP6VHqQ99ujdk84o1DxCs2XAcT%2FzewLlKCQwb2AJWVvK0F%2FW5Ts1ynHM37zxHvdoVMMyjJaRSCXbsu4DQsKjPnP%2FE13MX72HnvvMIC49Gg7oV4dGnKd%2F%2F1t3nePb8HczNTLBj73k%2BDo39vj1KlSiA85fu4Q2bkw4e9cZ91s%2BqlYujSYMqfBw8dOwqPsbEoUSxfOjfszHvs76iWgW5w13fzRH7jgfgXXAsypeCVvmRXl1E4itRgt8TZSgElSx5spowmVyUUaP%2BqSk8ddu1iT%2BZkZOBbV%2FvCRub5CSjSBlNOKovmtQIs6b2xm428ZABz%2FLaAa8Z%2FZKlAgODwpTH%2FLpoDxsUysLN%2BevfXkxsHLx9H6FTu1pfbOvUrjYbEO5%2BJje7a4r297PJ6%2FotPz4p6guOnnnL33u1L6JXpCRR9TYwVCnCPL5fwgVy%2B1ZuuM28wlnzdsoFvIN8oHUqYIfCBR34QKYOK%2F44hl8W7Ebj%2BpXRpGFVHD3ui%2BcvArmNDR%2B3kn1WBf17NcJ2Zq9kU4SwiA%2BYu3gfpszYDOeqJeBWvTQGj16OgNfBfPtwz5VcnA%2Fs3ZiLHxJ5CgeD7JX6Ri%2BapNRh0IhleMK86RFD2qAhm8wGDF8MvxfvULSQI58wPKfKf3SZorxTZv6pTNnSQD1k1DLExsajfesaOHHyJqbP2c63vXkXyvvftb8Xn1RIGOorajKHokQRc%2FjeDeW1JPoERc2LlYWRXt57EmCUjTh55jaqV5M%2FkmnKzM3498wtDGEipVPbWsw%2B1%2BOyzyPkz2vDuHYUV9hYq8o9VSd2G3N4%2FBmH2reqgfuPAjBywppUz%2Bv5w3rOz8H9m3Hu9Rq0gHNBgT0HL%2BHBY3%2B0a%2BmGl6%2BCMHTUco2u59qNp4wTc7n46ti2Jt4z5%2B%2FoCV8Eh0aiQ8%2BfmVNjhVHMkaGauJ7snCQ4CX8wEeYxfAlsbSzQtqUrF2t7%2F5KX1eR1sOY8V3DewFDKBdPUWX9yXg4f1BJH%2FvbFouUH%2Bf63773g0XwSdC2Yk0fHDmY8JpAgNTYy4oKS2iIHj%2Bai8T9s4A4g3e%2BPH%2BN4ZicnwNLCMBlPdGLTanSRIvKVCOwFCbAUMFTTKFd46rZrOzJ2%2BG8f7v38Pndwqt7Jg4f%2BWLD0YLLPZk%2FrhXKWhVCooD2PVvUZugg9OtXlBFTFnfsvlccGh0TwqAVNThQ5SAshIVFISEhCvrxfprto4KAohwKJzFNTtB8XH8%2FPQd5WuTIF9cKobz2UX4tbFVu9Jid5meTdcqIyr5IEBaFh3Ur8nQZxTTxB%2Bt4Xr%2FwLW9eMU04iHdvU5IMrpcq%2FZ8KHBjYCT4l3ngHPkR3531SbsufPicoI3f7Dl3magGo1yA5nMvukyAC9enWtr%2BwfTVBdO7lrdJ00mD71e4uNK0dzL5lqcC5ffYgjTCh%2BP7g1Fv3yLVp1mYnFK%2F5iTs0FLGGcIo4oJ6sRHTGACUFCqeIF%2BGT1y4%2FyWhkTUyPs%2B3Oy0pvXZ7hVtuVpvTsPI5DfwTRb9zWRuc5%2B%2Fh9w9up73HoQjjrV7VHEST%2B%2FA6rHff0mGOuWj%2BR8oJpHck5vnF%2BkrMmkaDBFW2u5lkHPLvWxaesp1HQpwx1r%2Bvz4%2Fs%2B%2FDd2vZyNlTRjxplbTCV8U2SvPcXYRbG0t%2BGfklPyx6R8s%2BHkg%2F5v4pchekGNVre4Y%2BAcEJ%2BNGali65giG9G%2FOo1IEEjY0FlC0m5ybUUPlmZKarmVRs8l4zkWKgBEWzx3Er4vw%2BMlrXLv5DF061EGjepV4hFqV85RS%2FHV6P%2BWxdM2jJ63lddGEerXKY8m8IfIxgzmH1dzHIDLqIypXKAp7e0t%2BnKLGjKJwBZ3s0LRBFRgZG6J542rIKaD6yG0HX2HZpqdwsDVBmWIWsLPRTa3vF7pIgqNMCs5MGfnSSIR9juLghhRoKVOzPSEBfuykebR1cRQtGD%2BqE%2FfaKVVUplTytFi9OhWUBpgahg5owSbdvejXq9EX2xrXr6IkImHj1pPcm7p44tc021OkQqOYkVOkQhVk%2BOYqqVIjQ0Ps3jRB%2BTd5cQ3bTEVdRhqKiKQX7D7LdGnUoWFx%2FN3e1uQ%2FtaPrfqeEaoEnpeji4xMz1M67wFA%2BGaQs%2BCfB89TvHU8dKFC6ZAG%2BIozSATx8zcSXQoDxaIalGZtg5f0goTZuyjouDqtXK8EHddV0iaagwZxSh3WaTUz2eZFCjkoBSotSWn4zAyOGtIY7s8NkIXaVOlhKU1Ba9cMHebSIJsnMFmBZZRcOdnJ7DgmPy%2Fb9ptRK7S6n%2BL%2Fr13DAloU1kn1P%2BnLf5y%2FZz1NnV0%2FOVxbLU8SWUmINW09Ltm%2FTRvJHNVHKnrZRtoMiPbXcyjJbTr0OjgQTpeLeBYUlqwelFCY57woBRqBCdVp0lRrs2H621hZ48y5ErQh7%2FPQNTz%2BmHAsoPag6T9FnNB7QwjCFkJKqfImWbCwI%2FFRLnBqePHuNURPXwNDAINn48bl9abLxjTuMaYxxFE3be%2FASKtUexdOTzZjoHMjGG6qt1ndek4OybXEN9BrrjXaDL6Brq0JYPtNZp%2F0nXcS%2B2TYJMnRh70nqGkpVhLEDL7IDA9h7U9bgWvY%2B9mvbGZ%2B80hMJS%2B8FUpiaCq0jIqPRd%2BgiHNw2NdUoVJoXSelHZvBSDUYuim689A9ik2PaS9hpIqLw89kLd1G8aPKM7LlL9%2BBaLe0oGqW98uezhR8bGDIiwnzvQ6JLglh8Cu9%2BjEmErVXGUyC67re2QAKchFRY5IcvorKWFqZchCtAAobsiES5QsikhT7dGnAbp1TpkRO%2B6D5gHq6fXyT3sGSaXzadi2zz%2BP7pae6z58BF7iEfOOyN7zxafZHeVwrw8CguvMzMTLR2P7PKLqKj5ROUeR7DbN9vB%2BbJ%2FzHHBRd8g7Fu93NMnHsHi3%2Boqnf3nUSJWR4TLibWLhkBAwMpG19MeY3jpX%2B8kjkoClAKjZxsSjvuZnY7e1rvNNunWsj4hAQmQsxTjGFy%2FhGPFOeIiIpmXE49bkCRrOiPsbCxtlB7TcT58IgPqY4TqmMBP2dkcgc9xZyaPKqS4s6amZli%2FfJRnLcZitKoNEjpziO7f%2BTi1Of6EyxcepApBZlysZs%2B85pWDw%2BZeg357E0xol9J1Kxqp7X%2Bp%2Byfqi5i76tMjbAuJh4eTNoOkkkQnloqkgvolI2wt12sgfLs5W9ogPLX7mOcuu26KtKf4tkFbs6l0XfIb3yCy3SPk3kiv688xKMDNEB8DVRvM495dtdvPlN%2BRimfbbvO8dRXaiCPj4q2KRpWMxOXamsTxQrKB7Q7j8KRE0GDMolq8sg1AdVYuDqXwvI1n1e4Us0K2U7jBlWwbfc5nrIkUKEvRbM0KfClmhSKDlD6cPi3rfAhOgaxjMHUN1oo8iE6VqP%2BuTMv%2B2VAEE%2B%2FKECrgKn4l3DgyBWcPn8He7dM4nY%2BcsJqZZ0KITxSvpKYxOMydo20uEUdF%2FQRCnsuUTj7p%2FWMjaVo39QJXhMro3xJS2w9%2BJI%2FJ0zfQCn%2Flb8NQ3h4NMZNXceFQYWyRWDJhMnytZ%2F5RI9ouHT1ofJvSo%2FTuEzRJBJkKcdUBTZsOYlK5YugQP7kpRMU9bK2NsO%2BQ3JOUE0v1QlTgXpq7Wzbc5a3UapEfrXXRKlLOi%2BJNgKlMKlOjNr%2B%2B5%2FrypX9xL9HjwO%2BiDyn5eRTrbKqiGvJeEiF%2BtR3heCkWleNxixLM17HqcCFy%2Ff5HESLzyj96eZSij8JICdgPXNSQsLiMGV4OXh0KYaKpa20fs60dNHFW7hD7wYGKM1MfRfbL5Lt7P%2B1SBg1QgruihFrJBVhpW67TibMRb94oM%2FQ3zBk9DJsWjGGf06rHumlin1bJmv0TBpaPUkvhfFTaPbXGf2U22lyLljOI9kx5EV06%2BTOhOBHXmtG3h2Ffim%2FvnzhUGWtkIIsiuMpIkdprM2rx%2BjNM1sa15avNtlzNADN6%2BbMle2Urh7w3WKerhg%2FshO6dKzz1f0Xe32LoaNXwLnuWF40m8fUBLs2jue1h0NHL4d7i4ls4DPnQmrDitEa9WHjtpP44eetKFPSCX7P3%2BHHCd15hIpssmql4ryexEAixbG9P30xyaQUieQxe05eh5leO7iwo0L7Rb9%2By2ttps3awvo6kdvs7B96o%2FWn%2BjBaTUWgVV4bt57ikxKl%2FlcvHp7jvu8XAdHwuRMKp7ymKFfSSq%2F6ztOoTyMRFh7H%2B69voMjqhhWj8E1fL77oY8aUntxeR4xfg9Xrj%2FOFMeFR0ZgxqSfgJj%2BmgXtFzoOBvZt8ES0jx5fECH1uwETaplVjvzgnORHL5w%2FD0LHLeUE8CZD6dSvyVKcCZ87dgVuj%2F7E2pEhITOS8lWiQOaGUPvHVpYEnbK3MubO0cI4HF2E8ldpmKkqXcMIzv7eYP3sgj0KpA%2FGOapJrN5sIQ9afQzt%2FwMwpveA5bT2quY%2BFnY0FQiM%2BoEPrGtxJUoeBfZrwBUNbd57lNWu08OfbkUtR2MmBz080Zkwb3y1HcFtZPmOjs2c%2BqtVFnz4bV7MSvJhMmJgyMib5FFaLZo2sZI2kmlZUtz0jYUafc%2BtyxJdOUQ%2BqHZCw%2F9TVD2QUrvU8Mj3M63OwnUb7xsYlwbXDvwhmxv3v5nooX0rzScu1%2FV%2BZ328t2Q0tL49LSNBokFT12GmAt7e1TPY5eb8xTMRQKiVdA0hoFKKYcKMVmykfHEuRNhJOikdLaAJakSVl%2FdP0mgaxgZmWynflDkZMuu6FvtgznzinX8eOw%2F6YOaYivutdImvtOR39JvQffxVHTr%2FF5O%2FKYXT%2FUvyRGzmFj8QbcmZTOhm00KRt99nwOb0g1dXLCt445bf7atSWoru0QtrczJTXfaUEPUYmIuojCuSzS3d9FNWJUrlMSueaPqeV0bToh%2BrV0gPifB7T5HWYivbS20eK1NGCMsUcpZi3TEyMMo3nWc3rN0ExvA6MnKxj6%2BvCpVL6FpOllx8Z1UW0epLEGDvBMHYeMx4JMzRA8a81om57bgYRIb2TrT7BxFiKX%2F5XCR6TfDD8p%2Bs4uNodluaGOe46FXVRx0%2FewOoNx9Pc78eJ3ZRF%2BWkNXikXa2gKisTZ2qZeh6KogVyw9AAueT9Msw3VRSBUe5gRkNijV04ERXXpQa0VSlvBo2sxvev%2F4O7FcfpyEOaseMBfmj4xXx%2BQFm%2BIj906uqf5%2BJiv8SZlROxrYzVFhFSfMUZODEXo0kKndjXRu2sD%2Fm9yjlJzkNL6XBOkVvec0fY4pwua5Nh5q0GvM%2FyJ%2BQRavOJcwUbr58yoLlKNjPF2VD5Ud5BADgGtFEzPT0K0a1IAm%2Ba7ITwyHv5vojWKhkV9iNfLe0PLtbPzkm3FknRtgFZk6uMDGzW1Z6pNpvK333%2BsxldRkYOhKbRhz%2BnlIaGuqwOuH2qK%2B0%2FkNTxli1tkWf91BVpJXiMLamjJiVF1agSy7zxFT8z%2F8DER5nkMlA9uTQ8ywo%2F%2FqosUxxuKrzr3wcbSOCE4PNbQ0U7zmpJWDfKn6xyPn0eIG61nUCydz6n2TCU%2BGY0aacOeM8JDgp21Mdxd7HMNH9u1chPkFPPUV1HtP0a%2BspIfUvFV5z5YmhuFBbyN1uo5vG%2B%2Bl098MpDLnijuuoCwZ933W%2FBRQPA6e%2FNDiLBcCHtbkzPnfbSbYT5x%2FjV%2Fl0lAv4Yu0tkCwp6zoN%2BCjwKC19mbH0KE5UI8eflxzuGT%2Fglx8Ulaad%2FPPxLP%2FaMUFkYPUnsp7rqAsGfd9lvwUUDwOvvzQ4iwXIhTV6J9jY2kPtsPaedHWyd5%2BX7%2BQwZ6nPQJcdcFhD3rtt%2BCjwKC19mfH0KE5VIEvI%2Fus3b7o5jbD0Mztd25q%2B%2Fg6YtIhUE%2FYy%2BXJCn2iDsuIOxZd%2F0WfBQQvNYPfggRlkvhy2wvLl7WecRPlxMzy8DJoHeqei0SnJcAV6%2FfxU1xxwWEPeum34KPAoLX%2BsMPIcJyMa7cTjwS9TFh8NDJF2VLNt1HRnPvlFPvPvJ0coOWYQv7fwuZAcSDdgSEPeug34KPAoLX%2BscP8ZywXI5r97DetXySdPOepyu3H%2FQzrFXNAS0bFEKZklYo6pT6gyCjYxLw8FkEvG8E4Z%2Fzr5lRRyXfgQxagsYSCQb6ME9G3GUBYc%2BZ32%2FBRwHBa%2F3nhyQrbij9JpQwq4whM36TKzVUr4iWSOK%2F9G7A%2FszY72xQTl2C8%2By9JfMo%2Bl%2B7i2PCbgSEPeu434KPAoLX2ZLfqcEgK0765j1m0MvJEdOFuab%2F3mml3SA8ccqPncwgS7KXI%2FMKnjFDj2VGStHStH6SPortEyCVwVsmwW02IheVShDEjujBDPqqsBsBYc866bfgo4DgdTbjh6YQ6UiBz96LPBTbybkiqkqT0Jn9uznzOiTsP%2FM0DrGQyRDGDJp%2BM8KbeRMzfETRr4CwZ133W%2FBRQPBa8ENAQEBAQEBAQEBT%2FB%2FcxbeNvJKpNgAAAABJRU5ErkJggg%3D%3D)
+
+```
+keyblob_block
+ ::= KEYBLOB '(' int_const_expr ')' '{' keyblob_contents '}'
+```
+
+referenced by:
+
+* pre_section_block
Comments:
@@ -859,52 +247,18 @@ keyblob (1) {
}
```
-
- keyblob_contents:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
+**keyblob_contents:**
+
+![keyblob_contents](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAARUAAABHCAYAAAAp39OqAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAADvlJREFUeNrtnQl0FEUax%2F89R%2B6D3JgEEgiBJCQBkgABwxUhgnKYRRTR9UBFBJVDXXirz%2Bsh%2B1jwAmFXYEH3rcohsAqKouAC0QiEcIVgDnJADgi5L3LN9FZ1CAZNMpkwnZnMfL%2F3JjWTmqnuru%2Brf39V3V0FEARBGBCBqsB4RAZDpFqQh5MXyLeNhYqqwLgkHd1ClWBgosbMpUowIgqqAsJco0CKBElUCIIgUSEIgiBRIQiCRIUgCBIVgiBIVAiCIEhUCIIgUSEsg7KyalRVXaeKIFEhzIma2nrs%2Birxlv%2Fxz6%2B9%2FZns216xZie2fnpQen%2Fw8FksWrZZ528OHTmHy%2FnFZDgSFcJUKS6txMuvfnzL%2F0IG%2BWLC2LBu3Y%2F%2B%2Fl6YPDFC5%2FfWfbQPZ85lk%2BF6MPTsTw%2BhuqYOG7d%2Bh6TTmfDr44l5j8ehn5%2BXlPftD8lwdLDFmZQc%2FHzsV4QE9cGiZ6fB3s4aO%2Ff8BI1Wg3c%2F%2FFL67gPxMahvaLqlW5KXX4JNnxxAWmY%2BhoX1x%2Fy5d8PZ2V7K2%2FqfgxgRFYh93ybhNGvsd44MxoKnpkCh0O95vaYmLcoram5%2BPvpzKr785ph0XPw4Hp09Adm5V5FfWIq9bFvpmQUIG%2ByHSROGkvEpUiHk4PFn10qN7rmn74V%2FX0%2FMmL0SV66WSXn7mag8vWgDKiprMP2eEfj5%2BK9Y%2FvonUp6nuzMgCOjj4y69rG3UOMvE58tvjkv55eU1mDFnJVx6OWDR%2FKkoKa3Cg0%2BsgUajlfK3MFF5YsE6ODvZYerkKKk7s2NPgt77n3GxAJ%2FvOiK9P3nqIl74yyZMGBOGmdNHMcHRIPnMRTixbVhbqeHm6ijtK98ngiIVQgZOn81GWkYetv3rRajUSoweGSRFDZ9%2FcRRLFk6XvrPgySl4bt490vvwwf6YfP%2BbeGflXIwbEwqloMCs%2BDvbLHvX3kQEBfpg8YJp0ufo4YMwetIyJCRewLiYwdL%2F3mPl3BkdLL3PzrmK5NNZmD1zTJeP5wI7Fk8PZ0ycMEQSkdbRiLubI0aPGMQEbDgZnkTFMhk2GEMUIv4EEaPYx0D28oOB56nJYhFKf%2F%2FekqC0MGiADy5mF978LLTaYoC%2FFxpZF6ekpEpn2Tz6CRzg3aocAYEB3sjKuXJTVFp3dZwc7VBaVn1bx3PvpEhs352AsOgXEB7aD7Fjw%2FD0o5OgtjK8O3biSWWen8uDKWa1RK2A3afO4wx5NolKtzMiCAObBKwXtAhlXvk5c821Si1S%2FdORuxPQGMjhJRzsbVBVfeulWf7ZwcG2ze%2BXlldDqVTA2dkOxUxYRFHssOzikso%2Fls3%2B3yYGkEsXFwfs3fYKcvOusajnIt7fsBeNjU3SOJDUyg04YYGuyZpmAcqcgfDTKBDCPsayE8S3EcFIUYlYyHqR6eTpNKbSPdFJCO7SCPiFeevhikb4J1%2FA0uRfse9EOrI6Kyj6EB01EAWFpTh2stnH%2Bf0f%2B747IZ3hW6isqpVSrVbE%2Bk3fYHxMKOxsreHsaIvGJg0u5bV9mTZ2bDgOHDyNomsV0ueUC5eQknoJY0aHyFZ%2FiSfSpMvGfr4eiJ8aLXW5WqIfHgllZhV2my25vbjduP24Hbk9uV25fbmdydspUumWCEUjYic7mz7KHbE7tskHMD9Y9RTmPb8Bfn4e0rgGH9NoPRaxe%2B8v%2BOLLRNQ3NEpXUzavXSj9n1%2FFmT0zBnHxr8Pezgbr33nm1uOJDMRTj03ChGmvIrC%2Ft9SlWvXWY%2Bjt5SLb8ZSwyGjuwnXwucMNGo0GNtZW2LrheSnv8YdjMX%2FxP6TuUey4cKx87ZFutW9mJupZsiIiCKfZGXcns3c0RSz6QfN46t9HP8CSIyysXmGI%2Fr4%2B00k2sC7C1aJyFn3YSULTwqLlmzEwwBtz%2FzwRlZW18PLs9Yff8vtVFIICri5tX1HhXR5%2BydfD3Ulq5HLDry4VXCmVBmr5oG1rrtc1SONBvj5uXSq79XSStzNXLbPPqywZy8qII8%2BnSEWebs9gDIEWYY7XMd0Y27dSq6RLre1ha2MlvdrC3dWpw7L5fS6O7YzRtMXhhPNYt%2FHrdvOXLY7H8IjAdvP5mE97x8KPoauCYkiYnddU2WIhtzsN3pKoyIJCi5nsvPfZ%2F3JQZ0r79fCscXBytO3WbfIrQy1Xh8wVbufIEHwm2R0kKiQqMiACowQR75vcOE9kIBlHPqMfYnZfTBWhx8mXqqDzsM45H6Q9TzVhOXB7c7tTTZCoyIWHbTWuUjVYDjfs7UE1QaIiFzaJeaY1nkLIyw1721BNkKjI2AOiBaosDBF06wWJCkEQJCoEQZCoEARBkKgQBCEzdPObkWn9nApBUKRC3Bb8YbfbeeCNIChS6QAxaZ76i8RfFqWmlz2adrEisLSiwfpaaV27Dc7NxbrJ3lZd7u5qfTjz0vW%2F%2FXis9iSZk%2BipmJP%2Fm4SofP9x5LOLP%2Fjv6vTsSvupsX1w3%2Fy%2B6O1pB0%2B39u85KiqpU10pqnVPSCqamZt%2Facb08XZJ%2BcW1j5xMwcWeGLFQs7JczM3%2FlUZVZ%2FENRYhryY51H194%2Be7xvlYrXoxA9DAPeHnYwt6uY73j%2Bfx7w4e448Gp%2FRRaEb7nLpTN83QXkguKxEw59tfbA28UFuNNagaWhVx272n%2B3yNEhVfolu0Z9695ZTjiYryhVHbthM1%2FNyTYFVHh7qrvj%2BbP9nDR5hVcwykSFcKU7d7T%2FL%2BzGG2glod8m7el37%2F6r1EIG2SYqQt5OR%2B%2BGa1UqRSbh4WALqsQJt3lMVf%2FN4qo8EGpfQcvr34kPsBgFdq6YufM6C%2BoIHwUFYIp5L6EqWHu%2Fm8UUeGj3Jm5Vfazp%2FaTpfxnHhoEKyuFivUzt0eGIsCQ%2FkBNwuIw%2BEOkPdj%2FTVdUUjPKHps8zgdWank2z8sdMcSDe4MKGqwxYNH14%2F3pMXhLYpSvZO868n8TF5W0rMqAmCgvWbcRN1ZadY9P3BojTVhtGEpqHGjCHkviugO4o14j%2FzdxUSkprbfx6W0n6zZCBvRqCV6LbkxcbAiymrQ0taAloRQwmPV90sn%2FTVxUSivrBTdna71%2BU1xaj8uFtSivbOzU9329bhqNL3QzyRD7zZwrSdAihpqaBSEglnUjEo3h%2F3z5V%2B7z%2FNXQoNVrG3L4v16iMjIUHcZiuvL1RasRodDjmnxGbjUiZxzEhIePSBXcqQO7UT4zjCtL%2BhpEVAR8LQh4ADQTmEUgjZ%2BJmKNVYJcx%2FJ%2F5Gt7bmoGI6Qex5G39Vgjpiv%2Ffbjtv%2Bb0kKo0aFEQGY0d7herKl5tFb51BbZ0Ga5aHI2yQs54nGkmpDbLfp1LxIytQERXSveEkYRyqbPESS84ZcyGx1cvCER7kjB3f5OH7n%2FSfc10f%2F%2B9qOx8RjPjIEFxu0iD7pqgIzeksjQZ5bRWqK19OjhwvxomzpYge6or74ry73DU21EmG1cVSpv4fDg2CPzU78yUiCFNZslQp4jmjjumwiGPli6HS%2B3c3Z8jq%2F%2Fq28xYx0QC7WUTni%2BaB4VsfKBSbP%2FNC41mhe1RKPH8s5bclKXTly8H%2Bw1ekdM70vibhbEmp2B8RgrXM2Y6ydE5yKo5SEzQfBgyAtbMaL3NBYWeQWScvGH9x9pHshNq%2Frz1Oni%2FDleI69HaX964GXe2ci4lGwFoNF5I27uBRdaZQfTdqSM6mVUjp8HAXk3E8JiQrI4OQI4jYFRGMJJZu1ypxwrkGWaa2JCrRMbPYWTxnIPw0CoTcGJR9iPl3ikpEtCkISgvDw1yQdakGKWmVsotKu%2B1cwP4m4K32xKRDUbkZ6wOnWTw0WdSR39SEbLZRWRbzLStvkFI3F%2BvbKoftnyx3wzInnML%2BTFFopT443w7Rg8j6zY6tbdqbnYnTTMmW7q7N%2Fl9a0dDt%2Fs%2FbOauTe5tE3M9Sra6CVO00lJ%2FZD%2FNZOpEVuJmlSzrKV6uwSp9IRZ8DdHBo3sXrdRq4OKm7bBSas4QwFbrSwGtrNVJqb6uSzf9%2Fv1%2Bt2zlLP7JRY0tdI%2BayQOIpUUDFjXGUjkWlpRCxuZBjaiWCuViwjS3pKF9OA%2Fj72OPU%2BXKkpFfA25PukCcsE%2B7%2FnP597GTflo52vnRkKFY1arCsPXFpLSo7dYjFzu4UkxZiR3lgz4F87Nqfj7gYL%2FIuwuLIza9FUkqZdFINCnCSe3M62%2FmN%2F7UrLi2icp0VkteBWOjKl434OB%2B8vf5X7D1UiMWZlQge4EReRlgUqzelSXfXzp8TIN0QJyN6tfPfiwvbtfk3RUWlRL%2BOCtGVLyfWVgqsfCkUc5cnYcHrp%2FDVxjvhaE8rixCWAY%2FS%2BY1vIYFOmDvLX9ZtdbWdtxaXm6KiqyBDCwq%2FhVifW%2FWn3XUH%2Fr1mOCqqGpFXWNupaKW6ppE8kjBJOuv%2FPDrhl1rWvjYUoyPcpBNsZ%2BmK%2F99uO2%2F5vVFO%2Bb0crZpKKupVHq6dH3idMq63XtvIyKkk7yVMks76P%2B%2FqzLzbp0vbMKb%2FG%2BUpZUd7dXn%2BlVpZt3H8THGzYURUsURDrkyYCubu%2F0YRFTcX68MJSfIO0XyfUNAcQgooYslVcmXCVDB3%2FzeKqPAV1b4%2BlNfU0KiVpfzsvCrk5FW3HCG%2FafISuTJhKpi7%2FxtFVPgSjVZqRdK2fdmylL98VasVIEXUcOEmVyZMBXP3f6Ot%2B8OXaNy8Lb3uXFqZQcv9%2B8YUXMytaqnQLPaKNPQkOwRB%2Ft8%2BRluhsLAIZXe4C6cOHM2fHRXmrvBytzVIhe5orf4C9gpAcXIq1pIbE6aEOfu%2FUZc9zS8SM9xctJf3H8qbXluvEYaFuHVp6Ufeh5z%2FSiISTlxtHfZ9yio1jh3hQ9yA5MaEyUUrZur%2FJvHkblQwnhQE4Z9qtUIVPdQdk8f5YmCAE%2Fy8Hdr8fm1dE1%2FmAMdPX8MPCQWsUqtv%2FUJzhcYKAp7kkyqR%2BxKmjLn5v8lMBxAxGJOhxU6hOXrqWizI%2B5ACElg6WVTiseTz%2BJZclugJmJP%2FK02lUguvIdO7N3awCglgLw%2BmslmsgutZJfG7fq3a%2BVk1%2B06%2BQsRxUcA5EfBTCLjGfjGbVegJclWix4yxmJH%2Fm%2BTERXxFtRsLIMWxCvZhe%2BnbgTrnsfx89u4AH%2BU25sznBEH%2BTxAEYWD%2BD1%2BHl%2B8J2hbbAAAAAElFTkSuQmCC)
+
+```
+keyblob_contents
+ ::= '(' option_list* ')'
+```
+
+referenced by:
+
+* keyblob_block
Comments:
@@ -913,172 +267,41 @@ The keyblob contents must define:
start [integer] - start address 'maintained' by this keyblob
end [integer] - end address 'maintained' by this keyblob
key [string] - key used to encode data stored into address range defined by this keyblob
-counter [string] - TODO
-byteSwap [boolean, optional] - TODO
+counter [string] - counter value
+byteSwap [boolean, optional] - true for byte swap
```
Anything else defined under keyblob is ignored. If definition of keywords listed above, except 'byteSwap' is missing, a syntax error will be raised.
-
- section_block:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
+**section_block:**
+
+![section_block](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAArEAAABFCAYAAABdRr4LAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAIABJREFUeNrtnQdYVMcWx%2F8Li%2FSqYBcVKxYELNgNdmNMjBpL7Bp7jxrjMyb68pLYYixRY8FoNPbeEo0aewMrNlQQBRULvbd9c2bZDSDIglRzft%2B37HLL3Lmzs2f%2Bc%2BbMXIBhGIZhGIZhihiKgrioa02ouOizh9ftvP2uVJ7DDLafOz%2F%2Blk9I%2F7sPwqoGh8UbvgiOzfSaxa0NE02NDUJL2BieuP8o5vvjF6K9uN4whaU%2BM8y7BNtnhu16xigL6mY9T3nwN64j9ZsPztP0j%2FzqOnLCot3zfPzCTTu7l8dHIyqglJ0J7IobZXrO81exymfPo0uc9nzezT%2Fw0YddWpl4Br6M7uvljQdcb5iCrM8M8y7B9plhu14IRSyTs15ubvZ0VKpv9LYu3rFl7grv7n0%2FdsDcLxugmIGeTueSAaVX3Zo2GNqrmnLzfj%2B31Zt9vOvXUX3seSPpEH9jTH7XZ4Z5l2D7zLBdzxo9LvZ%2FL2QgPbbc675gRgP07%2Bqgs4FMD51H5%2F88283IpJhiX31HsKuNYRiG7TPDsIhlch8aohI98%2B7zptdHnerWuZImpbN0lpu%2BUqm32pkNJcMwDNtnhmERy%2BQmNElg%2F9HH8%2FqK3nluGcjUhrLPh5UVSih%2BET3%2BjlzaDMMwbJ8ZhkUskyvQLNf7%2FhGmvTpXypP0h%2FeujmLF9JTJKmxxrQ0HLnGGYRi2zwzDIpZ5a27dCxnQoWXZHMdYZQWl29DJliK7lUjCfC5xhmEYts8MwyKWeWvu%2BoY7NKtfMk%2Bv0a5FGXozFq9mzrXgxKXOMAzD9plhWMQyb8Wr4DijsqVM8vQajlWs1B8UeK6XjG5c6gzDMGyfGYZFLPNWBIfHKYpbGmbrnJfBcXj8NBqh4Qk6HV%2BupNYIm4lXWy51hmGY3LPPKhWkTaZXfHxytq7B9pl5V5APO2hUGyUveCMos4Oy2p%2BnP%2BiQSPz48x6cOX8bMTHxKFemONwaVsfIIR1hamKIn1cdxPFT3q%2Bdt%2BzH4bArYSk%2FHzzshU3bT%2BLeg6coXtwctWtUQP8%2B72H1uiN4HPgqw%2Bt2bl8fEZExOHHmpvy%2Fkr0d5v13oPwcGxeP5av%2FwP4%2FPREVFYtyZUtgUN%2FWeL%2Bdq%2Fb8Gd9uxB2fQHw3sy%2BqVZFDN%2FDzD8Kcn3ZixcKRBfqlJyepoKev%2B1rE9%2Fwj0abvSRgY6GHX8sawsrDMuneUkr4wtDaKAnioRu8hC%2FDlpG6oW6tilsdu23UGH3RqACPDYoXuB%2Fr8RRguX3uADm1c2FoxzL8AXe2zQhyycO09%2FLbrET7pVA4%2Fz3LW%2BRoFbZ9zkxevwnHJ6x46pWp%2FV%2F16GNExcRg%2F8oMidz9XrvnCoJgStWtWeOu0qAwO%2FumF7h81KXT3%2Bba6UnO%2BrLwJSXjiWhM7lPoYm1GiWe3PK1TiF9Zz4DxUdSiDJfOGwcLcBNdu%2BGHD1hP4sFOw2F4a932foqStJfr2bJnmXEsLdU9zwdI9%2BH3bSXz9RU84O1VGaFgUdu%2B%2FgJ%2BW7cPozzoJYRwnj%2Fvfgu1S8HzQob78v3QpG3m94NBI3Bfid%2FLYj9QGJlmF%2FsMXISEhEXNnDYCdnSW8rj7AtK%2FX4emzYAztr%2B7Uet96JERwNOYu2onVS8bIbZFC8NKxRY3xs68hOjYJq76qhzrVLbN1rkLd0zfO7zx369JY1AsrnerYhC%2FXoGWz2jCyLXwi1ud%2BoOz4sIhlGCY9876oi2u3w7D1YAA%2BalcGbZtmL5a2oOxzbuL78Bm%2BnbctjYh1cXIQuiWpSN7P9r1npfbIDREbGhqFSf%2FxKJQiNqe6smFNdE1SYHFiEoqLf02UKRWZwgp6iO%2B8q0h0V%2FpEs9qfVwQ8eYVbdx9j45pJWq9qhXIl8EHHBkhM%2FGf4pGyZ4mjcsMZr5z8KeInFv%2BzH%2Fi0zUMfRXm4rX7aE%2FBwmxKylpan2WGvxuVIFu9fSsRSVycTEECXt1ILoj78u487dAJw58gPMzYy1aVqYG2PkxBXo1a05zEzVz7QePqgDZs%2FdIntWJKCLIicvvsSl68Fwq2cjjWQO0c%2FvfL8KjoBCofY2%2FHn0ivyu7t4LxLGTN2BfwRZTRKeEvv9tu8%2FKY1Z4%2FCG%2Ftw5tXeBYvXyW6R86chlHjl%2BVnZlGDaqjhzAShsUMcPbCHdlpog5Lm1Z18eknLWU%2BqL6t23Qc7dydsWrdYbx4GYZ%2BvVqh7Xv1ZHoRETFYKbZTHq0sTNGiqSPeb18f2%2FacxatXEfhRdMaIzwa209a7zIiLT4DHb0dx7uId2Zkb2Kc1XJ0d4B%2FwAjvE%2FX42QKRhbqytz9QxowZg78GLsBUdwkuX7%2BHCJR%2FUq1sJY4e%2FLz3UQc9DsefABWEMm8r3pORkbYeNYZiCQV9fge8%2Br43On53Bj6vvZVvEFpR9vub9UI6O0kgrja726dECVSqXlvsOHPaSNoZsa6e2rujRtan2vAtePti177y0l7VFO95btLc0khYWEaW1kUP6tZGjpXHxiamcAU%2BwZv0RBD4NRkPXqtKOGhupnRakEdq954wtu07jjk8AOrR2xoA%2B7jrfy26R1%2BOiXVHoKdBYtAXdujSBUqkn25qtIs34ePV9aIQkja7t2n8ebuJYjw1%2FibYhWtjSNmjW2FHm8%2BoNPxiJtoTup2RJK3zao6XUO2s3HsXpc7dgamIk2o6WWq2yXbQRle1L4oxoe85duiP1zcTRXaTd3rb7jHTUaMqG7HdpoWU8RFrkUKPRbFfnKuj7Sct8r7vZ1ZUa8ZqkQjn1w23VpImJVamHFSjRAJHoVnLXZmd%2FbkPC0draDItX7If%2F4%2Bdp9lEl0RAoxC412Klf1JD%2FfeoGalYtpxWwacRpKgGbHSi8oK17vdeExHvN60BpoA%2FPK%2Fe120jYjh7aCd8v3FFkjeShE8%2Fke58uFYpUvkmUPnseohWxg0cvwZNnwegiOkA3bvrjv%2FO2yn22JSzke5nSNrIzQj%2FqrFi%2B5g98t2A73FvUQetWTjgkjO5D%2F%2Bc4dfYWRk1aIbbVFUbwPWzeeRo%2FpHz3oeFRmLtoF6bP%2Bk12aBq4CEM6fpmsu8Soz1fgiTCwgz51l%2BKRRLLMX3ELWa8ob%2FRSKrNub4aO%2BVmOUIwZ9j5aiXo5cNQiGcpiX85Wdgo%2FFz1z4up1P0yfvUEbcrH30EUMG%2Fcz4uIS0KVTQxw5dg3ffL9Z7nsaFCLz32PAHNz3eyqFNcMwBU%2BjejaoXMEUXjdD8OxlbKHPL9k8CvdydXKQTh%2FqaJ88qw7bW7XuCJatOoh%2BPVvJzvdyYcc3bT%2BltePDxy1DvTqV0LlDA9wWtuzcpbvChltCqfePjdQXNvL0udtCRF6X51HnvVu%2FH1CtalmMGNwe3rf8hZ1bps3PkhUHMGLiMimmScBSe%2F33aW%2Bd7mXOwp1YuvKgHClr5lZTCuqXr8JkCOPUmb%2FKsERyZKxY%2B6cMfSSoXfrf%2FG2yDWnkWg21apbHwJGLESIEvYmxIcxMjWFubiLvRTOaOG7qKhlWRqPHHdu6YPj45bh555Hct2PvOXl%2BYmISPuzUCIePXZV5UrdvllpHG72MDA3wzZzN0tnSv1crKZz%2F%2FOsKkpKSC6w%2BZKUrSby6OuJxErATJGDTocwiUamQs9qfV57ZYgZKeCwdi6%2B%2F24S1G45K75GLEACDPm2t9WARl4RwDBK9m9RQTOyz56FSnOQm5EGrUa3c670KhQKlhOh%2BkS4fg%2Fq6Y7XoAZ4U4pcEeVHj%2Bl31%2FTSoa12kDf2IwR0wYZQ6PorqEQkyolWz2vK9S8eGsLPNOlSCesSLVuzD76smwaWeep3wj95vJL2Z3wphPFoIx66d3eT2cmVKoGO3Wfg8JRSF6vOODV9oPcS7D5zHdSGoaSTB%2B%2FYjzO7aTPau6UWeCU3%2Bjp64nsYb8SaoF%2F%2FA7xnWrRgPPT2F9DqcF4aejCoZwIXfDUHH7rOxaPk%2BbNl5BkvmfoZyZYtrz%2F98zEcY%2BKnaC1GlUmn0GboA383sJ%2F83NDLArg1fwsLCBAzDFB4a1LGG76MoeN8NR6kSRoU6r%2Fd9n8GwmBLthWAkW0LOAIJsKNnWA1tnwL68ndw2MaKLDB%2Fs3b25DAGcPrkHPkmxhSTm6BwbGzPsOXAxUxu5YfPfcgSMPLREfZcqcGoyQY56VRfCllgjdIZDpVJqPXH5vhw91bQNmREVHSedJUf2zNJ6kbt%2F2ETmicT3F%2BM%2FlmJbOs3EfQ4atRijhqofkmZjZYYtaydr09qy8zTu3AuQtr9K5VIynEBzP2TPyTF36fh86dAgLl%2F3xf5DnqhVQ%2B1c%2Bs%2BUHuj5cTP5meYOHT5%2BRdt%2BUHuTumxu3XksyryuFLAEhd4VBl7TlQocSgRmp%2Fe86iRiNQhtflUP6KDKYn9iIvzERfMkroYa4UM7ZsrYDu%2Fb%2Fjh17haGjFmK31dP0n4JJCKmf979tXNpeJiGcXMTSpOGMjIiXGw3NU1rQMilT6598sj9MKv%2FW19flLMqPytWSGi8fC9ubVik8p2e1BMlyKAkJOQsXipI9KLp%2B08%2FYYwE4wO%2FIDlUr4FituMTEmWstKajoxGwBBmqpJS4LRK6k6Z7SHHtUq8yBvdtA6faFbOdv3v3n8ih%2FyZtv0izvUI5W62AX75wBDp8PAtjhnVCU7ea6Tpj%2F3yuXLGkDIugyYuaupzbArag6wXDvAuUsFHb5%2BCw%2BEL%2FO2zcqLq0n%2FWaTUQtxwpo0cRROhmihSgkb2TPgWmfv0BzYqRte%2FBEnGf%2Fmt3NChqFauhSNU2bTPbQ92GQVsSmTodsZEJi1u3Do8fP5ciYRsCmzhNds1pK2kT1KmVl6ATpGGln0%2BX7TW0ShRjQXJ5mHb5Ms13jLCH09fTS5D91uGV6yJkx8cs1WL%2F5uIwd%2FrRHC7RoWqvQ2HXSlaJ03k9Uobt4T84qoQxFrDjxrDgxULy3EQmuFu8T37TfQIk52fHE5uQGraxMpWil12XRS6KeiEbEZnodZwfMX7xbzl6kYdncwLluZfy25W8ZZ5JakFBvicQD7U9Pr4%2Bb4xePP6U37G3xug1FflYwMzN1FYmJTYK1hUGRyXdeQZ0Y%2Bt5DI6JEw5G2TpmbGckVLTSQAKRhGurYaIRgZlBMEvWIKdTh4BEvOaHxyumF6h6qSvfbpmuRR%2BHw7m8yPWbHnrMyxIa8FyMHd5S%2FrQw7MGGR0uCbmBjmWXlmVS96CPv8sBrsk%2FTgKI50Fwf3FqXhrVRh9MU78GH5whQmGtZAtUQFfhb1tLaop5uExTqmn4xbFX3gvw3QqeecEzsXHa1O2tRYmSe%2Fw9zMN41I0UgRtZcUl0leS%2Fr89bRe0rYe2P4Vilubv3YehfCFhkdnoFcU6vXG3mATwyPTOp7ITpO9zlD%2FKHQrClNTYxm2SPG36Ve2MTMhZ1d0muvp6%2BvBxFRHW6pK2%2BaULmmNs3%2FN0enU1Pmnz%2BnbjzatnHDl5ELcvPtYhlwOGLEIJw59J%2Bcb5Zddz6i%2BpNaV4v0XIwN4xCZgsJDnQ1UKhGUUSiA7DekTEW%2FbRAI1xStAdDJqXr6NSVntz6tJXjQ0SjF7jwNfardRHMjNO4%2FRwLlKludTvAkN%2BY6csFwGU2ugof3Zc7bkKE80XBAmfkg0GzIxpef0%2FGWYnOHe9QM3lC71%2BrA7xe9OGfcR1qz%2Fq8gZ5Ypl1QLH2yfsnWx06EdO3kWKIdUFiqWuL%2BreslWHtNtosgEZYfeWdWX8lqYX%2FNvmv6U3Nb3YzVBY7j0njTuNPIwa0hFR0bGIE79gyhuFxdDQlS40bVQDjwJfyMkGGiienCZSEHsOXpDxXjs3TpNe2LFTV8rhLw1hKYaXxPfP4h5pyI%2BMb0FBDf8lH%2FhevoP9ZGvCElBR2KETSQqcd3ZEa5ZNTGGB6iPVS6qfVE%2BpvlK9pfqrq4DNKRr7XLl84Q%2F1uXHLXy4%2FSXNeaEJpe3dn6aUkkUo2ae7CnVobSqNex4XQImiuAS2dpWl3aclMioulES1yVGU2Qtq6RV3ZYdc4GMj%2BRUTFaMPBcgqJPvLCrlx7WLvtxOmbcvSX2oKN205qbSu1BXRvNPk3K%2Bh%2BHvj90x5R%2BAPZfwqr0EBxxann32SGZgIveYY10ATeZKEIqW0aPrg9TIWYDw2LLLg2OBNdefY6vOldXx9VhQ7fJo6LEAcHvKavUrcXKrUCvmAgEslAmGa1P9ehGNMAIWCbd5wue2bUmNKSWNMndUuzigAFTGuCpjWcPzpXBjJ7LB0j12x1az1VxjxS5bW2NNPGR76JWULobt5xSv5o%2Bg37Cb%2BtnCArxWaPyZg8Yy1qNxknZ5LTTHhy7c%2Be0TvTtGhFhWWrD%2BFVSNGaEOPe2Ba7Dgdix6FAtGtWEu8iwwe2x8CRi2TM8pSxXbNcjmTRnCEysN652UToiw6KsZEhtq2bgnEjOovty9C0%2FRewNDeVQvTX5eN1ysO6Tcfw1f9%2BRzWHMvB7GISZU3tKDymJWKfaldCo9RToK%2FTwx86vM%2BwopRbZa5eNw%2BdfesiOGgljmqi18IchMgZsxn83irx%2BIScQfPvVp%2BiUEh9LIS%2FERmEo1%2F1%2BHDGx8XKVhpWLRhWq7%2Br%2BfZCa%2F9alhgxl2ibMgBt7ZJmChjywSaKhFY1tfxKu%2BXlt%2F8BoeHqHoIydEWo4WBT6sqK1S4ePWyhtG60QQAJt9ZLRct%2FiOUNFx3oV6jYdDysh5kLCo6R9ponTX035BGOmrIRT8wmwNDNBLK3CsnQsnOpUhFuDanBrOxUGQvHs2Tz9tbaX4lybtp0Ge3s7BAS8xLL5I6QNfFuW%2FzgCIyYul0PzSUJ4U3zuzt%2BmYdqEjzF4zFI0a%2F8ljI3VwnXtMt3aAnKUde83Bw3em4yKFeyEvZ4q2pFx0lG2YPFuWWakY%2BbMGpBlWuTFpYllHbvNlh5pKl9aVWfqzHUylML%2F0XN079JYp%2FXU88pPkZWuTNk2qVFtzBFS7Iv0nllFils3WiSyQiSSYVhAVvuzC7mRPU956Hx8Qnwinr0IlZ9JmOYEcvm%2FeBkOI1EBciu04GVwuAyithEC2zQPh1zrNx%2Bs%2FZxbwz6ee3VbBDouPhn1PzyKV6HxOPpbc9SsonvZ1e%2ByL%2FfznY16kx0oVik%2BMVG7lJsukAeeOlbph77IKxArRGB26yrFg0UK4UsrJqQfniJPLxldTc9aF54FhUBP5E%2FXexo6dimaN3aUkwAoFCI7ZVEQ9VnUhxnirYVIox3LKKYgEXWR3HEnRV38Nj%2FtMzHmmyvYciAAsyfUwshPdV%2FKsaDtc0DgKxk%2FmtHka7LHJNRoxYD0w%2FtkJ2mugWbZS609fhEmZ99nFrdPHlIKKyhlayUfJpCbkH0mh0H6yduUJ1oqjCbvZgfyRD8NCkZpO2vtZC5NehQekP7es4KcZxR2YZOSP%2FJa04o51lZm2iVB89uu51RX0uoFJGbFBUaI66jXiVXqo9KbEslqf15DFS6n4lUDiYK3TSM9ugwTF3UMi%2Bnhu8m1MXiaJ0Z9fQV7VzaFuanynbtPTVwoLU%2By8tfDmR4384tPtL3WzEReTjtJZAAzW8FCY7To4R3nLt7NNI3t66dqP5cqmbMVJUgs54aXIq8xj8H8CGOMdq4Fpys3cY2lFFMQUP1DMuqI%2Btglv69No2T0oAPHqhYY3KNikSq31KuiZGSPM4vVz8xGZrW6DI1SZWdpTVrLdePWk5nunzOrv3ZFg8xEpS4r3mSouZR6GeqVnKaX3tFCzpDsOETygpzqytSeWZlOqo1ZncS8I9BM%2Few8evaD1qWxfn4DhEUkIOBptE7e2MiohCJZNu3c68lXYeXzMR%2FmWdq0IkJOjWRB8PdDxLo64ne9ZHQT%2F7KIZQrGnlL9U%2BB3qo%2F5aZ9pvg6FXC6eWQ9NXIpLh4OuFFX7nJ9QiGDqFQCY3OVtdaXmfCUX5b8PK%2FNiia%2FC4pS2NroPI3RsWSpb17j3MJwLuojRpFGNopdpFY6JdnwCf3tMwVVBNFao8FN%2B22caZe%2FWvmyOrsH2mXlnOpFcBP8%2BzE0NQgOfRefpNS5eU68oIYw7zWRL4lJn8oIkFW6KtrwalwRTUFD9o3rI9plhWMQy%2BUBxa8MTpz3zNkLkyOkn8l2lAD0vmMNRmDzBOFLWLVsuCaYAsU2ph2yfGYZFLJPX3H8U8%2F2BYwGJ8Ql587xkv4AIPAyI1NQwX%2FH3EZc6kxecC5BxiEZcEkwBYpRSD9k%2BMwyLWCavOX4h2quYgZ7n5v1%2BeZL%2BtDmpnkymAj1n7wiXOpNH0GriCi4GpgBRALn3NEG2zwzDIpbJgsCX0X1Xb%2FaJvXE3JFfTnbvSGw%2F8IzQG0le8XJP1sINLnGEYhu0zw7CIZd4aL2HL4hNU3cZ8fT4ptwwlGcitqb0HCpxWAJd4DU%2BGYRi2zwzDIpbJNS7cSDoYGZP42fAvz6qWrL%2BNnMZgUYxVz7F%2FpzWQKmwUf9ur9DGVS5phGIbtM8PkNrxO7L%2Bcy7ewtn7NZL3fdjxYsXmvn9KtXgl0aFkO1RwsYF8m4yejRMcm4q5vOC5efYG%2FTj8RRjIy7QFkIBVwVygwyNMbD7iUGYZh2D4zzDsjYlM%2FZ5cpWDxvY41LLVVgUnzSthMXg%2FTFK2fPo6MYKwVOi08dVHoY4HUTf3C9YYoa9Ax4LoV3G12e7c72me0zwyL2jQaEG4tC1OMXBs21NuohCfPFt9Jc9NKfis2WKgVsxP%2BZPXA6UnyRLxQq%2BCQrEC2%2BzIZ6gJlKiSaX86CHz%2FWGyTfhcMqDC%2BEdpSgKLbbPDFOIRCxTSL0TasPW1bkWnFKeR98OycIwKTI1kmYqFUKFIbUSny%2Bq9DHLkycJMAxTyNEIraLkkWX7zDCFTMQWJQPybyJltiq9ZhZKY871hmEYts9sn5l%2FPbw6AcMwDMMwDMMilmEYhmEYhmFYxDIMw7wZfvQsU1Dk6iNnGYZhEcswzL%2BL2MblYMTFwOQ3KfUulkuCYVjEMgzD5IQXMWYoycXA5Dcp9e4FlwTDsIhlGIbJNirAR1%2BBWlwSTH5D9Y7qH5cEw7CIZRiGyTYK4Bw9RpNLgimAyucu6x%2FDMCxiGYZhskuyHnZAhT6tKhbtuNgXr8Jx8LBXmm2rfj2MRcv3Fep879x3HhGRMdr%2FPa%2Fcx4ARi975eifrm6h3sv4xDMMilmEYJrukLP5%2BI8IYk4vyffg%2BfIZv521Ls83FyQGNGlQv1Pme9vU6vHgZpv2%2FTCkbdP3A7Z2vdyn17cYVfgoWwxQY%2FNhZhmGKPPoqjElS4LxLDVy9fAf78%2Bu617wfYtP2kwgOiUS5MsXRp0cLVKlcWu47cNgLew5cQEJCIjq1dUWPrk21513w8sEu8mBGxKC2oz16d2uObbvOICwiCj8u3SOPGdKvDWLj4hEXn6g9z%2Bf%2BE6xZfwSBT4PR0LUqPhvYDsZGxeS%2Bxb%2FsR7v3nLFl12nc8QlAh9bOGNBHtyiLpKRkrN90HH%2Bf9oaVpSk%2B%2FaSlTJ8gz2rQizBER8Xi4BEv2Ba3xIRRH6BMaRvsFvcXn5iEtRuOwdrKFO4t6sK2hAVeBUf8I%2FbEPS73%2BANXrvvCoVIpmWf7crZy3%2F4%2FLsHO1gpXxb6TZ2%2BJsiuFKeM%2FhqmJodx%2F7OQNeUxMbDwqVyyJAb3dxfGWBV7fRD3rLN4miXrnxr8%2Bhik42BPLMEyR5%2BId%2BCQr0EOhwHrXmphRpQoM8%2FqagU9eofeQBXB1ckAvIUItLUyEELsp961adwTLVh1Ev56tMLBPayniNm0%2FJff9efQKho9bhnp1KqFzhwa4ffcxzl26K8SfJZR6%2BihftoR86Sv1cfrcbSHkrsvz%2FANeoFu%2FH1CtalmMGNwe3rf8MUyko2HJigMYMXGZFNMkYL9fuEOKUl345vvNUiwO6tsazRs7YsiYJbh0%2BZ7c53X1AcZOXomL4n8S46Fhkeg%2FYhFUKhVK2JiLRkSBUiWtZJ7NzIykwF4j7p9ITlah99AFeBYUgnHD30dJIVg%2F6vUdXoWoRe7eQ5cwcNRihIRF4cNODXH%2Bkg%2Fm%2FrRT7jsnvtQpX%2F2Ktu%2FVQ9fOboiJicfVG34FWs%2BoXlH9onpG9Y3qHf%2F6GKbgYE8swzDvBFdu4WjDGnBLVOBnSwOMdqmJTVDhmH4yblX0gf82ICk3r3ff9xkMiynRXghGCyFg3VvU0Qq3RSv24cDWGbAvbye3TYzogg1bT6B39%2Bb4adk%2BTJ%2FcA5%2BkeGY7tnWR59jYmGHPgYtpPLap2bD5b7Rzd5YeWqK%2BSxU4NZmAu%2FcCUV0IW2LN0rHS20lcunwfV675olWz2m%2B8j8ioWKzfchxn%2FvgB5coWl9ueBAXLeNwGLmpvbKd2rpj334Hyc5f3G6J2o3G47ROAZkLwKpV68h4qV1Rf96LXPW3aFzzv4umzEOzd9B%2Fo6SnQWHxBJIrJ6zxicAd12Yzqgs8GtFV7VfT1sHbjUfn55p3HKFvGBm1a1oWBKOd27vXyvU71APQfVoN9kh4cUyZx9VYB3koV3Lxus4BlGBaxDMMwuUSKZ6ytcy046anwsfg8LlkfVX1rwt41l5%2Fq1bhRddStVRH1mk1ELccKaNHEUQqz6Og4hIREoufA%2BWmOr%2BpQRr7fe%2FBEnGefZh8JvKzw8w9CwxRRSRgZFkOFcrbwfRikFbGp0zE3N0ZCYta6PSDwJQwNlFoBS1SvUlYK6owwLGYgQwnIu%2BpYvfwb0%2FYVea7qUDpNvqpXLQNfvyDt%2F%2Fr6%2F%2ByzEHlOSkxWi%2BVODbFz7znUbjwOTnUqoW0rJwzq20aK5tzCteabn7blq34al7%2FI4T1Re84lK9CBY2AZhkUswzBMnpEiNHIkNrISNhqKCeG3bsV4BD0Pld5FChmgz19P6wWFQoED279CcWvz184zNzNGaHj0a9sVpLFVmV%2Fa1NQI4alWASBoVQBzs4wXZaA86AKlGxefgPiERHlPMt2IGJnPjKAwAhLpNlbmqbZlnLaZSJvSSpvnWBl2kFWe7UpY4uD2mXj46LmMy%2F1x6V4kiwsNH9Q%2B1%2BqJ121%2BXDHruBWuAAADNklEQVTDFGU4JpZhGCYH3Ljljzs%2BgShpZyWH29u7O8sJXiT%2BmrrVxNyFO5GY4lUkIXf81A35uXWrunKoPjFB7SW99%2BCpjIu1MDeRy2ylF30aWreoK72jmuWsKN41IioGLvUc3uo%2BKJaVQgE2bTsp%2F6d8bd5xCu4t66QRy6oUpbpRHGdqaignpBGWlqZ44Pcsw7SbNKopPc%2BaWFa6v0OHvbShF2%2FizPnbePI0GBUr2KH7h03QwLWKKN8IrngMw2hhTyzDMEwOiI6Jw%2FBxC2U8LK0QEBUdh9VLRst9i%2BcMxdipq1C36XhYCXEaEh6F4QPb473mdfDVlE8wZspKODWfAEszE8TGJ8Bj6Vg41akItwbV4NZ2Kgz09bFn8%2FQ01%2FugYwMZ59q07TTY29shIOAlls0fARPjt5%2FDtnT%2BMAwZvVSI19NCaIbBpW5lbcwqcd37Ieq3mozk5GRxr4ZYuXi0dlh%2F2IB2GDP5F9hYm8tzHGv8E2JgW9wCC%2F43GP2H%2FYRKFUvivt9TDO7bRsbSZsWz56EYMnYpypcpIT3FJJZniLJjGIbRwEMpDMMwqaBwAs9THjofHxD4SsZ8UpxoekJDo6S3lFYMSD%2B8T0PyNIRPntzUPH8RBiNDAymOMyIsLEqGFZSytZITnnIL8rQGPHkFY%2BNiKGFjod3%2By9o%2FceOmP376YSieBgVLz216wsOjERuXkOnyVyRC6b6sLExlrK6ukCebrmkoyoPCC3KD%2Bs0Haz9zOAHDFG3YE8swDPMWpJ4QlR4rK1P5yghra7MMt2e1Dip5JOmlK7v2n8fGrScz3T9nVn%2B5ogGJ7IwEqraxUOplup8Et8Ub8kCTwd6Udk6uyTAMwyKWYRjmHYbWWKVXTqElumh1AIZhGBaxDMMwTJFBs3wXwzBMYYNXJ2AYhmEYhmFYxDIMwzAMwzAMi1iGYRiGYRiGYRHLMAzDMAzDsIhlGIZhGIZhGBaxDMMwDMMwDMMilmEYhmEYhmERyzAMwzAMwzAFCz%2FsgGEYJh31mw%2FmQmAYhink6HMRMAzD%2FMPTl5hFrzK2%2BIZL493%2FrrkUGKbowuEEDMMwDMMwDMMwDMMwDMMwec3%2FAYz400B3cxffAAAAAElFTkSuQmCC)
+
+```
+section_block
+ ::= SECTION '(' int_const_expr section_options? ')' section_contents
+```
+
+referenced by:
+
+* command_file
Comments:
`section_options` is not supported and raises syntax error when used!
-
- section_options:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- section_contents:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
+**section_options:**
+
+![section_options](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOUAAABFCAYAAAC11SH4AAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAADR5JREFUeNrtnQl0FEUax%2F9z5Q4hdzYJBkhCSEhASYCIgQgLGAXxIbDiBcoCcoq6q%2BDTp6vPZR%2B7yO6CsqsiqLvKEdGHRDxBkUg4JhwSEgk5OJIAue9zZnqrejLsAJnMTDJXmO%2F3Xqen093Vx1f%2F%2Fr6qrqoGCIJwKCSOciKCcpHi06zDK3Pza%2BaeLayLrq5rd62obr3p%2FPx9XVWe7oraAD%2FXAwUXW%2F7yw5HmbDIjQaK0MN99kLgkY9%2Blv%2BUX13tOmzgAKUlBCAnyQJC%2F203blle14kp5MzKV5dj9%2FUWVm4tMWVrZ%2FFh2DgrJnASJsrfeUfiTdOeGXTs2b8uf9diDkZgzbRBcFFKT92%2Fv0GB7RjE2b89vbekQHlSeVn9FJiX6OjJ7HjzOr2rnlh3nZq17aRSmpIRCJjPvGcG3HxHrh6ThAfLvDpbOCfTVlJRV4ASZlSBR9jBk3fhh3vNckAkxvr1KKzjAHUkJAdIvfyiZHugvXLpCwiRIlGaGrcpFig3bju67JzXchXtIS8CF2dKmluTk1UwNDYSSecwCMi%2FRF5Ha46C8lrXgQoMnL0NakqcejoGLi1SuEbAjMR6RZF6CRGkiuedq5qWlhplVqWMKPL3RIwJ57ZUcaqwj8xIkShM5W1QfmZIUbJW0p4wXw2F3NqXcMQwjyMQEidIEqqrb3MJCPKySdlxUf%2B0PCcqlGswkExMkShOorm%2BT%2BPu4WiXt8OBrYvdi02QyMdEnRTkmHt3GksbWm4tGLUAqs067BV26ggA%2FNruNTEzYit7qRLe%2FKMoONcoSY7HTUKLG1jsiEq2nDKasQtiKnupkdCxmJMbhkkqNYr4s78zAXJyz1Wq2Mhafy2VYcSQHV%2FUyeLfrrcnmncU4lVeHtPEhmDohxNzdZZRVCBs6ArN0wsWolmADCxzDIfz%2F%2F3L9jQTtssFEja23Bj8rq5Dxw2WEBbv3RJQEYXOM6cSQGLsUpaFEzT2oJYkZ7I2a%2BnbcFupO1ib6tjgl%2BEoFvG5IjN2K8lqFDHCS%2BeM0wch6lQrF7KBWUc3qxTG92p%2Bdl0DZg7AnXCcstJ2qEjCLzTXGMqTcQGx8iO1YyuaTWIKb2fzZ7tYr5Fhrjqc0Ryhl5a0ovtQEb085hg%2F1MfuGZOd13z1tNit3nh%2BCCLUUcWzLiWzjh9nJ5cgFLDv6K%2FIpSxFiyDkUQ1QSvM3yRzzLH9tYDt4v0yB3YD4upAPqrvK1vk7Y%2FB03Bba0dmA%2Bc2QLBAnqwD2mMVHqEhG0iRxRyBDLxcYO9mx36615M958Px8ffXYBLy4Z2iNRGkO8ofkoYj%2F5lBEVhRd9FHiexfyH74jD7BO52EdZ0rlh%2BeC3LORMZ%2Fl%2FfV0HphUUoE237lg3Ts2ATp4bE4%2B1HWqsMiROfVGmGxFbui3FqOPgsUp4ecgxf9ZAmxig84a%2FMXKoGJqnsydkMnlM5%2FaQXJCCgLnHf0WGKc95Yzrp%2FJ9BcepE2cISKelGbMbWW4WSKy1i6Lrs8Uj076ewqTG4AViEsJ55zLfY4hTKns5Jp%2F3XmyhIs3RyoziZh118TZRyGQZ1l4ix9dYiU1nJu2JhyaOD7WIQ7xasa3DHMt6w%2FcQZnKIs6mRhK%2B%2FQoEECywfTTdm%2BpzrRF%2Bc1URpLyNKC5E3hTGlqd29qCO5ODkRwFwNoGaKxqcNi5%2FnjebQmxuGTzobtJEonQ7S7BJ%2FwfGCGuHqMbn%2B7NEjv7%2B2iqqprM7qdj7cCIQFuZqV97ny9ZU9WwH4WktxJWdT5EO3O7G%2Fzh4FdwkJPRW3plWarpH30VKU4lwhoQGdVda%2FKFALOMH8%2BhLKo88Htzu3vFKL093U9kKm0ThH1u8wy7VNOgnI26%2FVB3BvFNAIpizolgZ32v%2FVFyUc2%2F3J%2FiYqP22pJiksacL6kUXdl%2FL3jxd6mmVUilifcKH86JW6d9r%2F1Rck%2FNeCikCr5QMqWZPXabP0CQRN3nJYpWjjO5x0IW0ewtm%2BmKbXX1fJPDfCRzU%2BfrbFIen99NweFFxp0MipiU6JGil2Ur4i%2Bht1Eyb%2F90d4hzFz%2B6mF1b4XJBblT3%2BtKkMkeccfo3SJBojSTI6fVextbVAufevGQsPGjPJhbxuRlyIdW%2FHi9IAV8zP7eI8jwApmX6IvI7X0Cx3OxNSlWI%2F3PrsJ%2Fb%2F%2BiWJ58ewDSUsMxJLIfIkK9rtu2uVXFh6fE0ZMV%2BD6zjImy8cbS38diTw8JnlTSV7gIEmXPUebh%2FZHDhFJ1uzr9wNGrMjaZ1zeTlyFZyAre91OKedln8LUj33Tq42nFYlFe36%2BUkzvKiRxnQkqMx%2B3iyOYCxjFvd5n920eQwI8te96weSO78xUSAfkaCZpZDh%2FN4nAvQY6xx%2FuIh1Qe3EIKsjBJ4%2BaTp7T4U04rqBm8IXBne9Mp0LAnn%2BQmUXoJAmqZYPnIy0dZ%2BfE1JVXqEHpRSF%2F2mHJHPKnOWlM%2BvULZjHA2pHQLCIJESRAEibLXUFM758MuTexIlKbTemc4NUp3Jjrt3UqidFwqWrzouyTORKe9K0iUjhu75sskGEZ3wnng9uZ2J1E6buEiizffozthGjU1jWhoaOnrRp8o2p1E6ZiIXcAEPHL3wL5TrmxqbsOuL67PU3z5lT9%2FYvVjv7EuHVs%2F1o5hve%2FAL1i5arPRffb%2FdBqXSisd4t6Jdmb2tlfXPxKlCXQ2Zjjd4I4%2F9pVzrqyux%2FMvf3Dd%2F%2BJiwjFhfIJNz2PwwGCkTRppdLuN72Tg1Olih7h3nXY%2Bba%2Buf3KSnIllDAHL%2BacM%2BMjpJg7MaxEam1rx7tZvoDxZgIgBQVj0xBQMitDWOX39%2FXF4e7njVM55HDryK%2BKGDsDKJffD08MV6Z%2F%2FDLVGjfVv7Ra3%2Fd2MFLS1q64LK0tKq%2FDeh9%2FibEEp7kgYjMXz74GPj7ZF49b%2F7sPopGhkfK3ESSaWu8bEYumCeyGVmvdmSKXSoLau6drywUO52L33iHhd%2FDrmzpmA4gtXUXq5GnvYsfILypAwLAKTJ9xuFzsz%2B05js%2BeYvZPtldfIU5oI%2F3SBRoLZEgk%2BSozFy1FRcLXFcZ9YskHMtMsXTsXA24LwwJw1uHJV2yn8KybKhSs3oa6%2BCdPvG41D7CRXv%2FqhuC4owIeViyQYEBYgTq5uCvzCxLt771FxfW1tEx54ZA18%2B3th5eJpqKpuwENProNare3TuoWJ8smlG%2BHTzwPT0pLEcHTn55lmn%2F%2B5wjJs2%2FWT%2BDv7RCGefuE9TBiXgJnT72SCVeP4qUL0Y8dwdVHA389bPFd%2BTraG25PblduX29men6ogT2lOGJuLffzbIvzrSz4KLBsZ2%2FXXlyzFyV%2BKcfZcCba%2F%2FwfIFTKMHTNU9FrbPj2IZ5dpB%2B1e%2Bvt7sXzRfeLv4cMGIm3Wa3hzzXykjouHTCLF7Bl3dZn2rj1ZGBodhmeW3i8uJ4%2BKwdjJq5CZlYfUFG1F899ZOnclx4q%2Fi89fxfGTRZgzc1yPryePXUtQoA8mTRghilDfGwb4e2Ps6Bj2ABhlE1t287W15Ow8%2B347hkTZA4%2FJZpPFniwCHmS%2Fn9bIEF0Ui4hEC7f6KWIecvDAEFGQOmKiwlBYfPnaskTviJGs%2FNbBQtSqqgajaXPvGx0VqpeOBNGRoSg6f%2BWaKPVD1X7eHqiuaezV9UydnIgdn2UiIflpDI8fhImsfLtw7mQoXCyfDY31WS3Stta5wK7wHLNaFvOOaY4yfAyJsneVP6eskWF0eHm6oaHx%2BlcLfNnLq%2Bs%2B4NW1jZDJpKxc6IFKJkxBELpNu7Kq%2Fua0PQ1UMFvgcePr64U921%2FChZIK5nUL8Y9Ne9DRoRLLwRzBgo3a%2BnLXLSpTOjDJSUNQdrkaR7K10RR%2F%2F5fxzTHRw%2Biob9CONK%2FRCHj7vb24OyUeHu6u8PF2Rwcrs10s6fo1w8Txw%2FHtvpMor6gTl3PyLiIn9yLGjY2z2vVkHTsrvvaICA%2FEjGnJYsis877cExcUXSajk6d0bHgFyD%2FXLsCiFZsQEREolut4mU6%2FLPbZnsP4dHcW2to7xNrMzRuWif%2FntahzZqZgyoxX4enhhrfffOq6tEcnRmPBvMmYcP%2FLiB4cKobEa1%2Bfh5BgX6tdTxXzzPOXbUTYb%2FyhVqvh5uqCrZtWaCu0Hp2Ixc%2F8SwxvJ6YOx5pXHnNau1PPBzvAw1dzhgNpZyHe1fJa5v08RKHqWLl6M4awcuD8xyehvr4ZwUH9b9qXv6%2BUSqTw8%2B26RpOHrPyVRWBAP1Ek1obX7pZdqRYreniljz4tre1ieTg8zL9HaesPB0IjDxBWxUUhF18VGMLdzUWcuiLAr1%2B3afP3nN5epo9TdiDzDDa%2B%2B6XB9auemYFRI6MNrudlXkPXwq%2Bhp4Kk8JVwCB6dncrKYu42PSavmdXVzhIkSuIGeLmQuPWg2leCIFESBEGiJAgSJUEQJEqCIFESBEGiJAgSJUEQtoYaD9iJW%2BWzbYTlkdEtsD2XK%2FEan0ID8Se6G9a7xxS%2BEgRBEMStyP8AXI8W%2BBK4i5IAAAAASUVORK5CYII%3D)
+
+```
+section_options
+ ::= ';' option_list?
+```
+
+referenced by:
+
+* section_block
Comments:
@@ -1086,1901 +309,562 @@ Comments:
The IDENT in `<= IDENT` must be an identifier defined in the sources block, otherwise an error is raised.
-
- statement:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
-
-
- basic_stmt:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- load_stmt:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- load_data:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- load_target:
-
-
-
-
-
-
-
-
-
-
-
- ::= '>' '.'
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- section_list:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- section_ref:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
-
- erase_stmt:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- address_or_range:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- symbol_ref:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- load_ifr_stmt:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- call_stmt:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- call_type:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- call_target:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- call_arg:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- jump_sp_stmt:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- from_stmt:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- in_from_stmt:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- mode_stmt:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- message_stmt:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- message_type:
-
-
-
-
-
-
-
-
-
-
-no references
-
-
- if_stmt:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- else_stmt:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- encrypt_stmt:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- enable_stmt:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- reset_stmt:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- const_expr:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- int_const_expr:
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- bool_expr:
-
-
-
-
-
-
-
-
-
-
- ::= (
-
bool_expr
- ( '<' | '<=' | '>' | '>=' | '==' | '!=' | '&&' | '||' ) | '!' )
-
bool_expr
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- expr:
-
-
-
-
-
-
-
-
-
-
- ::=
-
expr
- ( ( '+' | '-' | '*' | '/' | '%' | '<<' | '>>' | '&' | '|' | '^' )
expr
- | '.'
-
INT_SIZE )
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-referenced by:
-
-
-
-
- unary_expr:
-
-
-
-
-
-
-
-
-
-
- ::= ( '+' | '-' )
expr
-
-
-
-
-
-
-referenced by:
-
-
-
-
-
-
-
-
+**section_contents:**
+
+![section_contents](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAUEAAABzCAYAAAAGy7AjAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAHcdJREFUeNrtnQlcFVX7x393Yd9kEwNUDGUTFxYRzdTUFHPN5U19zcrcSrPFbHnrfdP%2BVq%2BatqhvWq755m71pqW55UK5AaIoCLIqIIKI7Ou98z9nLiCWyHbhDvc%2BXz7D3Htn5syZOc%2FzO885M3MGIAiCMGBkdAr0jwBvCHQWmofwGPIZfUNJp0A%2FCTu1kU6Clgl8fDqdBD1ETqeAIBoWZVOkTSJIEARBIkgQBEEiSBAEQSJIEARBIkgQBEEiSBAEQSJIEARBIkgQBEEiSLRizobH4WpcWr3XDz0djcTkDMkdR0JSBv44e5UKlCARJBrGdztP4LdTUfVe%2F5sth3H6fKzkjuP3MzHYsPUIFShRK%2FTssIFz8XIytu85iTs5BXB1tseUif1RUlqO6NhUZGXnobi4FB3aO2LCmL7YuuM4Ii4mIDevCC6P2OPFaUPg1qEtwi8ksCjwFg4fu4hbt%2B7Co7MzRob0QmFRKdZvOYSwC%2FFwsLfGjOeeRFevDuJ%2BN%2F33KHoFdMFPv5xDTOwNhDzpj7EjgplgHcbZ83Hw8WqPN%2BePhYmxkbj%2Brcy7TGgPISr6OjxZ%2BnOmh8D5ETtUVKjx5dp9GDU8CJu3HUXK9SyWTm9MGNtXPKYjxy8i5UYWVq7%2BH5RGCsyfPZIKnaBIkNCQlp6NyS%2BuQEAPd0wa%2FzhsrM1x8o8rsDA3ESf%2Bvb2LAxztbcT1M2%2FnonegB158dggUChnGP7sUFeUqWFqawszUGLZtLMT17e2soFYL%2BPuMlci%2Bk49XmPDw7Z554VNRzDgbmQjOmLcabWwsMGRgD3z4750Y9vQi5OcXYwwTsYNHLuDrTYfEde%2FeLcSYyR%2FDybENFswbI27zt%2BeXiwKoUquwggnc3AXrmDi6YODjvnj7g28RGZUEI6UCtraWYt54vrhwEwRFgkQ18YkZLNJSYthgP1gzwRvUv1v1so4s%2BvP2bI%2BJTz9W%2FRsXoPyCYiSw7bhwbdp2DGkZ2fDs4oJH2tki0L9z9fonQq%2BgpKQMH743RfwexKK%2BYycu4TCLzKb%2BbYD424qPXsBjwd7i51Ono9HDtxMTzBHidy6e4ZHx4ucd359CnyBPzHx%2BaHVa3%2B87g4tM6Hy7aiLLHZvehB0TPM5vJ6Nw4WIienbrJAp8QUHJfcdBECSCrQC%2FrughFzAOAvqwr124LkHL4z%2F26e2J7l3d0LPf6%2Bjq0wH9%2B%2FqIzUwrS7O%2FrKtSqVmEtQXHmMD08HUTozEOj8YeRFxCunhRInjwW%2Ff9XiV6YjNEfu9wLNk%2BZbJ7361YdFmVdlx8On49FvmXtEpKy%2B6lVXNbKzNUqNTNWj71GEmGL09h0zVWaqfVMnx%2F4QoukmWTCBJ1EOQFjwoZ1sjU8GVetJ250pcKNaLd4pCym2mRlhxUxNhIiS1rXxWbqOGRCfhq40Hx86dLXtB4sXAvmaMsiuMXGUJ%2F%2FQTmZibibwcOR9zv9TX2amlhip7dO2H3lrcadyJqiBpPa%2BKYvlj8j8l%2FWa20rPwBm8r%2BlC%2Ftj3xV1%2BCqEwFFsgc6quTwYV8HsQrtoL83LisFzD13FXFk6dKB%2BgSlFP35YLBKhjPMu07klsMtIgZvRFzF%2FvNxSKyvADaEqOgU8TYYp7Zt8NTQAAwb5CdeTODYWFuw5vLN6nXLmNgoFAoolYrq5m5xjUiM9x%2FyyK%2BKJx73ReSlJBY5Xqr%2B7VrCTfEiSEMJGeKPPT%2F9cd8tO2fC4pCZlVvntryZn3w9U4xkWxJeXrzcePnxcuTlycuVly8vZ7J2igSJB0SAKgG7WdAyjTtOS%2ByzqLgUs%2Bd%2FJgoFv3ggXs1dNVdcNmlCP%2FHiQ%2B%2FBC%2BHj2R7rvngZG7cehd%2Fjr4tXbPmFDqVcUZ3W1GcGYtqcz3HgULjYZ%2Fflsplsm5fw1r%2B2VEdmPCJb%2B9lLDc5n395eeHPeWIx79t9oY2Uu5tPOzhLbNyyoc9vB%2Fbvjy7X7EThgARRKOcKOr9BJ%2BcbHo5TNlvh7IZJFHrtZeQdTRCgN6H0JEoE1Yfml0JOsmbVEC2kJDRlePzUtW%2Byf47ec1KS8rAIZWXfh3M6ORYHy6nXNzU2qL0L8uWnKozN%2Bq03NJmn6zTswNlHCwc66ScfFo7n0jDuwYULIhbsh8Hxz4axqyjeGmsPrN%2BVdI6x83mez%2FiyNoWT51BwmoLkIwmbdrIrxqS727%2Bpi%2FxcB5BgZK8VbS6oEsGrdBwkgh0eIfP0%2F98nxtJsqgByeD55%2BQwWwKt9NEUBtUlnO3SrLnSARJORqjGdxxbbjySihs6H%2FiOXMylssd4JEkBDvpejD%2Fh2jM2FQhX5MLHeCRJAQO2b5RZErdCYMB17evNzpTJAIEhoczQpwi06D4VBZ3o50JkgECQ2mp1OpP9CQqCxvUzoTJIJEdYuYXuhtYAigW9RIBAmCIEgECYIgSAQJgiBIBAmCIFocGkBBT6n5nCtBEBQJGhT84f6mPOBPEBQJ6gFC2CyjPafPvBodlzMtNiG3y53cMpOsOyV1CoO9rUmFhZnRXQc7kxPx14s%2F%2Be1sUTiZCUF%2BoL9%2BoJcieHhzwEuvffHj8rikPIuRg9pj7JwOaNfWHG3t6743NTO7RJmRWeQQGpY5PiXt%2BpjRA83D0m4XTQ2%2FjITWGBGSDBgu5Af1Q6FXtZ6wSO5jl71r1eaYhcMGuhovWeCPYD9HODmawcK8fnrP1%2BPr9%2BrhgGdGdpKrBbhGxeTMausgi0jPFOKbI9%2FOjlh08zYWk9saFs1V7q3VD0gEtQAv%2BI07r0349L1eGNrPWXwtZJNODtu%2Bh7cdArs7KA%2BfSpvkaKtOTc%2FCBRJBQsrl3lr9QFfozYURHvqv3xE3Yfk%2FAtHN01arafP0Vi8OViiV8vV%2BPqDLrgT5gR75gV6IIO%2F83X%2F0xvKpT7trveBrGsCUMY%2FKlJCtC%2FTBcHI3gvxAP%2FxAL0SQX%2F2KT8m3mDSyU7PuZ%2FZkTxgby5VqATsDfOGuTfslFzY4tD5ohh74AYlgY4m%2BlvNcyAAXGBs17%2BHw9IN6OHLrVUKl1feBlA50o2GVDIk%2BrmJ5l5AfkAhqhdjEPPd%2BgU4tsq%2Bh%2FZ35zIxN%2FbT4opzsQksaYNOQKLYEN9gs8gMSQe0oyJ1SU5d25i2yL5%2FObaoaM5lafFFOYoWahlo3JBQydGVt4TjyAxJBrXAnr1Rmb9O41ymmZ5bgxs0iFJWo6rW%2Bq1O1kfH3Tj6pjfwzZwiTqdGPpMGAkGEQa06e1pUfZNzW2H1BUUWj9tUcfqArxDsne%2FvC6ezl2t9xUddyXaNWCZA38F6ouOQCPLvgHBKvF4rf1y7xx%2FhhLnXXGpX7EQTYybT0xI0gw8%2BsNvqSffwQdJFE7%2BH9v%2FkCpqjlCNGVHzwz%2Fyyir%2BVBydafPrETPlrQtWHRUzP4QUNpqi5VbS9GguUqpAd4Yxf%2F8UEr17W8NbJyfZwogJNGtsePa%2FtiQC%2BHBlbkYg2olfNxIRq%2FsQTlgT70HlpDIN8Mb7JZ1IUruKirPHzxfg%2F8d2UQbKyN8PWORMTE5zUyoNWeHzSUxupSkDeeDvDBjQoVkqojQZmmWTxRpWILvfGDUoFXaipsXctbI5l3SsX5rEmd0M3TptFdO9qqxNk5foPVqpt6eiEs8iqSSSr0E38vjGSzNxQCgnWZj54%2Bmj69%2Fr0c8cOhNNzKLoV3Z%2BjaDxoqwA3SJS5%2BKhm%2BZAGza8321n1hrKD5XmuidS1vTVT1hVhbGkkiP2HROODvgy%2BZc5xi8ykR0ThFkqE%2FdO4MExsjLOQCyGq8ieEx2r0o0lisLJX3%2BUNrpC5dqk38HiiCtSXa0J1KFRU7C0mphTh5%2FjYuXc1FX397dHA2l0z%2BmPB9HOCFZJmAvf7eCGPznWoFztsUIvF4Mr2SszUxkUVHyR7oqJLDp%2FIiyGTmN5eVLAKUigByeD%2F49p9uYM23CXCwNYGHmyXs2hjrhxjKcIBJ%2B4e1id9DRbC6jQZEsngzRKhjeUUFkthOzaR%2BknjI32fCb5pmQJADvlsZBFkTB5tix90sFzJYtoazf8PlarEPie%2BHaEUk3ivHmmXajkUksVIqSx4IbP8iCFNeP4dRM3%2FHxOGu%2BM%2BHfpLxg8bAdYmd6xEVAiawubqujClrccA%2F2IZpbD6EJbiezV9%2F2HIjJZZWRYIPqQHnnrvaPDVgfQvAgdVwGz4JwO%2Fh2di4JxlvL7uML%2F7ZtPs8acw%2BQio0Roj4XRKz3ouAk70p5k1zR%2B8edpLwgyAveFTIsIYl6ssOajs7smMKNaLd4pCymzXqHnS8NXWJzdeZGmFjSTmms0BthiBDLnhEWJcIViUiaBI5a6SANxc3trPXH7a8ZhpiBuPEipBP%2Bzt3xru8L4TVgGf8fDDxQjSO6spIjI3lGD3EWZxOX8jGtp%2Bu4%2B3ZnnBuS0%2BsEYbJJhYM3Llbho8W%2BGJCiIsk8sR0YjBrwu5merMytxwj4%2BNRWrXs%2FEOCtlp06Y3evlharsLbtYlhTRHc%2FTBxq8fyB1J5AEv8vcSm826m8MHNFRE2BAc7EyAhH3dzy0gECYMlhwkgx14i%2FYA8AuQCKAiYFnEV%2B%2BuxSZ26VPlbrWJYJYLFLJHUh4hbXcvrhB8QiyhXsohwNfs6VNcn28pCc%2BgHT92C56NWTR54kiBaGzezShB2OUf8bG0pjTdtVOrDynoKYIN06c9iyDx%2BTrUIKhXo9LBE6lpeb%2BEpxqf5ZpjLH7jW5Y2inJnPdMLxM1n45Kur4lTfJ0YIQh8YMOWE%2BMQIh18k9Ku8b1CnzWA%2BEIMa3ZhOjK7P%2Bo3VpZpiWC2CdSWkrdtf%2BG0eAT7YVvnAtdZEkD%2FC09BH5%2FoFOuDC%2FiGIic8Xv3t2sqzXdgWF5eRBhCRpiB%2FwJ0YKi1WwMFNU3zjdEJrDD0RdkGFbfW8Ha6ouVW3f8jGwgGMshH1Nm0m2sTKuyM4tVTraNaxvz87GGI8F2Ddom2vJeeRthCRpiB%2F0bGLk1xx%2BwHShj0zA5y1eebR4m1%2FAFVZPaXXYKCsLo7tpGUUtkv9zF2%2BLc1ZYPIRUkesRUqG1%2BwHXBa4Pei%2BCZgViCKrVAUTtbU1OhIa1zAMrh0PTNbWWDJlsdotcj5AKeuAHjpX6oN8ieDpVbO9r9Z6U%2BOvFn%2Fx8LLWirFzdrHlPSs1HcmpB1Znj90FeJ9cjpIIe%2BIFppT7otwhqmv7avbv8t7NF4cZG8rAd%2B5OaNePvLA2veRR8IMLD5HqEVNADP9D6y6ekKoLNQtrtoqnrd8SVRMXmNEv6y76%2BjISU%2FKqCT2RTgFqOveR6BPlB6%2FYDvRHBcFY2ZeXC%2BHkfnFFp2wB4we%2BqWbvKEMqqrPO6vteRIMgPmo5OBkN0dsSim7exWOu1YKZwzd5WfePAsdTRRaUqmZ%2BPfZOeBOF9H3PeO43Q87dqhv%2FfscIfys7c5JuZyCG3IyQXDbZSP2guXagLpb4ZQEQ0NgV6q%2BVb9yas3fFTkjK4pwNCBrjCw90aHZ0ffkN0UUkFf20hzkVm4UhoOiv8gvtX0BT8IJkML4SxGpfcjSA%2FaP1%2BoNRHAwiLwQb%2FrkKaqky1%2B8S5Wwo2NW2sQ973wUJ%2F8LEV5Xgu%2FAoOkpsR5Af64QdyfTWACFZAMgV6so%2B%2FssLLZo2By2y6wQqxsB6bF7B1k%2BQC2xb4QQBMxBfKKNE3ggSQID%2FQKz9Q6rMBhGtC9af5g9mVzysPhZoVvwwWdWxqKQi4K8jAny06JyiwOIwughDkB3rpB0pDMILKq1d8%2Bhe5BGGokB8YWHOYIAiCRJAgCIJEkCAIgkSQIAiCRJAgCIJEkCAIgkSQIAiCRJAgCEJ%2Fb5YWwmYZ7Tl95tXouJxpsQm5Xe7klplk3SnR%2BsuF7W1NKizMjO462Jmc4CP78oEtm%2FvYArxbfuBJonGEx0AmBTvXhZ2SCOqQw5sDXnrtix%2BXxyXlWYwc1B5j53RAu7bmaGtvqvV9ZWaXKDMyixxCwzLHp6RdHzN6oHkYH9gyvJlH1wg7tZGsV%2BIEPj5dMnauKzttDejVeIKCsEjuY5e9a9XmmIXDBroaL1ngj2A%2FRzg5msHCvHn0nqfL0%2B%2FVwwHPjOwkVwtwjYrJmdXWQRaRninEN9f5mzV9DKmMxPl60%2F%2FEstK2vTfGznVhp1LRhbrQqz7BXV%2Fu3blx57UJK97vhWlPu8PYqGUPj%2B%2BP73fNh8Gm5sayfYE%2BmE5SQEjNzslO9VQEedNg%2FY64Ccv%2FEYhunrY6zQvf%2F%2BrFwQqlUr7ej4SQkKidk53qkQjyzuH9R28sn8pqN10LYE0DmzLmUZkSsnWsph1O7ktI0c7JTnUnglp97Sa%2FOhafkm8xaWQnSZ3c2ZM9YWwsV6oF7AzwhTu5MSFFO5eInerkdZu6FMGSPq7aewF79LWc50IGuLR4H2Bd8PwE9XDkpauECp%2BSGxNStHMp2GmlHpToYt%2B6Uo2sYks4aSux2MQ8936BTpI03KH9nfmMv9uhHx%2FZl1yZkKKd69pOK%2FUgy2BEkMW8cQoZumorvew7paYu7cwlabg%2BndtUBfuZlUObE4Tk7FzXdsr1gOuCwYggC7tP81f2aSu9O3mlMnsbE0karqtTtdHy9xw%2BSa5MSNHOdW6n%2FBWeXBcMRQTVcuxl4eCUgW7a6RdUqwTIFTJJGm5VvgQBdmzWgVyZkKKd69JORR1geiDqgqGIYOULX6LyzfCmVAzsamI%2B3lkWhQpV81ygkmlqWCdyZULK6MJOK3Ug6oKO3mSns2eHFQLmqWQ44%2B%2BFyIir2K%2BLPJRXqHHgeAY27E7GHxHZULLa8P%2Fe6CqaQmmZGmFRObVu69nJEg52DW6atPhjihcvJ2P7npO4k1MAV2d7TJnYH50ffURctn3PKRw6dgFmpiaYNL4f%2Bj%2Bm6aaNvJSEG2m3MWp4L%2FF7WXkFVq%2F7Ga%2FMGgEjYyW27T6JoIAuuJ6aJa47dmRvPOrWDgePRLD0IlHO1u%2FdyxMTx%2FaFibERLl1JxtYdx5F2MxtB%2Fh6Y8%2BIwmJoY15n3A4cj0MbGHNGxqTh%2BKgpuHZywcP5YWFtrmm6rWJ4SkzOQm1eETh2dMOv5oXBqq%2Bnb2rLtGPx7uuPnX8NwJeY6hg32w7jRfbDh2yM4cz4WXh6uWPjq2Op8ZGbl4psth1heU%2BDh7ow504fBhZ2v1sr6XUm4GJOLkP7tMOKJdpK1U%2Bb%2FI9nsDaYHwTprrelqx%2BeuIk4tw0SZDN8GeOP9zp3RYp16GbdLsHRdLPxGHsWL74Yj8Xoh3pzhgYh9Q2Ck1JySjKwSjJ3zR63TifO3Je8IaenZmPziCgT0cGci9zhsmHic%2FOOKuGzl6v%2BJQvHspCcQMsQPr76zHkdPXNJE6pcSse%2FAuep0SkvLsYKtX1ahEr9vY6I6deZnbPvfkF9YghK2fN2mX7Fk%2BW4M6t8NQ57ogYNMwJKSb%2BHCxUS8OG81%2BvXxxmsvjUb01et4%2B1%2Ff1iv%2FXFRfmLuKCdRdjB4ehMjLSfjo093Vy7Nz8vF43654fsog8fO02Z9XL9vMjm3GK6thZWmGJ5%2FoKebtyTEf4G5uIcaM6I0jxy9i7YZfxXXzmIiOnfwx7O2ssGDeGDjYW2HitGWoKFe1WhH8PSwbO%2FbfQFRsriTzx%2F2d%2Bz33f64DXA90lRedjiJzIRpHg7wQXCHDGhsjzPX3xnYIOKZQI9otDinM3LVuhe8uv4wt36eIUeDA3o7499u%2BYm2p%2FFNfi4OdMVZ90LPWdAJ9bSXvCPGJGSwSU4pREI%2BeuEBxVCo1vt58CHu2vg1fb033D4%2BmvtpwEIMHdK9X2i%2FPGI5pk5%2BoTm%2F8s0uxdd1rCPTrLP425qneUKsFzJy%2FBm%2FMHSN%2B53Ryc0LQwDex4qPpUCrrroPnzngKr8weIX42tzDFZ2t%2Bql626J1JyGWixo9zKBO63T%2F8ziL4cjH65Cxb%2FDwG9NNEt7%2BfvQpvFv299vIozfGy7fhvnJ1su0D%2Fziz6CxG%2F8yj3h%2F1nEH4pAb0DPFqlCHo%2BaoWcvDJ0cDaTRH4msugy2QMdVXL4VF4EmSwAl5UsAgyP0Z0A6lwEqyJCNnuS35skFzCOfZ6vVqBLojc6BkD7Y7FFx%2BeJAmhnY4y%2B%2FvYI6m73FwHkmBgr8FhA7c0he9vGBa4tORZgn96e6N7VDT37vY6uPh3Qv6%2BP6OiFLHrLLyiGR2fne07TxQVJKbfqnXZbR5vqz7wpyaOp7r5u9zcz5DLEXktDRGQCvvhqX%2FXvvMlaUloGS2Xd18UUintCac2iOpVKUy8Wl5Rh%2FlvfIDIqCT3Yfs1MjasF%2Bd6298rVkgmorEYxW9ZI61p8Og6zyDB48Fv37bu0pFxrZdHSY0C%2BM8dTUvlN1DwNksKK4Brz6tMs%2BgvRVR%2Bg5ESwOirUnJCLzV1ge%2F%2FTR%2BwH3LgnGR9%2FdRXLv4lDyAAnPD%2FODf2DHO41JTOKETj2aK3prF3ij%2FHDXBqcV20Mslnf4zU2UmLL2ldxK%2FMuwpkQfbXxoPj5AxZByZgicCG0t7US1%2BWfuVDc6y%2BtfxBuYW4ipsebmm0dbO5bxpuj77w%2BDiNDejXZRmqK2K7vQ5GecQenDy2F0kgh5v%2F7fWfqte2fv1tYmmLcqGB89M%2BpzWbfLVnunPTMEiTdKISVhRLdvWx0kt%2FWghIGBo%2F6Rg1%2BRJxik%2FKxeU8Kdv58A%2FuO3oR7Rwv8vvMJMYKwsTLCW7Nqr0193K0kf6xR0SkwUirh5eGCp4YGIDH5FiIuJojC1Is1%2F%2F674zhefWmUGD19t%2BsEBlU2hXmUFx17A0XFpeKFgx%2F3n33ofnhTm6fHm9MfvP2MJsIPv4YOrg5iU%2Fw%2F6w%2BgX7AP2rSxQAWLwn89dgEjWH6aQlm5ShR5mVzjq%2FyCTGPhfaIvvLwKU%2F82AN6e7e%2FLfzsn21Zp5ys2xOHb71Pw7ktejRJBg9IEQz54z05W%2BGShL96f54Vdv6RiExNElVoQRbCNtREWzvRo1cfHRWz2%2FM9EkeLNxcKiUqxfNVdctvLj6XhuzhfYdzCMNY%2BLxb46flGAM3hgd6z55hcEDFgAI4UCw%2BshWJ8vnYE5r34FP9b05pEZF89dmxdi3synkJGZg%2BAhb8GujSVy8goR2LNzk0Vw4pi%2B2LH3ZPX%2B%2BgV7Nzot3u%2F3zmvjMOG5ZbCxNBfPGxfsbesXtNqyP3X%2BNizNlZg%2BwY1Urq4Whj4cBG8mhP00SrL5Cxy9T%2BvNooYMr5%2Bali32zzk%2FYvfAZcYmyr80YwVBQGp6ttgPZ2NjUe99ZWXniU1NBzvr%2B37nfXi32TJHB%2Bt63R5TH%2FiFF37bjY2VefVtM9pIr6HHXGu51xheX2vlXg87T80oht%2BoI5j7rDsWzffRmZ1SJEhIBlcX%2BwYv43187V0cGrwvR3vrB%2F7OI9Ga6R0PvYzVX%2F9Sazrvvj4eAX4PH9WJC3tj8thS6emK0LDbfGgsvPT3R8n4DUUE%2BSM%2FUn10rqCwnKzsAQzs5ytOhPbtfPiAdhgY7AinBrxYzJDtVC9Glm5jZVyRnVsqybxdS84j7yVa1M75Rb12DqZkp4YkglYWRnfTMookmbdzFzVPlsgE5KMZbv4mDIfmtHNDtlO9EEF7W5MToWG3JJm3w6Hp4lyQIZPNbpErE1K0c0O2U70QwfjrxZ%2F8fCy1oqxcLal8JaXmIzm1oOpMJ7L%2F18mVCanZuaHbqV6I4G9ni8KNjeRhO%2FYnSSpf7ywNv%2FdFQCGvcMmVCanZuaHbqd68dzjtdtHU9TviSqJicySRn2VfX0ZCSn6VYSWyKUBXg0YS%2BoO27ZzsVI9EMJyVZVm5MH7eB2dUuhZCbli7atbWMoTKgPNSeWCcIDsnO9VDEeScjVL9UlBcMXP2u38Iq76NQUv3EfK%2BlWdeOX6%2FYQn4jv0fJijwFrkwIQU7Jzu9H717YiQiGpsCvdXyrXsT1u74KUkZ3NMBIQNc4eFujY7OllrdV1FJBX8NIs5FZuFIaDozroL7V%2BCGxcdOk%2BGFMFaDk%2FsSurBzstOHo7fPB%2Fp3RQjU2C3TDBXesiNL8r4V1rRg8xBWsz4XcQUHtZl8S49NR2ihGdtMz%2BI2yc6b2U5bCwp9PbCbWYh3boddrIDd2eTIarlEZiilrNB59Gus5d0VsLTT5ALOCTJEMYXqKJchi%2B1pEjOs81o%2FtttYzCdnRywieWkl9sjKSwJ23qJ2Ss1hKdS%2BmtD%2BaXHUas0LpYeyWlPG%2Fiy0vCtLQcBdZlj8LT%2FnWK26OIwughDSs3OyU4IgCOJ%2B%2Fh%2BpP1%2F45f%2BumwAAAABJRU5ErkJggg%3D%3D)
+
+```
+section_contents
+ ::= '{' statement* '}'
+ | '<=' source_name ';'
+```
+
+referenced by:
+
+* section_block
+
+**statement:**
+
+![statement](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOcAAACpCAYAAADQpio8AAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAHsRJREFUeNrtnQdYFEcbx%2F93HB2kCyJ2RMAKqMGOXaOxY49JNMZEjRqNmmLyxXx%2BSTTRJLYkiiUaK8bYTYw9dkFFRBRFwIpIL4LA3X0zc0BA6R7ccby%2F51l2udmdnd19%2F%2FO%2BMzu7CxAEoZVIdOEgvNygpEtZsQSGVqytKAPe0d9x9tz062EJ426GJzWOT8o0fBKf8cI%2BbawMs02N9RNtrQ1P3L6b%2FvWx808DdfWcy3TlQAL%2BWUsKqiBadxpfofn%2Fvd7rvRk%2F7vo2LCLZtH%2B3Ohj0bl041DRBTRujF9aNicuQRcc8tT0VEDM06sHdgQN8TAIexD4dG3gN4bp23vV04SAc7fDFO%2BMHkooqiFXrdotzzKdHsZivNm%2Bp%2FELqbh23fdn60Nm9fZwMFszyhLeHHeztjGFqUrjf4L%2Fz9DYtbTGifwOpQgmn4NCEd2raSi49jFHe1qXzLiXTIzTF9qW%2Fb1u77dawxfPaYNzgRjDQL5s58vX5diu%2B9DYyMZDsbe2O8SROglBDKOu3NWzYt5%2B0RvMmVi%2BVF99%2B%2BXxvPZlM6uehQwIlcRKVDu%2F82Xfk3rdjmdd7WWHmF%2BjogQ0lMkh%2BYR60L4mTIMoB75W9HZViOrJ%2FA7XmO2lUExgYSGWsHbrNqxkakTgJooxcv5XwRp8utcvcxixNG7RtSzt%2Bz0cGOb4jcRJEGbl5J7lRx9b2FZJ3r86OfGbMpo4eTdGSxEkQZSAu%2FplRbQeTCsnb3dlStSBBjFSBoSTOKsTDR%2FHIyswmhWiQ%2BORnEhsLwwrJ28k%2BT%2FRmbOpZ5cX5SjMUG2OUlF6V6Dv0S4Tdeai2%2FDKzsjFs3CKER0RXSHmvhkTiytWIcm%2Bf9vQZduw%2Bo1XXQCFXQqpXMaMBc%2FNVKmHNZnU1cXwvq5fc7YU4s%2BR46OWG7UVlWlJ6dUZPKsWIwR1gbWlWIfnv%2FysAO%2FeefYkQMgWz562vdtdFovKcGrHX8uqlrRsGe7njXrYcojaW5RwIF6mvXM4S3fCHTA%2Fvn7%2BGx%2FkOtNj0qsaj6ARs%2B%2F0UIqIeo09PT4zx7SJ%2BvxMZjXW%2FHcXjJ4kwNJDBu20TjB7WGRKJqjbmHujoiWDIZFK4ujjhjdHdYGpiiEePEyCV%2FusJ9h8KxOFjVyCXK%2BDdpgmGDWoPA%2F3ihzFzz7t%2Bk2rf9naWYhtLCxNcCLyFLHa1lizfDWsrc7w5phs2bDmGVi0a4ADbT0joXfTs2gq%2BrIJYs%2BEwzl28CRdnR8yePhjGRgbw33UaCqVCbM8ZPrgjnGrbVJlr5bc9AkGhSejT2QH9ujqUue7UUMVQJr1wUcolWMoCCqf8j3AUaHMqVWLlmd4vTPklpVcV%2FrtoO5wcbdDDpyUWLtmJP%2FadE78nJKTBzrYGfJkwenXzwMrVB7Fx63GR9tu241i17pAQTe8enrgV%2FhD37j8RaT%2Bs3IvElKdiedkv%2B7Hoh50i766dm2PvnxfZerElhp4DR3%2BFhvXtMXZ4FzjWssaR40EwMjSAuZmxmOrUtoWDvaqz41cmzrffXwEzU2MhzK%2BW7ED31z5HfEIKBr7aFkdPXsVPfgfFujVtLZi1SMT2fDI00q9S1%2Bp0QBy27ruH4JtJVc7OStJLrqeUAzvBhfkcshIyFcovKb2qedKVSyahqauqOZKSmoEdu85gcH9veHk0ElPk3RjmXePxSmsXBF4Jx7hRXXGNeagmjR3RtVMz4Un79fJ6Id9sFs8sX7Uf23%2Bdg5bN6ovfeL4KRfFPtD14GIenac%2FQl3lxB3srdO7QNC%2FNrYkT0tMzhWfMzzdfjEM3Jn7OWeYtGzeshZlTVYP%2Fk1hFcfJ0iFju0rEZq4ElL2xfVWjS0BwJyZmo62hcZUPsF%2FQiwcFs4MvnPWWpxJnXcAeuMNfaR1lCenY2IthOq%2BTZa9TAgXlOVZvufGAYZsz1E%2BGjc6NauB3%2BCA3qqSq7N1kIO37yMjRrNw2tWznjtb5tMGxg%2BwJ5PWThLfeCzd3rFeykkBbf%2BdGY7Wtgv7Zo12MuqwBqo4O3G96d0Ad2NjWKbevmYm5a8NTXMDdBNrOEiqCyn5396N0mVaq8JemJWUK%2FbCWGsbmipILJioiZz7ANH7B5D5ahH5t%2FUFw6a04tzPWcvsxuIl1QTy6FO1uxG1tnFFv3mkyJKRduIEzbDCY1NR2WNUzF8mf%2F3Yz3JvQVnpKzat1fuBoSJZZ5G%2FPM4YUIvXkPFy%2FdxhffbIWVpRm6d2mRl5eZqRGUSiWSk5%2FC0tK09G0U5om%2F%2F3oCPp8zAgFXbou2J68kNvnNzO15LGH7F65fgTSlGjtG1fHQdVmu18OYDETcS2MVkAwtXC00Ut4CoagrXLIlWMEybcYOYgs7kqN6ClyvH4Yof0Be2PHl1wub%2F8JaFmszsjCeVa9vs2uTVFhI%2B4I4czNRqjI5r68HNy46trMPikvPn4coYBju8P4VNu1zdsbHFvqYzRq85zzc4Xv5Oo5ougbLSM9SzZ9lYvOOk%2BjL2pCil42FAEZGBmKZC4yHi6Ymqgd%2B%2Fz52BW09G7Mws44Qqv%2FuM4iPTymQr7WVGTxaNsTKNQfxyaxheSEn986i7VcEPIyOjUtGaw9n0YZMTkmH369%2FizQLVnHkVhDloQZrr%2FJw%2By5r99Z1sq1ykc3iNWHYsDMKH7%2FnWi5xqhNmv91ZKOrPdLAkKQv9b9%2FGs9y0i8U4uSL0MpO1QReySzO3KJHmF6d%2FcaIrRXqh5BzAAk9XEQL7s5rHu6I8aGl5f%2FYq4VISklLhw9pk48f2EL9%2F%2BP4gTGcei%2FdsSll6g%2Fr2TJyqbUJC77HtVotOm1gmSh66DmCh6PMsWzQRk6b%2FJHpJpSz05N7Uf8OcYsuTnS3H5Fm%2FiH1ygcclpODHhRNF2oC%2BbbFu0xG09pkF%2B5qW2L%2F9szIdq4WFKUYN64Reg%2F8jKprl372Ddm2aVBlx%2FnMxFmYmMowfVl%2Bj5eAekwuTRTHjLt3AvlJsUqJecn4rUqSSHDf8lGXyM8tkYWGZlJRehnBmHpt1ZqFGL3WHtWV9TQnvhNE3kL3g0VKY10pMToOjgzX09AoOoOKe9klsMjMWI1hZFX9fMyY2SWxvw9qvpSWatVn5bRPeq5offkvmYXS8EGdJt2SKIjY%2BmYlfKsRfVvK%2FpkRdYW3AntdKXO9%2BdDo8XjuMKa83whfT3Etf3gF71R7WsjIfYrOTLL8FpVi3XHrhvblcpKzA77L9qN4FIdNDg%2BIyKSm9tJin47sUY0zhA5IvhyBIkzVhbcfC7%2FWZmxuLqTD4rY3nhVMU%2BUXPb8fsPnCh6N7jxZNQ085C9NQW2vnDRF7a%2FRaFrXWNKhfSngqI5Y%2BA4b0xDTUbzvIB9Ao0Z%2FY7oDTrl1cv%2BT1pXlhbUkbquk1yPBIZXu7YnDMgOQjVhNdH%2BoiJUMGH2JVmCF%2FfLg7w8baDfSEv%2Biqygy8tS%2F3l5fYqwWZuv2UQWbnJ3b7yB74rcZS5%2FHZkotUXS3OD7LikZyW3l8314WBrVKa8b0UmV4DJMntldlvplVhl75BVmCGsvnQhE62%2BmJvqJz6IfloheV8IUo3GkijBu9LVcrOX2yu3W50Xp3GqcNl2ZKLVFxsrwxOnAipmQNnfp1RPHCkliGEzde3ELsdudVucZ%2B%2BLuN2ITLT6wt%2FUvv%2Fo%2FezMLIVa8424n4LI%2B6m5ls3vs99VU9ZGOXar2%2BJUhfC68RkIonzwTygY6EsDtu6LUGu%2BHy0MzG9ladyRqilrSY7d6rw4CQL8Ewp%2BW8Mygm8mqCW%2FRauuITwqJVeYd9jkpZDi96p8jkichEbg3zbJzFIOnfqfc%2FKXFSgX5vb8XliCU8zVXdT0vXQSJ1FlOR8sP5Canj1x0sdnlMs2hKKsbVDexhzx%2FvGCwlRiE%2FvbW6mHOVX9%2FMjIRAhNcuk61rV2U0g3%2Fh7%2B89Y9ETLvVrbo08UJLo1qoJ5jwaGGTzOy%2BWs1ceHKExw%2B9ZCJM%2FX53oxN4kkoCd4K0IGvjumMOCv6M3VExREQijWeTZUP5Jly%2FxMXHuuxqWzPBvM2JgtlwZ89luKNwBD8qQvnRSfCWj64uaI%2F7kpUsAdlgpLooRVb%2FIuJLY5dzGtsuseualohq6eytAipkq0L%2FKEEDMULvWRof0lHhElhLaFdlawqFB3MB5rnjL%2FuBQWTpwTPP7luplQiUSkBf6nSBda%2BnB8QontjtXVKnOQ9dYOcXlY%2BfV6dzwP11hIEiZMgCBInQZA4CYIgcRIEiZMgCBInQRAkToKoaujEIARt%2Bh6GrkEDO0icL01ZXypNlAw9TEBhLaHlUQlFJiROgiBInARB4iQIogqKk3oBiaqApNqJs50TvVia0H40aacaE2e6Gezp0hPajibtVGPi1JOgKV16QtvRpJ1qrs0pQTdN7To1LQP3HsQiMTGNrI%2FQWjvVnDiVGO1Tv%2FLj%2BaMnr6JN1w8xfvIyLF%2B9X2tt4p8z1xERVf4PWz14GIcjJ66SuF4CYZ%2FMTjW1f00O3wtOMcaHbL6gMne67Jf9WDBvDIYO0O7v965a%2Fxf69W6NBvXK1%2BQJvh7FKp8D6N6lBamsnOTYZzCbHKqVOPWUmCqX4JynK65cuoF9lbHPw8eDcOvOI5y7eBNRd2MwdoQPzl68gfp17ZHGQt0LgbfQo2tLNHOri70HL2L3gfOQSCRCyH16eIo8uDc7fS6UbVMTG7Yeh7GxAWa89xqSkp%2Fi181HEZ%2BQijdGd0O3zs1LVaZzAWH4Y89ZJCSlMSHWxJjhPngck8D2E4O%2FjlzGw0fxaNK4Nl7t5YXvV%2Bxh89ZYv%2FkIWydRlL9Fs%2FpYvf4QroZEokuHZnh3fG9kZmWzsl9A9OMELFm%2BW%2Bxn6qR%2BMNCnN6GWFmaX%2FdlsJrNTb2anN6uVOC%2FcQJiHO3xZXO3v5YYlSVn49vZtPKvIfVpZmEEmlcLaygx1atsKY9217zyu37yHhvUd4OrihLSnGdiw5Rj8NvyNTz%2F0hUKhxJffbENKSjp8B3cQ4pz3v83o1qk5evi0xFl2IEPGfANHR2v4DuyA2PhkTHx%2FBS6dXAwLC9Niy3Mj7D5bdzkWfDYGZqbGCLh8GxeYWJu514ORkQErp7kop7W1uSjHYiY0LtgRQzuidi0bsZ%2B6dWwxhFUe%2Ffu0wTff%2Fy4E3r1zC9ha14CBTCa2V7Vf6LZyaXB2hqGFPmZzYSok8A0MRRizz2oX1uLydRxp6wrvbAlWsBMyxdMNW1iMf1RPgev1wxDlr6bPhufi5dEIZmbG8GHCatemSd7vwwd3xKypA%2FP%2BnzHXD1%2F953V07fSv91v0404hTnEBG9TC2hXvi%2BVO7d2xc%2B8cnDu6CIYG%2BuK3zf4nceP2A7zi5VK8OG89EALs2bUVTIwNC4Sgtewt0cbTOW%2BfcrnqIz8bV32AmnYWYnnH7jP46IOheV790pVwBAVHiv87eLvicvCdvO2JwvFlQVykC%2BrJpXAX31kBRimBazLmMbkwNVk2jcc53IOyWU%2Fxlm8lhrDlaQo9NL7jhnpelTQ6wz7H2DnZWXLcvR%2BLJs61835r0tgRdyKj%2Fw3Jpf8Wy9z0xc96mLMKQJ5d8hezuBh%2F23YCLdpNR4um9Vml0QzvvNULRoYGRW4jybdvMzMjEXbn32%2B2XF4h50hXn0y5o%2FoobhQ7i7eYtZ1l3rKPtnw6UGsaIfne8q1Rw5Hp68GYhZTJLIx1rKX6jS9zj6tuuJh2bJiD%2Bw%2FicCkoHEt%2F2S9u83wya5hIV5bxqCTPVWVKpfr0RA9dVz408L0QeGfOb9uP5%2F2%2Fcetx0Y5TN7yNyduwTrVtMODVtujSoSni4lVfZ65hboLwiEflztuihgkePoxHxrNMuqBVFOq%2BK4T%2FzhuDN99bCp9%2Bn7K2nhKWlqZY%2F9M0te8nMSkNb7z3Ixxq8u%2FxqBzT2pWqtuzYkT54a%2FJS7PszAN5tm2DxgrfKlHcbj8aoW8cObX1mi%2F9PH%2FoG5ubGdHGrEBoJVXgYqs4wiedXEa8peRSdIEJFB3urCjsXPPS8%2FzBO9BzbC5H%2By7PMLMQ8SYKTo02BtmVZj4G3Tc3LEZbnf01JdQ5r1W2v5DnVQC2HlxPlfxdtR9C1yELTeLt246oZQnS5tzueh%2Ff%2BFpVWWcdAUFirk3w2ZzidBKLcUIcQQZA4CYIgcRIEiZMgCBInQZA4CYIgcRIEQeIkCBInQRBqQWdGCNHn6gjynFoIH5RMzxsSJE6CICisLY8HpUtKkOckCILESRAkToIgSJwEQZA4CYLESRAEiZMgSJwEQWgGnRiEoKvf8SgLNACDxKm1VMRLpasKNOifwlpCy6MHiiBInARBkDgJgsRJEASJMw%2FqXSSqApJqJ852TjCi605oO5q0U42JM90M9nTpCW1Hk3aqMXHqSdCULj2h7WjSTjXX5pSgmzacfLlcgXsPYsUXoAlCm%2BxUc%2BJUYrRP%2FcqP50dNWIyrIZFiOSY2CZ36fIKxE7%2FHxOkryp1nyI27CLwcXu7tM55lwv%2BP0yQELUPYJ7NTTe1fk8P3glOM8SGbL6jMnQ4d0A72dpZiefvO02jVvAFWLpn0Unn%2BdfgyHsckwsujUbm2T05Ox4yP12DYoPbiM%2FSEdpBjn8FscqhW4tRTYqpcgnOerrhy6Qb2VdZ%2B4%2BJThADCI6Jx6NhlGMhkWLJ8N9p7u8G7tUux20bejcG6347g0eME1LSzwJD%2B3mxuiTMXbiItLUPkU6OGCd4e1xOb%2FE%2BgqWtdHDp6BcHMU%2Ft0ao6xI7pg7cYjOHM%2BFA3rO2DOjCEwNTHE9hyvuWTFHtFvP3RgO9SrU5PUoUGYXfZns5nMTr2Znd6sVmHthRsIU0jgy3SywcsN85ydYVgZ%2B%2F157Z%2BIjkmAsZEBzEyNYGxsiDq1bWFhblzsds8yszBw5FdwcrTB6yN8xDZ%2FHw%2BCoZE%2BLJggTVle%2FLdaDtZi%2Fc3bT2LC1OUwYum9u3sw4e2Gz6ufMg%2BbgAF92%2BL0%2BRtY%2BvNesS4XOodvzycjQwNSh4bgdsjtkdslt09up9UxrMXl6zjS1hXe2RKssNDHFE83bGEx%2FlE9Ba7XD0OUPyCvqH071rKGSyNH6OvL4Du4Q4nrR7OwNTE5FX17esGptg06tXfPS2vqWkeEtc%2Fns2DeGLa%2Bp1gOuBLOwmkLfDxzWJ7Y9%2F4ZoGrbdGwm5r4U1lY6viyIi3RBPbkU7rzzh539UUrgmox5zMBQzQlT4%2BLM9aBs1tOjKVpKlRjClqcp9ND4jhvqeWnRKKJ6TnYYOaQTOvX5GC7Ojmj3iiveG98H9jUtiw7d9f4NTMxNC3pmc%2Baps7Oy1V5OejKlbNyBOF9RzNBuMWs7y7xln8shCNKGsmnN85w5JyRImw1y4Zdv4JNZw4QX3LDlGKbM%2BgU7Ns4VacoSSvC8Q5RUUL1DD13rDjTwvZTwe6HnAsJgYWGK7l1aYDgLYeMTU0Ua%2Fy084lG58%2BZeVCqV4PadaDrRhPZ5Tm1HwVzjjLl%2BYm5nU0PcI%2F3%2BK9UbCPr3bo3V6w%2FBq8ssWFua4e%2Fd88uUN%2B%2BcemN0N7w2YgHMzIyweMF4dOlIA6iqOxoJgXgYqs7wi%2BdXWa8p4R0%2FmaytyHtt83feKBRKPHgUJ3peDQ30y5V3XEKKmNtYmZdpu%2FyvKaGwVvvtlTxnGdn6%2Bz%2FYsftskek%2FfD1B9NIW1QHEw1J%2BG%2BRlKKsoCQprqwUjh3YSE0FoC9QhRBAkToIgSJwEQeIkCILESRAkToIgSJwEQZA4CYLESRCEWtCZEUL0GTyCPKcWwgcl04BvgsRJEASFteXxoHRJCfKcBEGQOAmCxEkQBImTIAgSJ0GQOAmCIHESBImTIAjNoBODEOj7IFUXGjii4%2BLkVNZLpQn1QQ8rUFhLaHnUQ5EPiZMgSJwEQZA4CYLEqWZ4G4N66YiqgCTHXquNODPaOcGIrjuh7eTYaUZ1EueTdDPY06UntJ0cO31SbcTJYoQwPQno082E1sPtlNtrtREnC%2BLPsj%2FdNLHv6McJ4svUBFFKY%2B0m7LW6iFMhxe%2FMfY72qV%2F57c4hY77BlasR1dbW5HIF%2FP84jazM8ldQFwJv4UbYfZ0%2FV8I%2BmZ0Ke60u4rwcgiA2C04xxodUNVcuWdnZmPHxGjxNf1buPDb5n8CRE1d1%2Flzl2Gdwjr1WOhobW6unxFS5BOc8XXHl0g3s00jbV6nEuk1H4ObihHZtXaFQKLFp%2Bwkc%2BycYMpkeRg3rhK6dmiPq%2FhPs%2FzMAk9%2Fum7dt5N0YHD4ehNdH%2BmDFqgOYPLEvjAwNcO9BLA4fC8JbY7uL9c5euMGEkInuXVpgx64zaOpWBzFPknEpKByv9vJCYnIadu45hyexSbC2MkPfnl5iXc6V4AjcvfcEcoUCew9ehKWFKT6YMgB1atuWykNu2XESp86FwtBQH83d62HcqK7Ma54R6Sv8DrLy6qNf79aQSCSiPA72VuL4zUyNMHPqQDyOScTGbceRlPQUb4%2FrgY7t3BFy4y6uh94Tac%2BeZaGukx2GDWqvc8JkdtmfzWYyO%2FXWVBk0NgiB2WyYQgJfZhcbvNwwz9kZhpUtzI%2B%2B2IijJ4Lh2aqR%2BO2TLzcKj%2FDOW70xuL83Zn26DucCwuBQ0xI%2FrTmI84H%2F9gv8tOZPPHwUD0MDfSG6y0F3xO88ZPz8q83CeDnrNh3NW96%2B6zTenLwUfhsOITk1HelMtI8fJ8K5YS0hHI%2BWDTF19ipcvHRLrH%2F1WiSmz%2FXDydMh6NPDU4hhzNtLhPBKYsXqA%2Fh9z1mMGtoZPX1aIvBKOOLjU2BnW0Ok165lLURuYmKIW3ce4aP5G7GZCbNb5xaiMhkw8n%2F4ctE2eLZoiCaNHTFh6nKkPX0GUxMjmDLxWtQwFdvb5uSnK3A75PbI7ZLbJ7dTTZVFo0%2BlXL6OI8xheWdLsMJCH1M83bCFxfhH9RS4Xj8MUf7MAVTUvj%2F%2F3xYmrjisXfk%2BDPRlzJslYdf%2B87hy6nvhATk3bz3Abvabd2sX5kU7Y8PmY3jFywUpKeni90O75ov1uEc5H3BLeN%2B%2FjlzGwFdfwYFDgcJ7clF8Ots3b79vjemOd8f3yfu%2FVYsGyM5W4DYTiKGBDO7Mi19iQm%2Fj2Vikd2Ne9PuvJ6jay6zCaNFxhmgze3k0Kvb4Qm7cE96yS0dVp3j%2FPm1U7ShLUzEf1O8VWFiolq%2BGRKGZW12sWjpF%2FN%2Fawxk9Bn6GwBNLIJWqxops3HZClLFls%2FqoV9cOLo0c4Tu4Q5UXI7syepEuqCeXwj2n82eUErgmYx4zMFRzwtS4OHM9KJv19GiKllIlhrDlaQo9NL7jhnpeFTSK6Ltlu5hBRuLi0e%2BEMDnc8NIzMuHz6rwC6%2Fbo2lLMefjK057EJWPPgQvwbtOEhXS2OeJ0w9ad%2F4hQ19zcRAjwq8X%2B6Nm1FfRZeFyPhX651LSzLJA%2F97r%2F%2B84fjRo4oA7L7xHzpEV5Rpm%2BHuo42iD6SWKJxzjxjZ6YNOMnUVYeGfgO6sBCZs%2BimxnSf4MoczMjVgZlnjBzf8vOqrC6UmPP5N5Rjf6JYkd6i1nbWeYt%2B2iqjal14nyukyioMi6si7MjTIwNMW3uavgtmwo9PSnMmPGZmxnj7OGFog32PDyE69TeHVv8T2LH7jNYMG9MXloHJs45n%2F%2BKPQcvoD9rw3m2aogHLOQ9ePgSOni7FVkOfktn7n82YNv6D4W34kz%2FyK%2FYsickpcE6x%2FsVB8%2Fv4rHvEBp2D2fO3cC0Oauxff1suLM2ryqsf9lmgXqvPz10rUVtTk0yoG9b%2FPzDu6KjY%2Bana0X7071JXZizttRKv4N568XEJuHsxZt5%2F785phuW%2FrxPeBQu1FxsrMyFeNf8elh08nBx92XzH3%2FeK7xqUSgUCmTLs0WHDYd3JvHOlvykpmXkeVLehuTLXjlCLg4eVvNIoKlrXYx%2FvYfo7IlPTBWRAg%2FbwyOiy33%2BLFh0EB7xiNRTXTxnZcMNdP1P0zDk9YX44uutmP%2FJKKxbOQ1TZ6%2FGqnWHYGpiiKTUp5j%2F0ShA1VxDlw5NUaOGKmx93rt2ZGK9GhzBwlYL8f9rzIOuXn%2BoWM%2FJyzBzykAMGvW16KgxY57b0LDgJQllbcdXus8WPclcWKt%2BmJwXihfbXAgMw8xP1sK5US3RccUrE5%2BOzUS5J43vjVETvoOlpRk%2Bmz0cUr2y1dEjh3XC8De%2FFeVybeyEX3%2BeTkqqAHQilOBhrTpfU8Lblbx9VcvBqsDv3Nv0H7EAAccXC%2FGqi7iEFGSkZ6I2a0%2FmZ8OWYzhxOgSrfpyMh9HxcGLphYXcRcHvZcbFpwhPxyuVAuFxQiqymee2sylfbysfxMDbvrXsrSGTlS8Ay%2F%2BaEgpryXOWiqIMdhXzhMMHdVCrMHPDYlgVnc7bxPnvbWY8y8TYiT8UuT73kFPfeVW0q01qF15WKyuzlyqzvoGsVPdbCRJnpdCRhahtvRpX2v54SMzvgRYWDu%2FYMIcuCImTyOW1vm0qdX%2F89gqfiOoJvaaEIEicBEGQOAmCxEkQBImTIEicBEGQOAmCIHESRFVDZwYh0OfkCF1DTxcO4lEs5vPJ0Q5f0CWtuteQzgKFtQRBEARRfv4PvSXPLW5Y%2FaoAAAAASUVORK5CYII%3D)
+
+```
+statement
+ ::= basic_stmt ';'
+ | from_stmt
+ | if_stmt
+ | keywrap_stmt
+```
+
+referenced by:
+
+* else_stmt
+* encrypt_stmt
+* if_stmt
+* keywrap_stmt
+* section_contents
+
+**basic_stmt:**
+
+![basic_stmt](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANUAAAHdCAYAAACKZDxaAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAIABJREFUeNrtnQdcFMcXx3%2FH0TsoYgcVlKIiYAEroij2irHFGqPGllhTjDExMYn%2FaIo9dmIswSS22HvviCggCIJYUBAEFKQc958ZiqAgncO79%2FVz3m2bnd15v31v3u4yAEEQZYpEGQ7C2RZyasqy5WqgctiGIlBXlgO5cno9tWYZ0bzdGDoJpUCNTgFRkPenCIBERRAkKoIgUREEQaIiCBIVQZCoCIIgUREEiarsePgoFmmp6eVSbnqajCyKyBRVq8Ywf9tKhS1%2Fl%2BgxaAECQ%2B6Xebld%2Bs%2FHnbuPSlXGiTM3ce9%2BTIm359vyMoiSUVo7z95eiIpdYB862%2BKvggotbDlRNiz7fR%2Bu%2BYWWeHu%2BLS%2BDKBkltfOWtujnbIfIdBnu8mnx7J8kU1xeMhlbaIt%2F1aWYcvEmHmdvVNjyd5kdu85h%2F%2BFrUGcH9V7%2FNnBv31TMfxIdjxVr9%2BEx%2B5awf45N62H08M5svcyI%2BfGTZ1i5bj%2FCwh%2BjaWPLYoV%2BZy8EYud%2FF5GQmIz6FuYY%2Fl4H3HsQg%2Fvss%2B%2FgFYTdjYK9bV24t2uCpb%2F%2Fhx5dm2Ot92E8jU3EyCHusGlYC79vPIRbQffQqYMDxo30wIukFLEtL2PJsl1iP9Mm9oJUSt3molJcO%2Bdikknwm0yO2rkf6MrzQK08c7rAQgtb%2Fq6xct0BIarPpg9ASkoa5nzljfmfDhZG%2FCz%2BBfT1deDSopFY9%2Bflu%2FEs4QVmTe2HpOQU9Bv2A9q3scPIoe64E%2FZIbF8UrvvfxaQZq%2FHtl8Ogra2Jy9dCcPV6KKwa1ICWlgZMTQ1Qp1ZVmBjrI5Vd%2BhYzgRw9eQMD%2B7RGfEISxkxairp1qmJA79bo7uGMhUt2wJpt69KiodiWl8G3F0YioQfNS0Jhdl6QmPIVVUGFFnen78SJk8uxiolqzdJJaOlsLeYlv0zFCuZ9uKgaWtXEzCl98eDhU9ZXiUZbVzth%2FJxd%2F11C1aoG%2BGH%2BCDHdqUNT4VGKQlDwfbatETp3dIC2liY6uznkLDNj87mI%2B%2FZoJaa59%2BFsXTcDhoa6mb%2F%2FPoWvmPDd2jYW0xcuB8OPCZVP823vhEXBq18bUkZ5iEuC%2FenANwWJ6a2iyiaDXViZP%2FSUF7I8PR132U513qUTlshCr5jYBDRi4smmkXUtEc5lG%2F%2FE6augLpWKcItn99SyQqnbdx7Awb5eifbbrbMTtu44jSYu0%2BDAwsaO7Ztg3Kgu0NQouCkkaq88jr6ejghHszHQ10a6LKPczhM9qZ5p5%2ByM90iXYyD7zijshKgXEFueYxs%2BYN%2BdWYFr2fcnb1vO7OHHbE%2FlBUjDG8JCpgY7tqI7W2cIW%2FemuhyTLgUhuLI0vLaOpugfJTxPhpGRXo7QDPQzrw3f%2FeSD7l2cRbjH4X2gP%2F86KX5raaoj6tmzEtWV72vX1s9Fpo4nFn5duUeEjtMn98nxoMXrCEhed8Flem6V5WXFljZomC7BcnYwjdkZ2sos5pg0AwGWwYjwAWT52VFuO2ffq7U1sP5lGsawS%2BsHcgniwT1WYaLKLkSeWchFDSlsuVjYzj552%2FLcZYgKBiOM%2FeSfvVZW%2BMxIA7NYDHrB0Q5evgE4WhlOMvcMbV3ssHn7CdanGiiMefP2k3BnnoOTmiYT%2FZPssPDU2VuvUqfNG%2BLjOeuEp6tqaiiWvXj%2Bskj7vXg1GDXMTVG3dlXx4X2qp3GJmYJjIV7o3agSH5Ohga5IeKSmpb%2FV86kazO46sZDNh9nvkvg09LxzBynZyy6%2FxakUYOfTWzXGj8w85hQkrtxn3udtYinC8nzJOoBvnWxEqOjDrhgu5eWxissPX4%2FAqIm%2F4cgJPyQnp6FmDVN8%2F9XwzMzZhJ4YM3mp8E784m9vUydnu47tmsCtXWO06jibeTwNuLK%2BjAY7KUXh6dNEsc9aNaogIyMDGqxDumHFVLFs5JCO%2BHDaCuzYeQ4d2thjHus7FYfWrRoxkRugRYeZLEbJwLWTS6Chqdri4h6KC4q14YhrQdhbhE0KtfOseQWKS5Ll9pJYIatYIT%2FmV0hhy4sRps1lX%2B1ZSNGlrMO%2F0rxOz5MRGuzKXs3MKM98niiIZV7EvJpxvld%2Bnnbn%2FR2zKobFi9FZVP7g0VMWRmq8sU%2FuFWOeJuRk8EoC7%2F%2FxxIa%2BnnaJts%2F9Ov27Hv4x2zjEvk6x4%2Fi2COuWyM75fS0uLnaiJrD96ApLYRfLem8rpLDlRcUgGT8l6mCSoz0cfG%2FBr7Kc%2BFo1q%2BQ7X09XS3wK4nVBcL78dgsCg%2FN%2FYsPYSBdrl06GGhNiQaLR0dYslaA43OMSLOxjdoYMNGF217so65fUznN7rpzwr7CCyipdfiIcL53tsEUtAwPYpJ8yNuSCuUPJmisJws4k2MLtrhjiKDHZ21f87XY5jjEX60pNTpS%2FqTE7Y%2FZW4WKu6B2yTuMtFns2pCYnyhtuZ9zelF5UOs%2BFizSjJicqALMse1NuUZ2%2FL%2BJbbWpvogLQzrI35RZVZqhLf1KYqKgIsOIfs6L3AgiCREUQJCqCIFERBFFylOZpSxr%2BhSBPVYbwhz5pkDKCREUQFP69Gx6LmpQgT0UQJCqCIEhUBEGiIggSFUEQJCqCIFERBImKIFQRpbj5S3%2Fvu%2FKjSjfmleaJitL8MU2ifFG1h50p%2FCMqLJpQlYiCREUQJCqCIFERBImqgqDXNAiltC%2BFicq1Nv1BTUI57UthokrWhzk1PaGM9qUwUUklsKemJ5TRvhTXp5LAXRG75aMMpqWml0u56WmyEm3Lx%2BiNfBCDJzHxpIZ33L4UKyo5hrpZVnzc22PQAgSG3C%2Fzcrv0n487dx8Vul5CQhIGjlgkhkTlhIQ%2BQquOszDmo6WY%2FeWmMq1T4O1IXPG9U%2BLtU1LT4PPvWTHI%2BLuEsCtmX4ravyIfU%2FJP1MFM9v0tVAgtbQ2816%2BNGEmes3HLUQzo44q5swaV%2Bb4OHbsuPGBzR6sSbZ%2BQmIyPP1uH%2Fr1dIZW%2BO8naLLvyZ5%2FqKiUqqRyTZRJc4KPWF3HU8HJhx65z2H%2F4GtTVpXivfxu4t28q5vNBsles3YfHfLBs9s%2BxaT2MHt6ZrZfp3B8%2FeYaV6%2FYjLPwxmja2LHLop6GuLgxdysq5fuMuzl0MgkWdaliybBe6dnZEfHwSXqakisG7T5y%2BCTubOujYrslby4yIfIINm4%2FiYVScGIe4Xw8XVDc3xpkLgUhkwuBlG%2BjrYNyoLtjicwp2jerg8InruHEzHB3aNsb7g93E9mfZ%2BvUszDH74%2F5iEG7upTg%2Fr9gNNYlEiMuybrVKLShmTz3Z13RmXy7Mvm6rVPh3KQjBGRJ4sbby5qPWW1lBq6LrsHLdAfEZMrAdendrgTlfeeO%2Fg1fEsmfxL6DPDLFP95bo3b2FEN%2FPK3aJZUnJKeg37Adm%2FGkYOdRdGGwK%2B10U%2BMj0i5mR8zL09bXFwNmGBjpi8Gw9XW0hBF6P2fM2ISY2UdSjsP5Yn8ELUaO6Kd5%2Fz02Uc%2BSEn%2FCIxkZ6YiBwPq9GdROx%2FpYdpzBm8lJoaWkwETvhl5V74Nb9CzxiguzdrSUuXA7GL0xEnGpVMwcK59vzjzbbprLC7YfbEbcnblfcvlQx%2FINvAI62tIFLugTLjTQwyckWW%2FkYrdIMBFgGI8IHkJXXvnk%2FYRUT1Jqlk9DS2VrMS36ZihXM%2B%2FTo2hwNrWpi5pS%2Bou9z73402rra4er1ULHerv8uoWpVA%2Fwwf4SY7tShKZb%2B%2Fl%2FxDaF%2BDdSuWYV5wfrwYiFhNs2a1MPvv34EiaTwkIt7zNhnz9G9i7Mw%2FHat7XKWNbatK7xi7rI5C%2BYOQw%2B2vmgDvzCYmujji5leYjotXYZ%2F9lwQvzu0ayy%2BB%2FZpzcK%2FyvXwDautNLwhLGRqsONJCXamhrCe30115qGuBipOUAoXVbbHYl8ejvZwUJOjP%2Fs9NUMK6zBbWDiX411xHhbFxCagERNPNo2sa4lwjhMUfB8Tp6%2BCulQKm4a1RHZPLcuwbt95AAf7euV2TsyYhyiKoLK9yFCv9mjv%2Bbm4ELi2bIQJYzxZ%2BGdScOit9qpsHublhntdmazcrmVl9u5bWOZgbhHsSEKYlZxn3snT9xb8KoPgK837VFknxK%2BiGkpbR1P0jxKeJ8OIhUnZQuNGxfnuJx9x9Z81tZ%2BY3vnfRfz518nMZIOmOqKePas0V23uMT%2F7ZACu%2BoXij20n8NH01fjnz0%2BzPPLbt31du7mns3%2BXZfJPFV5WVNkHajU11NHWxQ6bt5%2FICQc3bz8J9%2FZNsvoqMtHvyA4LT519Nch5q%2BYNcfykv%2FB0HL7sxfOXCjmO%2Bw%2Be4vzl2%2BLCwJMsg%2Fq1ZeFgoljGM4xh4VElTolzL8bDvtAi3CogKqGnUsgV%2FusRGDXxN9GxT05OQ80apvj%2Bq%2BFi2bQJPUWHnnsnbpP2NnVytuPZODfW32jVcTbzeBpwbdEIGhpShRxDBqvc9M%2FWIV2WITJ%2FvI%2B15LvMN217eDbH7xsPwrnDDJgY6%2BHo7gXF8%2BZamhg11B19hiwUSZX%2FLRhVaCaSUNCTvDxcK8swgJdXmtfpeTJCg3kubpS5eZGUgti4RJHe5p7tdXjaXcL6J2ZVDBXekFxMPBNYq0YVqOXqM3EvdZ8dHz82Lc2SZe9i456z%2BFqOKiYGJdo%2B9%2Bv0FRn%2BlbWdkacqBrVqVsl3Pk9H809BvC5CzpffbkFgcP5PbBgb6WLt0snFqttf%2F54Vn4JYsnAM6tauKoSff59JIpIZpYFnBwkSlcJYMLdsn44Z1K%2BN%2BBCUqCAIEhVBECQqgiBREQSJiiAIEhVBkKgIgkRFEASJiiAqEKV5okLVhmshyFOVK%2FyhSVUaVIwgUREEhX%2FvsseiJiXIUxEEiYogCBIVQZCoCIJERRAEiYogSFQEQaIiCFVEKW7%2BltXf51Yl6EY5iapQSvPHNFUNeviYwj%2BinLw7eXgSFUGQqAiCREUQxDstKso%2BEUppXwoTlWttaFO7E8poXwoTVbI%2BzKnpCWW0L4WJSiqBPTU9oYz2pbg%2BlQTu70oDJT5PxtO4zHF009NkYuRFotL3qNxVT1RyDHWzfDf6Vdt2nMaXC7aI3xH3o%2BHe68tSl%2Fn37vN4%2FqLkg29fv3EXN26Fk3jyQdgVsy%2FVExXgn6iDmara8LO%2F3ISnWaPbl4R%2F917A3gNXSEH5RRaZduWvqP0r7Nk%2FqRyTZRJccLLB9WtB2FtR%2B01LTYf39hO4dj0U%2Bvo66NShKbq4N8OZ8wHYs%2F8yop8moIqpAXp2bYEObUsflvv8exbHT9%2BEuroabBvVwcihHXHwqC%2FSM2RY530ExkZ66OTmABNjfRw7eQONGtbCpi3HxMDdU8b3REpqGjZsPoromHgMf89N1PVO2CNcuxEGdakalizbJcYe5ssIgNlTT%2FY1ndmXC7Ov2yrlqS4FIThDAi%2BJBN7OtphrZQWtitjvB1OX4%2Fgpfwzo0xr2NnWwYu1%2BMT%2Fq8TNh0COHuKOpvSU%2BnLYc%2FgERpdoXF8da78Pw6tcaXTs74fadB7j%2F4CmqmhqKAa5rVDcVg1zr62kjkoWVX%2F2wFStZfdq1toOUCcZrxI%2BYNXcjGtvWhXOzBhg%2FbYUQvY62pthGX09HbF%2FQINqqBLcfbkfcnrhdcftSOU%2FF8Q3A0ZY2cEmXYLmRBiY52WIri4WPSTMQYBmMCB9AVpb7432QS9dCcO3UEmGYnOwr%2FMC%2BrUUS4s7dR9DUlMKqQQ3Rb2liZ1Hi%2FQUERcKmYW24tW0sRNSji7OY39CqJqQSNXTv4gSLOtWyRB2HurXM4L36YzHt0bGZGJX%2B1P6FMDTUFfO2%2F30GgazM9m3s0bBBTWhpaTDBquYg214s2AlvCAuZGux4UkICDJEDN9WZh7oaqDhBKVxU2R6L25CjPRzU5OjPfk%2FNkMI6zBYWzmV8Vzwk9BGsmViyBSVctVrmLv70OYn%2F%2FfIvrJnB165ZBTHMI8hkGaXa38hh7hg7aSkau05FC0dr9OrWAgN6uxYcEktfHa4BC01fh4er6aWs0%2Bu8q0%2Bqh0HUO4KdsRBmJeeZd%2FL0vQW%2FylC3SvM%2BVdYJ8StPw%2BAhU3x80psd2%2BfJ%2BPybzdi%2FYx7sWL%2BH8yELE0sLL%2Bv8kUUIvB2JS1dDMG%2FhFtF3cm%2FfpEzOmVxeej3Qy4pK1KdSBC7NG4ow6%2FDx62I6I0OOvQcuQ86%2BZekZ0NLUEPPD7z1h%2FZ%2BHpd7foWPXmYhfiATFiCEdYclCvdis%2B11GRrq4ExZV4rKNDHVFwoKofKir0sEaGelh1S8TMf3z9dDR2oqEF8lwbFIPPT1bYMqHPdCl73yYVTUUGblsgZUGnuiYOnsNGtSrjicx8WjG9tW7e8tMTziqCyZ%2BshKmJgaYNK476lsW76ma%2FiyM%2FGP7CbToOJP1xari782fkjVXEhTi%2Bnm4VpZhBy%2BvuK%2FT8ywc9xa5%2By4xsQlIS5WhRnWTMjvWlympiI5JgIGeDoyN9fIsS0hIYsvTREq8JKQz7%2FrocSyqmxlDQ7Po18fcr9Mrc%2FhX1nZGnqoQateq8sY8nuouDoPH%2FCQMOz9aOFphzif9oa2lKdLe%2BcGzeoalaTx1tQLLJij8eyfZtn4mnQRCtRMVBEGiIggSFUEQJCqCIFERBImKIEhUBEGQqAiCREUQyorSPFFBw8MQ5KnKEP7QJL0XRJCoCILCv3fDY1GTEuSpCIJERRAEiYogSFQEQaIiCIJERRAkKoIgURGEKqIUN3%2Ff1b8HTijnDXuleaKiuH9Mk1A8yvoQNIV%2FhMKjDGWLNEhUBEGiIggSFUGQqCoIek2DUEr7UpioXGtDm9qdUEb7UpiokvVhTk1PKKN9KUxUUgnsqekJZbQvxfWpJHCnpieU0b4UJyo5hrpZVnzcy4cgHThikRiDV5U5duoGHjx8WuLt%2BWDjp87eqpTHJuyK2ZfqiQrwT9RBhQ9FqKujhff6tYGermrnSX5esQc3bkWUePtLV0OwesPBSnlsWXblr6j9K%2BzZP6kck2USXHCywfVrQdhbEfu87n8Xx07eEL81NKTie9OWY3Br3wQWtc3E9OVrIYh5mohuHk7Cm%2F2z%2BzxcmjfCuj8OQyaTY%2BIHntDR1sSaTYfFlX5g39bo26OV2PbshUAkJafg8ZNnOHzcT4wr%2FMmk3kUaSzg1LR3r%2FziCa35h0NfThlOzBhg%2BqANi455ji88ptGllg42sri%2BSXmLs%2B53h2tKmSMd88swt7N5%2FSWxX37I6Rgx2w52wR3gUFSvmB96OhEOTemjjYoMVa%2FajR9fm%2BH3jITyLfyH2Y1m3GtZ4H0ZQ8H10dXfEqGHuYgDwA0euCW%2B1ZNkusZ%2Fpk%2FtUCkExe%2BrJq8Psy4XZ122V8lSXghCcIYGXRAJvZ1vMtbKCVnnvk49Ez0eCX8wMISUlLVNUW4%2Fj3r3onHWu%2BIZi%2F%2BGr4veT6HgsXLwDP%2F76D1o1bwgTEz0MGbsYEz5ZBesGNZgh2uLjz9bhbsRjsf4ZJqqJbFlQyAP0ZMYZwcodP3VFkeo2%2F%2FttuHA5WBg9L%2FcgM1q5XI6nsYn48Ze%2Fsei3f9Hc0Qq2jepg%2BLhfhEEXBr9AfPzZWrh3aIoBvV2RmpomRGtkpAdNDQ0hdj4Qt7GhHpKTUsV5mTVvI5rYWcCmYS2MnPArho1bArMqhvDs5Ijvl%2BzAedZwUnUpTE30oa2tIbavDIN5c%2FvhdsTtidsVty%2BV81Qc3wAcZRdcl3QJlhtpYJKTLbayWPiYNAMBlsGI8AFkZbm%2FBvWqo7q5CeZ85V3kbbjBbV03I8ebbNpyHP%2F5fJnj2fawq70%2FC6PqWWRmcN8b0Bbfzh0mfnt0bIambaYJj1arZpW37udW4D10cW%2BGtq52YpqLIBs95rmy6yDiZra%2FPfsvY8r4Hm8tMyAoEjXY8Xp0dGAiUhf1yaZKFQO0Zt6Pe2ROHPOInL82zoK2lqb4%2Fef2k1g4b3iOVzx9PgB%2BN8PFdEvnhszbxcGLhdKKwIsFO%2BENYSFTgx1PSkiAIXLgpjrzUFcDFScohYsq22Nx%2B3O0h4OaHP3Z76kZUliH2cLCuRI8daGm9qoK3DD5Jzf6zPulyzLyF6SxHkyN9RH1%2BFmhopr8YXd88vl6EeI5s9BvmFcHtGttl%2B%2B69SzNEfUkrtC69%2BzWAj67zqFxqykixOvEPNYH73tAPSv0zf94XwUvBga6bxxrWpqsXM5zcZ9UD4NYP4K1TgizkvPMO3n63oJfZQhBK837VFknxK8iGiQ3LFxAWnp6uRxTOjPAxOcvYWqqX%2Bi63Iv4nlyCANZ3OXHaHyPG%2F4JTBxbmu25sXCLqZnnKt1HFxAB7t89FROQTXL0ehp%2BX70Z6eoYQMCdDXrzT9voVTl6Gb2wo08uKKv9ArVlVI9b3uJPZh4qJx6lzpUsT8058Nqs3HkR95lWyQ8O3sXvfJciZWTk0tsT4MV2hq6eF%2BKyyZEwIL5JSxO%2FgOw9FEiQ7bHsbvP9z%2F8FTWNSphv69XFi%2F0FoIMjOs1UXo3UclPk5DAx3RZ0wvJ8%2F1LqOu6idg4phuGDt5KXawMElDXV0kIErD2YtBcO4wgwlBBhPWmV%2Fz26QibXfwqC9mz9uERta1mLE%2BwaB%2BbdHYti5CQh8hlXnSLn2%2FgoyFmTwrN3f2INg1qlNomfwiMXrSUtSpWVV4Y34bYf3yKWLZqGGd8NH0Vdjy1ynhJadP6l2s42zfxl6U19yNHWtGBvzP%2F0ZqKsCjVwg8XCtLd8%2FLK%2Brr9PzK7eoxG6F%2Bq3P6R4nPk4Wx1jA3hbp6yZ33j7%2F8g4TEJMyfM1gYdGH9qNdJTGT1SHgBE9YP42l1DhdVr8HfIujycpGqNzLSzUkkFAUuxIdRsdDS0kA15pVzw9P%2FsbHPReq%2FpPAkjDGrr55u8ZO3uV%2BnL4%2Fwr6ztjDxVPqHQsVP%2BuOJ7Bx3aNM6TcOCpdv4pKzQ01fMI6uGjWEyds7bA9XloNtSrPQxYSMU%2FBWFezTjP9KfzvXEnLCrfdatWMcCqnydCKlUrMOXNb4Tr1irdnYziXjgo%2FFMiarLGN2Ud96ED26NPz1blsg9%2B4zQt9c2kR80aptjhPbtEZVZnQvr%2Bq%2FfzXfbD%2FBFkwSQqxcHvK00c61mu%2B%2BB9oLKGe65%2BPV3IUt8h6HV6giBREQSJiiBIVARBkKgIgkRFECQqgiBIVAShCJTm5q%2ByDstCkKdSCPyhSWUcPIwgUREEASV79o%2B8FUGeiiBIVARBkKgIgkRFECQqgiBIVARBoiIIEhVBqCpKcfO3NH%2F2mSgZdKNdyUXFKeof0yRKDz28TOEfUU7RAUUIJCqCIFERBImKIAiFioqyR4RS2pfCROVaG9rU7oQy2pfCRJWsD3NqekIZ7UthopJKYE9NTyijfSmuTyWBu7I1JB89kY9OSFSKHpW76olKjqFulsrVr%2Frok1U4fPx6uZXPhyrlI0KWFD5Uqc%2B%2FZ%2FMdmE6ZEHbF7Ev1RAX4J%2BpgJl1Si87p87ew4c9jJd4%2BXSbDx5%2BtyxnpXlnJsit%2FRe1fYc%2F%2BSeWYLJPggpMNrl8Lwt6K2u%2Bq9QfEyOp%2FsSt22N0o9Ovlgk7tm2KN92ExHrBzswb4eGLvnAG1b4c8wDrvI2Iw6pbO1hg3qgt0tDMHsubGuZqV53vjrhjV%2FmlcYp59Xboagi07TiEmJgGuLRth%2FGjPIg3UzQenXr%2F5KCIfxKBqFUP08mwOa6uaOH7KH%2FfZsiXLdkFTUwOTP%2ByOv3efh2WdajhzIUDU37WlDT4Y6YHN20%2FgxOmbYmjUTz8eAGNjPeGlOCvW7Ye2lga6d2kOm4a1lEpQzJ56sq%2FpzL5cmH3dVilPxaKY4AwJvCQSeDvbYq6VFbQqYr8r1x7A%2BGkrUdPcBO1a22PmFxvRa%2FB3IjTq072lENsWn5Ni3Yj70Rgw4kfYNKqFCWO64mZABNt2RU5ZYyYtxY1bERg1zB0WdczECPfZnDxzC9PmrEFXd0dMHt8D5y4G4ZsftxUeFcvlGPD%2Bj2J0%2BpFDOqK%2BpTkOHrsODakUxkZ6YvBrPjB2rZqmYv2%2Fd58T9eD15yJZyy4O7T0%2FZxeDh0yMLRBwOxLfL9kh1jXLGp2%2BZnVTUYaurpbSiInbD7cjbk%2Fcrrh9qZyn4vgG4Ci7sLqkS7DcSAOTnGyxlcXCx6QZCLAMRoQP6waUx35XLBmPJnYW4vfBo75CTO8PdssU0r1o%2BN0MF7%2F%2F2HpciGLM8M5iurmTFRxafyy8VxLzUoFBkbhyanHOSPd79l%2FO2cdvq%2FZg3pzB6ObhJKarfj4E%2FYf9gG%2B%2BeHuon5CQJDxUNw9n4UXauNjmLHN0qI8U1h%2Fy6tcmzzafzRiAwQPaZXrWOw%2BQnJyKH7%2FOHGRbR0cTS1f%2Fl9nXaNdYfPft0Up4rncZLxbshDeEhUwNdjwpIQGGyIGb6sxDXQ1UnKAULqpsj8W%2BPBzt4aAmR3%2F2e2qGFNZhtrBwLqe74mpqr4o10M%2BbK9Fn0zzU49yNeIJWLOTLRltLE3Vrm7H5jxH37AUaMaPPFtTrBIc%2BxBcLNuPrH155J%2B59CsOIeSM%2B4He3AV%2FDqn4NtGD7nzDGk%2B23asGhtJpann1wUb06Hh3Wl8oot%2FZT1JPqYRD7jWAtGcKs5DzzTp6%2Bt%2BBXGQRfad6nyjohfhXdsBKJpMBpLrDEFy%2FzdoKfJwvDTWKGm5iYXGC5fJ3%2FLRiFtq52xa7T3FmDMG1CL1z1C8X2f86I8O7Irq%2Bz48PiHU%2Bu61L2Mrm87HRALytWruxfpce9fRPs3HtRCIlz%2FLQ%2FE1kynJo1QHNHKwSG3Bd9Fk4g%2B%2BZ9sGy6dnbCr6v24nmWKHkae%2F%2Fha4XuM%2FppAk6cuQkDAx24tW2M4YM6IDYrAWJooCu8p6yEnkdDXSqSLKHhUdS4quCpKiO9u7XElWuhaOPxKSwsquH%2B%2FRis%2BGmCSBbUra2FGZP7oNvAb2BiqIfaLDzj4WE2n37SH3PmeaN5hxkwNdZHXMILkWXM7mO9jXnfbRFi5Jm7h49isXDecDHfw81B9I%2Bau82Apqa%2FwD3%2BAAAgAElEQVQ6Lh79X7G98vgxXTF07GLWp9LH3Jle6M36k0TZohDXzcO1sgwbeHnl%2BTp9fPwLJDBvVd3MGBqaea9DcXHPkfwyVQggP7g44p49z3fbt8GfzkhJSUMNc9M30vD3HzxFlSoGOan94sLrnJ6RAbMqhiXaPvfr9JU5%2FCtrOyNPVYbw5AH%2F5IeJiT5M3rIt71vlTlDsPXAZG7ccL3D9b%2BcOE1m%2Falnp7%2FyoXatKqY6H15kgUSkNPT1biA9BiQqCIEhUBEGiIggSFUEQJCqCIFERBImKIEhUBEGQqAiiEqM0T1TQ8C4EeaoyhD80Se%2F1ECQqgqDw793wWNSkBHkqgiBREQRBoiIIEhVBkKgIgiBREQSJiiBIVAShiijFzV9F%2FT1vouxRhhv4SvNERXn%2BMU2iYlCWh6Ip%2FCMqXdTxrkceJCqCIFERBImKIEhUFQS9pkEopX0pTFSutaFN7U4oo30pTFTJ%2BjCnpieU0b4UJiqpBPbU9IQy2pfi%2BlQSuFPTE8poX4oTlRxD3SypX6VI9h26KgbuLim3Qx7gwpXgSndcwq6YfameqAD%2FRB3MJNNWHAsX78CdsEcl3v7EmZvYvO1EpTuuLLvyV9T%2BFfbsn1SOyTIJLjjZ4Pq1IOytqP2uWn8A7dvY469%2FzyLsbhT69XIRo8av8T6MK7534NysAT6e2Dtn8OrIBzFYx5bdCopEU3tLTPzAE1VNMwegPnryhhjD92VKGhrUq46RQ93F4NT8Cu697TiiYxJQvZoxBg9sB7tGdXDVNxQ%2Bu87iSXQ8TIz10cW9Gbp2csyp27Xrodj29xk8jn6Gti62SEuX4aMPuollaanpWP%2FnUZy7GAQDfR2MGNIRLZ2ti3TMB4%2F6Cq%2BUzsqzql9D1POaXyieJbzAX%2F%2BcwXlWZqvmDUUdN%2F91Eh3bN8GajYfEcU0Y3VWMEbxm0yGERzxB3x6t4NWvjTiGk2dv4vGTeCxZtgs6OlqYONZT4YJi9tSTfU1n9uXC7Ou2SnmqS0EIzpDASyKBt7Mt5lpZQasi9rty7QGMn7YSNc1N0K61PWZ%2BsRG9Bn8HmSwDfbq3FGLb4nNSrPv4yTP0G%2FY96ltWx6yp%2FcS84R%2F8DLlcjtPnAvDpfG8hCm5ofBT6GzfD8ezZC%2FR%2F%2FwfYNqyNYV4dUM3MGEdP3Mgsj4mlvoU53h%2FshhZOVpj%2BxXqcvRAoll2%2FcRfDPvwZlhbVhNGHRz7BinX7c%2Bo9YfoqBDBhTxrXHZ07OuCDycsQfOdhocd7%2BPh1zP9%2BK3p0bY5e3VogNu45K%2BceTIz0oa6mxupnhDq1qoqBwuPin2PRr%2F%2Fg6x%2B2obmjFWrWMMXQcUswlu3LorYZ3No2xpyvvBF4OxIa6lIYGepBV1dLbF%2BzholCxcTth9sRtyduV9y%2BVM5TcXwDcLSlDVzSJVhupIFJTrbYymLhY9IMBFgGI8IHkJXHflcsGY8mdhY5V3EuJm7onIh70fBj4uBs3HIMPZkxcq%2FA4UJo1uYThDIPd4sZZp2aVYWX09BUz%2FE4fFtZega6dnYSXqtD21dJqO5dnIV4ecilraUh6nCVeac2zCutZB503AiPHM9Us7oJdu27JH5zI%2FYPiMD5wz9CKs28Dl66GoL%2FDl5BQ6vebz3WW4GRsKhbDe6sntz7erJ6ZaPPPJ5buyZwbdFITIeFR7F6aeKvjbMgYdbJ67px81Es%2F%2BlD2LCLBOfAkWu4cSsCtsyrNWtSD1ImTO65KhovFuyEN4SFTA12PCkhAYbIgZvqzENdDYRCO3oKf%2FUj64ri4WgPBzU5%2BrPfUzOksA6zhYVzOd0VV1N7VayBft5ciT6bfhgVK36HhD4UHfEDR3xzluvoaOJFUgr69XTBzr0X0aT1NDgw4%2FJg3mPU0E5CKJ06NEVLt5nCENu1tsOEMZ4wZSHUrn0XmdfYhnp1zZmhm%2BHBw1hhuMKgmVC5x8s3IcA8UgwLJdt0%2BTTP%2FEFFMOaBfVpjDwtRG7tOgZNDfXTp6CguINnifCNpJoEQlAjR2Tp6b5wfHRGWljeFPakeBrE8gtU0hFnJeeadPH1vwa8y9OkqzftUWSfErzwa4G1kG1B%2B03p62hg9rBNmTO6T77YH%2FvkKdyMei77S4mU7xbZj3%2B%2BM5YvH42lcopjP%2ByKz523E6l8%2Bwqy5G7FhxVThmThz5m3KJW4dxBSQiePL6tapihP%2FfVfs46tdqwqO7v5GeFfuFf%2F327%2FMs0pFaJqZhZWX6nzJ5eXzlsa7%2FLIiPVD7Fjw7OeFP1nGPYP2b3Bmv%2BPgXok8V9TgO9VgfaWDf1swLNGD9lUTm3R7huv9dVDExEImIvj1bITb2ubDdtDQZtFjYx3n4KFaEdNl4sHU3bjkq5vn6hWH5mn05y3hCgqe%2BfVh%2FLxueQOHrFcbJM7fwJCZeJFK4Z%2BPJFl4fjpGRrhBbSTE00BUXlYwMevG6Unqqykg3DydhdF37fw1T1rFPfJGMGuam8Nk0Swhq3NTlqMs68MkvU0V4983coSK58cGUZdBUVxed%2F2es87%2F8p%2FGiPzP74%2F54b9RPMKtqyLyglvCE2fD%2BFC9z%2FNQVMDbWQyc3B2icD8zxVBuZh%2Fvks%2FVYuGSH6I8lJaVi8cLRhR5D5MMYjP94BSzqmIlkSo3qphiR1X8c%2B74HPv1qE5b9vk9cGPr3cinW%2BeH9SC5%2B5w7ToaujhbOHfiCjgYKe5OXhWlm6d15eeb5On848zKMncTBmIuEG%2Fvp8bW1NkZTIzaOoONFf4uFXbnj2LYn1yV6f%2Fzp79l%2FGuj%2BOYOeWz%2FLM56LlIRjP2hUVno6Pin4m%2BoPZtwOy4UJLSEgSmb6Swr0mv1DwJEdpyP06fVnYR1nbGXmqsjxJGlKRNi7qfE6N6vmnmLlH45%2FXuXc%2FBjPnboCNdS0hGp4Eyc8TmVczzjM9acZqPI6Oz3dfPH2%2FaMFIkZ0sqJ76zFvq65XuwZaCyqbwj1Ao1cwMM%2B9PsT4K73f9u%2BVTcX%2BsMHhShCBREfnAQ6ceXZzpRCgBlP0jCBIVQZCoCIJERRAEiYogSFQEQaIiCIJERRCKQGlu%2FirLMCwEeapKAX9oUhkGCyNIVARBKHP4l%2B2xqEkJ8lQEQaIiCIJERRAkKoIgUREEQaIiCBIVQZCoCEIVUYqbv6X5s89EyaAb7UouKk55%2FjFNIi%2F08DKFf0Q5RQcUIZCoCIJERRAkKoIgFCoqyh4RSmlfChOVa21oU7sTymhfChNVsj7MqekJZbQvhYlKKoE9NT2hjPaluD6VBO7U9IQy2pfiRCXHUDdL6lcVlRdJKfh79%2FlSlcEH1c49KLiyIuyK2ZfqiQrwT9TBTJJL0YiJTcCsuRtLVcbK9ftx%2BdodpT9XWXblr6j9K%2BzZP6kck2USXHCywfVrQdhbUftNTUvH%2Bj%2BO4NzFIBga6GLk0I5o4WQtlm3%2F5wyaNamHh1Gx8PULQ%2B%2FuLREdEy%2FG341%2BmoAqpgbo3sUZHds1EeunpKZhnfcRXPe%2FK8bN5eUMGdhOLOMjza%2FZdBg3A%2B%2BJcXwnjPEscBzg3PBBr9f%2FeRRXr4eKMp2aNcDwQR3g8%2B9ZyDJkWLJsl1hvUL%2B2om4PHj2FXA78s%2Bc8qpubYMaUPrgVECmOJTUtDVPG94RDY0tcvBqMe%2FeiceDINdyLjIZtozro5uGkdIJi9tSTfU1n9uXC7Ou2SnmqS0EIzpDASyKBt7Mt5lpZQasi9jt%2B2goEhTzA5A97oJNbU4yZtBQhoY%2FEsm1%2Fn8aICb9gw%2BajSHzxEskvUxH15BkaMlGMHOIujHPiJ6tw%2FcZdsf4X32zGNb9QtqwjWre0wf7DV8X8uLjn6Dv0%2B0wjn9wHhoa6eG%2F0%2F5CenlFo%2Feb%2FuE0IfsRgN7RxscXBI77IyJCjWlUj1k%2BQiEGr%2BUdLWwO%2B%2FmGYOnstjp66ge4ezgi%2F9wSe%2Fb8WHql1q0aoWsUQYycvZaKTw1BfB9o6mjA1NhDbm5rqK5WYuP1wO%2BL2xO2K25fKeSqObwCOMlt0SZdguZEGJjnZYiuLhY9JMxBgGYwIH0BWlvu7FXQPAbcjcf7wIqip8XuD1rh4JRj7Dl3BtIm9xDofjuqKse93ztmmiZ2FEMOdsIfQ1JQygdXEtRuhaNa0HgKCItGvp4swfs7Avq3F91YmTj5v3EgPMd3S2Rp%2F7zoP%2F1vhcHSo%2F%2FY6Bkais5sD2rraiekBvV3Fd4d2jSGVqMGrX5s867t3aIJfvh8rfnNPOO3Tddi2PjOqfpmSij%2B2ncCT6HjhmaqZGaFlc2sM7NP6nReRFwt2whvCQqYGO56UYK05hDnsm%2BrMQ10NVJygFC6qbI%2FFvjwc7eGgJkd%2F9ntqhhTWYbawcC7ju%2BK3Qx4iOjoBrT3m5Jk%2FeEC7nN%2FmzPByw73XD0v%2BhlWDmuwKX4VtHw%2BZLPPhbO7tZs3biLV%2FHIaTQwO8%2F54b8xA2CA59iEPHruPshcA8ZXEjL4zJH3bHx5%2Btw6atx%2BDMQr%2BhA9ujfZuCs8Nqaq%2BCDX3mjXLDB%2BdW15AiLU1Wbu2nqCfVwyD2G8EMJIRZyXnmnTx9b8GvMgi%2B0rxPlXVC%2FMqzYQ30tWFpUQ3H9iwoUrlJySn4bP4f2Ln1cxH6cT6avjpnOe9feTCvcot5rGMsBBv2wRKcP%2FKj6AsNYh5l%2FqeDi30s3Ev5nlyCgOD7OHHaHyMn%2FIqT%2Bxcyu5GIMK60yDPKVgP0smLlyv5VOC7NG4k%2B0o5d53Lm3bsfI5IS%2BcH7MukyGbQ0NcR0xP1o1h%2B7n7N8176L4puHghPGerLwUB3xCUnw7OQo9nGb9d2yOX%2F5Np7ExBdax937LkHOzJSLePyYrtBjF4L4hBeiT5SWLkPkg5gSH7%2BRoR5Cw6PI6lXFU1UEBgY62LBiCqZ%2Fth7f%2FeTDwiMNJCenYvHC%2FN9k5R6H97V6eC2AWVVDkS3MFhjnv4NXMWeeN2wa1sbd8McYOdQdjaxric%2F0Sb3Rb%2FgPMGbb8HtMVaoY5PR13gYPG2fP2yTKiLj3RPR%2FeL8uM0xtC4%2B%2BX0FPVxvLF48v9vHz5MfYyctENrOtqy1%2B%2BnY0KaAcUIjr5uFaWYYNvLzivk7%2FmHksiUQiOu%2BF8TQuESkv01CzhukbyxKYZ4pPTIKpiQEz9rwJTJksQ6TnjZiweAawqCQmJuMZ804mxvpC2Lnh96vUJGpsfyXL3vF%2BXXRMgsgAlpTcr9NX5vCvrO2MPFUhmFczLvK6VZhgCoKLpSDBSKVqeYz3UVQcpsxeU2BZ%2FXq1wjCvDsKj8k9%2BVDU1LNVx8%2BRFaQRFkKgqFTzlvcN7Np0ISlQQBEGiIggSFUGQqAiCIFERBImKIEhUBEGQqAiCREUQlR2leaKChnchyFOVIfyhSXqvhyBREQSFf%2B%2BGx6ImJchTEQSJiiAIEhVBkKgIgkRFEASJiiBIVARBoiIIVUQpbv4q6u95EwWjyjfileaJiuL%2BMU2i%2FFD1h5sp%2FCPKLXpQ1QiCREUQJCqCIFERBImqgqDXNAiltC%2BFicq1NrSp3QlltC%2BFiSpZH%2BbU9IQy2pfCRCWVwJ6anlBG%2B1Jcn0oCd2VqxPsPniI9PSPfZXxkxNi452TpKmJfihOVHEPdLJWnX9Wh%2Bxd48Cj%2FQa43bjmGBYu2l9u%2BE58n4589F0pVxokzN8VA4cqAsCtmX6onKsA%2FUQczQZSamKcJmDNvU6nKWLF2P676hirF%2BciyK39F7V9hz%2F5J5Zgsk%2BCCkw2uXwvC3orab2paOtb%2FcQTnLgaJ0eZHDu2IFk7WYtn2f86gkVUtnDx7ExeuBMPJoT4%2BntALGprqSEtNx0%2FLdopxe5NfporR48eP6ppnbN57kTFYtf6gCAX79GgpRpbPD17Gmk2HcDPwHuwa1caEMZ6obm5S5Lpf8wsTA2w7OzYQYwT%2F9e9ZpMlkWLJsl1hv8IB2iHoch0fsk87m%2F7vnohgEfMaUPvC%2FFSGOMz1dhinje6CpvaU41kjmpfYfvorwiMews6kDz85O76SgmD31ZF%2FTmX25MPu6rVKe6lIQgjMk8JJI4O1si7lWVtCqiP2On7YCQSEPMPnDHujk1hRjJi1FSOgjsWzb36cx%2BqPfxKj1fbq3xK7%2FLuF3ZvzCoJkRpqSkwaNjMwwZ2B5%2B%2FuGY%2FkXeh3jn%2F7ANDepVR8f2jTFv4VYcPn79jf3zvlXfYQuFkc%2Bc0hd6TByDx%2FwkRrIvjHnfbcFFJoARg93QxsUWBw5fE%2FOrVTWCRA4xQDb%2FaGqp49qNMEyZtQYnTt9Ejy7OCL0bha795mP1hoNo08oGpiYG%2BGDKcsjlchixC4OWlgZMjfXF9qZvGTi8ssLth9sRtyduV9y%2BVM5TcXwDcLSlDVzSJVhupIFJTrbYymLhY9IMBFgGI8IHkJXl%2Fm4F3UPA7UicP7wIamr83qC1MNJ9h65g2sRemcL4fDATVCvxO%2B7ZC1zxvSN%2B6%2BlqYf5nQ%2FA0LhF3wh6hU4em%2BG11Xge7fvlkWNSpJn5HRyfAZ%2Bc5IcLcbPE5hfat7fHBCA8x3dLZGv%2FsPi%2B8lkNjy7fWn9fds5MT2rraiekBvV0z%2BxDtGmPh4h3w6tcmz%2Fqd2UXj5%2B%2FHit%2Fm1YwxY%2B4GbF03Q0y%2FSErB5u0nEM1CR9tGdVDNzBitWjRC%2F14u74SIvFiwE94QFjI12PGkBGvNIey6clOdeairgYoTlMJFle2x2JeHoz0c1OToz35PzZDCOswWFs5lfFf8dshDYeytPebkmc%2FDpZywVO2V8zY01EEaC7mESJjxTfx4pQipGttZIDU1DbL0gr0L91hnLwW%2BMT8k9CEOn%2FDD6XMBeebzkLIwJo%2FrIbwjT3zw0HT4oA45Ass3DJG%2BOhYDfZ08y%2FhFQsqWp6fJyrV9y%2BtJ9TCIciOYgYQwKznPvJOn7y34VQbBV5r3qbJOiF95NpyBvjYsLarh2J4FRSpXkkvTq9YdgKmpAXy8Z4vwkHuNIaMXvzUjZ2yo98Z8Ee71b4t5c94r9nF2cW8G35NLEBB8H8dP%2BeP9D3%2FB6QPfi%2FrwMK60lEUZr6OKLyuq1AO1Ls0bIerJM%2BzYde5VcuF%2BDHxZx7%2FQJEFqOrQ01YUB8%2F7PkRNv6j85OS0ntOLJgK6dHd9Yx7OTIwsLz%2Bb04zg8acI9YWHs3ncJcmaiPEwcP6YrdJi3iU98IRIuKcxzPnj4tMTnxshQV%2FS7CCXyVBUBz9RtWDEF0z9bj%2B9%2B8oE265wnJ6di8cLC31QdO6IzvEYugmO7T4SwuEDfWGfyUvCLfeyzRHT3cMaQAe3fWKd9G3vRf%2BszdCGMmRi4AKtWNcDW9YXfXThwxBez520SmcfwiCfC49nb1BXLeKaxU5950NXRwupfJhb73IwY3BHjpi4X%2FTve51u0YCSpo4QoxDXzcK0swwJeXnFfp3%2FMPBYXRzUzoyJvw9PqUdHPRHaM90nyg6fTtXU0UNXU8K1lcW%2F3MCoWRkxYhsxLFBX%2BdMazhBcwMdYXafXcxMQmQCpRg4mJfonO48uUVETHJIgMYGnI%2FTq9IsO%2FsrYz8lSFwLNhxYXfryrM4GrXqlKksniSIHdZPHSb9um6Atfnmb4hA9sJb5v73lhuChNyYWhraZZaUIQKi6qyUatmFezwnk0nghIVBEGQqAiCREUQJCqCIFERBEGiIggSFUGQqAiCIFERRGVAaZ6oUPXhWwjyVGUKf2hSlQcZI0hUBEHh37vksahJCfJUBEGiIgiCREUQJCqCIFERBEGiIggSFUGQqAhCFVGKm7%2Fl9fe6iTehG%2BwqIipOcf%2BYJlF86KFlCv%2BIcooKKDIgUREEiYogSFQEQVQKUVEWiVBK%2B1KYqFxrQ5vanVBG%2B1KYqJL1YU5NTyijfSlMVFIJ7KnpCWW0L8X1qSRwp6YnlNG%2BFCcqOYa6WSpnv%2BppXCL%2BO3ilTMq64nsHgbcjS7x9bNxz7D1wWaX0JOyK2ZfqiQrwT9TBTGVs1PDwJ%2Fhm0fYyKWvb36dx6Nj1Em9%2FLzIa83%2FYplKiyrIrf0XtX2HP%2FknlmCyT4IKTDa5fC8LeitrvqvUH0Kd7K%2BEBQkIfYuQwd5gY6WPr36dw9MQNqEvVMHhgO7i3byrWfxITj7WbDiP83hOYmuijaydHdGzXRCy7GXgP3luOI%2FJhDFo4WmHiB92go62Jv3aeRUJiMpYs2yXWGz2sU6GDW98KuofN20%2FiaWwiatYwxZAB7ZCRkYGbAfcQwYTBB97mQ5i%2B178tVm84iHat7fDXv2cRdjcKfXq0QpeOzfD7pkPiuJwc6uOTj%2FpAXV1N1OX585c5deHHW8XEQGkFxeypJ%2FuazuzLhdnXbZXyVJeCEJwhgZdEAm9nW8y1soJWRex35doDGDjiR%2Bw7fBXxCUlixPmvFm7FgcO%2BGDeqCwb0aY3Z8zbh7IVAsf6wsUsgl8uZMNxhY10bB474ivl%2BN8Mx%2BqPf4NqqETPg3ggJe4QZn28Qy%2FiI9%2BpZA2Xzj7qG9K11ehIdz%2Bq0CA6NLcVg2Vy8J8%2FchK6eNvR0tWBspCfKMatqlHlhWHcAH05dgZrmJmjfxh6zv9yEHoMWID1dxi4YLbFj1zkm0BOZdWHbSNVf1UVTXTmHeeb2w%2B2I2xO3K25fKuepOL4BONrSBi7pEiw30sAkJ1tsZbHwMWkGAiyDEeEDyMpjv99%2BOSzH2%2FD%2Bz1%2F%2FnoHvmZ%2Bhq5Op65DQR9j530W0at4It%2B88wHfzhqOlszVcWWWzWbF2P6aO74l%2BPV3EdMMGNeHQ7mMm0rFwa9NYlOnVr02R6hMaHgUNqRRd3R2FR8uuG6eepbkQw%2BtlLV88XoiQw8PDHl2cMXJoZt%2F83v0YJvq7mf2Lto2x%2Ba8TRa7Lu4IXC3bCG8JCpgY7npSQAEPkLHhQZx7qaqDiBKVwUWV7LPbl4WgPBzU5%2BrPfUzOksA6zhYVzOd0V554kx6DDovAyJRXuPb%2FMs04HZow8fJoxuQ8Gj%2F6JGXc1ODtYYcLYrqhvWR3BTGyXrgRj%2BZp9OdvUqGaCF0kpxa5Pi2ZWaNncGk7tp8POtg7at7bHR2O7wcBAp%2BAQQ%2B3VqTHQz7sen45Ml5Vruyn6SfUwiP1HsLMQwqzkPPNOnr634FcZBF9pYoGsE%2BJX0Q1soK8NHeahzh3%2BMY%2BhZjNtYi%2BMHeGB6zfC8M%2BeCxgydjEuHv0f9JnhTp3wylPlhoUgLGQsRiOw8HDt0smi%2F3bteqjoMz14%2BBS%2FLRonlhdWlkTyluli1qWo0MuKlTP7VyloaFVLdNyX%2Ff5fzrzopwk4z1zo8xcvsf%2FwNeizvk1bVzuMYv2quLjnoo%2FFQzXet%2BEpaw5PJGSn0Q0NdRETk4Bnz14UqQ4BtyNFooL3fzw7O6G7h3NOuUaGerjD%2BmslxYjVJTY2UdSbUDFPpbAspFQNG1ZMxZRZv4ssHxfQs8QkzJs9CE3sLfHT0p349CtvWFiYITIyBt%2FPH8E8gQQTxnji0eNYtPaYA1NjfcQlvIBj03ro0bU5rOrXEAmENp6fisTAjj%2FmoEG96gXW4WVyKsZOWQY9XW2x%2F8TnyVj960eZfYe%2BbTBo5CK0dJ8l%2Bm2b13xSrOOrZ2GOju2boG23z0Rdtm9k5VjVJMsvRxTiwnm4VpbhAy%2BvLF6n5x4qPU2GGtVN8syPiU1AMjP86mbG0NDMex1KfpmKGLadWVVDaGtpvpHV02LrGxnpFWn%2FPOTj8NR5bnidHj2JQw1zU9HPKwk8tNTSKHpd8iP36%2FTvQvhX1nZGnqoEmFUxzHd%2BVVPDArfh96V4du5tCRGezDh%2B%2BmaBZWxe87EQ5Otiyt3nKmgfRU7OVDWiBiZRKQ%2BTxnUXH4ISFQRBkKgIgkRFECQqgiBIVARBoiIIEhVBECQqgiBREcQ7gtI8UUHDvBDkqcoQ%2FtAkvd9DkKgIgsK%2Fd8NjUZMS5KkIgkRFEASJiiBIVARBoiIIgkRFECQqgiBREYQqohQ3fxX9d72JwlGlG%2FNK80RFWfwxTaJ8ULWHnSn8IyosmlCViIJERRAkKoIgUREEiaqCoNc0CKW0L4WJyrU2tKndCWW0L4WJKlkf5tT0hDLal8JEJZXAnpqeUEb7UlyfSgJ3anpCGe1LcaKSY6ibJfWrXocPeL1n%2F%2BUyKYuPdH8z8F6Jt%2BcDge%2Fed%2BmdO4fCrph9qZ6oAP9EHcwkGeUl8mEM5i3cUiZl%2Bew6h%2F2Hr5Z4%2BwdRT%2FHlt1veuXOYZVf%2Bitq%2Fwp79k8oxWSbBBScbXL8WhL0Vtd%2FUtHSs%2F%2BMIzl0MgqGBLkYO7YgWTtZi2fZ%2FzqCRVS2cPHsTF64Ew8mhPj6e0Ctn8Gw%2BGDXfNvJ%2BDKpVM8bAPq6wt6mLlesOoF%2FPVrh0NQR3wh7BqVkDPHj0FMO8OuTs97r%2FXdwJfYSBfVtj538XUd3cBBcv3xbbOLL9TBnfA1qaGvD59xySklKwZNkusd0IVr%2B3jTnMCQq%2BD%2B9tJ8SA3jWrm2DwgHaQSCS4cTNcjEnMy%2BL7G%2BrVHms2HUbrVo3wz%2B4LCL7zEL27tYCnhxPWeR%2FBpWvBcLCvh%2BmTeotj9vn3LJKSX9Vl%2BGC3Sj92MLOnnuxrOrMvF2Zft1XKU10KQnCGBF6s7b2dbTHXygpaFbHf8dNWICjkASZ%2F2AOd3JpizKSlCGHGztn292mM%2Fug3YZB9urfErv8u4fdNh3LCsp6DvsXLlDR49WsDIyZI7y3HxbIVa%2Fdh4IhFOHDEF%2FEJSTAx1seXC7bkjDbP%2BeHnv4WBcnbuvYgPpyxHWroMvZhR8%2B0WLPpLLDMzM4SaVE0MnM0%2FGlLpW4%2FnaVwi%2Br%2F%2FIxrb1hWiqcIEeOyUP3R1taCnpw0DAx1Rjjm7CHDWsOMZN2UFzKoaomP7xvjs6z%2FQw2sBO65Udsyt2DFfxMYtxzLrwgQkzVUXTfXK%2B%2Fw1tx9uR9yeuF1x%2B1I5T8XxDcDRljZwSZdguZEGJjnZYiuLhY9JMxBgGYwIH0BWlvu7FXQPAbcjcf7wIqip8XuD1rjIPNK%2BQ1cwbWIvsc78zwcL4xJCYn2KK753Muop8zUAAAxXSURBVAXHvFjDBjUx%2F9PBmXF728bIyHj1fOh3Xw5Hh7avEk4e7s3wp88pzJ7WD6F3o%2BDHvMa6ZVNyls%2F%2BuB%2BGv%2BcmftezNMeoib9hwRdDRbkbNh8Vwi0K4eFPxHfXzo6oYmIgts%2BmQb3qMDXRf6Os3xZ9gOaOVuL3sZP%2BrN6NMW6kh5h%2B%2BChW1FUcY7vG%2BH3DoSLXpSLxYsFOeENYyNRgx5MSrDWHsNa4qc481NVAxQlK4aLK9ljcBh3t4aAmR3%2F2e2qGFNZhtrBwLuO74rdDHiI6OgGtPebkmc%2FDpZywVO2V8zY01EEaCxc5IaEP0cTeIq%2BbV3tVvWpmeUO0USxs%2B2j6akz%2FqDc2sSv%2Fe8ww9XRzOWPJq23rW1ZHAvNwyS9Ti31MzZrWQztXOzRvPwN2NnXQrrUdJo7xhJGRXsHhSa596%2BvnzRVxz8Y9aHlRVk%2Bqh0GUE8GOJIRZyXnmnTx9b8GvMgi%2B0vjzrBPiV54NZcAMyNKiGo7tWVCkciW5NG2gryNCu6LiylywCfMSPFmwY%2Fd57PP58q0ZP10dLWhraYrQszhmx8Oz1b9MRExsAq76hmLNxkOYc88bq36eKJbLCylLIpEUOM1%2Fy%2BVl%2B7aGKrysqFIP1Lo0b4SoJ8%2Bwgxl6Nvfux8DXL6zQbTt1aIq9%2By8j8kGMmH7%2B4iXru9x46zYjh3TEl9%2F%2BCWeHBrCsWy3PsoQsgaanZ2DFuv3o5uEkPJ%2BhoS7iEl6IvlJRCAp%2BgBu3wkUyo2snR%2FT0bIFYJlKOsaGeSJyUFEN9XcQ%2FTxKCJd5BT1UR8NBmw4opmP7Zenz3kw%2FzDBpITk7F4oWFv5navo09xo3qgi795sOEGeuzxCRMGN0V7u2bFrhN%2F96uIj0%2B5v1Obyzz3noc6%2F44IkI%2BnmRYneVZLGqbwcPNAe08P4eWhjq2rp8Bm4a135LNTMPoj5aKY%2BHelIt1xc8TxLIBfVwx8P0f0dJ9FupZmGP7huLdwahdqwo8OzmhfbcvoKWpjs1rPhHZTqKwCEcB8HCtLMMAXl5xX6d%2FzDwWD2%2BqmRUvRZySmoYn0fGoUc0E6hpvz8wdP%2B2Ped9txan93%2BUJq3hSonNHB%2FTr6YIXSS%2FzTVPz9D3Pthkb6xWpXjzBwBMnXAi54Z7w0ePYItW3IIpbl9fJ%2FTp9RYZ%2FZW1n5KkKITvFXFz4vSSeXi4Kv7P%2Bzahh7m%2F0W7LhiYs8yYtcZAtt9YaDOHy84K4m97zcQ9WsYZp%2FA6urFbm%2BBVHZ701R%2BKcicA%2FRn3mibl2c31j2wYjOBYrgdcazEJN%2FCBIVnVjmIQq6v9PW1Y5OkBJDr9MTBImKIEhUBEGiIgiCREUQJCqCIFERBEGiIghFoDQ3f1VtuBaCPFW5wh%2BaVKVBxQgSFUFQ%2BPcueyxqUoI8FUGQqAiCIFERBImKIEhUBEGQqAiCREUQJCqCUEWU4uZvWf19bkJxKNONe6V5oqK4f0yTqDwo28PQFP4RlSbaUJaIg0RFECQqgiBREQSJqgLgsTO9pkGUJxJAMX00RYnqpWttaFO7E%2BVFln29VCVRRSfrw5yanigvsuwrWmVExXxysFQCe2p6orzg9sXtTGVExYLd8%2Bw%2Fd0XsO%2BpxHFKzRpwnlLpH5S7sTFVElaGGv5m7GupmWfH9qv7DfsD1G3crTMCHj1%2BvdPb2Iiklz2DiJeHU2VsIv%2FekUupJ2BWzL2FnqiIq31vg4236J%2BpgJpSYgNv38b9fd1a6esXGJWLmlxtLVcaqDQdw%2BWpIpTzvWXbln2VnFY7Cnv2TyjFZJsEFJxtcvxaEvQrp28nl2PDnUdg2rA3XljZiIOo%2F%2FzopBsBWV5diyMB26NiuCSLuR%2BO%2FA1fw0QfdcrblV%2BkjJ%2FzwwQgPMSL86o0HERL6CMaGeujQrjG6ujvi3z3nER0TjyXLdoltJoz1hK6OFnbvu4Td%2By9BTSLBgD6t0bWTo1geFh6Fc5duo1P7pth78Ar09bRFHfig32s2HYJ%2FwD00sqqJCWM8izS8aVpqOtaz47t6PVSMLezsaIVhXu3h8%2B9ZZMgycurFR3x8%2BjQRkQ9iwIcn%2Fnv3eTEm8owpfREYFIltf59hIXMaJn%2FYA82a1MMlJqbwiGgcOOortrFh5697PsOwKgJmTz3Z13RmXy6KqoPCbv5eCkJwhgRerBG9nW0x18oKWhUtqE%2Fn%2F4FjJ%2F3h1KyBmPf5N3%2Fg6Mkb%2BHB0VzFy%2FIwvNuDClWBUZwa2ct1%2BXLz6qt%2B7ct0BMSI8Z9y0FYiJScDoYe5o2sQSBw5fFcZZtaoRNDTVxUDW%2FCOVqmHjn8ewmBmzV9826Mv2Mf%2F7rdix81yWqB7j%2ByU7MPzDJbjPjDXmaQKePXuBPkMWwtyMGfnkPjA20sOgUf8TYwoXxjeL%2FsLZC4EYMdgN7Vrb4xATgUwmRzUzI1G%2F7HppaWnguv9dTJ29BofZhaKbhzPusQtJtwFfY%2Fna%2FWjdqhHbxhhjJy8TFx5DAx3o6GjA1ERfbG9qaqBwMXH74XbE7YnbFbcvRdVFoU%2Bp%2BwbgKHMQLukSLDfSwCQnW2xlsfAxaQYCLIMR4QPIymvf877bykTxFOtXTIGmhjqeRMdj538Xcf3Mz9DW0hTr3A55gF1snkvzhsxjtIf3luNo5dwQiYnJYv6hnV9nhnlB9zBqqLvwdvwzfFAHMb%2Bdqx3Ong%2FMM%2FbvyvX7sejrUejQNjP5ye9OLlm2EwP7thbT3NPt%2FetL6Ghn1mHV%2BgOszEYYN6qLmG7pbI1%2F9lyAHxOBs2ODtx7jrcB7cGvfOGeM4f69Mi%2FeHdo2hkTtzTGJO7Zvgl9%2F%2BED8rl2zCibNXI3tGzIj9JTUNHhvPS68JvdM3JO1dLIucFzj8saLBTvhDWEhU4NdVlJiCDuXN9WZh7oaqDhBKVxU2R6LfXk42sNBTY7%2B7PfUDCmsw2xh4VxOT138tHQnbtwKx%2BVjPwlBce6EPULyy1S4dZ%2BbZ93OHR3E9%2Fvsas%2BXRTPvwcM3lxaNULd2VbFsJguTpsz6XYRk3OvxkLCxbd18w7H7D56ikXXNnHk8nAtlHiobQwPdHEFxgu88xMFj1%2BHSaXaesl6mpBZ6nJM%2B7I6PP12LP7adgJNDAwxlF4ZsMecbkktfBS76%2BnlzSFqaGtBgIXFauqxc7aGoT6qHZV6PIpiBhDArOc%2B8k6ei%2BlCVTlSvJS%2F8yrMhsmnIDJn3babOWYO1SycLY%2BJGZKCvg%2FNHfmSh0Zta5mFOu9Z22OpzSmTOvp07LGfZSOalBvVvC7%2Bb4djH%2BkI8POMeLzvMzDnZGlJhnAnM01U3N8nsVLPfBnoFJ0F5v8qL9bu%2B%2FnxIsc9Lpw5N4XvqZwQER%2BLE6ZsYNfFXnNj3LdSYl8pdrxKH0OVgB8rwsqJKPlDbu1tLrPplAuLjkzD9i%2FXCwOwa1RXGvYL1IbJ5EhOP85dv50yPYn2m31btZUYpEQLLhodjXCw8TBzP%2BmMvXiQjJSUNRszrPHwci6TkFLEeF6t7hybYvP1EzrZ%2FsN%2FuzPgLwrOzE3bsPoeg4Ac583g%2Fj4erhcE9qkyegab2lqyf2EVcOJ6xY%2Bb1krE%2BGU%2FAlBQjFqZy705UYk9V0fB%2B08aVU9H%2F%2FR8x%2F%2FttwhNsWDEVk2etwe8bDolsWfzzJHz9KfMQLTK36dDGHoaGuhg9rFMeb7bO%2BzC%2B%2FO5PWNevibsslJvPtuFer1nTerC1ro1W7rOgJlHD0b3fCA83auJvcOvxhUgamJjoif0WROtWNpg5uS%2Br5w8wZmLg95hMTfWxdd2MQo%2BRZydnz9vEws1aiLj3hPWpXOHQ2FIs46Fg137z2XFqY9n%2FxhX7%2FPHkx%2BiPlgrh8jouWUhDGWWjFE%2BK8%2FCvLF%2Bn5%2F2m9DQZalQ3yTM%2F9G4Uer73La6cWCxEl5vYuOfM4F%2BKzBr3WrnhN4G58RoY6OTMexQVJzJw2WFgYchkGXgYFSu8DBd2UUl8nsy80wuYGOuLUDI3MbEJQuw8i1cSeL8uOiZBJDXyC5mLSu7X6ZUh%2FFOn68qbmFUxzHf%2B7xsPYVDfNm8IisMNsyDjzE84rwu2MHi%2Fj%2FfrcguVe9WC6NuzlchCco%2FJP%2FlR1dSw1N4%2Bd50IElWxaetiK1LalQEu1B3es6lRSFTvNr26taCTQBQKvU5PECQqgiBREQSJiiAIEhVBkKgIgkRFEASJiiAUgdLc%2FFW24ViIdxepMhzEoxh8zT81zTCfmvTdb0sK%2FwiCIAiiPPk%2FPvfPgDjCXHUAAAAASUVORK5CYII%3D)
+
+```
+basic_stmt
+ ::= load_stmt
+ | load_ifr_stmt
+ | call_stmt
+ | jump_sp_stmt
+ | mode_stmt
+ | message_stmt
+ | erase_stmt
+ | enable_stmt
+ | reset_stmt
+ | encrypt_stmt
+ | keystore_stmt
+```
+
+referenced by:
+
+* in_from_stmt
+* statement
+
+**load_stmt:**
+
+![load_stmt](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAasAAAAlCAYAAAD83MZxAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAADbxJREFUeNrtnQl8TNcex3%2BTzCSRWBISxB4EIfZEKBpLmiCeoqFIKdWmiigJ8jSK0jZ42lheLS26PKpF7ErLp4qKrdRaxJJaYkkkYiJC1nf%2BJ%2BZKppMMkWQk%2Ft987mfm3nPuuXf%2B%2F3vOfzlnJgDDMAzDPOeoTHHR1i7IKq0CPXKm8GRamuXE8mf9sH5Yj0%2BD2lQf9o%2B9y0udAt06vsVyYvkzrB%2FWYxFgxqIv%2FKiRPT6WP8P6YT2ysWIYhmFeMNhYMQzDMGysGIZhGIaNFcMwDMPGimEYhmHYWDEMwzAMGyuGYRiGjRXzXHD9RgLSUtOLpN30tAwWcAmU%2F63YRDx4mMrK4f5ReoyVhyuq5FfJWHlREvTBcuw%2FfM5gGT0kC5dug3fvaWjbdSL6%2BIdh7YZIg3XnLNgAvyGzEXv7bq7ja9bvk8dpe3PEPEz55HvsO3CmxCnSt%2F8MnDl%2FrdDb9e47DReibxTpvcfFa%2FHTL0dKdEd6HuXv%2F044DhyOMlov5no8ft1zolQPdM%2BDfmisMZXzYEodP6v90J0vjZUY86%2B3dsHqvBo1Vl6UHD8VjYSEJINlI4IWYfO2w5g%2BeRDWfDcRAUN9EBYegc%2F%2FuzFXvZQHqVj67Q7cSbyHDZsP5Cq7GnMbKhUQPLoXBg%2FoBBsbK4wMWoKQqd%2BxK1NMXIy%2BiU%2FmrGFBmIgTpy8jfOFmFkQRkpWVhbGTlkGrTXnhdFxQ%2B9HGBX1aN8bV9AxE0778bUBVttHql5EhCl2wXm2OwIOncEt3krFyUxB58Cz2Rv6FyJ2zUMmunDxWs7o9HOzLw%2B%2FN2Rg8sDMcKpWXx7ftOAqXhjXg388TX337CwKG%2BeRqy17Ua9emkXzv1ak5hvl3hY%2FwmNq6N0Cfnm1LZOdYuzFSfm61UNbrfdujy8vN5PHYuLsiGv0Jt8SrSvy1bOaEYW94iXpmSupo0bJtuPT3LTRzrfNUKY74O0lYvGw7Tv51GY0b1hTOgzeqVrHLvh8R8dau5YA9QmdHj12EeytnjH6nB9Qac%2BlxJmqTFSdj%2BGAvVKhgU6IHJ1PIX6u9j4Xi3NNnrsrnPene%2FRxO39%2F4IWKvvH65cmXg5dkMPbu542FqGjZtO4QbNxMU%2BY9%2B1xfHTkQjYtN%2BxN2%2Bi4p2ZdHNq5XsG6WF4tbPmkcZn8XLt6OscIi7vdIKVSvbYf6SLYiNvYvMrEw0d3XC8CFesNCocT%2FloexL74g%2BRPqhOuNG9RI6TZGO99HjF1G%2FXjU4VraFZwdXNHSuLts%2FeCQKq9buRXy8Vo5p5MBnZGYY1DFdpzh4WvtBRipDhfkZWaiR8wedcs1ZZWUbL2r0miFLaKy8OPnt91Po%2BFJjxVDpcGtZXyow8uDjVF6EeDBf69VOPiDkxZ%2BNism37coOFeDf3zPPlOLzziLxkNM20K8jenV3l1Hi1p%2F%2FkGWJd5NRtmwZvNqjDXr1cJedNnxh9gNMHaSP%2F0w8eJiGNwd1QTlR76F4%2FySkpqXDb%2FAsWf%2F9ET1hYaFG70FhuJf8QJav3rAPAWMWwtzMTA6SG7YewOz567PlbV8BGnNz6WzQptaoS%2FRAaAr5Z2RkYuDwz3D5ahyG%2BneBo3ASku49UMrJ6NSu6SCf6w4eLgidvhI7dh0TA4AK9hXLi4FLo8ifjsXGJaJ%2BXUcMEU5fq%2Bb1EDjxKzkQlgZMoR9yoolqjhWljG2sLaUzUcbKQvQHNzk%2Bbfn5MMI%2Bj5D1ku8%2FxGfCsND1%2Fjx%2BCbcTtDI6GxwwF6fPXpHXr%2BdUVX6OqAvX5Tm79p7EuJBl8OnSEqMCfPH7gb%2Fw8ZzVeeq42KNLI%2FZDF0kJ878OZKj0UBtpVFpCY%2BWmiLSo8%2Bm8dn3oeGycVvGUDv4RhS%2FmvCs9Gm%2BhyIhNkQgd3y%2Ff9uvUqowt2w%2BXyHQDeWRfLRiFNq2dlTQoedy%2BPm5oUL8axgf2ljnsK9fi0KFdYxwRkQ6xcesh2NuXw8xpQ%2BR%2BV%2BF9L%2Fhy6xNdd%2Beu41CpVJgeOkjuk1dH8yUkwwGvdZTHJk%2FsLztlto5sMX7yN%2Fgg2A%2BeHV2l59evT%2FtSke4xhfz3RJ5GgohsN%2F0QCnPzbB905Zo9SjlFRdTe%2BYs3xACpQQsRMRw9dgmvdG6Blzwa4dip6FzyJ4eCDCDVtxSORxMRKVN9j9YNWD8F0E8nEf0Qvbq3kc6wjpCxfXHz1h1EX74Fz%2Fau0sDkZMWXY5VxjrJJNG2x9rsQJdJbt3G%2FUnfeoi2YOmkAfLq2lPt2IQMwYNgcTPv3AIM6NpkO9O2HCtvSgen6kdQTGSsdmcAxIZJuWUbK09MRLS5apjg%2FMM0tJSUZzv%2BSR1murJV8v2HLAenNkBdJkMFaL45NCvKDmVne3sWdxGTY2ZYt8P2Z6pelSSbkhTUUnU4HpQgobUGcjbqG94IWQy0imUYNqsvVTGaPBrdzF2LQvIlTga5L7TfIcU15XbFPnVBJB6gey7uu8AoppUKDR1Hwosn%2F3PkYuDaurRgqfbbvPIrQGStRo1ol1K1TRQ7EutSRISgF%2BPHs1bJuLRGR3RADKhkv1o9Tod0LZXlGjF0kU4CNnGvIhUb6Mnawf2zYLom%2B5FzPUTFU%2BkRdvI4Ppq%2FA1E9XKcesRQRXlDyLHsl%2BiBHBNz0LfuI101hD6jxyjJHixBjx6iUaXCpex%2BVXrlFj1tNEVoXxoFJqYmZ4BNLTM3MpjwbA8xdjZHl2bno%2FatesjMhDZ5U691NS5Yo%2FSiMaFKIQG6WpfL3dCnx%2FhfHPyQoiJ6syFlIe2nspyrwPdVBKWRC0kKGHd2tMGNMn25hvPYiVq3fL9%2BRB30xMLNC9knOg7zzQPVSvXsmwM5BwTzgDNtKAkQ0rbJv1osnf0kIDbVLek%2FcTPvwG4WHDlXmnaWGr%2FhFx6KAl3iFTvsX3y4KV6GPcpGWsn2fQjyE5z5q7To5BU0Jel%2Fu%2F%2FHoM8xZvzrePxd3W5llOjvi8mcOV%2Bff8rl2cetTXU077IV6XiEB%2F%2BYM0vCVG8bezVLhrKAVImOk3Il7WiAZcxHZNbQ6Xo2cQZKzcFIstfH1aywnC0On%2Fk%2FMlMt8soqExIUvlZCl5%2BeQlXb4aK0L%2BkbKj6rbevh6I2Lz%2FH21SJ6WJZVrCniliUprsLGmQTDq0bYwVP%2F6mPKArftwtZNJU7qemZcDSUqOkP%2FbsO62c6%2BHWALt2n5Sep0wtibLkHPMe%2BUGTvIePnseFS9nLeK%2FFxMt5Rd3EtTRe2uwJf5qUXrR8uxgUsp2BCuWsZVo3KSkFJR1Tyb%2BNmzMOHzmPv6%2FEyn2a54iNTVTuIY2ua6FRUuN%2FnohWzq1Q3hoxQl%2B6ZdViwEBaerpyn6RLWrRRGjCVfsgpKy%2FkTNGUjtTUxzKmMYzmnPKjfVsXXLkaJxdQUD%2Bjz3D2wuP5925dW2Luoi3KPDGNZ7SIRNHx9Xi5oMZU5GU%2FIk%2FgFL2KYNZZqGONqJckKl%2FLL7KiRsjSHdSIRgwYIGPlRUbA%2Bwtz7VNOdvkXgVi1PBjBoV%2BjadsxMmUXn5CEbl4tEfYop0yTo7SowsrSItf5ZKwGB4Tj0ylvyP1NPx2SG6UFadKSVj4FvttT6dwljZkfDcHQ9%2BZj52%2FHkZKSJtOgYVOzPystfnhr9ALpLZKj1aRRTeW8zh2bolNHV3h0nig8UA3auTeERij7SaA5vmmTBqK3fxic6zri3IXrCBr1Klxdail1lny9Xeb4aaLarUU9zJkxVEnD0EDQzjsEajMzbPwxFLVrOJTYAdEU8m%2FSqJZ0rjr1nIzyNmXQQMjU0kqjDJQ0N0L3RBP9VuJ4zhS3e8v6qFnTHm06TZD7%2B3bMRHBgb%2FT1nynr04IDS8uSvejF1PohRgzzEdedBzu7spgQ2AeBAb4Y8t5cOU4RzV3r5Hs%2BLZL4cv5IzApfhwVLtso5sxqOlZTU76RgP0wUEbSbZzAqCv3e0SbjFRFJdxdjoNRxDXu4e45XdKyLJosJo%2Fbj0bEgD1fMEj5DiH6kpXoUpt0XjSwWjRhM5xkrL0j4Xpj%2Fjjrhzj0k338AWxHWF7MCcpHz3z0XVprjWeREnpRGeJI5J3QJWmlEk%2FFVKtsaXL5KnrdKGG7d0v%2BngQwROQ00GFJaQkf%2Fof%2BRCy28u7SQHjx1PEPXtRKeJnmgLP%2BCyZ%2B%2BPkAetaHFR5R5SEpOkavBDHHj5h1hmKyUPkT9KkXos3q1Stw%2FCkk%2FpINUEbVWfjQXRdHb7XitvIendY4pQ%2BHeZTxWLg2SXxXRQZEVfae0qoMtNBbqfHVcHHosqP2g1YJktMQFRojrWMtPIsIxp%2FwaMVZuauh7ILQxuclrkKFlszb5TLzqd17iw4%2B%2Fx5kow78AYFvBGksXjJbvrctYwrq6Zb559ZxGzNh1Wf5PJ3%2F9r3LkqmdrI7e8cKxq949%2BhVLcr0yhH33509L1vJwHQ9BcIi2dpyhp977T8rtZOQ2VsT6mr%2BPioKD2I2ekpaQBjTX0PBsqpniYMXnQM50%2F8u3ucKpThQVpIvkzpUM%2FA%2Fu9jOMno%2BX3wcaN%2FJdc7v6886z2Q3e%2Bmh8zpjjQfc%2BEYZiC06Kpk9xeRPhX1xmGYRg2VgzDMAzDxophGIZhY8UwDMMwbKwYhmEYho0VwzAMw8aKYRiGYdhYMQzDMC86JvtScM7fl2JYTix%2FhvXD5Ie5KS564zY%2Boq2aA6aVVsHS52M5sfwZ1g%2FrsXDgNCDDMAzDMAzDMMyz8n9uqXH4%2FMp%2BvQAAAABJRU5ErkJggg%3D%3D)
+
+```
+load_stmt
+ ::= LOAD load_opt load_data load_target
+```
+
+referenced by:
+
+* basic_stmt
+
+**load_opt:**
+
+![load_opt](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANUAAAB9CAYAAAA1DyYAAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAEgdJREFUeNrtnQdYVMf6xt9lQTpYKGJQUBEFK6BgiYagKKKiqCTYIhdbVNBEY7wa9apRE3M16t%2BuN0SNLRd7j8ZuRDRWFAELYFdsiCgCu%2FufGWADXspCWBaW7%2Fc8y9nTZmfPvO%2F5vplzlgMQBFGqSLThS7g5QVFZGuz8de1oM21GV1u%2ByJ8nw7S%2BsVq2DybFVgB06BBUvKhcmSIzmYogCDIVQZCpCIJMRRBkKoIgyFQEQaYiCDIVQRCqIe6o8GgC68ireFzQRkWtryjEJz7GhKlrlfMzJgeicaM6%2BObb9Yi98UAsq17NBI4OtdC7R2vUs6%2Bp3HZD%2BHFs3x35P2XOmTZQbD9o%2BELI5DKsXDgKpiaGYt2xU1dxOjIGwQM7ImTC6gLrlVMPQrP8XZ3n7C9MlSHDAzcnbNWVIjS%2FQotaX1GwtamBWVMGoKPfVOz5dQoc6tmI5VHRifBwc4RXh6Z49jwFh49fQRf%2FGZg3Owg9fT3ENnfuJkG%2Fii5ChvvmKdOmZjUxPXfhBj6oVR0rf%2F4NX4X2EsuePn2F67H3ULWqMcaH%2BIllmZlyBAbPw5J5w1HTqqpYVruWBSm6HFBSnbs7wV8mwf9lylCDzRoJU0my0sAAmQz%2BrNDt7xda1PqKgh4zBRd%2Bjhn0q%2Bgp13GDtXFvJN5392mFHl3dMXzMUrRyaYBaNln7WFqaK7fJjwlj%2FPHFpJ8QNMALFtXNlMsN9Kso98tIzxRT1%2Bb1YFfbipRcjiiuznPMJFPANveNY3luqFVkzRdYaFHrtQketZwa1cbe3%2F7EsKDOYllSUjIizsbk2a6Js50y3WvkaIsuXi5YvGIvS%2Bn6kUorKEXpvCAz5Wuqggot7odqC%2Fa1LXHvwTPlfHTMXcxfsut%2F%2BlSmDobK%2BfEs9fPuOQ3DBncmdWqbuSTYz%2FKMmQWZqVBT5SAHLrF46KMoYn1mJuLZhxpq20F9mZyK%2BnVtlPMftW%2BChd8NKXSfOrYWCPBvx8y3A%2B08nNRWN7pTvezgOmepYbdMBfqyqbyoA69bQG55mu14n007sQL%2Fw6ZfFrZeTxdzcyJVACBNcISdTAfObEMvtk0%2Ftu1VXQVGs8wprqII7MHD5yzVi8Wk8X2Lve%2FYkT3Q3mcSLGqYqa2h6ceKxYN1aR0zJVjKDloTJpZNTDFHpHJE28chMRyQ5aej3Dpn05UGeghLy0AwCyRDFRIkg0esokyVU4giq5BIPSmcuFnYh31Z2PrcZYgKxuE2e8tfexwcMMlcDxNYDnrGxRkBF6NxuDwf%2FJSUt4g4F4sZ32%2FGwEBPODesXewyLJmZggd2wuo1B9G6VUNStIZhuuvIUrZwpt8fkzPQ%2FeZNvMtZd66QoFKAzsd5NMHcDBkmFmSu3KYKL8wsKqzPl%2BwvMMu1kUgVw9kZo7W6IlZRxN64j0EjFor3PQJnY%2BWCkXBtUT%2FrSE0OEy8jQ300dPwAoSO6IbBP%2B7wHYPsf4pWb3Zu%2FUZaRm5HBPli3%2BSgpuhxEKG4ohQKfXYjBHhV2KVLn2csKNJckO%2By9YYWsYIXMza%2BQotYXI02bwiYdWOpSqr14HrYr28%2FpKf1TWRsH2eQEO16zVNi2RDrnF325uViDfM4%2BJ%2Bs6la4UdQsrpKj1qmL6FvNSDDHapTGaX7yGy9TkhFrTPqYzyNGU6c5Ple1LqvPckYvP6%2BRaWNROf5tjCUhj59eNOnL0oSYn1I3QGdOb0J3q5igxOfuX%2FQ21ChxhIbYNNTmhfqkxnTG9lbmZy%2FoDWafxGss9HanJCXXDdcb1pvWmMnwtQqQlNTlRBlhm6027TRVxT%2BS3BtTeRBlgkK037TZVVqpLw8FEWWWAZX87F%2F3ylyDIVARBpiIIMhVBECVHax6lQ4%2BZIShSlSL85lK6wZQgUxEEpX8VI2JRkxIUqQiCTEUQBJmKIMhUBEGmIgiCTEUQZCqCIFMRRGVEKy7%2B0v8V1x604QK%2B1txRURn%2Bmaa2oy03RVP6R5S7rKOiZx5kKoIgUxEEmYogyFRlBP1Mg9BKfWnMVG1s6R9qEtqpL42Z6q0JrKnpCW3Ul8ZMJZWgMTU9oY360lyfSgIvanpCG%2FWlOVMp0N%2FTvuzz3n5D5uPKtQSVtuXP9017l14uNfMkKRkHfr9A5skHoSumr8pnKiAqxRBflfWH9vFrA2vLqkV7XqHAF5N%2BwqtXb8ulcOJu3sfchdvIQfmQrasoTX2%2Bxu79kyoQIpPgDH9qvYpPDS8Vnj1PgUSSNdr62%2BGLMDUxFE%2BtP3IiCnZ1LDEhtBfMzY0RvuO02GZF2AGYGBvAx9sVzg1rF1n%2B%2FkMXcOjoJWRkZMKjVUME9GoL%2FSp6OB0Zg43hJ%2FA6NQ2dPJthwCcfiXokJ6di7aaj6OzlgtVrDyLpaTIGBXrC%2B%2BMWWQJJeYtVbDmvY1UzY3Ro54xuXVoifOdpPHuWgh%2BX7BTbDQvqLL5LYbxLz0DYL4cRcTYG5mZGCOrfEW4u9ZF4Lwlb2fcdNpiVYZpVBo%2BCcrkCvp3dsGvfWVhamuPchRuIPBeHFs3qInRENxjoV8HjJy%2Bxc28k%2BvZqJ6YyuRxDP%2FPWmKGYnrqzyTimr9ZMX7GVKlKxdo2TSxDAdLWOP7XewQH6ZfG53CSPnrxQmip49GI8ePQcfl1bIepaIr7993%2FFOksLMzGtZVMdtT%2BwgLFR0dVb%2FtMBzJm%2FBV4dmqKjZ3PsP3geCYlPcPJ0NEaNW8GWNcPg%2Fh9j87ZT%2BH7BVrHPy1ep%2BGHRdkye8QtcmtdDK9cGGDZ2Ge4%2FeCbWjxq%2FAg8ePsc%2FBngJMXPTivrVMIOunlTUjb90daVF1m9oyFLcvP0QIcO7wbN9UwSNWoT4xMews7VEdOxdjP8m66bkS1fiMXnmejRrbC%2Fmd%2B0%2Fi%2BFjluLduwz4%2Bbrj0JHLmP7dZrHu4eMXov4Bg%2BfiZvxDYXRNwPXDdcT1xHXF9VXpIhXnYjQOuzdC60wJlprrYbSrEzbxZ7RK5Yi2j0NiOCBTdx0%2BD%2FbBF6N6iPf8LM0FIvLyD5uIqV9Xd1ixs3RRZGbKsWjFbmxcPQ6uLeqLZb26eYiz%2FSxm1NFMyP7dW4vltrUs0LXPDIxnUZFTRU8XW9dPVEbQHXvPsH5fIj6oVQNXr9%2FBTP8P0YYdKP7qH9BBWb%2FDx68gwL%2BdSt%2FzUlQ8bsU%2FwtoVY6GjI4G7WwOcOReLfcz4o4f5YsGcIejadyYWLd%2BNX7f9gcU%2FDIPtBzWU%2B48P6YWgAVl9f4e6Nug%2FdD7mTBsk5vUN9LB9%2FSSYsehXVgSwZCfBEXYyHTjzQQl25PopgKu6LEKdv645Q2ncVDkRi028XRqjuY4Cvdn7MXIpGtx2gp1bGVwV15H%2B9RE8JcrIKJmPH7Pox1O1nLO7snwm4Fvxj0VqlUOD%2BjZIZ%2BnhQxYhxUAVM1OOoThmpkaQybLqwY03bnKYMLtri3oIHtgJzZvYF7t%2BN24%2BEKlaW%2B%2BJeZbXsbVUnlCWL%2FgcPr1nsEjmi3atnfIOpuVqiXr21iKNTU3NekghTwNL21BF3al%2BO%2BthbomsWjeYSiJYdPK5eA2Xy0Ofrtz8nir7gFxWRwOUBbzfxY3xMiUVFtXN8qwzNTFAyuu%2FBjy4IGUyOYzZPjnCLIiBrO%2FFB1d4arrv0Hl8GvRvXDy1QDmYoir8s%2BrXrYmDO6YXuM1W1k9r6mzH%2BkZnMTK4K6pWNc53uxfJr4WRjIzUl7FX5B8r0g21BcANws%2B%2BvA%2BiCnxwo6WLA5at3q9cFnk%2BTkQHr4%2BaYdOWkyJF5Pyy%2BZiINu%2BbL1%2Bh74oQ6SFP10YN6YrUN2l4l5Yh6vaIlZ365p1K9Wvn0Qh37iex1DJSuSzx7hNcvpog3u%2FcF4ljp65i24Z%2FiigV%2BvUqkbrmkJzyRkz5yWAp%2B45dOrpAKiX5lOtIVR4ZEdQFQSMXoVo1E0wI9UffXm0L3X7R3CEYMXY5XD78ElJdHRga6CN87QSM%2Bbw7W74M7bpMhLmpsTDGmuVjVarD2k1HMHX2RjjWr4X4hMeY9vWnIoJwUzVvUhceHSdAKtHBgW3%2Fgk3NaoWa%2FudlYzB%2BUhhmzv1VGJUPPCz4fogYWZzy7QZW14kwMtTHrKkD4Jvdv%2FpytJ%2FYf8N%2Fj2PtxqN4m5YuRkFXLRpFAinohKyJD%2BXpWmmGd16eun5O%2F%2FJlKtIzM2FlYa7yPk%2BeJouzeI1qpnmWJz17hTQmSj5aVxxevHiN18yIfESSp115%2B3IvhRFyhsJV4dHjF6wvqaPydxoaugTt2ziLQRGeuhbnWBSH3D%2BnLw19lLbOKFKVEjn9ioNHLmHVmoMFbjdt4ifKQYqCRMeHwUsCj5T8lR%2FWVlkXsucv2YmIswVfltmy7mvl%2B5rW1UpUD25e%2FiLIVKVCZ68W4lVeGR%2FSU21l8xFHVS4rEGQqQkXaejSig1AMaPiGIMhUBEGmIggyFUEQZCqCIFMRBJmKIAgyFUFoAq25%2BKstj2EhKFKVC%2FhNk9rwsDCCTEUQhDanfzkRi5qUoEhFEGQqgiDIVARBpiIIMhVBEGQqgiBTEQSZiiAqI1px8bc8%2FNvnsoYudJOp1I66%2FplmeYRuHqb0j1BTdK6MEZpMRRBkKoIgyFQEQaYS8L4AjV4R6kSSrbNKY6q0NrYwoHYn1EW2vtIqk6mS3prAmpqeUBfZ%2BkqqNKZiMTlOKkFjanpCXXB9cZ1VGlOxZDeC%2FfGipifUKDIvobPKYiq5DraycNXf0157%2B1XnL97CtZg7JG4NIHTF9CV0VllMdfEaLrNJVIohvtLWhg3f%2BQf2H7pACtcA2bqKytZZmaOxe%2F%2BkCoTIJDjj2giXLsRgT1l9bnpGJsJ%2B%2BR2nI2NgZmqEwf0%2FRivXBmLdr9tOiafAHzkZhUtXbqND28YYPMALa9YfxsmI67CrY4mJX%2FSGqYkhUt%2B8w8qwA%2BjSyQU%2FrfsdL16%2BxqBAT3h1aCae9n7laoJ4Pu6PS3bCpmZ11LW3Fg%2Bw7tXNQ1kXXoeXyanw7exGTiglmJ66s8k4pq%2FWmqqDxi7%2Bno1BnFyCAIkE69ycMMXBAWXyhOYRY5chhok%2BZHg3dPRshuDRi3Hj1kOxbvPWk2JeV6oDH29XLF65Fx91nYw795%2FCr2srkdLxB1ZzUt%2BkiffTZm1E8yb2cG1eH8NCl%2BHq9TswMtKHsbEBzMyMxJPora3MUZW9%2F3rqGqSkvFXWZdqcTXTzXinB9cN1xPXEdcX1pam6aPQu9YvROOzeCK0zJVhqrofRrk7gKjsilSPaPg6J4YCsND%2BP93GiY%2B8i4tAP0NHh1wYbIPLPOOw7%2BCfGjuwhtpk%2BORA9fbOiyZWoBBgyg0z%2FZ6CY5wbYtOVE3jRv3cTssoCb8Q%2BxY88ZTJnwCerXrQmLGmYI8G%2Bn3Laps51IC%2FmDqSPPx%2BFVyhv4dHQhR5SAAJbsJDjCTqYD5%2BxBiX6sfa7qsgh1%2FrrmDKVxU%2BVELDbxdmmM5joK9Gbvx8ilaHDbCXZupXzXReyNB0hKeoW23hPzLA%2Fs0%2F6vtFTnr%2BBtwtI8mVyunOdpX0ZmwT6vZ2etjHr5Mbi%2FFxYs2yVMtWbDEXwW%2BDGk0r%2BXLFTWO9VvZ53jEplAbjCVRLDo5KOpPlS5M9V7gxeX1SksUxMD2NtZ4cjub1UqVyIpfP59nr94jerVTJTzCkXeavl6u%2BFf323Cjr2ROHoiCrOnDvzbx41%2BrFj%2BqFQ31LZu2RCPnrzElp2nlcvu3HuKi5dvl7jMV6%2FeKMvZyczi26WlmDdnfahb8Y%2FynsH0pBj4qSe%2B%2BuZnMTiR24CE9qBbmb6sqakhfl4WinGTwjB7XjgM9PXw9m065s8p%2BS9p%2FfrNRnp6phj9GxfSkxnXUSzv27Md%2Bg6aC3evCahnb43NYVlXDz5hfSw%2BIhg8qBOpj0ylHXi4OeKPg9%2FjMYtYEpbPWVmaK9dt3zApz7Z8wCE3Pp1cxSs3x%2FbOxtPnr2BibCCG0HNoUN8G54%2FPx8MnL2BjVU25%2FMzZWLi7NUATpzqkPjKVdmFtVbXUyrKyMM%2F%2F4LJ0jw%2Bp52bVmoMIHdGNlEd9KuJ9zFgqufC7IcrhdFXgF4yHB3Vm%2FamWdAApUhHvY6BfJc81KFUwNtIv9j4ERSqCIFPRISAIMhVBkKkIgkxFEASZiiDIVARBpiIIQhW05uIvPV6GKC9IteFLPHyKGfxVyxLTK1sD8u9NMqb0jyAIgiBU5%2F8BExVPjF8CsmIAAAAASUVORK5CYII%3D)
+
+```
+load_opt ::= IDENT
+ | int_const_expr
+ | empty
+```
+
+referenced by:
+
+* load_stmt
+
+**load_data:**
+
+![load_data](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAX8AAAD1CAYAAAC4GPVtAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAIABJREFUeNrt3QdcE2cDBvAnDAEBcYAbwQ24CjhwK%2B49qXvUvWet1dpha9vPVuuoWke11Wq14qzaWltXHbi3qKgobsWFoKiQ5HvfF4hQUUCBAHn%2B%2FmLI3eVyubs877jLBSAiIpOjyQpvwtsdem7KrOHwmayxTxJldBZZ5Y0c2rWIWzOTq1izF1cCUTox4yqgjNaKY0uOiOFPREQMfyIiYvgTERHDn4iIGP5ERMTwJyIihj8REcOfiIhMLvyrlEW%2B102U1PjMpFPvqThx%2BnKypvVfuwdPnz3PkO%2FjTmgYNv9zhHswkYl52zyOe74K%2Fygtbni7Y%2BWrZprU%2BMykXcuqyOeUM8np9Ho9RoxbiEePIjPk%2Bwi6cB2Tp6%2FhJ4HIxLxpHld2RxtvD1yN1uKSfKyu7aOJKQT8tFox0h1rLcwxdP8p3I57UlLjM5N798Oh0cRcO%2ByvrUdhb2eDc%2BevY9u%2FJ%2BFSxAljhraGg4Mt%2FNftVdPMXbQZdrbWaNzACx6lnZOc%2F59%2FH8Hf248hKioaVSqVhl%2FrarDKZom9%2B8%2FiV%2F9%2FEfH4KerXKY8u79ZWyxEW9hiLl29HQ19PLFi8BaF3w9CtYx00qPuOml94eCTmi%2BFyGXPmsEWt6h5o1qgi%2FNfvxb174fhu1no1Xd%2BeDdV7eZ1nz6Ow6JetCDhwFg45sqNn53rw9iyOkGuhWC3eb98eYh72MfOQrQqdTo%2BmDb3x%2Bx8H4OTkgINHzmP%2FwSC8U74ohvZvBmurbLh95yHWb9qP9q2rq3utToc%2B3RvwE0qURlKaxzL0tRrM1OpROP6FUxL0%2BetjCgM502uJlSxJjc8MZJjfuvPAEP69Bn%2BPG7fuo2WTSjh5OgRffLtSjXNyzKHuCxbIDedCjrDNbpXkvH9YuBlfTV0F31rlUK9OBfy55TAuh9zBrr2BGDRqrhhWHj0618WKNbvxv2mr1XMePnqMb2asxfiJv8CzQjFU8iqJvsPn4PqNe2r8oNFzcePmfbzXxVeFrixc1PLlyQELS3O1bPJmIfaApPQZMhsXgm9iSL9mqFOzHHoOmoFLIbfhUtgJgeeuYvRHMRfHO3biEsZ%2FvhTly7iqx7%2F%2FeQD9hs3Gs2dRaNm0Mv7edhyffb1Cjbt5%2B4Fafr8ek3Hh0k1VIBFR2ksqj%2BNq%2BlpgDWTw%2F4dFEjNVJUtS4zNzS2BAr8YYMaiF%2BlvWemWQSXVqlFX3LZtURl5R601KdLQOM%2BZuwK8LRsHrneJqWOtmVVTteZIoUAaLwG3T3EcNL1zQEU3aTcRo0cqQsllaYPXSsYYWybpN%2B3BCFESFCubBqTNX8HmbGqha2U3dOvvVMizf1p0n4NemerLe57GTl3Dx0i0snjscZmYaVPYuiX0Hz%2BEPUUAN7tsU077qjSbtP8eMHzbgtzV78P03fVG4UB7D80cPaY2eogCSShQtgM59puKrT7qpx1bWlli7dBxyiNYEERmtEIjJYw3%2BjAY%2B%2F29NP1nhH0cnMkM0DRrrkxgfHY1L4kVtMuOKMzN%2Fcfl42RUSFaV9o%2FncFq0J2UUTV1s2zF8E7cVLt1WXSpySxQvgeVQ0booWh2rGidCPC34ph312aLUxyyELiFHjF6lCyeudYujVtT4qlHVN8fKdv3BDddFUazA2wfAiotYfV%2FD9MG0AGredKFoGTVHdxz1hUzPeVfaLueZT3VePxU2S3T%2BpHfy8sidRysg8Fh%2FTZtF6tBf3uqQ%2BQBav6FPaK554XdzXFzP8UdyPfN14UXGdHFfz9wPML5eCi9YMHmJCXzFNJzHtKQs9Bh84i6C0eNMZISjkcQEZ4A%2FDH8Mxd44E4%2BztrBEe8eLAsQxOrVYHW%2FGcuAB9la7v1lYHqWWX1B9%2FH0aHnt%2Fi6O5pMSW%2BPvlvW75W8aL5sWXdZ6%2BcZvX6vSjn4YL1mw5gYK8myJnTNtHpHoRFqMDPnoyusDfFH3UhUyQa96WiNZgtdv6y4tO9XCTbNnMdAl2DEOIPaBPLu%2Fh5LO7niYb4oqdR6CUq5n30GoQl1uWjKqb%2FnYm48xczcBe3axbmcD9yBqOSGh%2B%2Fy0cu4MEgBB85i41yXFgUXMXzdmo12OfpgXqZZSPIIJe1WdlHnhzyIHFFzxKYs%2BBPw7D9h4NUbdu3dnksX7VLdQ1Jv6zYoWrv%2Fy0kEg3k3wNUt5DsphnUuwkeP3mKZ2LLymW7Jeb9%2BMmzZC1f9SpuuHI9FOs27TcMC7l6B8dPXVZ%2Fr%2F9jP3bsPoU1yz5Utf6hH8xXXVZxwsKfqHtZaM0W77FRPU%2BYm%2FNrIkSpReajzEmZlzI3ZX7KHJV5Ghf8ycnrvSdwSt6bm6OkqB%2F6i%2BnCxcTXXlfzlzORJcd%2BSzGTRPrwkxqfqAsXINNpkpeb6iLyFyWbT1q1AFJb%2F56N0HPgDOTKZYcxQ9ugfetqr51%2BxuTe6D%2F8B3jWGAlzCzPYWFvBf%2FEYDBvQXAyfg%2BqNxsLB3lYF%2BM8%2FDE%2FWMixevg0ff%2FkrShUviEuXb%2BOTDzqoGrkM%2Fwpli6JKvTEw15hh85pPUSB%2FrtcWTj%2FNGYbR4xbh88m%2FqQJFHsCd9r%2Fe6kyiCV8sE8s6FtltrDDp4y5oGtv%2FP3JwS%2FX8ZSt3YvGv2xH59Lk662n%2BjEH8tBKlYo1fK4JahHV3GfjJeEqSeRw7bFSVspgcpcXY%2F7YENLHNiCdiJnPFTCYnNpOkxqege2aCuKslmvQNU7vbJ61%2BxvHhw8d4Hh2NvI4OyX7OnbthqlacJ5d9guGh9x7hqQhPeXZOSjx4EIEIUWDIM5Bkd0t8smUhAzvuFM3kuHX7AczE8iX3PfUZOgs1q3qog8uyyyol6yIl4v%2BMI7t9yJSIDNsi7v4V%2B%2F2kZEz7RnkszwaShYD4YA0Qr5Nd1fxFc6Ho62aS1Pjkso%2FElHAbDPYsgwpHT%2BN4Ztgocf3eW7Ydw%2Fyft7xyuk%2FGvms42PuqcJSnZ74J2fKQt8TkyxvzhbWps9Yj4MC5V85j1ZIPDH%2Fnz5frjZZDFjLyRkSp2N0j8hA6lBP52DI5079pHsdvCRi6fZKaUWqdxrnjMp56e%2BBXMx3aiYfHM9MGauj7jrplVKOHtEqzecszjJJzuisRpZzKQw1%2BlfmYghB%2FY3HPT%2F8jdnpsE02WqtzkmUe1Km4oUawAVwRRmkSiyEORi%2Ble6KT3C2r1OK0BSnGTExGpA6%2FyYO%2FpLB%2F%2BNhGqyeHETU5EpDjF5mLWDv%2BAa6pfy5rbm4hIsY7Nxawd%2FlBdXDyNj4goliY2F7N8%2BBMRkZEx%2FImIGP5ERMTwJyKiLMkiq7yR%2BNeFISIiE6j5y4uA8UJgREQmFv5ERJQyFlnpzbD2T0TEmj8RETH8iYiI4U9ExPAnIiKGPxERMfyJiIjhT0REDH8iIspsssSXvLzd0%2F%2BHEMi4%2BIU%2BIoa%2FcmjXIm5NE8GL%2BBG9PXb7UKZt7bHFR8TwJyIihj8RETH8iYgow4Q%2Fz9YgIlNntBw0WvhXLQxrbnciMmXGzEGjhX%2BkHfJx0xORKTNmDhot%2FM01KMNNT0SmzJg5aLw%2Bfw18uemJyKQZMQeN9w1fPTrXccVHOy7jaXq%2B7P0HEfhu9nrs2XcGkZHPUbhgHvhULo2BvZvg88m%2F4eKlW4k%2Br2HdCqhVvSwmTFpmGFa8aH6827o6vD2Lq8enz17Bp1%2BtMIyfMqknXIvkxYhxC3Ht%2Bj3MnNwHBQvkVuNOBobg52XbMPXL9wzTnzt%2FHfN%2B%2BgtHjl%2BEVqtHkcKOqFbFDZ3b10KuXHZJvrf3Bs3E2BFt4VaqcILhPyzcjK07T6i%2FnQvlQetmPvh%2B%2FqZXzmfFwtH46IuluHj5doLhNtbZ8Mv8ETh%2F8SbGTfzlxXpwzYf2rauhklfJl%2BYl3%2Fv9%2B%2BH4ac4wmJu%2FqGt8N2u9eH9O6nlEpkjkn3W4yEHTC3%2BRf%2BE2eF%2FcT0q38kavR4ee36Jk8YL4%2Ftt%2ByGGfHcdPXsLSlTvRqul9dHm3Fh4%2FjimLpsxch2Ii3Nu28FGP8%2BXNiXsixE6J0P5pzlA8f67FvkPn0K7HZGz8bQLKuhdBiWIFMG5kO7Ts9CW2b5yEQvljgl6%2BhpmZBlNF4MWF%2FaNHT3D81GXDsm3fdRIDR87F0P7NMLhvU1haWuDYiWAsWb4d9nY26N6pbpLv7%2BDRC3gUHvnS8I5ta4hCL1wVTh%2BK5TMTITx6SMvYAuuqKAx%2Fx8LvB79oilqY4cTpENSpWRa1qnm8GG5uru4jIiLVe1oybziiorTYfzgIfmK9rv91PCqUdTVMfyH4Jv7efgzZbaywKyAQdWqUfVHQXbgh1gnPNCbTFZt%2FJ8Utv0mFv7keQ7Qa7PNyw7EjZ7ExPV7z2o17CDx3FcsWjkJeRwc1TNauWzSphOhoHSwsXoRR7tz2cBbjqlZ2MwyT4S%2BDMW5Y7RplsGf%2FGezaG6jC3yqbJQrkz6XGFRItCstsL1bvsAHNMfaTJaKF0VgVEvFFiwB9f8LPmPDBu%2Bj6bm3DcLlsLZtWVq2VtyFbDQ45bEXN3UoVYpJTnhyG8dkszBO8zziykExseExB8GI91KpeBgH7z%2BHfPacThP%2Fq9QFo3rAiHBxsxd97E4Q%2FkSkTuddc3I0SOegjcvCcMZbBaFWvA2cRpNPAT6PBEm93TChRAlZp%2FZoy%2BGQQzpy7ESFX7yQsBS1SvipkaN8NfYQizk5JTisLmx6d6%2BKb6WteGnf0ZDAePnyMDq2rJ%2Frc3Mno8kkL5y%2FeQIDYUHG3A4fPJ74eRMEZek%2BuB8cEraw1GwPQtlVV1Xra%2FM9RPH7yjJ96Mmky52TeydyT%2BSdz0BS7fXA0EFtF5dEnWoPZDpYY7OWO5dBjm7kOga5BCPEHtKn5etksLbBo1lB8%2BtVy%2FLR0K%2BztbeBVoRje61IPDeq%2Bk6x5PI2MUv3V0r5DQXB3c0YjX89kPXdwn6ao2nAsjp28lGD47TsPkdcph6GlEPU8Gus27TeM9xTL%2BN%2FWQnr48%2B%2FDOHjkguFxXJ%2B%2F9OzZi%2FVw4Mh5FHPNh2YNKhqm3XfwHDTiX2WvktCIPd2lSF788dch%2BLWpzgQgk%2BEnGsmXS8FFawYPeXBXA3TSA6csRI3%2F8BnjBb%2FRwz%2BuBSDuGniWQQUzPdrKHhKdOUoGu8PFOw2%2B%2FVbZuyT%2BXP2JqmmfOhOi%2BqJ7D5mFX38chRpVPZI9n6vX7%2BLMuavYuuGLZLcacuTIjkG9m%2BB%2F01ZjaL9mhuF2djZ4EPZY1ZZlUEbrdNgrVoy0c89pDB%2FQ3CjhP2xAC8Mxj1e5fvO%2BOni9df3nsLA0NwxftT5AdZutWrdXPS6YPxdW%2FR6Q6uHPK3tSRhYMtX%2BGiCA7L9IsQNT2Gx89jeMZYdkyzPX8Y1fI8fQKgJw5bVXYy9uR48E4ciI4WeFvbWOJUUNaqb9HjV%2BEngNmYPXSD1WtODl6dauPhb%2F8owodQ82%2BXFE8exqljh3I%2FnM5r2lf91bjOvWemiF3aiurF%2BvBwtwMPcR6WLNsHGyzW%2BHps%2BfYtOUQ6teuYCjE5DGUtRsCcPPWA8NxkdTAH3UhejMmdbqF7G4Z%2F%2FlSVWuPI8%2BAkWe8VPIskeL5Tf6suzqTZfDoedDpklf%2ByGAfOaglFi75xzBMHhDt36sRRorC5NDRF90sMkQjHj%2FN8Ov1y4%2B7qvcwcOQP0Gp12LL1GJwLOmLWlH6qEJO36eJWyasU1m7cx08dEWv%2B6St%2F3py4JoK%2FZpPxyJPLXp2xEhn5DONHtXvlWS2vI%2FvoF8wcjOYdJuHzb35Dy8aV0F8EoOTbYgJ%2BmTcSpUoUfOl5ndrVxNxFmxMM%2B2B4W3VGTp8hs1TXj6xZPwx7LJartOqqSq42Xb5O8LhbxzrqVNFl%2Fv%2Fi%2BbModO4zFb%2F%2BODpZ8xo6Zr66xbGztca5w3Ne3okszbFgxiCxHr7Ep18vx5WroWjdvMpL08lhPy39B4P6NFGPv525Vt3iFHPNj12bv%2BKnkigdGKXJLLtpUrO5LueXkp9xlAdUb4U%2BVH87F3LMcBvlxs370Op0yOvkoE4fpYTi%2F4wju30os0vtPGTNP4kae0YM%2FThx3wKO7zNRoz515mqi09vbWatv0BIRMfyzmM%2FGdeJKIKJUw%2B%2FXExEx%2FImIiOFPREQMfyIiYvgTERHDn4iIGP5ERMTwJyIihj8RERlRlvmGb%2FzrvRARkQnU%2FOVFkXiBLyIiEwt%2FIiJKmSx1YTfW%2FomIWPMnIiKGPxERMfyJiBj%2BRETE8CciIoY%2FEREx%2FImIiOFPRESZTZb4kpe3O%2FSmssH4RTYiYvjHc2jXoiy%2FsXjxOiJKLez2yYStHFNq6RARw5%2BIiBj%2BRETE8CciokwR%2FjxrhYhMndFy0GjhX7UwrLndiciUGTMHjRb%2BkXbIx01PRKbMmDlotPA316AMNz0RmTJj5qDx%2Bvw18OWmJyKTZsQcNN43fPXoXMcVH%2B24jKfp9ZKXQm5jzMeLDY8nju%2BIMm5F8NEXS3Hu%2FA01LHcuO5QqURBtW%2FigmGt%2Bw7TL%2FHdi7Yb9L83zq0%2B6qum79ZsOrU6LedMHwd7ORo3bsfsU9u4%2Fi15d62HImAWvXK645SAi0yHyzzpc5KDphT9wMtwG74v7Sen1goUL5MGkCV1Qr%2BXH2PjbBJQoViBmQQJDUMW7FHxrlcO9%2B%2BHYuvMEGrWZiClf9kSrplXUNFeuhsIqmwWG9GuaYJ4F8udS9wePnEehgrkx76e%2F8P7Q1mrY3buPcObcNeTMaYvRQ1qqYdHROnTsNQWzpvRD%2Frw51TDngo78JBCZmNj8Oylu%2BU0q%2FM31GKLVYJ%2BXG44dOYuN6fGaliK8ZUDHhbZVNkvDOFkQVK3spv5u3rgSWjSpjH7DZqOSZ0kULBDzHCcnB8M0iRkzrA1GjFuInl184Zg7h2G4tVU2w%2FOinkere68KxeDinJefACITJHKvubgbJXLQR%2BTgOWMsg9H6%2FA%2BcRZBOAz%2BNBku83TGhRAlYZaSNI1sB7m7O2PTXIcOw0NAwBIgFj38Lj4g0jHcrVRiNfD3x%2FdxN3LuJ6CUy52TeydyT%2BSdz0FjLYtSreh4NxFZRIfaJ1mC2gyUGe7ljOfTYZq5DoGsQQvwBrTGXz9XZCddu3DM8Djx7FVNn%2FZ5gGtnnb1%2FCxvB49NDWaNDqE%2FTt0ZB7OpGJ8wPML5eCi9YMHvLgrgbopAdOWYga%2F%2BEzxgt%2Bo4d%2FXAtA3DXwLIMKZnq0FX8P05mjZLA7XLyN%2FC3gh2GPUbxoAcPj2jXLYvrXvV%2F7nCKFHeHXprooJNahehX3NFs2XtmTKOMLhvqchoggOy%2FSLEDU9hsfPY3jGWHZMsz1%2FGNXyButlLQIwhs37yPgwDmMG90%2Bxc8dPrAFajYeB8c8OdJsffFHXYjobfDCbv8RHh6JLduOwa%2FHN%2BjasQ48SjuneB5OIvR7da2Pn5dt4wologzJwpTe7Lnz19Gt%2F3T1d4uOX2LetIHweqe4ejxq%2FCJ1y25jhdKlCmFo%2F2bo2K5mguf7r92jbvFtWPGRYR7xDezVGEtWbOceRkQZklG6DmQ3TWp2W8j5mdrPOLLbhyhrSO08TC52%2BxARmSCGPxERw5%2BIiBj%2BRETE8CciIoY%2FEREx%2FImIiOFPREQMfyIiYvgTERHDn4iI0lOWubBb%2FOveEBGRCdT85UWReKEzIiITC38iIkqZLHU9f9b%2BiYhY8yciIoY%2FEREx%2FImIGP5ERMTwJyIihj8RETH8iYiI4U9ERJlNlviSl7c79NyU6YtfqCNi%2BGcIh3Yt4tZMJ7yIHlHmx24feuPWFltcRAx%2FIiJi%2BBMREcOfiIgY%2FrF4tggRmTqj5aDRwr9qYVhzuxORKTNmDhot%2FCPtkI%2BbnohMmTFz0Gjhb65BGW56IjJlxsxB4%2FX5a%2BDLTf%2FmQu89wuMnz7giiDIzI%2Bag8cJfj851XDN3v78M4D%2B2HE4wbMHPWzDjhw1p%2Ftojxv6ITX8dUn%2F7r92Dz%2F63IsnnbBLLeu9BOD9wRBmAyj%2BRg6YX%2FsDJcBu8n5k3XvDlW5j0rX%2BCYV4ViqNKpdLpuhwe7s6oU6NsktN9Mfk3XLp8m586ogwgNv9OGuv1jXZtH3M9hmg12OflhmNHzmJjer3u8VOXsXzVv7j%2FIAKFC%2BZBZ79aKFGsgKFmvH7TfkRFRaNpA2%2F4talueN7%2Bw0FYu2EfwsMjUdbDBZ3a1VQ17rDwx%2Fhu1no1Te9u9fH02XM8ex5teF7QhRtYuORvXL95H5W9S6Jvz4awsc6mxs2ctxEN63rit7W7cTboGhrX80SPzilvBT5%2FFo2IiEjDY9ka2fzPEWi1OpQsXhA9xTzl8oeFP8GK1bvw757TqFq5tLi58RNIZAQi95qLu1EiB31EDp4zqZr%2FgbMI0mngp9Fgibc7JpQoAau0fs3rN%2B6hU%2B%2Bp8Ba1844ivB1yZMe%2Fe0%2BrcQsW%2F405C%2F5Atw51RFjWww%2BLNotCYpca99fWo%2Bg%2FbA7eKVcUzRtXwplzVxFw8BycHB1gYWYO50KO6mZuYY7dAWew7d8T6nkh10LRrtv%2FUKpkIQzo1QinAkPQT8wnzvdzN2HAyDmqEJLB%2F%2FW01dix%2B1SK39fRk8H4%2Fc%2BDhuD%2Fcoo%2FWjSppG6h98Jw5vw15M5lBwtzM%2BR1yqmWNYd470SUvmTOybyTuSfzT%2BagydX8VWgFYquofPpEazDbwRKDvdyxHHpsM9ch0DUIIf6ANjVf70LwLVhls0AjEbQy%2FHxrlVPDdTo9ZszdgE0rJ8DFOa8aNjK8JZau3IlO7Wti%2BpwNGP%2B%2BH96NbQk0aeClnpM7t51oKRxI0EKIb%2BmKHWjo66laBFJFrxKoUG0Ezp2%2FjtKiQJAWzhqK4kXzq78PHrmAo8eDk9WF8yqnz15BMdd8qFuzPCwszNC4vpdhnG12a%2FWeK3qW4KeQKB34AeaXS8FFawYPeXBXA3TSA6csRI3%2F8BnjBb%2FRwz%2BuBSDuGniWQQUzPdqKv4fpzFEy2B0u3qn87beqVUqjfBlXvFNjJMp4FEGtah6iRt4YT548w4MHEejQc0qC6WWXiXT%2B4g3xPJeETSazpBftUshtVPYqaXhsbZUNRQo7IfjybUP4x5%2BPvb0NoqLfrrzr0LYm%2Fvz7CMpWHapaODL8u7xbO1nL%2ByZ4ZU%2BiVwuG%2BnyEiE%2FfeZFmAaK23%2FjoaRzPCMuWYa7nH7tC3milJDeAsllaYPHc4bh95yEOH7uounbk359%2B2BEa0Q7btOpj5Mll%2F9Lz7O1s8PDRk5eGa2TZpH%2F1S9vaWuNRvL54KVw8trdL%2FCQnuQxvq0hhR2zb8IUosG7iyPGLmDx9DaysLA2tFr0%2BdbM6qR91eU3NZ7Axm7xEqaGyG0rJnguxX5cV%2B3Wa9lykNpO6sNvJwBCcDbqOfHlzomlDbzTy9VQHfmW4V%2FdxxzfT1iA6WhcT0uGR2L4r5kB8vTrl1Smc0VHa2JbATdXvn8M%2BuzrdU06bmHq1yqtuofDYAkD254c%2FjoTXO8XT7D3KZZbLVLJ4AdEKqIGy7kXEe4w5vVMe47h46Va6rnP5ATgYhGB5UP%2FIGYwKi4Kr%2BKDslAf7PT1Qj%2FFBmZXcf%2BV%2BLPdnuV%2FL%2FVvu53J%2Fz%2BjBn6Fq%2FunhSeQz9B82TfX3yzNu5Jekfvx%2BsBo3c3IfDP1gAcpXH46cItQfPHqM%2Fj0boW7Ncvh4zLsYMmY%2BKtQcAQe77Hj6PAqLZg1FhXKu8KlUCj4NPoCluTnWrxif4PXkAVfZj1%2B9wYdwccmLa9fuYs6UAchuk3bHtkOuhGLgyLlwLZIXj0Sh5CxaAp3b11Lj%2BnRvgI%2B%2BWKqOYcgD3iMGtUj3bXDhAuQ30ybJs7xEzcNfHvNhC4AyY41fq4e%2FaEh3T8%2BzFVOTUa4oJ7tpUvM3YOX8UvIzjteu31N94AUL5H5p3MOHj1XtXJ6B899uGHlc4HlUtGo5xHcnNAzWVpavPIMmLOyx6v7J75QTltnSvryNeh6NW6EPkT271UvdWLIVEhHxFAXy53rj%2Bcf%2FGce32Y7yrAdxV0vMoyHjhDITse9uEXf%2Fin13UkbLQ9b8X6NwoTyvHJczp626JSZXLrtEh%2Bd1cnjt6zk42Kpbcq3duA%2FLVv77yvGTJ3Y3nCGUGFnAyNM5EyO7uOQtI7CPxJRwGwyWB%2FszykEwoiS7e8T%2BCh3Kif23ZWZ%2BHxbclBlPm%2BY%2B6pbV7biMp94e%2BNVMh3YAw58yB7W%2FavCr3H8z9fvgpiSj0mObHqjKFUGZZ5cV%2B6vYbzN9IcZNScak1eO0BijFNUGZhdxf5X7L8Cd6CzYRkFeac%2BKaoEzEKXa%2FZfgTvamAa6rflD%2FpSZmJdex%2By%2FAnegt6GPFHrInegCZ2v2X4ExERw5%2BIiBj%2BRETE8CciIqPLMt%2FwjX%2B9GTJtWfk3BlL7mlimsk8Y49o5DP903LD8YRGKk5IL%2FZlyBScrridWDJOH3T5EmaxVw0oO1xtr%2FmzaERGx5k9ERAx%2FIiJi%2BFMGxks8UGaRJS7twPCnjOJp1cK8uBtlfLH76dOs8F4Y%2FpQRhEbaIR9XA2V0sftpKMOfKBWINnSQuQZluCYoo5P7qdxfGf5EqUADBIj%2FfLkmKBPsrL5qf80C%2BAPuZHQ6M6w202FzHVd8lN4%2Fij1q%2FCJcuXY3wbCyHkXw2Ycd0XPgTEQ8jlmcPLntUb92efi1qZ5g2qALNzBz7kYcPnYBGo0ZqlQsiRGDW8KlcMyPk926%2FQBDxixA%2FTrlMaBXY8Pzbt56gKEfLEDdmmUxuG%2FTDL19LoXcxpiPFxseTxzfEWXciuCjL5bi3PkbaljuXHYoVaIg2rbwQTHX%2FIZpl%2FnvxNoN%2B1%2Ba51efdFXTd%2Bs3HVqdFvOmD4K9nY0at2P3Kezdfxa9utZT6%2B5V4pYjvYj90zpcj85if23M8CdKBUdP47i3O06G2%2BB98XBSer728VOX0KxhRVStXNowzMHBVt0fOHIeHwxrg9IlC%2BJC8C189d0q3LrzEEP7N1PjzwZdR%2BvOX6FXt%2FoYKQJfp9Nj2codaOb3Bf7w%2FwRFCjsi8ulzHD56AedFIdGhTQ22cGJZAAANE0lEQVTkEiEpLVi8BafPXoFzoTwZfvsULpAHkyZ0Qb2WH2PjbxNQolgBNfxkYAiqeJeCb61yuHc%2FHFt3nkCjNhMx5cueaNW0iprmytVQWGWzwJB%2BCQu4AvlzqfuDYh0XKpgb8376C%2B8Pba2G3b37CGfOXUPOnLYYPaSlGhYdrUPHXlMwa0o%2F5M%2BbUw1zLuiYrushdv88KfdXhj9RKjHXY4hWg31ebjh25Cw2pudrly5ZSIS%2FW6LjZCugomcJNf5BWAR27DppCP%2FJ01ejVbMq%2BGB4G8P0n43rpAqI72avx%2FSve6thVtaWaNG0EhYu%2FUcF3KNHT7BpyyG0ae6DyMhnGX7bWIrwlgEdF9pW2SwN42RBELfumjeuhBZNKqPfsNmo5FkSBQvEPMfJyeGV61caIwrYEeMWomcXXzjmzmEYbm2VzfC8qOfR6t6rQjG4OOdN93Ug9svmsqEo9lOfrPKZY58%2FZQgHziJIp4GfRoMlohUwoUQJWKXXa587fx0BYgHibs%2BeRyU6neyqcXaO6c6RtfxdewPRtuXLWSBDfeeuUwmG9X%2BvEX5ZvkN1Iy1evh3tW1WDnW3WO7tVtgLc3Zyx6a9DhmGhoWEJ1q%2B8hUdEGsa7lSqMRr6e%2BH7upgz3fuR%2BKPdHuV%2FK%2FVPup1llW7HmTxmn%2BycQW0VFzydag9kOlhjs5Y7l0GObuQ6BrkEI8Qe0afG6G0VQ7T1wzvB4znf9kdfRQf29YvUu%2FLvnNG7dfog9%2B89g%2BaL31fAIEV6ySyeuCyK%2B%2FPly4e79R9DrX3wXyLmQI%2BrULIsFP2%2BB%2F7q92LhyAuYu2pwlt6OrKCCv3bhneBx49iqmzvo9wTSyz9%2B%2BhI3h8WjRImrQ6hP07dHQqMvuJxqhl0vBRWsGj9iDu53EVjxlIWr8h89kneBn%2BFOGbAGIuwaeZVDBTI%2B24u9hOnOUDHaHi3cafQt49JBWaNao4ivHR2t1WLMhAN9%2F20%2F140s21tlgZqbBo%2FDIl6YPD38C2%2BzW0GgSLu6gPk3QsM2neK9LPXWA9G1k5CtUPgx7jOJFCxge1xaFXlwX2KvI9SoPpk%2BdtQ7Vq7in2bIltd6CY769GyK23HmxtwWI2n7jrNLHz%2FCnzNEKiPnAHU%2BLD3hKdGxXU%2FX5l3EvgpHjFsKliBM8SjurfvCy7i6q66ech0uC5%2BzedwZe7xR7aV7y2MLIQa3QoW2Nt16u1LiCbVoUIDdu3keAaEWNG90%2Bxc8dPrAFajYeB8c8OdJsv%2BKVf19gnz9RMjRr6I1BfZuge%2F%2Fp6vRNSZ7BMnPeRgQcfNFltH3XSfy4%2BG8M7pP46ZsjBrUwnOmSlYSLFtCWbcfg1%2BMbdO1YRxWQKeUkQr9X1%2Fr4edk27nCs%2BRNlHMP6N8fF4FvoMWAG1iwbp7qKwh49Qf9hc1RLQKfTqem%2B%2B6oXqvu4Z5n3LQ%2BIdxOFntSi45eYN22gaNkUV4%2Fl9yTkLbuNFUqXKqTOhJKtpfj81%2B5Rt%2Fg2rPjIMI%2F4BvZqjCUrtnNnSwdGaQLJ5iabX5SW%2B1d6%2FjyhPPPn%2Bs2YA5zywG5aif9zhKnV7WNqP%2BOYEXPHWHnImj%2FRW5IHftMy9InSZL%2FlKiAiYvgTERHDn4iIGP5ERMTwJyIihj8RETH8iYiI4U9ERAx%2FIiJi%2BBMRUTri5R0oS4p%2FPRfieiLW%2FMkEyItk8cKBXE%2FE8CcioowgI%2F8EHRGRKeQha%2F5ERCaI4U9ExPAnIiKGPxERMfyJiIjhT0REDH8iImL4ExFRhpUlru3DL41lHrycABHDP1Ud2rWIWzOD40XEiDIOdvtQurfS2FIjYvgTERHDn4iIGP5ERJSlwl%2F2%2BfKsDyIydZrYPDSZ8H9atTCsud2JyJTF5uBTUwr%2F0Eg75OOmJyJTFpuDoSYT%2FqKNE2SuQRlueiIyZTIHZR6aTPhrgADxny83PRGZNJGDKg%2BNwCjf8NWZYbWZDpvruOKjHZfTt79r1PhFuHLtrvrb0tIcZdyc0aOzL5wLOaphnftMxfPn2pi%2F%2FWqhbQsfLFm%2BHb%2F%2FeRDvda2HZg29DfPq2GsK5kwdgNy57AzDflmxA%2Bv%2FOIDPxnVEWfcihuE7dp%2FCrPl%2FxJT25mYoVbwgenbxRfGi%2BRH1PBoDRs1Fn%2B71UbWym%2BE5h45ewPyf%2FlKvYSGW9VW0Wh06vDfF8Di7TTZ4li8m5tcA9vY2atiHny1B4%2FpeqFOjbKLPX7jkb6zduB8PHkYgX96c6NC2hnr%2Fcb6btR57D5wzPC5dsiA6ta%2BV4D0SUfKJ%2FLMO16OzyMPGJlPzP3oax8XdyXAbvJ%2Fer3381CVUq1wao4e0RN8eDRF8%2BTa69p1mGP%2FNxJ64E%2FoQLRpXRIM6FdSwy1fuiFAMxxeTf1NBHWffoSBRUEQlmP%2FcRZvxMOwxflu9O8Hwu3cf4e69MPW6%2FXo2xPOoaDR79wvcuRsGy2wWqF29jAjoXwzzj47WYeynS1C%2F7juvDX5JL9qNAQfOqrCW85f3f209qp4f52RgiFqGxAwf%2ByNWrtuLCWP84L%2FkAwzp1xQz5m7Al1P8DdMEXbyBIoUd1fxHDGwOnU6Ptl2%2BRnhEJD%2FFRG8gNv9OxuahaYS%2Fqv3qMURWxL3c0Dy9X7t0yUKqhu1bqxz6iiC%2BcfO%2BYVzhQnlUi8AxTw5DrVmqV7uCqhH%2FsnLHK%2Bcra%2Boy1L%2BY0BnrN%2B1HdJQ2wXhbW2v1uvVql8fkid2RzcICh49eVOO6dqgDOztr%2FPDTZvV4weItyJXTDn6tqyX7fXmWL6rmL2v4fm2q48at%2B0kXxMeD8ceWw1g6fwSq%2B7irFlADUeAsmj0U83%2F%2BC9eu3zNMK8fJ%2Bdeo6oH3h7XG4yfPEBb2hJ9iohSKzb1RsTloFEYLf1FRDdJp4KfRYIm3OyaUKAGr9Hrtc%2Bevq5ryzt2n8cOPf2L00FbJet640e0x84eNKvQSs2r9XrRp7gOfiqVgkz0btu8%2B%2Bcp5hYnWwZPIZ3Ap4hSzIcw0%2BN9n3TF7%2Fh9q2WYt2KQKCI0m%2BV%2BHOHriknru39uPYe3GfaoGnxTZHVVVtITy58uVYHgZtyIoXrQAdu8LNAy7ev2umr%2B8fT11lWphyMKSiJJH5pzMO5l7Mv9kDhprWYx6Vc%2BjgdgqKpI%2B0RrMdrDEYC93LIce28x1CHQNQog%2FoE2L19341yFD%2F3Xw5VsieM3wbpsaCfruEyNDvVwZF%2FwoauXDB7ZIME5212zYfBCrl4xVgS0LgVXrA1QtOs6t2w9V37m0%2BZ%2BjorZfGx6lnQ3jy3m4qL72jr2nYnj%2F5up4QEosWvoPrK2yqX6gq1fv4p8dx1GnetnXdhuF3nv0UvDHyZ8vp%2BqWirN3%2F1nD8ZIbN%2B4hj2MOXLx0K8XLSWQq%2FADzy6XgojWDR%2BzB3U564JSFHj6Hzxgv%2BI0e%2FnEtAHHXwLMMKpjp0Vb8PUxnjpLB7nDxTqNvAY8e0grNGlVUf8uDnX2HzcZ3s9dj0oQuST73w1Ht0L77N%2BjesW6C4f%2FsPKHuT54OUTeN%2BPf3tmN49OgJcuTInmBa2f%2F%2BPCoKY0e2e2n%2Bg%2Fo0wcJf%2FkH3znVT%2FL6%2B%2F6YvirrEfH1Ctk6atv8cK9ftSXDg9r9ss1vhbryAjy884insbV90fcmCaeTglobH8pjAuIm%2FYOXPY1K8rLyyJ5mC4Jhv74aIIDsvIiFA1PYbG6uPP8OFv6EVELNC3milvE2QyDNv3ilXFPsPJa8Qlt0hdWuUw%2FfzNyUYvvr3vXArUUi0KM4ahuXJY69aGXHhK2vSo0TBI48FdO77HYa8Px8LZg5WXT5x5MFf1Q2kebseORnq8tiGPFj9Ol4VimPlmj3qWEU2yxe7w%2F0HETgdeOW1BaJ87rpN%2B99o%2BfijLkTGZfIXdpO18BWrdqFW9eR%2F5%2ByDEW3wq%2F%2B%2F0EbH9Eo9fPgY23aexExR8572dW%2FDrXe3%2Bli9fu%2FLJa6lORbMGISgCzfw%2BTe%2Fpfp7kmcKbd91Ejt3n0Ktah6vnVae0SQLqQ8%2BWYynz56rYbK1Is8AqlyxJCqUdU30eSHXQtUB4VrV%2BF09oszIwhTfdL%2Fhcwx%2FywOWndvXUqd9SrWajMeV63cxfuJS3L33SH0H4L9ci%2BRF6%2BZV1Dn90u9%2FHlCth0IFEx78bNW0Cr6aukodKP0vBwdbLJk3HM07TEJRMb%2FEXielajQaZ%2FjbrVQhfPVpN3VmTpzhH%2F6obnFkgbd84Wj8%2BuMojP7oJ5SvOhy5c9nj3v1w%2BNYuj28%2F75dg%2FlO%2BX6duqlUjpmvZrDLGj27PTxFRJpQlmt6y24c%2F4%2Fj2HjyIQMSTp8iZwzbBaa6pJf7POLLbh4g1f0rCiHELE5xvH59suUz%2FuneqvE6uXHbqRkQMf8oAUivciYji8Je8iIgY%2FkRExPAnIiKGPxERMfyJiIjhT0REDH8iImL4ExERw5%2BIiIwoy3zDN%2F51Y4iI6PXMs8KbuHkXE%2BWtoBM%2B4ybNPNuMa4HIeNjtQ0RERERkCv4P0mcxEcIS6ucAAAAASUVORK5CYII%3D)
+
+```
+load_data
+ ::= int_const_expr
+ | STRING_LITERAL
+ | IDENT
+ | section_list ( FROM IDENT )?
+ | BINARY_BLOB
+```
+
+referenced by:
+
+* load_stmt
+
+**load_target:**
+
+![load_target](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAR0AAABRCAYAAADvh3LYAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAEcpJREFUeNrtnQdUVVfWx%2F%2Bv0EFFmgUDRkVRbIA19oJmaUxsoyb2Fo1RR41xYuZLNGtm1Ilx1IkxGY0FY1TQWMZoEhF1grEBmoiKiAICgoAgSOeV75xDERV4IK%2FC%2Fq311iv33dPuPv%2B79773vQMQBEHoEYmxNEQdOtfs4IWLi29GZUy9fTezTXpmoUVqen612%2Bdgb6GwsTJ77NjY4lz0%2Fbw1Zy7lhtWFA1Tdcamr%2FSdIdHTCqV0%2B84%2Bfjv88KibLZuSgFujj64wmztZwdrCsdhkpj%2FKRnJKLkNAUHA26r7A0l4UmpuVODovAXVM9ODUZl7rYf4JER%2FtncfUqacDmQwe274saN3lMK0wc2RLmZtJal1tYpML%2B4zHYvj8qP69IPSb0uvKkSXk3tRwXU%2B8%2FUbeRGbLy9o0fBew4cGfc%2Bo%2B7wa9PM8hk2tFAXk5nz8bw7eQoP%2FVr4kQne1XCg1RcNZWDUttxMfX%2BEyQ6Ogsd%2Fr371nI%2BsTq2tddJHS6OVvDt6Cj98UzCKCcHdXyyCUw8bY6LKfafINHRTfgQOtds877Lp4f1dzXnZ3JdwideXoFSEnErY0QzJ4SyM3600YZVOhgXU%2Bo%2FUT%2BQGqJSfjUmOu6JDc9V6IN3J7WFublUrlLjgI8XWhnrwdDVuJhK%2FwkSHZ1x807GtOH9m2slaVwdeD3dOzvxrLkcSqw31oOhq3Exlf4TJDo64%2Fa9rFZ9fF30WqdfPxGuWLFHn64d0NkYD4Yux8UU%2Bk%2BQ6OiMR%2BkFls2bWOu1zvatGxW%2FkCBFqsJYYzwYuhwXU%2Bg%2FQaKjM9KzCiQODS30WqerS9lktmWPocZ4MHQ5LqbQf6IeiU4PL1Tp02vaXlNUSjWkMv3el1han1qNxuzpFWM8GLocF1PoP2Hc1FYHSvcXolOkxAMfTwRUVqim7bpk56FYHAt6gCKFSivlSYrP9C711XDqe%2F%2BJl%2BdldaC7J0b7tEe8QokY%2Fl5eYohcfMYrlWyjJw7LZVh4KQIPyxlqldt1SURUFvx%2FiIOLgyWmjH4F08a6oYmjZW2LldVz%2B5HRFCJe4oRVIx3gYqOUYDNz4F2hfvq5vPyX1MXvKy1U03ZdsHa5F%2Fr5OmIXE57126OwcecdDO%2FfBDPHuaNvN0eyBILQM5p0oDKxqVB0Kiu0ppVqEzO5FG8ObSYed%2BKysetgHAJOxON4cBI83G2xf3MPtGhqTZZAEIYWHwlOKoDPKhObKkWnFBVwjflTw9UatisUiGGVWum6ky1dbdDLuzH%2BiHyMi9fSEZOQi%2BwcxUuVxdqrrs8GU9%2F7T2gPrgMs9BqhUGMce1ZpMix5JbHbb2zHRPY8hBW4nT0vqWq7mRzrauLp1NTgk1LzRV7nuyP3kZyWL3I6H85tK3I8L5vfCbtV9d96jAdksR5wU0rRnn1zEPvyJNboCLkaCy5HIsrQQnD593QUsaPcoU0DNGpgpvX%2BE%2FWL7u3goZBgCzMKL2aE%2B5glBstUuOkehbhAQFmRfZbXAfb8jaUZduQXYSZzRGarJcgE93g0iU5pIeriQi6ZyeDJxYRVtqSq7bocjE27o7F2ayQUzGfr4%2BuIf3zghdcHNIFcx5fcxUBH4R57yR%2FHW7fGRw3NsJzFqhe7tsf4qzdx2pBGMmXZFaRnFuLQll7o151yW8TLw%2Bx5MJtegWxGbcgswsjoaBSUbrtShVNSiQ4s7eGFdUVKrKhMfMqLTqAGMQnUp9iUkpJWgOlj3TF9nBvatrQz2IEpORB%2F824nQspAdmboqSuPhyD06eFwwVGrMTU8Esercz7WpAMln1UqPqWik8cKSahCTDRt1xl%2FX9bBqA4SPzDM89vAPJ4v2Vs%2FQ7XjdtAwmjFErSmx4w3VFJwa6cDz4sM8pHlloiOXoWVVhWjaXt%2Bwy8P6J1ZYwH84efUGfqcRIUwyrOI%2F%2FFWhI7PnUdX5%2FsvqQHnx4e%2Bl5T7UtJPW4Lfk81v%2B9Ul2TpHWyjobi3wW2H6v7R9O6nJctNl%2Fom4g7JfZsbDn6ovHS1O6v0F%2B8NnIzlzxKLNAr3Xeic3SboFqBDN56GUq46L1%2FhMmj7BfZsd6FzuDhCc2Zo8Tk3P1Wufl39PEs0SNJyi5BFirWFiNGyxG9TCVcdF2%2FwnTh9svt%2BN6IToO9hbnQkL1myI6FfKgWN0lSGFPta7cKluU4WQq46Lt%2FhN1AqcSO677osNXoPwxOEHB12fSBzEJTxCbkF3aY37fzf3alnkhQcTBlqYwLrroP1EnsCyx47ovOnzJW3MzaShfEE4f%2FGVdWPlANoef%2BLUTEmv3rl5djYuO%2Bk%2FUiQhL%2Fz%2BHkRqqt3zJW74C5fXbGTqt55%2F%2FicDduCelE%2B4ee%2FiopDhkrFag7XExtf4TdR%2BDiQ5fY7uwSD32%2FU8vKnUlPHzCBZT3GiQIYdJ%2BxZjvrdHmuJhi%2F4m6j0H%2FzCkxRX3HwV4VfzI4YVRugVLStb2DVpYW5jmMeR9fQMiVh%2BXDir1s0vmxHk9KSoFWVK6ZE1YlpWG1sY2LvvpPmDa6sl9NyA3d8fCb2OnrqZLuOXT36%2F3HYuQ9uzhieH9XeLRqALdmttUqIzdfwZdvweVrqQgKecAmXfbz2Ze94pfiEswIZZ6EKRhETcalLvafqLvIjaERobfwrXcHdaKyUBl47vJDGXto5795eA6DhRTg%2FwkkxbSwG%2FjJlA5OrcfFxPtP1E2kxtKQcDYhJDJ0YS9%2FZpPlEQsmItgjnk2anBoUk832iZGqWRnAYTVgIf6IXI7e4SY64Wo4LnWu%2FwR5OjolrNj1H81%2FiFbyuyY%2FqNj0ksCmmkXYqtV4rJaAryx3WS3D6tA6kDStwbjUyf4TJDo6p%2BTqCn98QoeIxoWg8IogCIJEhyAIEh2CIAgSHYIgSHQIgiDRIQiCINEhCIJEhyAIombIaQiMB1pfnNBEXVgOmkTHyAj9dQcNAlEhvn1nUnhFEIT%2BvWFT94hJdAiCINEhCIJEhyAIgkTHCND6MjQEoScMsvwMiU7tye%2Flqt0F9whCH5TYbb4h6ibRqR2pebZwoWEgTI0Su00l0TG92CpKJkEHGgnC1OB2y%2B2XRMf0guILfGkXY29nVlYuMjKyK90en5gGlYpuhq5nxjtI2C%2BJjmkhludV4%2B0B7sad19nufwpr%2F1XxSsJFhQr0HPwhHmfm0AGtJwh7ZXZrqOWlSXRqQckfpV9%2FYoUPaDQIU6HEXq8banlp%2Bu1VbWNjNd5XSnDRux2uhUfiuL7q3Rt4DqHh0chkoVOzpo0xc%2FJgvOrepGz7voO%2F4qegcDg7NcSj9CdwcmhQti0uPgVfbf8JKamP0aVjy2fKDTh8Hp06uCM5JQPh1%2B5i5PBu8GjdDD%2BfvorDxy8iP78IwwZ3xaRxfcX3c%2FMKsH33KUTcuo8Gdlbo2a0txr3ZW2w7eOQ3BP%2FvOuRyKdp5uGL6O4NgbWWhsW9hV%2B9iT8BZpLN29%2B3dQfRNJpMiv6AQX207iTnT%2FHD851AkJadjyYJRkEgqv2vhzt0khF6NRv%2FXOuBHtk%2BDBtZ4c0R3fPHvo3iY8pj1p1C0be6MYbC1KXZY%2F7XlGEYM88V3B87ibkyyeP32%2BH5lZfLyDvwQwsYvE316ekKpUmHezOFiW2GRAjv2BOG3S5FoyOqa9vYg%2BHZtbTT2yux0JHtayuy2p6HaQJ5OLbkciSiVBOOZ3fv7eOKvrVvDQh%2F1pqRkoruPB2ZPHQpzMznGvLNWGDxn09b%2F4pudP4nJ37tHOyE6paQ%2BysKoCf8QE2LyhAEvlBvAJtO0%2BRvxrX8QnuTkI49NSv99Z7Dhy6OYOLYvq2%2BImFS7vw8W31%2F28U5ERiViOptc3bzbCKHj7Nl%2FFv%2FZ9QvGvdUbw4Z4s8n%2FAPfj0zT269ofMZj23ib07t4Os6YMxakz17Dys%2B%2FEtvy8InzB2vHWO2vExE9j%2FVJrSEVF30vC378IxJR3NyIx6RHSWP95OUqlCn6DumAiE8%2FQa9FY8cnusn02bDmK%2BUu3ChEfMqAzVq3Zh4uhUWWCyMtq1bIJE5SBuBf3EF9%2F%2B3Qdw7mLvsLtO4l4f%2B4IDOzXCTPe2yzaYGi4XXL75HbK7ZXbraHaQp6ONsKsmzjN5khPhQRbGpphgbcn9rGYOVimwk33KMQFAkpt18nP8NlMFLhBD%2B7fCbv2BrNJnQr3Fs7YyiZBwO7lwmPhxMQ%2BFGd1zvcB59Ddtw1WLhsn3vfr1R7%2F3HT4mbJns8k%2BZ7qfeK1ms3r6vE3Yv%2FMDtG3TXHz2waK3RB38LH4zMp55CX5C3DgTxvQRzzci7zMPojkG9vUSnsgIP59q55%2B4gP1p9GvivWdbV3QbuAwfLRlb9p1dWxehRXPHao%2BVg70dThz8P1iYm5V99smKCUy0stj4JbM2dmIie%2BqZffy%2F%2FjOaN3MQr89fuiW8vp6%2BHti64yTmM6%2Bm1LNxdmqEk7%2BEidfXb8YxwUnA%2BV%2FWQSqVsJNCG1xiYnXiVBgWvTtSrzY5njnhsR5wU0rRviRpPInpc4SceThhtwwnOCQ6WvZ42NNQsQqnGmPY60UqGdrc84Sbj5bvWuZn6ZWr9%2BAX5gV09moJ%2B0Y2QhwUChUSH6YjJzcfHdu7VbhvJDsLl4pRZTg7Nyx7%2FfhxDlLSMjF13kaxpGgpbq84i%2BfF899gnsgebPnmBLy7tBJnf%2B7xTJs0ELMWfAmvXovg26U13ni9W1nYVRX3YpNF%2BFbWFhYe2tlZIy4hFW6uTmWf1QQeUpUXnOSHGZi35GvhAXbwbIG8vEIRIj0TAkifBgF2tlZQKIvPGzHMs%2FnT6D4V1hMV%2FYCJeyZ6D13xzOflQzNtoemX5veK7zaOY0fsDjtsF5h3M%2Fyqkaz2SqKjba%2Fn6SqcWjekUs6dv4EzIREI%2BXktbKyLo7lTZ4urtGSTi1%2F%2B5l4QnyzPY2FhhifZedVuk5W1ucinHNm7Ek2b2L%2BwfcwbPTFimA8ibtxHEGvDxBlfIPTseuahtMBvQetw63Y8roRH41MWotg3shVeWVXYsjZnZeeWvedCmptTUJZv0QZbtp1E86aNceT7j8pCujmLt1T6%2FfI5I1sbKxaiZlbcdtbGlu4uOH3sM53bmSn%2FmRfldEyQwsIiyJj7zhO0nJALN5GTXXxHu4tzI%2BERBB45L94%2FyniCy%2BF3yvbtzryQEywc4KLEOVmSg6kMSwtz9H%2FNi4VgP0BRVHy25%2FuePveHeH3kx0uQSaTw6doK781%2BHQqVknlaBSIXk5mZI8RnysQBaOnmIhLDmhjUryMCfjhflp8KOBwiEuWvumvvxm9eNhffUlE7%2Fb8%2Fqr0vz%2FHs%2FC5YJM55yMUT26XwPFQS86IOHXt6%2Bwv30LioEeTpmDSD%2B3XCdv8gdO27lImCmbg6Ym7%2B9FCuXT0Vcxd%2FJc7oIon4atOnsT4LcfhVHO%2B%2BSyBlHsywQV011rdhzUwsXrENHV9bDPsGNsjIyhF5F%2B618CtUf1nlj3ZtXEXuaMn8UXBt7iBEb%2BHybUIsePK6s5c7Ro3orrGuWZOH4PeIWPQasgIuLIziyeJtmxdUeYWqpvDk%2B4QZn8O731LxvoevR7X35fkcftVqzsIv0djeDgP6euFSWHGKxM7OCju2LMSylTvwt88DREjHr45tWDOLjLa850hDYDzw8Komf1ea%2BOARrKwsmPHbvrCNX8rmOYumzvaQm8le2J6UnCHO9hXtWxncc8lioVnzpg4iUfr85w6N7Z65JM4vcaemZcHW2hL2Nain1EPLZR7T83Vp09vhyfXn21xT%2BG0Eew%2Bcw8E9z%2BZxeN6Ii7qzY0Ottbn835WacnhFno4JU3p1pSL4RLJuXvlkqig%2Fo4mGDW3Eo7qf89Cs%2FFUmLk6zFlaeO%2BEJ5DnThorX%2FIoTf1QFF9ap726qMlTjIV9F8NsManIFrJTY%2BylY8ak%2F2rZuVhxeHr%2BEjetmv%2FC9Ji72ZKAkOoSh4cJ00P9DrZXHhVWb5VUHnjObOnEAYuJSYGlphqP7V4p8FUGiQxA6wcrSXNyhTLw8dPWKIAgSHYIgSHQIgiBIdAiCINEhCIIg0SEIgkSHIAgSHYIgCN1DNwcaGeV%2FX0MQdREZDYHxkJSG1fzRzAmraDQITbZC4RVBEARBEISx8f%2FrTwtRODMf6gAAAABJRU5ErkJggg%3D%3D)
+
+```
+load_target
+ ::= '>' ( '.' | address_or_range )
+```
+
+referenced by:
+
+* load_stmt
+
+**section_list:**
+
+![section_list](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAL0AAABRCAYAAACHUafJAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAADXBJREFUeNrtnQlYFEcWx%2F89wykgcmoAxQRQQREFYjDiEQweiZv9vI%2F1WmNiNsZ4bDySTbJxN18SjdENJsbEIzGXBx5rlJjEeLOe4BERFJEjAoqA3PfM9FY1R0CBmdEZZhje7%2Ft6enqqu7q76t%2Bv3qvprgYIoo0hmOqJiTEvmu88dXp%2BfGLe9Gs3CnzuFlRaZt8tv%2B98nRwsFTbW5vnOjpbHkn4ve%2F%2FImdJYkgWJvtVx8Kugv%2B0%2FdPPDxJRCm1FhnREa7IpOru3g6mR137p3cstx%2B04pomPuYO%2BvvyusLOQxGTmlU2PjcIPkQaI3fusuviPbEbFr%2B8atieOmjvHCpFGPwsJcpvH2lVUqbNufgo3bEsvLqsQxMZeVB0gipofclE7GzzF3x%2Bbt18et%2BsfjGBbqBrlcu2uarx%2Fg64jg3s5mB09kTHJxUKVnZuMCyYREb7QuzdotCYu54P27OzxUXh2drRHs7yyLOpL%2BnIuTePM2CZ9Eb4xBa8TWs4eGD%2Faw4BZeF3Dhl1UohbiEvGfdXBDDLH4SycU0kJnCSfBemqS0Ihvuw%2BuSOZO7w8JCZqYSsT2oF7xILiR6oyH%2Bet6MEYPdtQpaNYHn1y%2FAhUf7ZlBiFcmFRG80XEsu9AoN7qiXvIcNktwlazaF9u2JAJIMid4oyL1bYeXeqZ1e8vbz7lD9RcAdmQpjSTIkeqPgbmGF4GRvqZe8PTrWXUy2bAonybR%2BzEzhJFRKETK5fv5nq81XFOEomEh5kegJjRCqLb01lQS5N20NORUBiZ4gSPQEQT69hvA%2BcJmIMRDRny36sMkTRngXaJAvO0JCE3g5pbHpOqvFUyoBuy9cwSUSPaNfD3RTCPhUUKEXK6WtrKgi5CrEd01EWiSg1LUQE24U4W5%2BJTw6WcPTXfu%2B%2FdgE033wRpeMZ%2FFPajd4KmXwY4thzKD9FOiLODMRc89eRWKbFX1fPwxViohkKlpdUIVRSUmoqE07p6d9zloag6S0YuzbMOCBRE9ohmSwEpHMvvJpv7c3Xrc3x2KlgNOs3sdfiMehNufTcwvPrv5IUcR0Zj3frS94fXEru1wSfL8AR4T0cSRltiC8fnk98%2Frm9c7rv82Jnl3xn7DZ6vNXsb%2Bl9hkdkyPN58%2F0JhUaiJr6Xl1T%2F21H9DU3bvnblbXsnYsnzuXAz6c9wgd0JPUZkJp69zfUDXwG8emlG7cEfH80FeU6yU8uaHQrwptzfWFuLoOgRShaXFJFKtUxvN6D%2FPB9zQ18Ld6jYxBLLwL92cdhXeXXwc5CkVugPiRwdbKEQ3tzrfK%2BnlpIKtWPCA5LOmgr7g0ztN2YYb6is%2BbSxjw%2F43apXo717KXqOEAQUQQNu1AJDWI6Vv9cB20pkHWxLkaWrjJzcrA8Fh2TpZcDPRidWW2YBNxhsyySq26oqX%2BXtiR6q1PpuvHnOXxksqjD6Qo%2Bbo0uSUkvQmp6cW1J8f7m30muuqGm%2Fq3akuiFatdeN%2FCh%2BCzMZTF8oCZdsmxFbH0ftIQbfpKrLkM7w%2Fy7bTI3nPGh%2BPjIZJev5ekkv5VfxOFGWlFt9SSzKUglwy7SauvHZETPx56srBLHvvLP08qHFT4X%2FI76rYaAaGaSzhnLDVMEib6OM5eVPxaXKV6Y8%2FpJce3XCdDWx%2Bc%2B%2FMR5RxsKXsR37HO4KMcSkotpYHKPC56Px5fBvirZN7turN%2F2Q4pZSB9njBjsgW5e7eHpZttg3dJyBR8%2BBGcvZuPX6Ewm%2BuJ7vc7vmJUPEwT8NYZGMSbRGzMxCdgU2FPMUFYqI4%2BdzZKzSbtnW7kPz1wa9m2EKMOM2Cv4iaRC7o3xW3wmVEGOPuzrz0zEucwnj2PTTSbmkkZWL2ZpKTKRrQvsEQFL6UFwMzx5ngRPlr61BbdsNlp6Kqv6Po9hUDHZC7C5Z1VbUUS%2BKICP7HSW%2Be%2FLYyhoJdG3Zmp6Xfj0NlU5QQ%2BGEyR6giDREwSJniBI9ARBoicIEj1BkOgJwnCYxJ9TNL5ky2EKwxqazD%2ByMSc2kyL1TPDAWeTeEG0P3qq29paVRE9QIEsQJHqCINHrBOptIQRD6cBQoq8Y0tUwA%2F0QxkF%2FD6n%2By9uS6HNLbA0zpBthHJTZgo%2BXnt2WRJ%2BsUBnuTRSE4ZEL6Ml8m8Q2I3p2sjGCCqFU9S1PRmYubmbkQBQNHFbxoVWAUwYT%2FRO90OyrOdSlay16AVGCgAlA6%2F5LOzu3ED%2F%2BEtvgtw1f%2FYKPP9tndMdaWaXAnye%2Fh9FTP8BfZq9GcUm5wY5FiudETNF2mMSH1WHt9tJtCFVKZAb5YpeZHPPOxN0%2FHLW6dG25EI8jQX6QBfthbEw8drZW0Sen3sa7H0bimWFBdb8FBnix8jK%2BYewPH%2FsNFRVVOHNoJQTBsLamyBqvsdllbYdJfFAd9vPFaKWACIUSTmyxnVl1SyNZ%2FPGsrkazTPfcm6m69AdAxfJcxFrYL%2Fv0QMzFq0htqQK%2FFJeKrTuP425eMTzcnDBl%2FCB4P%2FaIlBbFrPbeqDOoYlbxmfAgjB89oG67M7GJ2LPvNIqKytDLzxOTxw5E5J7%2FoaCoBKs%2F2Sut8%2Fy0p1FeUYmKSkXddolJmdj09UFk3LqLfkE%2BeGHmMFhbWUhpEZ%2Fvx7Cn%2BmL7nmhcTUzHiKF9MWNKmEbnsXPvSfj16IycnELEXryBkex4e3Rzx8EjF7GbHWdpaQXCw%2Fpg6oTByGPnunXnCcnar%2Fn0B7aeR4MLtSUJ7IFRbLZILiJEe49IOx3Wil0pwqN%2B56jZPb62WXOZqkvXBmbhDwT6IYKd%2FAk2n3I%2BHidawp%2Bd%2FPxHWL5sEpyc2uPylVQcP3lFEv2GLQfx3%2F2nsWzhWKhUIpav2AaFUoXJ4wbi50MXsPTtLVi2aCzs29vgwMFYnDp3DS7O9jCTydHZ3bk6OGMFEn0qAUUlZQgb5I%2B09GyMnfYBFrz8HP408nF8vfUIXnx1Hb75YoG0%2Ftr1Udj9wylMm%2FQUunZ2wftrdsGziyuGhPbSSPQpEVnwecwNPt5uKCurwPeRx%2FHlt4fw%2Bt%2FHwdLCDP9euQPl5ZWYOCYUDg62uJ2VJx2rk5Ndi4vd2xuW%2FD2yXPDM4o2PTXjwIFadDpsSe6OibypTbXeqKUzo7wX1QKogYlegLwtuRWxXyXHOvgTJunoJW32Skm9LYhjOLGr79u0kYUrNDhP5x%2Bv3IWrHm%2FDs7Cr9trDoOXy745gk%2Bv%2Bs24c3XhuPCTWWf2R4oLSNo6MtaxnONmgR6vPttqMYFtZXagE4wYHeCHhyAa5dz0B3H3fpt02fzIPXo52k7%2BfOJ%2BHCpWSNRM%2BZMTkML88eWbf84oJ1%2BOqzV9GzRxdpecmC0fiItUKzp4cjuI8XCgpKmjxWXdPgjeHVQetkphv%2BxvCQhxF8szoUcIC1sf9qSuzNir7OBwEuyvh4jmrSFQqksJ1aP8wJsEIZyT5GylSSz8fv5tM5%2FZ%2Fojt49u6JP6EL09OuCQU%2F64aVZIyRXgLsAE2c2fMOnj5ebNL9%2BI5Nt59mwB0Cm3i9OSctCv0CfumUrSwt08XBhsUBWnejr52NnZ40qhebxgKuL%2FR9%2BcnEZMpkLNWvuWmkIt1q4C6cP1N1pmfxHvdav407MAl%2FTdd1yHbK8n1WIGMfmKnX9UmZNCPAk2zCDzZ9mGW5k84XNpZubYYUuAlx9VUAtFuxAt6yfj6w7%2BZIf%2FNnmn6Tv%2F2TuDg%2Fuona%2BBSeH%2B5t%2BO1tr5BeWNlJOrASa6fqzsbFCIRNjgyCOLdvZNv5n9MMEmNbsgjIzlyNyy1J2YTnrvcwN8TDJvfVcX4ds%2FrmVOTaXV2EWM8SzRQEF4Ba%2FqS7L%2BpmwWSTLwJdN6cxt8T2fgEXq0g0peG24HJ%2FGAsYMdHTtIAVyw5nrwQNaLuoBIb5YuWY3FIrqMe15wHrkxGXp%2B9AhvaWuSEWVssby30LCtZtob9dO6rbk6zbG0EG9JfenqEb4R6PjJH8%2FkLkauoYLnu9vVcQeVNUE0iWsBfv1qOkNydmUDk%2F%2Bhjg%2Bl8vhw2xRJFuviK2c3pyl55nwK%2BYMKz%2FfRoSsLt3oKWXB3pxX10j%2BPO9B4aLYuHZudU%2FKitmYt2QDeg%2BYjw5MzHmFJZgzczieGuiPtxZPwCuLv0DAwAWwt22H8soqbGa%2BeIB%2FV4Q83g0h4Utgzkp677Y3GuyPB6%2FcTx8Qvgyenq5IT8%2FBulUvoZ21pV7O78N3Z2LB0k3wZ%2BfgaG8rncO0iUPw9JAAU9K8Wh3W%2FLboiV5YwezU0nstv1DTbJSyTNazTBp1U9SlGxre7GnzuGB6Rq7kS7s94nhfWn5%2BiWSNuS98r7vB%2FX7e7cdbivrcyS5g%2Frq5dDE1Bg8guZvTyaUDzC30%2F4Rm7f7cH3HSKPbQlPqPCxrIvXkgHfI%2Fpbj42QG%2FxI67up%2BeNQ%2BPNpeJuvTWhod708Fdhw420tQYvNtPXUDZGPb2NtKkKXv2n8Z3O443mb5i%2BfS6Hh9d7K%2B18KA6rG%2F569wbdRmZkuBbA6NHhUgToVsd1m5PT04RbQ4SPUGiJwgSPUGQ6AmCRE8QJHqCINETBImeIAyHyQzVbSrDSBP6R24KJ3ErB8v55OaCd6hKW67Myb0hCIIgjJP%2FAwvxQyIMYiCIAAAAAElFTkSuQmCC)
+
+```
+section_list
+ ::= section_ref ( ',' section_ref )*
+```
+
+referenced by:
+
+* load_data
+
+**section_ref:**
+
+![section_ref](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQsAAABFCAYAAABdcMP6AAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAD4pJREFUeNrtnQtYVNXax%2F%2BbmUGuIoJ4I7XwBmqJoFInLTE9VN610iLT9Jh%2BmJqni%2Fl58tNjF8W0zEqNrNMpb0ilkqaGZZp4QZRAVEQQgVRQ7vfbfO%2FawDQDowzDMDX0%2Fp5ns2f2Xnut2S9r%2Fff7rr32XgDDMIwBSGyClouPJ9RshZbJ6fPmb7tKNnvLJurIZjZCC8N3yPN%2FSLlWbHqGsUyv0dyeI4sFwzAsFgzDsFgwDMNiwTAMiwXDMCwWDMOwWDAMw7BYMAxjGPIIzsF90f5EHG7cLlFD%2BxnLJyu7AGs%2B3IVfjp9HcXEZ3Du5wG9QL8yZ8Sjs7Vrhw0%2F24scjcfWO%2B2jNC3BzdZI%2F7z1wGlt3%2FoxLl6%2FBxcURfXt3wdSnhyHkPweRmn5Lb7mj%2Fu6L%2FIJiHP7lnPz97q5uCP73NPlzSWkZPg75HuH7o1BYWAL3zq6YHjgcj4%2F00Ry%2FZMVXuJCQjrfeCETP7p3kbckpN7Dyva%2BxYe2cBs87jX7Xgtc%2FRRd3V6x56%2FeRkZ98fgDObRwwadwDmm3pv93C%2FEWfYugDXpg3e5ROPk9NX40eHh2xYskzmm1l5RWYEbSefrcL3l76rLwt6J8bcSMzV%2BfYdq6t8fGa2c32v21q%2B609XhaL8kr85uOJMKUCL%2BrLtKH9jGWjVqvx1LRgquyd8EHwLLR2tENMbDK%2B3HEYYx%2FLkhtBYtI1tG%2FnhMCnHtI51qm1nbx%2Bd%2F0ubAn9GUtfewre992DnNxCfBt%2BAu99tAdB%2F3iMBKhUTvfmuztxb59uGB3gK3%2Fv2KGtXF5WTgESSWRefnGcvL2qSo2pL7yPcmpwq5Y9Bzc3J5w%2BexmLlv4H165nYebUEXK6uPirJDZFWPX%2B1wj5YK68rYCERaQ1hCL6XXHnU3A1LROHfo6F%2F9B%2B8vYkEpz2RaU6ab%2Fec1w%2Brw2f7cfsGQGwVv3%2BtMTxUxcQG5%2BCKZOGoA%2BJpCBsVySiziYiO7dAky465jLZ8GEMIBvV0spa1az%2FX2Pb7yBPjK%2BUsK6iEi701U4%2BW6k6HHmishLjKdNv6mba0H7GskmjK2b8xVR89elCjZcgrrSjHx2IiooqTbrO5G3cP6h3veOvpt3Euo3hCN%2B%2BBP28usrb7iIvQHzOpcbl5GSvSetMn%2B%2Fu4lYvHycSDDvyYNq7tZG%2Ff%2F9DNC5cTMMvB9%2BBo4OtJs%2FWjraY89IGTJ44BA72NvL2F6YHYPmq7TgTkyQLVWNRUYVeGDQG76wJw7AhfSFJ%2Bp%2FRCtt9DEsXTcYbb27FwR9jdDwcwXNThmHdhu%2Bw8b05sgBv%2Bny%2FvO0oeWvaePa6S68dm4vGtt9akahUw117QLlOn4W6OiwRmaZRpjuE%2B9GY%2FYxlIhqos7MDVfRwpKRm6MapSisdNzzy5AWdpbSsHD8diYVnD3eNUOiIgJZQNAYRlozw768RilqGDekHpUqBqDOJmm1CQIJmPoa314YZbYMnxv2NwoZy7N53Uu%2F%2BmLgryMkppBCkDyaM9iOv4Vi9NJMnPoiTpxNwOfk69kecobCoMzy6daiX7jwJs7YNow30gprsQTbQfoVI%2BHghtZKcKAih0NdncYdMZSVqaD97GpaNcKc3r38RS9%2Fais%2B%2BjIAjNT7hJk9%2FZjhGDOuvSXeKGmjdeFv0WVzPyEGnjm1N%2Bpsyb%2Baid0%2F3%2BldJuup3IHHLrPM7pgf6I%2BSLg%2FiZREYIX2NRKKzwyvwJeGt1KB4f4Vtv%2F9e7IzH28cFyuglj%2FPA%2BeVLZ2QU6Zdm0ssbzgY9g%2FabvcPnKdbz5r0DZO6rLNxSeaff%2FyH0W%2FT3MF3bWbb8S9lUAy%2Bt6EgaJRS3kgJ6l60qAuoH9FRVIpkJtudlZLoN8emBf2Bvy1VPE8Eci4zFj7npsCVmIB%2B%2F3ktOMo8ay%2BJ%2BT6h0rwgERbpgSkWd%2BfrHefXm03b4mBNFuqC%2BJUIK8i3eWTTWqzMdGDMBHn%2BzF1rAjOttFKCb6X0RnZ%2Bg3v2jCqV17T2LaM%2F46aac97Y%2FBj7wK7353y56WPrEQNqztG2kqTXnyVLRfClEer1BjEq2rGspIeZsY5xgdmE7rRyjDEFq%2FdKf9dGFaWetZPEEifaUnulZawYsS%2BlOaKZQ2TqlGEHlcCdwsDWy8vdGzQsKHZL%2B%2BZL%2BtVCUOKaoQ3y0BKaFAZXNVpDZt7GVxEEt0TBKif03SiMVty%2FH2wOp13yLzVh7aubQ2yfl733sP%2Frv9Jzn21%2B5DEC7%2BDfJkxP56YcCEIdi4eb98V8ao2J7KeX3hRMx7LQRD%2F9ZHKySKg5VCQlZ2Po5RJRaIzuCwPZH1xEJ4Zf965Ul49nI3Sz0x5CU4deuBdvul9UYbFTaXlON5uvDPVEvI1ReC1OuzEJnQKpQy8KQljcILz%2BjzWNjQfu0QRFTkUwlIir6AcLEvtxzd6LjDlRKOe3thOMuAAQ2F7CTsJewm7CfsKOwp7GqoUDSGs7HJWLz8S6Sm39RsO3fhKi2pGOjdvcHjB%2Fv0xAByo%2Bcs%2BBgZWuGBCAmWr9xu1G%2BaNPYB5OYVYUVwKCrKq085g0ITcZtz%2FGg%2FdOzgXP%2FKp6RQYt44fPrFD0bbQgijuAX73fdRmm07dx2T72CsfXuGZvl47Wz8eu4KkijcqIu4I9KfPIs%2FG7drv8d%2BRZxYKxToQdocSunyKXHanTwLkYlQmhMqykRPH0RD%2B%2FWSmAhx%2F2nFgN5yyBJKV0w%2F9jDu7FFQ7BhK%2F7SpQiDMUaboA0gjoRjy6GK4ODvKcbm41bmYrrLavfZirIVYtDkesUq%2BS7F5%2FVx5zIPf8Ffh1s4J%2BYXF5Ko7YMH%2FjG6w%2FGUkKNvI9Rei8Oys9%2FDfTQvkK%2FS2zS%2Fj5SWfoe8D89CmtT1uZeVj%2FCg%2FLF8y5bZ5iTs4H4Xswy3yAoxl0UsTMerJFfJnMQbkQMRZWYS0EXYa4ueFsN2RtG98o%2FJ%2FdtZane9iHMaJiODm%2Fjc32H5rti0c3Bcr6V%2FxWl1PQ6pxU4ookw2UyUp9mTS0vxHx1RJaDSXXaSTLwm1tdEBclMlGK0wRzzbmtXrlZRW4npkjfxYCYAxiIFXmzTzY2FibLCS5mZUnDxRrSw1UDBD7q6P9Wj0DwxCj2q%2B4WyJEgwqYTeVUj7Mgd%2BTuO2XS0H5DcSzG6nxbBHn3wX1nziGGpaFO%2BEF2QRX6kZ3G%2FBHlq6yVRouEdkdjU%2FOoi2tb40XnyWnB8gAvvV6cTw%2B8On98i69XxrZfbU9DE4Y0lJGpbov%2BdAUlPl7YYlWFifSVxaJuB5Kwi4Qtwk5sDdOw4%2FNX%2FvI2aGr7rT3e%2FA%2BSqXGIdP5%2Brsb6TEN2IfuwJZg%2F5cXM3AVWqnGOYqCebPr6CLsI%2B7AlGBYLwrZAdmnasen10q7GPgzDYhGZJsfjNmx6vdjU2IdhWCyqQ3OeNvH2kQhPOciwWDAMw2LBMAyLBcMwDIsFwzCGomypJ6aOmqXaGXl8fnxC9tSLl3N7ZOWWtcrMKjG4Y9XFuVWFva0qx7Vtq8OJV4vf%2FvFE0WlLtIP2cwQMw2JRh4Of%2B8xZ8P63wQnJefaj%2FO%2FCuNld0MHNDm4uht%2BxzbhVoryeUeR6NCpjYkr61bFjHraLSr9ZFHg6DpctxQ61Dxk15QUpDNMixUKt%2Fj%2BrHevCtq%2FaEDcpcIIHVr0%2BENYq4yItISxiudezLWZO7qncFp7sF7ItIc63n3pCVGzlPq46DIuFBSOEYvP2S5PeXTIQ%2FXo5myxfIThTx3vA26utzdylx%2Ff4emFWVDw2W4pdDHmMmWEaosV0cIrQg678k4IX%2B5pUKLQR%2Ba5f5qdQKq1CvL3AnQEMi4XFhR9Rs1ThEanBgXT1by6h0BaMp8feIykhbSQP41GuQgyLRTO3b5hwyLe465GYkm8%2FeZR53nv4wpResLa2Ulapsd2nL0z1Dnce6s2wWOih5H530z1MFn8p%2B7mAhzob3ZnZWEQ5g%2B5rJ1q3EpVYbYo8a%2BzBD5ExLBZ1yCx2MN1sZheT8jwe9DXv5Ggjh8qT8Iq5Uh6UX4fXRGrskclVkmGx0I1BEhQS%2Bpgqv1tZpTadO9iZ9Ry8urepDR4yal4T2CSEPYRduEoyLBa6wXmkmIDIVPll5ZVKLk7mfeuze3uNOIn560aYwCj%2Bsl0YhsXid6qsEEbuxdMPdzNNv0VVpVqeMcqshqspT62GmOSzS1Pyku1A9pDtwjAsFr9TMw1AbL4tXrZ0A0rVnkWTOkxq7BDL0yMwLBb6YnQ15tJq4YDeGNUC7Kgw9sCa819YYw%2BGYbGoi5jCsErCE5KEL8RMZd27wyydDjl55Zi5%2BDQGjInA%2FH%2FHIK%2BgXN6elVMmbwvZnmyW8xfnK85bnL%2BwA0%2FpyPzZ%2BUOfDTkTjwgx96mYLdxJhaABnsbNFt4Yln0Qjz0R13CfpxO27L6KK2mF2PmhH1KvFdNSBFsbRbOc6x1ml%2Fc7fZ6FgmGxMMjDoNUIMVbBSo0J9HlelQI9kjzR1acZXuy798fr%2BPuQ9vhi9UCs2nQRwZ8k4MkXT6CkpBIKhYShg4ybeq%2Bhx8CTqkdnptAJXaKziiRvIoD7KBgWC2O8jOqGE9McDbWWgqIKZOWWoUc3B%2Fn7K%2F%2FohcLiSmzamiTf3Xhjrifu6mjceA1%2BspNhsWhB2FGIEb17OFo7qOTvEjXvZfO9sCSot%2FxdpeS3DDIMiwVhZSXp9RxYJBjGgPbDJmAYhsWCYRgWC52TUEjykG9zUlBYzrWHYbGwNNo4Wlfcyi01a5mXruRx7WFYLCwNR3tVTvr1IrOWeTLmpryW1MhHMwweYxgWi2bAxbnV4aNRN8xa5sGjv8lrtYQMWt3gqsSwWFgAYsaw7w6lVZSVV5mlvOS0fFxJK6i1YBL9vcpViWGxsADE1ILWKquobeHmeQhs0UqtmQzVKBSOBlclhsXCQhBTC4ZsSyiJvZjdrOWs2hSHyyn5tUKRRIsPv7SG%2BSugaCknci0D2R1dpTMHjqRP9u3natXe1bZZhGKHtvciYY8E3IyOxzquSgyLhSV5FxnqSy7OVan7DqWNKSqtlLy9XOQnSZuK6KOY%2Fb%2BROHrqhnb48RWJxUiy4BQhVFyVmJZOi3xS0tcTMyRJ2qBSWSn9%2Brsi4CF39PRoja6dHAw6vqikQkwvgJNnM%2FHD0d9ILAp0E1QLhb8kYUZUPHiSZIbFwpIZ0AcBqEKoVO09mSYmEX0UEo7SOkCtwHPR5%2FA9VyGGwxBL78PIRGKnDthBDduDlnbkBSSRcJRSYxdP2lobmE0BHZNupcZJtYRYNdDVSkIm5TCZhOIUVx%2BGPYsWhvwWruqJgEaScHSms3ZvhDeRRunT6dMBcdeD327FMAzDMHfg%2FwEp%2FejCVVvQAwAAAABJRU5ErkJggg%3D%3D)
+
+```
+section_ref
+ ::= '~'? SECTION_NAME
+```
+
+referenced by:
+
+* section_list
+
+**erase_stmt:**
+
+![erase_stmt](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAATsAAABRCAYAAACtxAFPAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAEQhJREFUeNrtnQdcVFf2x3%2FDgIKKBgsWNGABQbAgimDvJqtiib3HFo0tahL%2BcRPXJOYf3USjrkRdjYloNEGsa4sFJVEQe5dgBbFRohQFgWH2ngszMLQZXBBGzvfzGd7MK%2Fe9ue%2Fc3z3n3DsPgGEYpgygKImTujlBXdYq%2Buz1kqlrvh%2FM626%2FhmJaUic%2B88f6MmMorTqML%2FXXWJbuB%2FP62a8hmPCtfHXeE3tQDNsvix3DMAyLHcMwDIsdwzAMix3DMAyLHcMwLHYMwzAsdgzDMCx2DKMhPv45njxJzHf7vfsxSE%2FnqYfMq0H%2BgqKNC2qGXMHj%2FHbSt704mTNvPSIiY3TWVba0wHqfGbj%2B5z189tUW7fpGDWph6ID2cG3eIFc50%2BauwfOkF%2FI4hSLrly9JySn415q9OBhwAYmJSahevTI8Wjlg8rhesK5RBf47g%2FDL9uO5ylvwyTC4OL3JFlQA63wP4XHUUyz%2BYmyubakpafDo9jEuB69AVatKXFkMikt%2FNMdLsUtV4YGbE7aZKjEjr0L1bS9OLl65g949W8HTvXGWQosLIeISknA1NALrV05HSooKJ0%2F%2FiYGjFmGv%2F2do0riedv9rQhSPB1%2BHiYlC7uPp7qjdNuOjfyNelLNowWjUtH4DYTcf4Fchbleuh6NrjWaIfBAr95s73Uvnut60qc5WyDCvgJfVH3cnDFApsCJNhWriYwUpdoqMcHawSoUBotAdOQvVt724aWxvoyNQ2TFTKrXbOrV3xu%2FBV3E86JqO2JF35vU3dyiVCvjvCtbur1arcejoBfj7eqOVayO5rp4QsW6dmiEtLV17fLWqlvmev6zx89ZAnDl3E3EiRK1TuyrGj%2BqGBna1tNu3%2BP%2BBA4fPSa849q8E1KhWWbst%2FF4Uvl93AFHRT9GiaX2dcv12nEAzZzs8inqCcxduoc9breHQqA5%2BO3IeO%2FacRHJyKnp1c8XwQR3k%2FuSlr9twSHRKEdLT92jdGIP6tdXe74DfL4tO0QSODnUxbmRXVLAor%2Fe7nT1%2FCxv9juEvcd0d2jrL76ZUmiD5RQq%2BX7sfk8b2xJ7fzuDho78we5qXToSQkxu3HuLM%2BZvo1M4Ze8UxlStXQL%2Fe7ljyr13S200WEQVd2%2BR3e6FSRXN5zHc%2Bu9G7Vyts%2BvUYbt15JN%2BPGNxRWyaVRx1xVHQc2ns4QZWejinj35LbUlLTsH7jYQSFhKKKONfYEV21Nm3sFFZ%2FNCKnUqNu9h%2B46eTs1BlhLRUaKQr1I%2FevMNuLiz9v3EfwqVDt6%2FS5G3nulya6gNjYBNSrW0O7TqVKl43lHS9PDOjrKQ2PjFdWojBW%2B4Y2WPvTQYSG3deN702zqoYabfbz04vyUWWRqKg4uLs5YOKYHihnZoqBIxfJhkYsX%2FUfrPnxgBSdtm0cZb1piI6Nh9fQ%2F5cNcdTQzrnK9RONeOzUZfjB9zASniXL9ILvlqNYunIXhr3TQZyvu2zMGzYHZHjaf%2F9R3rNxolG3bmkvBZbY%2BMsx%2FFvcz0H926JX95ZCdB4g4l6M3u914dIdjH1%2FOdqKTm3C6B6yE5z3xSa5LTkpFUvEdfQf%2BbUUnBjxvdR6Uo03bz%2FEV0u2YvR7y3D%2FYSxixPencsgee3ZtgWFCtM9cuAnv%2BRu0xyz12YWpc1bJzqN75%2BZY8PUWnDwTphViKqth%2FVpCyLrgdvhjrP7hgPbYyTO%2Fl%2B1k%2BuTe6NKxGd59f4W8htcJffpDIufWBPdUwHaQ0OWVsyugUKmk%2BrYXt6dHvWnQqT91cnZk4JqcGzUIgvZp6mwrjUnDH8HXRM9pgRbNMjwJ8jjIW%2Bj3tzby86qlU%2FD3LzehR%2F%2F5MC9fDk2b2GLIwHaygWkIE0a0ZOXu3Dm7ymUvZ0ceTaIQI2pI5AH%2F9HOAEJNo2NWzxirR%2BPw2fCQ9NOLO3cfSiyE2%2BwXCvZU95s0dJD939GyCfy7XNa2JQmQmjeup9brHTVmOX378UHr2xIcz%2B8tzkNdyLfSe8Ip6SlElhg5sL5eU1nB0sEGXDi6yM%2Bvd083g%2FCIJ55AB7eRnp8Z10brLXHwy%2Bx3tPj%2Btmik9f0OpZmWJff6foXw5M%2B26%2Bd5DhVjGi%2Fp7JK6xmRD3QzrH%2BK7%2BADZ1qsn3J0KuSy%2BXcsir1u%2FHVOHFaTw56xpvYP%2FBs%2FL95WvhQugiceLgYpmqcXezR4gQyX2HzmLme31eOxvMpT8K7Bfd7Rc5PTmDxE6DCOQuCP%2FmLbWe7WlpuCNOalFcX27u9H7SpS%2BIiPsxUpSO7PlShh4atu0KEp5eNWwVYZImTPXfGawVO%2FuGteH300eyAYeGRcowYP5Xm2WIMHJwJ7mPp2hQa5ZNLZLvYsxPjiCvZN7nG3FQeD3NXerD6o2KUpQo5L%2F%2F%2BC88e54sO4u8CBX3RiOC%2BWFtXUX7%2FunTZ4iKicOYKctEGJMVLtq%2BaS2Xs6b2FZ7XRvis2YeWLRpKb4c6wLHDu2DCtJVw8ZyJVi0aoe%2FbrbXhbUHcvvtIhsnaaxGdoqVlBYRHRsM2M1KgdYWBQtfsQvfo8RNMmb1aerzOTvWQlJQi7Sw7JiZZtmtZyQJpokXLjkN4ckMGtM%2FzPJRnfiw87rY9vHXWZw%2BBi4rSZL%2BkP8IyeqepMUgs9Y7rm%2BYTIweJA%2B%2BLZXdR4DqxnF3QdhHNLC6MZ1eUFWZhXg5zhBgSH3zyA8ZNXY5tG72ll%2Fbs%2BQsR3pzH2z1aCq8vVO5TvVpl7NwXInvX6lWz8kmUN6EcB70ihIGfv3hbK3ZFib6HIA4GlHcdYKsyQROxZ1ex83BRWVdM1ZgmvkJYcRiNofcj8MRVHD1%2BBcd%2FW4SKFTJyYIeOXZRLc9GoaRoJdRrUSHNSvrwZEhKTDL%2BvFcrJTmvnz%2FNQu5ZVru0D%2B3qIDtANV65G4LC4hmHvLsGZY98Kj6wegg4vliP1p8%2FdxD9EKGj1RiXphRZEJXHN8YlZqQkS8OfPXmjzaUWBz9r9sKldFTs3f6INnSfN8sk%2FV5UtJ0jRSXRsXN7XLq6xvl1NHNn9RbELTFE%2FxNPdEQ5pCviIQl2EEW4RlhigTMc1uzCEbxX9a172mV1%2FxHKNuRnWJ6divOgmJqoViMsrhM2Vs6NCxGKrKMBJvCJFeOp07jrm6NteUtNScvLN52NR3swMMz5aKxseufkO9nWw4p%2BT8N3XE%2BRr%2BeKJwiuxw849IYh9kiB62lXSo9NAc7%2BCToaWWHKXbvDpMNw%2BF4o9VLdxqbAT9R6oUuCkaxN0K8n6TUlJhVKESZp85vHga3iWmCzf00g2eUBbd2Z40FS3p7LlVt2F17VP3A8SQ2J%2FZo4tP6iz6tTORYS622UulqBjjwReku937g2BUmECN9eGeH%2Fi20hLV8nOjXJtcXHPpOiNHtYZ9W1rygEHfXTt2BR%2B209o849%2BO47LAZgGdkWXlqaySfQ1Ynrk90sGH0s5vB83BcgBGQptacBEA%2BUZHwqvcdvuYO068khJTEszZM9k12TfZOdk72T3ZP8aoTNEn4Iu4QotlUrYi0Bjq9gvQewcWZBnR4WQUoaYiULyEDB924uNybO%2B1%2FlM87JoflZOzMqZYt3K6egz%2BEss%2FMZPTjnp39sj1379e7cRYW0QRg7pBBPRYPoMWSh7R3PhJT55mihHyDQ5IJkzPHAaNo6ndStjw8fafFFxcvMmXojFwpaOMmWwVdi1R3F5ePro1rEZ1vkehmuHOUKMzGSHUK5clgkt%2BnyMvFc%2BmQ2xUYPaWR6rCCVpcKhlh9kwER5br66ues%2B39OvxmOW9Fk3bzYJV5Yp4Ev9M5tXIS6MR1%2F9b4AtH%2B7oyNzh7qhfq2lSTYkudHYkUDYpQx%2BbV213vuSaM6o6LV%2B7Cs7s3aopwlQYh1q6YVuCIa2GhQZ2h736Dlh0z%2FIc2rRwMPpbydTQKO2nGSmH%2FlujcwQUhZzPMwDJz3unceeul3VPoTKO9S0XnXlohj04lhEmI0xgSOEP8AH36k7luThsXLBb9o3dOT0%2BR6SY%2BF4WsFoXkGY7q2%2F4yYVNpegw4eYE0YkbUtraCqZmySMvP%2Fljr%2FyUMEPX2KeX2RRk9izqMLcz9uP8gFhYW5fOcDExTQignlV89Pnz0RHo3hZlITJ5avAiBbWpXkwn4nOtpalD2qSU02h4dE49KFcxhVcgJy%2BSRPhceYs5zFaV3R4M2Oa%2B5sNAMg59%2FDYT%2FRt08HeUFqTOxrl6l1NlvDps7KBa%2Fi%2FIWGrDvS%2BkPjdaS6IkLniLOkzHPTriD9QsqRN92Y4eMup4RTBK2TMK3CRaY5uqM5uev4mJJXYdmtDAvqAFXsMm%2FEeeVf9NHlSoV5cvQ9RQCZ7%2BfJIoTZuSfG6OBiUlje8j3NIJKr4IgQR%2Fz3vICQ2IKrfOCpuu8jK3djYiC9z980bhRnYwwfk8Ili2emGu%2FWjWtSr0dk%2F0iHU2FPXsZsv%2FL6k92T08bxuor6HUWOmPi2F0kuzXBZpN00HyIi1wjhoulv%2B%2FHRVYeCXpRlmcIlBMdM6wz7oRHwdzcDLt%2BmSfzkUbpXJD9KrCZ7LkQovXSaI435aZgZKgRIFz6D7giyhY060Df9CvjMWF4KtRY9spFls3IuFCpcVUBOHBNMMYK2S%2FZMYsdU3APnyhd8hpcE4wRUyPTjlnsmPwJjpR5DnOuCcaIMc%2B0YxY7pkDUABRcDYxxR7Kv%2FmdnLHYMw5QJWOwYhmGxYxiGYbFjGIYxIkpsUnH239sxJQ%2FfD4Y9u2KAfkxc1M%2FFYvh%2BMAyHsQzDMIzxYcyPdmeYkrJf9uwYhuEwlmEYhsWOYRiGxY5hGIbFjmEYhsWOYRiGxY5hGIbFjmEYJn%2F4H%2B4wRjVJmX%2FWxrDYMf8TpemflucHP6yA4TCWKVNeKP9cjmGxYxiGYbFjGIbFjmEYhsWOKYXwv1NkjJUS%2BTeKLHbGS7JnXf5H2YzxkWm3ySVxbhY74yQ6qRJqcjUwxkam3Uaz2DGGxrBhSgWcuSYYY4PsluyXxY4xCAUQLP505ZpgjNB4u0r7ZbFjDCHdBNuEezeis13J5e2852%2FAiIlLkJKaprPeZ%2B0%2BbPILzPOY0ZOX4cath3wDyyjSXoXdSvtlsWMM4fxVXBSLywkW%2BLAkzh95PxY794bgbng0Dh%2B9qLPt5u2HiLiXd0rm9LkbSExM4htYRsm018uZ9stixxiGUo3pYjGnpSP6vOpzb%2F9PMHp1c8Xg%2Fm2xbXcw3wxGL5l2OifTbksEFjsj5VQowtIVGKxQwNfNCZ82aoTyr%2BrcJHADvTzFywMBgZfw9OkzviFMnpBdkn2SnZK9kt2W1LXwU0%2BMOZy9hiPujvBIU8CnihmmtXTCFqgRoEzHNbswhG8FVEV9zguX7yA%2B%2Fjk6eDaBUmkCF2db7N5%2FCmOGd%2BEbwmCwCDruOsBWZYImmYMRw9XAFVM1PM5eLzmhY7F7TTw8sejh6ozmJmoMFO9npithf9sJtm7F8CuLbbuCYfumNbZnhq81a1SB%2F%2B6gVy52%2FOST0sntjF9HhAvDuyGsL1h4c2%2BVVI6Oxe519fIyDOqljMpQ4UhLVWHX3hC09XBEkFBZwrKSBQ4du4i7EVGwEyL4quCHeDIsdkyxcfT4ZVhaWmD1d1N11sfEJsg83tzp%2FbiSGBY7xvjxFyHsgL4eudbTum%2BX78CcaV7yM821o5eGWjWtcDZwiXzfZ%2BhCnWPHj%2BqOLz8dwZXLFDscCjAyjDW2x7JzGMsUFp56wjAMix3DMAyLHcMwDIsdwzAMix3DMAyLHcMwDIsdwzAMix3DMAyLHcMwLHYMwzAsdgzDMK8F%2FCAARpL9d6cM8zqi5CpgHsbgc3rVqYEFxnTNfOcYDmMZhmEYhmHKIv8Ff9i5XBG%2Fx4YAAAAASUVORK5CYII%3D)
+
+```
+erase_stmt
+ ::= ERASE ( address_or_range | ALL )
+```
+
+referenced by:
+
+* basic_stmt
+
+**address_or_range:**
+
+![address_or_range](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAYsAAABFCAYAAAC7dcr7AAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAFSVJREFUeNrtnQdYFcfax%2F%2BnIAgCKiC22LCBFVGxRQlGBTUEY0miJhJ7rIl86tWbosZrol6vlxsLVxMTYhcbGsvViJoYFBQrFhAFVFRApCPllG9mDoegD3AOCIf2%2FniWPWd3dnZ2dt%2F3P%2B%2FMnl2AIAiCIHQgqYidOtlDTVVfPQi9XTHXEEEQhkVeUTu%2B9McWqv0qTvc3J1IlEEQNQUpVQLxulEiRIkGQWBAEQRAEiQVBEARBYkEQBEGQWBAEQRAkFgRBEASJBUEQBEFiQRAEQZBYEARBEDVKLJw7wra4RLrWlycfTlqD6zej9Urrf%2BBPZGXnVMqKjk9IwfHfLtMVRxCEQXld%2F63dXohFrhKPneyxp6hMda0vT0Z69IatTV2d6dRqNT5b9CNSU19UyhMWERmLlf%2FeT1cuQRAGpbT%2Bu6c9Rjg54KFCiSj%2BXTwbSqIRjdFKJVtpjwNyGWYHhyFOu5Gu9eVJ4vM0SCSaZ9X979QVmNepjfC7sQj8%2FQaaN7PB%2FNmesLQ0g%2F%2FBIJHGd8tx1DEzgdugbnBo94bO%2FI%2BdvIyTp68iN1cB5x7tMNqzD4xrGSEo%2BA52%2BP%2BO9IwsvO3SGePGDBDlSEnJgN%2FO0xjs6ojNfieQ8CwFH33ggkFvdRX5paW9wCa2nJexroUZ%2Bvd1wLAh3eEfEITExDT8a12ASDfFa7A4luLIzsnFlq2ncD7kDiwtTOE1diCcHO0Q8ygB%2B9jxTpnA8jDX5MGjFpVKjaGDnXDoaAhsbCxx8fJdBF%2BMQNfOLTF72jCYGNdCXHwyAo4EY5RnXzFXqlSY%2FPEgsiiCqKaU1H9zkVBK8B%2BlGk0LPsjnpTELtUY8eKaPClMiXevLA%2B78n8Yn5YvFxJnf4%2FHT5%2FBw74EbN2Pwzeo9Yp2NtYWYN25UH280sYaZqbHOvDf%2BeBwr1uyFa%2F9OGOjSBcdOhCI6Jh5%2FBN3CjHm%2BbFlnTBj7FnbtP4fv1u4T2ySnZmCVzwEsXroVjl1aoUe3NpgydwNiHyeK9TO8ffH4yXN8Ms5VOGkuRqJ8VhaQG8lE2fgkZ2dMF5NnrUfk%2FSeYNXUYXN7sBK8ZPoiKiUPzpja4Ff4Q3n%2FXPIzx6vUoLF62DZ07tBDfDx0LwdQ565GdnQuPoT1xMvAalny7S6x7Epckyj96wkpERj0RAkYQRPVHl%2F%2FWRhJKYD%2B4ULyCXEemQol0rTdkpDF9ohs%2Bm%2FGO%2BMxb1dzxcVz6dRRzD%2FeeaMBa1bpQKFTw8T2MHZvnoVtXO7HMc5izaJ0vZwI0kznoEcN7ieVNG1vDfeRSeLMohlPLSI592xbmRzwHj1zAdSZcTRpbIez2Aywb0Q%2B9e7YX09jR%2FfPLd%2BrsdYwe0Vev47x6Iwr3op7Cz3cupFIJejq1wYWL4TjKBG3mlKFYu2IS3Ectg8%2FGw9i9%2F098v2oKmjaxyt%2Fee5YnvJhgcVq3bISxk9dgxVcfie%2FGJkY4sG0RLFi0QhBEjRUNjf%2BW4JgCWPZqJKGXWGhRMZ%2FFQg83tY71CgWi2E5rG%2BJApbK%2FXp%2FAu2Zyc5WlyieORSu8y0jbGs%2FPnznme1FxootHSxu7RsjJVeAJi2hEWMdEQisUHAtzUyiVmnJwQZm3eIsQsW5dW2Hi%2BLfRpWOLEpfvbuRj0WXUZ9DCl5Y3Y1GFVig3rp0Ot%2FeWsshjKPr2sn859CzwlolWLWxFd1oGmzi8O6qshYKePEsQVQvuv5mbGKZQYxSbq3QZsLyIPq4gtmEsm7%2FNMvyBzT8vbj1raK8sSWRRGRwLH9fgDj85LQPW9S1eWmdexwRp6X8NlHNHq1SqYMa20Trcohg%2FZoAYlOddZEdPhuJ9r9W4cm6tRtHV%2Bh8235ddy4Y4cXBJkWn2BQShk0NzBBwJwacT3VG3rlmh6ZJS0oVAmOrRNVdadL0EaTQgi26L5kopHFhKV5b4Q1YbYXI1ZobcQQSZLkGUnJ7t0VYhwXpmTx2ZPe1knjVQpsKtFhGI8QeUhfnbgv6bzf9rYoQtWbmYyBr%2Bk9USpBTWBSUa0q9mwmb%2BLAN7Nj2Sy2B%2F%2BTbm6VpvqC6o4uCOn7eWeR%2B%2FPvBB8e6OrbFh87H8ZcGhEaI17zqgM3bu%2FUN0VXG27jojooNXRaVQB37ovOim4t1GMya5IyMzC9nsTPCyPWV5Z2Rm61W%2Bvs7t8SA2AQePBOcvi3kYj2th0eJzwNFgnDkXhv3b%2FyaiitkLNokuNC0paZlizkVuPTvGIQMdIZNV3M9q%2BIV7MQL3L9%2FBr%2FyaSclFC3Y9nVVKcMHRAQPJ7AmiZHC74fbD7YjbE7crbl%2FczrRCoY9%2FD7qOMD6XydCGtWf9Wbo0lvhRcZEFz4QrTbARy6QQAdC1vsKZ5jUEXp%2F6oF69Opg%2FewRGefYpNr3PykmYNncjHPt9DplcitomxvD3m48504ez5RvQd8hCWJqbCYf%2F88a5epXBb2cgvvzHDrS1a4yo6Dh8teB90eLnYtGlY0s4D5wPmUSK4%2Fu%2FRqOG9YoVs582zIH3oi1YtnK3ECA%2BYL32u0niTqsvvtnOyroQprWNsfzLcRiaN37x%2BUwPsf32PWfht%2BM0XmTliLvCNvnMqFTnKjISXDWXd2svujL9WQupF0UYBKF%2FRKFkjp0594%2B5QOjTXtPlv%2FOWzXPuiJW5Six8NdKQ5IUpmSwTX5ZJod1JutaXFB4WlddrVZOTM5CjUKCBtaXe28Q%2FSxGtbqt65i8tT0hMRRZztvzupZKQlJSOdCYw%2FA4t3v1TEB65cAevveVVH57GJUHKyqfvMU2evQ5v9nYQg%2Bm8C60kdVESCr5W9XXexc2uhy%2FYrD%2FLYzC5AYLQy2ZOsNnvzGaW65G2VP6b3y3FRYMZ9nS2H1MRWbBwpGVxmehaX5nQ9tufCLyKTT%2BfKDLdVwvH5A9uF%2BVM%2Be2upYFHNnwqDNsGmh8YrlkXgPMh4UXmsfeXBfmfG9rWK1U5uCjxqbJj%2FgL%2FTKuNmY4d0OXKTVwjV0AQxXQ%2FMTuBCp2Y3Xjok760%2FrtgpJHfDaUro6oiFAUZ7NpVTJUV71nvllve%2FA4sfW4friyciUaWkwN2SFUYyb6SWBBEMQg7kWAHt5sSOP1So92eHiRYDenj3B6tWzWqWoVWI5CFyr3p7BGELlNhdsLsxeAiRVVPVAaUatyUAG2pJgiieLidcHshsSBqJLXTRahrQzVBEDqxybMXEgui5nH%2Bkeh%2FNaGaIAidmOTZC4kFUSNRA6W%2F%2FZYgahCSPHshsSAIgiAqFyQWBEEQBIkFQRAEQWJBEARBGAB5Re244HOFCMJQqC9NNdp7%2FsLcWxFJH4ffS2nzPCXHOOF5ls6Bdat6xgqz2kbJ1vWNz0Y%2BePHt6eDM0PIuK70jpPrwOs9Oq9Fioa04MgbCkJz82enTz3wOro6ISjUb7voGPKc3Q8MGpmhgpfuO3fjELPnT%2BEzrc5fiR8bEPnjXw8X0UuyzzPGhYbhXnmUurwduEtQwrjKRBUEYLJpQL5Hu%2Bc%2B%2B3at8w0aNf88Oqxb1QC2jkvXAckHhU2f7%2Bpj8QVv5rl%2Bjev2wKyKseyf1e5duKI9RLRP6RIlVOcKoULGoDqEZUfnhQrFl991Ra77ogU7t6r12flxoPh5hB0eH%2Biazvr5wuLsDpl66BQoBiGoNDXAT1Rre9cQigFGrF3cvE6EoCM9v3dJeMrlc%2BoOjA2gQjiCxIIiqCB%2FM%2FvXUw9XjWRRQ1kJRUDDGvttKIofkvyzCcKdaJ0gsCMIA%2Fh1l%2BMgPftdTZEya2QfDW5Zroad92A61aknlKjV2O3WEHZ1GohypkEd9kFgQlY2s3k3L7mGCt%2B4mTXAb0KTEg9klheffs4sNt2I5lPgnnUaivMizj6yK2DeJBVGZSHhRB7ZllVn4%2FVS7ft1tDVLwwf0b8xl%2FsXo%2F8dpLgigH8uwjgcSCqNGw2DpCJkGHssov8Xm2SZOGpgYpu0PrutpOgvi818MSRJnD7YPbCYkFUaORAOfZP9eyyu95arbEytLYIGVvapsvSnXYNIjOJlFORuIq7ITEgqjJqKTYx8KLsS4tymbcQqVUQyozzE95tPtRq1GfzZoZuu4%2BnLQG129G65XW%2F8CfyMrOqZTXQHxCCo7%2FdpmMoRCEXTD7EHZCYkHUZK7cxDU2u5FWG%2F9XhaMjHlnYGnq%2FIz16w9amrs50aqZmny36EampLypl%2FUVExmLlv%2FeTMRRCnl3cyLMTg0OP%2ByAqFTI1ZikluNCtPa5evoNfq%2BphGHqHic%2FTIJFoopv%2FnboC8zq1EX43FoG%2F30DzZjaYP9sTlpZm8D8YJNL4bjmOOmYmcBvUDQ7t3tCZ%2F7GTl3Hy9FXk5irg3KMdRnv2gXEtIwQF38EO%2F9%2BRnpGFt106Y9yYAaIcKSkZ8Nt5GoNdHbHZ7wQSnqXgow9cMOitrhrHl%2FYCm9hyXsa6Fmbo39cBw4Z0h39AEBIT0%2FCvdQEi3RSvweJYiiM7Jxdbtp7C%2BZA7sLQwhdfYgXBytEPMowTsY8c7ZQLLw1yTB49aVCo1hg52wqGjIbCxscTFy3cRfDECXTu3xOxpw2BiXAtx8ckIOBKMUZ59xVypUmHyxxXXu8jsYTibzWP20auiykCRBVGpYPYeoZJgNPM3vzjZ44vWrWFMtaIb7vyfxifli8XEmd%2Fj8dPn8HDvgRs3Y%2FDN6j1inY21hZg3blQfbzSxhpmp7urd%2BONxrFizF679O2GgSxccOxGK6Jh4%2FBF0CzPm%2BbJlnTFh7FvYtf8cvlur6SFJTs3AKp8DWLx0Kxy7tEKPbm0wZe4GxD5OFOtnePvi8ZPn%2BGScq3DSXIxE%2BawsIDeSibLxSS7XrbuTZ61H5P0nmDV1GFze7ASvGT6IiolD86Y2uBX%2BEN5%2F1zyJ5er1KCxetg2dO7QQ3w8dC8HUOeuRnZ0Lj6E9cTLwGpZ8u0usexKXJMo%2FesJKREY9EQJWEfDrn9sBtwduF9w%2BKuoao8iCqHzdUbdwqmd79FJIsN7SCDO72WMn1AiUqXCrRQRi%2FAEl1VLxTJ%2Fohs9mvCM%2B81Y1d3wcl34dxdzDvScasFa1LhQKFXx8D2PH5nno1lXze0PPYc6idb6cCdBM5qBHDNc0dps2tob7yKXwZlEMp5aRHPu2LcyPeA4euYDrTLiaNLZC2O0HWDaiH3qzE82nsaP755fv1NnrGD2ir17HefVGFO5FPYWf71xIpRL0dGqDCxfDcZQJ2swpQ7F2xSS4j1oGn42HsXv%2Fn%2Fh%2B1RQ0bWKVv733LE94jdPcU9G6ZSOMnbwGK776SHw3NjHCgW2LYGFharDzNppFpdFt0VwphUPeYPaHaiBMziKK0NsVJxQkFkSljjDYbBD%2FzYJUjffY5zkqGdrct0dzJ1T%2BB1BW9OP3Cw7s866Z3NzS6Wsci1Z4l5G2NZ6fP3PM96LiRBePljZ2jZCTq8ATFtFwuEhohYJjYW4KpVJTDi4o8xZvESLWrWsrTBz%2FNrp0bFHi8t2NfCy6jPoMWvjS8mYsqtAK5ca10%2BH23lIWeQxF3172L6UrUDy0amErutMyMjS%2FeePdUWUtFLqui%2FuaX2fHsGLdZVf5eRZNuFXUGAWJBVG1ogyNoVwrD8N8SZyuPUeuQo0ObSxQ18II9x9k4ElCFhpam8CuuVmJ910WT1SuDO974eMa3OEnp2XAur7FS%2BvM65ggLf2vgXLuaJVKFczYNlqHWxTjxwwQg%2FK8i%2BzoyVC877UaV86tFev4ILy%2B8H3ZtWyIEweXFJlmX0AQOjk0R8CREHw60R116xZ%2BPpNS0oVAmJqWX89nVX7SNo1ZEATjI%2B%2BL8JwehOt3UsR33x33xfcNO%2B5Vq%2BPkjp%2B3lnkfvz7wQfHujq2xYfNfr%2BwIDo0QrXnXAZ2xc%2B8foquKs3XXGREdvCoqhTrwQ%2BdFNxXvNpoxyR0ZmVnIzsoVZXvK8s7IzNarfH2d2%2BNBbAIOHgnOXxbzMB7XwqLF54CjwThzLgz7t%2F9NRBWzF2wSXWhaUtIyxZyL3Hp2jEMGOkImI7dIkQVBEJjmNQRen%2FqgXr06mD97BEZ59ik2vc%2FKSZg2dyMc%2B30OmVyK2ibG8PebjznTh7PlG9B3yEJYmpsJh%2F%2Fzxrl6lcFvZyC%2B%2FMcOtLVrjKjoOHy14H3R4udi0aVjSzgPnA%2BZRIrj%2B79Go4b1ihWznzbMgfeiLVi2crcQID5gvfa7SeJOqy%2B%2B2c7KuhCmtY2x%2FMtxGJo3fvH5TA%2Bx%2FfY9Z%2BG34zReZOWIu8I2%2BcygC6SohgZVAVFd4d04lw69Y7D9dfc4XKbdDaL85fRa1eTkDOQoFGhgban3NvHPUkSr26qe%2BUvLExJTkcWcLb97qSQkJaUjnQkMv0OLd%2F8UhEcu3MFrb3nVh6dxSZCy8ul7TJNnr8ObvR3EYDrvQitJXZTouijwWlV6Ux5BEFUKbb%2F9icCr2PTziSLTfbVwTP7gdlHOlN%2FuWhp4ZMOnwrBtoPmB4Zp1ATgfEl5kHnt%2FWZD%2FuaFt6d5ZwkWJTwSJBVFD4XcEGeqRH%2BkZuVWyjga7dhVTZcV71rvllje%2FA0uf24cJEguiureezWspElOy5Tb1Tcp9X3ejU6nCqxh9nNtTJZSk8UVVQFRXzM2MkmOfZhpkXyHXnom5RA3%2BU1%2F60SBBYkEQVQWresZnz12KM8i%2BTp57LOZqCeLZLI5qnyCxIIgqQuSDF98eCXykyMlVlet%2Boh6lIfpRutai7rP%2FD6j2CRILgqginA7ODK1lJL2069eoct3P31aG%2FvVFjQweaFDtEyQWBFGFiH2WOf6HXRFZN8KTyiX%2FVZvCcC8mTSsU99nkVFEvpyEIEguCKCWhzJfn5KpHzvr6grKsBYMLxZ6CUYsE5yTAxcry4DeCILEgiBIQfEN5NP2FYsq0RUHq73%2B5jdcdw%2BBjFO%2FPPvOyUKixnf0fopZhAdU4UR2h31kQNYLLt%2FBTd3uVdOu%2Be767DkXJe3W1htuApmhrZ4HmjesUu21mlgLh91MRcjUBv517zMQi%2FeUEXCj4uwck%2BOQSi2SotonqCD0biqhRdOsAN6jgL9G8%2BrT2a2XGxygkOMfmbiyimHD5Jo6XZVkrwyPKibKlKj8bSkanj6hJPElAZOOG2MPcsB2bbFg0cJ9ZbzYzYR5l19KxeTpLGytVI0QtwQ3myZtLJUhgW37AhOJimZf1GZbyqbENltCZqybXHzufVbXs1A1F1LzWnaaraIR4C58KI9nnwSzakLA%2FXW85qqNWI5kJBX%2FKXQiLJpZeosFsgiAIgiAIDf8Pd8fA4bgNvA8AAAAASUVORK5CYII%3D)
+
+```
+address_or_range
+ ::= int_const_expr ( '..' int_const_expr )?
+```
+
+referenced by:
+
+* erase_stmt
+* keystore_stmt
+* load_target
+
+**symbol_ref:**
+
+![symbol_ref](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAR0AAAAlCAYAAAB%2FND0PAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAACaVJREFUeNrtXQtYVFUe%2F915IQ8fPIURNEB5KK4hovSVj6iUfLPaJ7thtlSofVoZuaWZK22t62qbpX2fFKG19S1iZqu4bduW%2BS1p6GgaCo4ohDxUnvIQRWbm7rkzw%2BygwAjNmbkznB%2Ff5cy9557%2F%2Bc15%2FM7%2FnLkPgIGBgcGG4OyRaUwk%2BP5SwCeK6JYxr0qVf3b0h%2BcLzzc8ob7YOKq%2B8ZZLTf3NbvP09nTRuLvKr%2Fl4uRy%2BcOnGxkP5rSfsUS53y9sefFn7pAuZvb6s6r9ZTl%2BhEyanULX%2F9a6Y5S%2B888Xm86VN7rPjgzB%2F2XD4%2B7nBz3tAt2mq627KrlS3%2BuSpqheUVV6aN3eam6qytjX5xBlctFW59Ia3vfiy9kkPUntkqvTFhtSUeU5fqe%2Fv%2FIf%2Buwrb5VqkW81L4DdIRnvV5WzbVbR6xrRAxRtp4xEX7Yuhvq5wd%2Bt5HBHihfNix%2Flg0exgiY5HYEFRQ6qfD3eyqpq%2FQNW76QNve%2FBl7ZMuJGyG6XjIeXfv7qzdxQvfWheLJxJDoZD3rRqFdEL6916PG%2BCm4A5MGI0UMfO2NV8GJjoMxqlJZvb5hZvXTsDYcE%2Br2BTsbE%2BPk8pkksxoSh3ZmrxtwZeBiQ4DDIuvud%2BUb04mo721BMe8I%2F92XggnA5dBPIhHxc6bJl8GJjoMRgi%2F9lwoa3ZPmh1Mxf7S34RDoZDIdDx2x0QhVOy8afFlYKLDYERhccOShKnD%2BryGYwmC3YnjfIXfUGXQYovYedPiy8BEh8EIdUlT6AMThlLNY%2FoUpRC4ku2B6DEYJ3beNPgyMNFhMKKuvm3AMH83qnmMHjnE8IFDtUSHBWLnTYMvAxMdBiPqm9o478EuVPMIHGoSBw%2ByPSJ23jT4MtCF%2FoqsSVEYmn8GV7s7yVI8LZSWXcXq1z4y7aevTcKYiOF49Y%2BfQF1cpT%2Fm5emBsJFK%2FHpOHELu8Ted%2B%2Bmew9h3IP8Om39an6w%2Ff3HqVmh1WmRsfRYDPVz1cd%2FlncGR%2FHNISX4IK1Z%2F0C2vDh62hk7LQyK1fNV6S6sGG94pRGFxE67UtmGQhwzzpyuxcvFISC2k77DP8%2FDirHTF%2Bt3y7tOoSYEva590dKAjvb6S2rWoionEXpkUK7syaime2qgb4I031j2Oh%2Ba%2Bhtzd6zAyJEB%2FvKCwDJNiwhA%2FZSxx3ZvxzeGfMCMxHVvefBLzZk7Sn3OpvAYuChlWpM7sZDPA3%2FCT7fGTxRim9ELGzq%2Fw0sr5%2BmO1tU0oUldgyBB3pK2Yqz%2Bm0eiQlLIF27ekwt%2FP4MoHKX1EPZLU1rfho8%2FLEBU2CN6eCpwqvIazRIDa2nR4eWn4XdngDJ6Dq6OMnvbg29%2FaZ191YGIkErUc3tVo4U12Ddeec4Zp1mNaLRKJ0X23G7UUTwtyUilCwXdUhotCbooTKvi%2BiRH6z7MTYjHn0YlIfe49xEaPgjLAkMbXd7DpnK6w%2BrlEvLDmQzz5eDx8vAaZjg9wUZjStd%2FS6MPx40IwIsjPITqgj5cLvv1kCsaGD9bvP7v%2BR%2Bz5sgInzjb01pTNb5PJzCnF6aJGJEzxx6wH%2FUXNt7%2B1z97qQIfYEEc30PwW2k5rOrzBPRWMVhCjOYI71Jt4e0IYVSIjgnDwK5XpWE1NI44eO9dpa265YYqPCAvEjPhobNtx0KnmzB5kLOkQnHYyEpZVteo%2Fj4sYInru36vqkJ1bjgJ1o1PViTO1T0s6IIhNzGiUa4HPIQhOV2s6PRjVK5qleFtPu7rDPUG%2BqKiqM%2B0XnivHW9v33zFnHjjy%2F154GnFdH5m3Hs8sme50C3YHD13BX7PO46dzjZg5zR%2BrUkaJnnN4yEA0NN3CcKWr09WHs7XPO3SAw5fE73r9ds%2FmrkTHtAAInCKuUAJvIV6jQSnJ1O6t5FrjdYQGB5j2p06OwtaNT%2FWYZnigDx5LvJ9U%2Fhe4f1IkNW72eEZL1melesHZ%2BFIUnl4U7BC8X1kW7nDl3N%2Fbp6ADZOo1S8NjIQl1lgzJupm7HSEJK0n4MDGYScJVPcXLZdjUG0%2BHRsOoulxP3FM11qQt7HXa55fPweSENfDxHkStUq3xsKTeltuDcX5Q%2Brki9ldeDsP7XEkz6hoMnk5QgJtDlHN%2FaZ%2B3l4u5DpAwY4AcWTfbkUIckad5Do1dTa3uEJ0OI7zBSL5cikhBTEhmq3qKt%2Bfo0dx8A0ePq5H%2B52wkJ03D6PCgXtvwJZWZkvwwPtj1b8TFhsNZICf%2B7nClG1pvahyG86YdauQeuoy0p8J%2BsdcjBjhj%2B7SgAy9OisKmdi1e7k58zEVnjwUx2WNrsVEXV2Lx0q36z3OS3kTG28sx%2Fl7DfX0vrs3Sb26uLggPG4aVS2chacHkzoT3fa%2FfzHEg%2B1WTDXMsT0nAx9mHnGoNIePvJSi%2FfANSaQTui%2FYGA2ufVoBFHTAe61Z8OKPb1EqM7CBGupwmWYrvi%2Fva3x4HaS23X7V%2FDn3ecw84FG8qfFn7hLV0QPh1SxAfksEyko%2FhOh2ZFME9GbEUz8DA4Pzoqw6Yez7CvsTsoKVEDHaGcMm%2FcEsBTbRcb3co3jT4MtDRgY707IZPB8KQgQpNXWMb1TyKf25yKN40%2BDJQHjxZETgOBrrLr1VeaaWax7HTtfqQ49FMAq3YedPgy8BEh8EIb0%2BXw3kqujPdr%2FMMd0fzHKpJcFXsvGnwZWCiw2CE8IbLg99WaG6166jYL61oxs8VLR0to4T8vyRm3rT4MjDRYTBCeKWuQi5RZeeWUrH%2FyiazN%2FbyuC44EmLmTYsvAxMdBjMIr9TNzD5%2Fs0DdYFW7f3n%2FDC6WNXd04BKyxegk2CtW3rT5MjDRYTBCeIf3rXZ%2BwYo%2F%2FKC1ZgfOMfdCOORxwPEfz%2BK0GHnbgi8DEx0GM%2BQXaP%2FZckPzzNI1R%2FhtHxehr2slwprIopXfde7APD4l%2F2fwUvxebLxtzZeBDmSsCBwTJwuxc0KkTvK3vRd3ZO8vlcXd64OEqYEICx2EEUqPLtMIN36qS5pw7FQN%2FpNXRTpxS%2BcThA7MIZ7j8DsV8UzszVsMfBmsD84emYr5mSfUpkVFdMp6%2FBgkQIc9nOFRnX17ppGwJkKmKCRMIB7DkpNn8S%2Fa5fGLeFPmy9onXUjt8QUv1yJd2JS%2B2NBfKlX4vlTs1uCC0h85pJuEks2XjPolpPW0kSYkeLGKbpK1kHMqJTyO8RwKSA8bIeFQQ1IkkQ583Cbl0TveNuXL2iebXjFYGqUMU4tE4Q2XxhfOTSdeBEf%2B3LtJ4sHzuEY6sPDQ5GPEW0hX2WERthe8RcGXgYGBgcEB8T%2B8KKbBbcdKYwAAAABJRU5ErkJggg%3D%3D)
+
+```
+symbol_ref
+ ::= IDENT '?' ':' IDENT
+```
+
+referenced by:
+
+* call_target
+
+**load_ifr_stmt:**
+
+![load_ifr_stmt](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAesAAAAlCAYAAABiZsHRAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAEJ9JREFUeNrtnQdcFMcex393HKCABQELYsUS7Ah2o8beo4KJsRIbxlgiPDVqipo8jRrDQ2OJGhJLjA171KdG45OgIFiJBVFEQRGQDlLuuDczeBcgwJ1IuYP%2F9%2FMZdtnZm92Z%2Bd%2B%2FzMzuAQRBEARB6DSSsriogx2U5bVBA%2B8UX5vqQztVtPoSpS8X%2BaEMmG544NLlubeD4ybee5DQNDYhwzg6Nk3ra1qYG8tNKxvGW9YwvhDy%2BOXK836pgaT3CF2R7%2FyQlVVlAy56lbsOdHx7coVqp4pWX6Ls5CInZ352%2BOgTz8NrgkMTTYf2rocRM%2Bqjdk0T1LSopHUZUS%2FSZJFRqZY%2BAVFOYRGP3x3eyyQgIiZ1fGAQHpDeI8pSvnXOWJdXVN5zWXheVF%2BiPMuFUrlUum%2Bd997Vm4Ocx4%2ByxepFHWBkKC1SWdyw89TGrgamjmkm23M8tPO2PcFBjq2VowJuKU5SDxK6pvek1OwEQegD3FB77b3vvPazDpg40rbIhjovvBxe3oblnSuZGEmOObbAZGptQtcgY00QhM7Dh75Z5Ou8ZrEjWjc3L5Fr8HK%2FX9bZQCaTbrMng02QsSYIgtAevpjs%2BO9P1oxn0W9JGeqcBnvsu40lMkh%2BYBH2IGp9gow1QRCEFvBV3yFhSaZjhjYqleu5ftAcRkZSWZYSex1awZZ6gCBjTRAEoYHb9%2BMmDexZt9jmqDXBr9OxrRVfOSSDAt9SDxBkrAmCIDRw72GibXfHWqV6zf49rPmmMkvd7VuiLfUCQcaaIAiiEF7EpleqW9ukVK%2FZokn17B0JoqRZcKJeIMhYEwRBFEJsYrrEoppxqV7TppbaOTBjqR%2F1AlHWiJeidGqFWn5BeF7QSZrySxK3xV4YPbIbunRo%2Fo88eaYCW7afxuHjfkhMSkWd2uYYN7onnEd0%2Fce5364%2FjMtXgrHxO1fUtKymPr7%2F0J%2FYyxLH1MQYDepZYUAfe3TrbKc3nRga9hzzP9%2Bu%2Fn%2FZ4jFo%2BVZ9LPlqF%2B7df5rrXNtGtbFq2UTMmLcJMS%2BSxLEa5mbo2b0lPnDqAalUP95t8sGUtVjk5oQ2LRtqPJf38bDBHVDJ2Ejn6hEVnYCrNx5gYN%2F2pI0KIEuhhNSgdOVSdT2lEjUkZfDyKJLv8sOb2k%2FV50VkzWzeUwc77OMH8ztZU35JciMoFLGxSfnmzXDbhGMnr2D5Z2Oxf8cCTHcZgJUe3vju%2ByO5znuZloFt288gLj4Zh49dzpX3JCIGEvZtdJ81HBPG9IKpaSXMdPsBC7%2FcoTfCYFPHAl9%2FNg6X%2FO9iibszmjSuI47fuh0G%2BzaNRN1Uadx7PUTe1RsP0adnG3GsV%2FdWWLf5OFZ7HtSbOjsN74JaVtU1nqdk2vaTRT8iMfGlTtYjOCQCq%2F5zEETx8JP3Ixw9%2BxSZ8qxiKU%2BSHVnXIvkm%2BS4qRbWfHe0w0qEFnsgVCFVH1pLs4fDRCgXLtMMhmQFm5%2FQENOWXBb5%2Bd3HR9zZ8z66ChXkVcaxeXUtYWVaF86TVmPDBO7CyqCqOnzxzFXbNbUTUvZVF4tM%2FHJCrLEt2XpeOb4n9vr3a4sNxfTBg1FJ07tAMI4d21nlhMDSSoa51DbHPRxeMjQzVedxwq%2BqWlxbN64k8ntLSM7DX2wefztOP6bkXzIGTSLKjn%2F%2F%2Bfg1VzCrj3v0InPvfLTSob4X5s0egWjVT7D%2FsK87Z7HUKZswRG9ivvai3JrjMnDl%2FHZmZcnTq0ByjR3QV7crlbvf%2B%2FyE5JY3JShvm%2FPQU95GQkILtv55H%2F972QsaiYxKE89fvnXaivKSkl2IUiN9j9aqm6NGtBYYMcMT%2BI7548SJJ7WBOc%2Bkv6lIY6RmZ8Nr5u3DOqlU1gcvYPnCwt0VYeDS8WX2nTWJlVMku49TZq8jKUmJwfwccPeEPK6tquHL1PvyuBKMdc%2BRmuw4REdnzqHgc%2Bc0PziO6ia0iKwtTJ%2Brf6G9QcCJ2HAxDLYtKmDCyPiY5NUBty0pvWqwByTfJ9xs4fK9lP7mRVkiwTqGETc6ffsk1Z63MNt680PD8PAFN%2BaXJHz5BeLtrC7WhVuFo3wR1alZnQndHfcybCQz3VLkgPwiNxN3giELLrsk6nAvpgVdfBH0m5OEzIfSqlPoyPd%2FznkXGoX49K72pF1dOkVFxamU2%2BeP1eBoZi%2BGDOuDWX2H4as0%2BkcedN451nRrCmeNTHZrY9OMprFh7AL17tEYf5rydPB2IR2FRwjmc6baZHWuDSWPfwZ6DPvjGw1t8Jj4xBas9D2Hxsp2wb9sYHdo3xbS5GxHx9IXIn%2Bm%2BGU%2BfxTJHsLdQIlxZivtjjqLM0EDcG08ymWa7MHXWBtGvs6YPQa%2B3W8NlpqeYCmlgY4Xb957AfUn2j0VcvxmKxct3qYdSj570x%2FQ5G5CenonhgzvizLkbWLpyT3b%2FP48T9z960iqEhD4TClYf%2BWZ%2BK2xb4YCmjczw7bZg2A89iw8XBuDilRi9qgfJd%2FmTb032UxVJK4CD4IY6DzINhQpPQFN%2BWUTa3LOrXSv%2Ftxnx41HRiWKfz5n4BQRjw7euwvPknqH3UV8s%2BdfoQstvWL8mjp%2B6ovfG%2BvS567h2M1T9%2F3crJqO%2BTfYXmrdD4PUQxDAv%2FtyFm9i1dZ7e1nPG5IH4ZOYwsc%2B9bv7F5PAhfs7wQR2FE6YJuTwLnpuPYfdWN7Rvl%2F0%2BjBFDOgnv%2FWumID9mCkQ12mJjbYlBTsvgzqIcjpGhDN67FqojosO%2FXcZNpljrWlsg6M5jLB%2FZXT2SMXZ0D%2FX9%2Fc7anq%2FL0Ibrt0KFw7l981yxvqCjQ1NcvnIPJ5jC%2FXjaYHismIJBzsvhuekY9h78E%2BtXT4NNXQv1591njYALU6hi1KVRHYyduhYrvpgg%2FjeuZIhDuxahalUTvZUDQ5kU7%2FazFul%2BWDJ%2BPhCGfSee4Pi5Z2jW0Ax71nVCvTomJN8k32XGP%2BynBCflwPK8kbRWxlpFFms7FnoPVGrIl8sRyi5auTQrzOeW%2BdBLfiQlp6GKWfbQ1%2BHjl4XXyYd8ONxgH2LHFrk5F7qYKi4%2BBebVzYp8f7ry27Uzpw7C%2B6O6F9zHSiUOHruEr5eMU89162N9cy5A4kNnmZmKIpXznEUzXK7yLuzhsvIg9LkYglPR1LYOMjLleMYiHjHcxZSYSpFxqlYxgUKRfR9c4fHFklzJtm%2FXGJPH90XbVg1f%2B%2F7uhzwVQ3pd%2By3Mdby%2BjZVakW%2FymIGBo5axyGTwPxZK5rg9NG5YSwx3prDE4cOFxa3IylIuGtmYokv7Grh5Nx6Xr8ciNDyV1VdO8k3yrRPyze0nu90hciWcJVwVazhfVsAYuy%2F7YATb9mUFbmPbeYXlM4dr1etE1sUh%2BO3b2oohGu4pymTSHMIYj%2FsPIkQ%2B58CRS2hQryZ8%2Fe%2Bqz0l9mYE%2FL98Rw%2Bj5NiJrNu41DunvWOT7K46fTitpBeE0vKtYBc6nDvjwERdulbddHuurDdyZ4wopPikFljWq5srjDmBS8t8OIlcECkWWcBxVCqEgxr%2FXU0zF8CHME2cC8b7LGlzz8cj2tJXaV5tfi6%2FoP314aYHn8Gmf1i0a4Mhv%2Fvho8iBUr26av0OakCwUmIlJyT0WVRZy8Sw6Tcxb7zr8GJExaWLOesH05mIOu6jz1yTfJN9FlYu8%2FZ7TfrLtDyzg90rLxGRmxaYqJUjIbwhcOFR5C2Gb%2FawAO5bCZQawu3oHbpryy2Kx2ZABDmJYZsnyncL748SzaHjOwm3o3aMNmjWxxt3gcIQ9icLW9TPhsXKKOvFhH28WTeYlM0Mu5kEmzfAUj4tMmdgXFQE%2BVPWpmxNcPlqHx%2BEx5apuXDFxb5rPgWkDX7TDnZeNW%2F%2F%2BSWO%2FwGDhBPbu2Qa%2FHrgoHETOzj1%2FiOghr9LLV8EcvSTklQ%2FrzZwyCCmpaUhn31B%2Bb5Gs7JTUdK3ur1unt%2FA4Ipo5k37qY1zGbwQ9EvtHTviJ9RwHf%2FlURB2zF2wRzqeKhKRUseVKeAOrI39M0cCg%2FLxuwXN7CNoPOyvmq5s0NIPXN464drwv5k9rVhwLzUi%2BSb6L3lcF2E%2FfmwjiWwMDNGV%2BzX52XhI7ObywyJoXwi29nyErJB8DrCm%2FxJg%2Bd2Ou%2F3kHeG2YjV%2B93OG%2B5Ce07jxHDFnzFZQD%2B9pj5dKJr6JqX7GoLO%2Fzh9xYT5jugRVfjBf%2F81WEPPGhIO7V8WcCZ7sOzbWqWpfhKzAnuP5H7A8b82%2F84PHRa0fIfNgq5GEkJrp64MjuxeJLXV5wdRnAHBFPmJubYf7skfk%2Bh59L4a%2BaAte5m2DffR4MZFJUrmSM%2FdvnY86Moez4RnQbsBDVqpgKhfTzprla3cP2X8%2Fh83%2FvRjNba4Q%2Beo4vFrwvIgKuzNq2aoROfebDQCLFqYNfihX9hSnbnzbOgfsiLyxftVcoSL6gxuObKUIOPvvqF3avC2FS2Rhffz4Og1%2FN7837eLj4%2FC%2F7LmD77vPicUa%2BaniL58xyZbyiYtLh4tQQLs4N0LxRlQrhbJN864V8a7Sfr465dWqFVZkKLMwbaUtehemprJDNrJB8h7M15RdlOCjgolextUJsXLIQrOqsozU9FlCSOL49udiHzYqznSpyffmoS4ZcnuuFOJoVf4LwyvM%2BcRD9IhFpTBnw1a2vQxyT02Qmp3wFb14Hkkc2XAGpHknRhsjncZCy%2B9O2TlNnf4%2B3u7QQi334EOfrtEWZy8XRYaUv38OPkXyTfL%2BxfBfVfvLV4txoswvMYNcxEZE1C8cbFVaIpvyyhr%2BBiyeCKAjVvBZfHb%2Fl59MFnvfFwvfUi28K%2BrKrnt9%2FXXjkY16AnNaqmf0CjLXfH8El%2F3sFlnFgxwL1fkFPQ2iCK02eCJJvku%2BSp6j2M2ekLcrJcVDThwhC7%2Bnfu51Iuor7rHdLrGw%2B1aHN4z26Bl8JXdqvHE1OyST5JvkuFt7Ufqo%2BLwNBEBWCrp3e0s%2BosYqR%2FEVCusyqRuktELv%2FKJEEhuRbt5xW6mKCIHSZKqaG8RGRqaV6Tf8b2U9FSJTgr7pSUC8QZKwJgiAKwcLc%2BIJPQOnOxJ3xyf61OqUEUWxD04AEGWuCIIjCCHn8cuVv58LlGZlZpXK90PAkPApPVmnIh%2BzvY%2BoFgow1QRBEIZz3Sw00MpQG7DkeWirX%2B3RV4N%2F%2FKJHCA23qBYKMNUEQhAYiYlLHb9sTnHbrXlyJXmf1liA8CEtSGeqHLDlkSeFNPUCQsSYIgtBAILOhGZlKp1lfXlaUlMHmhnpfzuhdAh8JcOXaX7hBPUCQsSYIgtACv1uKE8kv5dNcF%2Fkq1%2B%2B4g%2BKaw%2BZz1O%2FP%2FiO3oVbiF%2FZ3gNIAC6jlCV2AnrMmCEJvuHobPznaZUl3ej%2FYvOdoqKxzO0sM7GmDZrZV0cBau7cYpqbJce9hIvyvR%2BOsz1NmrJNzn8ANtQS9JRJ8GMAiemp1okIb65zvVyWonUguCG0JuIMf27dURigyFPsv%2BD83YKl4fhCAz1FL4MP2BiqlmBT4F06RfBO6gkFZXPRZDJbxZG2FpeW1YXn9KlI7VbT6EqUnF%2FmWG40Q69rYxwysLUtWLAp%2BKAHSmbHlAYiRlsUks89ESJXwV0pwSwk0kEoQzUoYc%2FUvXCG9R5SVfOtUZE0QBPEmBGYPUY%2B0b4m20iw4sf3%2ByGLmWgJtf9%2FVTKlEPDPU%2FFcm%2FJUGWBZAi8kIgiAIgiCIovB%2FIcjMsZpBK2oAAAAASUVORK5CYII%3D)
+
+```
+load_ifr_stmt
+ ::= LOAD IFR int_const_expr '>' int_const_expr
+```
+
+referenced by:
+
+* basic_stmt
+
+**call_stmt:**
+
+![call_stmt](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAXUAAABFCAYAAAC18HbRAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAD5VJREFUeNrtnQlYVdXext%2FDYQZBEWcMTBwAlRBFcw69Zmllpo%2FD560%2BNL%2B8DqkN3OtzLZtupV60kq73fmpl5YSpXUm9mZppaaKIqDghgoIigwo4cw7nrrUYAkQOkxy2vL%2FnOe7D3vusdfz%2F93nXu%2F57n30AQgghDww6S3Qa6AMTQ185Dh6vuVwx%2FtrKFyGVwdpSHR%2FYvZzRryDd%2BoYw%2FvU8X4RUFCuGQBtId02HzXwRQlEnhBCKOiGEEIo6IYQQijohhBCKOiGEEIo6IYRQ1AkhhFDULUPOtZvIvJKjnhtyjUi5kMlMM%2F6E1B9R79EJzcrbydz2usbqdbsx592V6nlScjqCn5pToddJIfr%2BPwd4VNTT%2BMceS0RM7FkmkFiE6ups4euVqAszdSHQB2vv1ai57Q8KSUlpePujNTy66mn8I7cewIbIfUwEsQhV1dkgHzwb6IvzBiOUI1H3ftHli%2Fsoo1Fs9MEGaz2m%2FXYUlwpfZG77ff2P3jFgxZqfEB1zBs7ODhjYvwsGBz%2BCPXvjsGlLFNIzs9HYrQGGPd4d%2Ffv4VauvtRt%2FQXbODYQt%2Fk79%2FdzwXvh246%2BYPPEJONjbqnVZWdfx%2BTc7MHXSUBw7cQ6J5y7BZAL%2BvXk%2FGro6YeaUp9G6lbva9%2FadXCxb8SP2RZ1U214cF4yuj7TV1oFmwfi%2F%2BD8DkZp2Bd%2Bs3YVLaVfh5GiPAX074dlhPdX2M2dTse%2FASQT37YJI4fCdnewxdmRfnEvOwPKvf0T8mYsICmwn8mPC%2F4q2XFwc1eukcG%2F%2B4SCMxjw8MzQIzzzZQ%2BQxDVHRp2EQ62T%2Fbo0aiP6DqTSk1qiszkoxN%2BrwidEEj%2BI3pChRUzfli7xsNLmsEcPc9vvBxOnh2PnzETz3TC%2F4dWyNz5ZuUetTL11Fh%2Fat8MLYYHTx88KkV8JxJC6pWn01dXeFtYikFGX5cHN1xradh7Ex8rffhWfDLzgUmyD2s0Ls0UTMCF2GXXuOYsigrrh9OxfjJoQpsVDvfepiJTxyAOjfpxNemPwxziZd0tSBZsn424jnGRnZaNncTYh1PxXD9%2BZHqMFEkpCYir%2F9fR3GTwpDckoGMsQAI0s4z4x9H1Y6HUL%2BOEi1t%2BDTjcgSg4Xk439swopVO5XIjx%2FdHws%2B%2BU4NyPZ2NmJQcFADg%2By7ebOGVBliEczpbKEzNwLrIQW9FNZmGlUjhrnt98u5yxrnfuGeon8OK3LK40cPUMuRwkXLk3DxZy%2FC1lYP77YtVD20s69nlfsbIERj9fo9GPVs76J10q19%2FvV25QCl4%2FtSCML7c8YXbX%2BsX2cs%2FGCCej5COEj%2FvjMKRF8vROcSvlwyA1ZWOuUY9%2B4%2FoRzilJee1MTBVRfi36%2B3n3rEJ1xEekYWAv0fxsGYeDz1RHe1vZEYeL%2BPmCNEOf%2F9Lf7XZvh3aoM3Q0erv4NFfuZ9kn8I38k1qEFp99YP0LSJq1qXlp6lnPvTTwbBp4OHGpiL909IHRD3fJ3VYYsBeKe0M6%2BQqBci%2FGaMsPJDTGa2Gww4Kzp1qOn%2F1GkxfW4nxKJQUNTUwir%2FNtXfROzC%2FEUb0M67JTxaNlYurdAh1yRyev7OvDU4dDhBuT293kqIjG%2FZwbQRLrOluyoV3LhxW7nZXn8ILbGP10PVm9zU5p3%2F6kL8d4hZwhtvfoEWwq17t2mOhKQ0NGvaqGi7SwOHIkGXyJmQFOeykG7%2Bxs3beHrM%2ByXWd%2Bnkdd9iyDs1kuoidVZ86oYaTBgplnnmDijre9R2fhUvTBHLQaLBpWI5s7ztNtb4qDJOvaIHupwKZ2XduGu9vGRu9jtfY8u6N%2BHbobVaN2l6ePVrWmLKLt14caRgjBnRF1%2Bs2qHei6yLy%2F3uxZWsa2jU0Fnt01aI0A8b59Zogmvixxe0FP%2FQt77EW6Fjipz5RwvX49r1W%2Fdso4GzvRpgyv7%2F5PuO7ZvehZOjXdnuyGSq1XyNAvSJ7eFptIKv2DNY7DxWvIOj1iZMERO7U5S0B4Ogjmhv0CFc5LeTyO8q8Qncoc9DnNcpJEUAxrI%2Bl8V1Viz%2FaW%2BD5bdyESKM9ESTDllllV6U8SrdiFhEiAZ8xCPZWg%2Bf6OOYZW77%2FTpp2rNbe%2BF2r2Dbzpj8EUuMUZFbo2ASS6MhD3a2Nmq9PMl1Mv5CtfuTJ9IyM3Nw9er1EuufH%2FcYIrccUKWI0lNzKTCFDnX9pn3IzTWiW1dv9O7REedS0vHd5t%2Fr8Unn0xBzRDuXzNWF%2BMsTtfb2%2Bf3IennUofhy2xg0wF%2BdNP1l33HEnTyv6ulGg%2FrMqJKLf%2Bc2mP%2Fx%2BqKcyb527TlW4Pod1TmQ2kR%2BoKNOISH6BCLlZykrF17ic7bLqMO%2BAF8MpBxqH5lHmU%2BZV5lfmWeZb5n3QkGviA7%2FGoujcqnXo53wHhFivxyxc3J5Tl02IkeE32xEI2UItbntNY6rqxOWLJqMWbOXw8FuFbKv30SA%2BFAOG9Id0yYNxeDhc9HE3UVdWVIoMNVBOmt5BUfvIX%2BGrbU1Ila8Ae%2BHW8DTowkC%2FB8WrtRDudfinDiZjB4DX1eCZyMC8%2F8fT4GtmLrYulrj8%2FBpeHX253j7wzVqnazXLvxwgmYOxroQ%2F9CZz%2BHlGUtUP7a21kKYyz%2BB2edRX7w2bbiaSchS0egRfdRSnnSVLAmbjGlv%2FAtder8CV2dHXMm%2BjhmTn1L9ylLbFyu3o9uAV9G8WSNErvlrrcc8Ph63xeK9rh1VaTNCOLyedOzaduhGIcBChJ%2BXQl6Rcd6czhasm9WjEz4SHjK0tHPXFdj%2BG6KRJaKRMsso5rZXZfpf2Z9TS07JFCLjKKbXv5fuMy5nCydnRIvmjWo0EfLkmZ0QEClqheWGoODX8f3av%2BJhr%2BZF%2B321%2Bifs3H0ESz%2BdipSLmaq2XFZpRrpdK72VurqjKhT%2FebSaKr9oKf7yMtJskYN7xbc85Cxi8PC3ELc%2FXF2xVMjlK9fUeQ%2BPVo1L7C8d%2FIXUy2jWtKEaiC2ZL5EnOar0E20MpjxqE5HDH8TiZ5HD9yqwb5V0Vl4dI8VdHGgvi34c1VErTEyb8hoxt702KP3hk7i7uVSqjTEhC2AwlH0yr3uAt3CFI4qm6cWR35AM9G9bQtBL1LCEEyy8Nr0spOvTOpaMvxT3QoGvCCOfnydmWM1VOUV%2BoUheUlpc0CVujZzVozTyRHh5uaxNGtzEghwHTAnwg%2F%2BhYzhMidRY2UXkDXnoLPL4dEX2r6rOFnfuReUXcw1ZWtBritXLX6vS6%2BQVHvLSxdL06tFRCH0zHr33Of6V5U8Th%2BBMQqr6ItGn815CYEBbTcbrp0TcCvTFSqs8PCf%2BpKhrDJU3HVbKPFZCnKtM4eutGXrzyOuny0LWgOWD1C2C%2B3VRjwcCE3aIKfkMZlWLqcOjOhMW1fpgwtATUncxmnBMB7RnJLSHzJvMH0WdEFKEwzU1pW7CSGiSJgX5o6gTQvLZm6zqsfaMhCaxL8gfRZ0QUoQJqP5lrMQi6AryR1EnhBBCUSeEEIo6Q0AIIRR1QgghdRCLffmo%2BP0xCONPag%2Fe4%2F3e1MS9leqlqBcGjgeXZQ9cxr%2F%2BUtkbutHoaAeWXwghpNgsRutmx6L3fnkQpjqcahJC6NQJIYRQ1AkhhFDUCdE6vFWA9rDILQIo6oRog1uPevCmXlqiIF%2B3LNE3RZ2Quk%2F6TWfwJ7Y0REG%2B0inqhJC7EHP4U3od%2FBgJ7SDzJfNGUSeE3IUO2Cv%2BCdbK%2B825dhOZV3LUc0OuESkXMutj0oJV3ijqhJDS5FnhW2HXxw3w0kZdffW63Zjz7kr1PCk5HcFPzalX%2BVJ5EvlSeaOoE0JKc%2BgYDovFkRwHvMZoaGCmkp%2BnIwV5q3WsmQJC6j56E6YaddjXtSNiok8gsrb6zb1jwIo1PyE65gycnR0wsH8XDA5%2BBHv2xmHTliikZ2ajsVsDDHu8O%2Fr3qV7Z%2F9r1Wwhb%2FB3S0rOQazDCz6c1XnphMBzsbWEw5OGTJZsw4Y%2BDsHX7IVXSmTZpKAx5eVj65TZERZ%2BGZ%2BumeMjDHT2DOqCzr6dF8iTyM0wsZol89bTUsUJRJ0QD7D%2BBUwG%2BGCWm1hGBPgjLysX8%2BHjcvt%2F9TpweDqMxDyFCTJNTMvDZ0i1K1FMvXUWH9q3wpFc3nEtOx6RXwrHuq9Bqiel1IerW1no8MTgQdrbWWLJsK84nZ2D%2Buy%2FCYDTg70LwI%2F9zAP6dvODoaAeTDnhpWrh67fNjH8PlKzlY%2BNm%2F4eRkX%2Bui7u0NO1cbvC4FPU%2BHUQePW%2BYkKUWdEA1xKA7bgzqip0GHcCEgU7r6YBVM2KHPQ5zXKSRFAMaa7C%2F2WCL2Cwcc%2FXOYcsuS8aMHqOXI4b3USdD4sxdha6uHd9sWiIk9Wy0xbda0IWa%2FOhJpGVk4k3ARA%2Fp2xvpNJc81%2FnPRn9BO9CU5EpeE6NgEHNodJgYBG7Vu8w8HayUXo8TkKbE9PI1W8C04KTrWBBy1Fg7dkoJOUSdEg45dLP4Q4Ad%2FKxNGiOfT8%2FRol%2BADz8Aa%2Ftbp6TMXlYAWCrrEyiq%2Fi28idmH%2Bog1o590SHi0bIyMzWzn66nBezARenvkP5dh9OrRGTs7Nu9ps6u5S9DwhMRVtPJsWCXpNYu5OjQn53xZNEtE4LaK%2BV7jzIZaqoVPUCXkQXHu%2BgFRJRCp6a1lnJ3tkZd24a728ZHH2O19jy7o34SvEVzJpeni1%2F0%2BLPtuk2pPlFsleMYL9ee5X99y%2FgbODGkzuB1q%2BgymvfiGElEnPbu2ReukKtu2MUX%2Fn5ZkQuTUKJrE0GvKKHHLiuTScjL9Q7f5ycw2ws8tvU5Z2tu%2BKLXf%2F7l3biQHmFpau2KZc%2B%2Bpvd%2BPwkcR6nzc6dUJImbi6OmHJosmYNXs5HOxWIfv6TQR0boNhQ7qrK08GD5%2BLJu4uaCj2q4kSyP%2BFPI5xIWHY%2BmM0TGIuEfhI23L3l0592eKpeG%2FeWiwTwt6vlx%2B8PJtCr6%2FfXpV3fiOkniHLL5X9ObvklEwh8o5KSAvJuJyN3DtGtGjeqMbe263bd5CekQ33xi4lavkVQc4k%2Bjz%2BFyz8MAQ9AttXuu%2FiP2en5fILnTohxCwerRrftc7dzaVSbYwJWaCuNy%2BL7gHeCJ05AvZ2tmjdyr3Cbc79cDUyM7OFQ2%2BGX%2FYeR8sWbgjq2q5e54qiTgipFVYvr%2FkvxI4a3gvRMQnqhOnLE4YguG9n6HT1uwBBUSeEaBa%2Fjg%2BpB%2FkdXv1CCCEUdUIIIRR1QgghFHVCCCEUdUIIoagTQgihqBNCCKGoE0IIqUn45SNC6iHF73NCHiz0DAEh9YuLGXhbPlo2wVxG494x0up7Z%2FmFEEIIIYSQush%2FASUBhLJAZsxPAAAAAElFTkSuQmCC)
+
+```
+call_stmt
+ ::= call_type call_target call_arg?
+```
+
+referenced by:
+
+* basic_stmt
+
+**call_type:**
+
+![call_type](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJcAAABRCAYAAADfLjTQAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAACQ1JREFUeNrtnQ9UVFUex78zA%2FJXQcxU0CACAkJdwaNSSa1hS5tr%2FoFaUzOVXd3Q3cLdPB5r28rTUUtPpLbGgrrmyiqbHvNP4UkrOwaGoq1%2FGxH8CyZ%2F4p9CMjNv733MzILMP5B5M%2FPm9zlnzpt597773vv9vu9377vvzb0AQdgJhRxOIiEGglwccuysPHzC8ZDLiRz9ZoPLn8PIsXNkFbmUFLydLwrLJRKTuAgSF0HiIggSF0HiIkhcBEHiIkhchBwQe%2BhHx2HAkVP40Vwma%2Bmuxon%2FliN7036cOFkOP18vRD4QjNRJiRiXNMyY5%2FMvSpCz%2BQu8lP4UWz%2FUuP7MD1ewas0u5K5d0KncjVsOQKPR4ncvPunS9rlbfxu2FyNXqxYVCTHYzleaymwt3ZUoOHAcz81%2BF%2FG%2FCMfW3Ex8uHo%2Bhg8Nw9srt3cUyr8Ooq7%2BJjbnfdlhfX3DLRwtKTVZ9sXLN3Dh4nWXv%2Fi66%2B9RMZicEIsr7PoqN0YuRVv1mKbVssQY7PRQYWF75VpLdxU0Gh2Wvr0Fry9%2BDjOefcy4PvKBQfjtlEeNvyuv%2F4SSExewe9trSEl9EzU%2FNaJf395uU5111d9cVFoFPtAKGNz%2BwVWHB9dC22%2BzhVpLd3ZOn7uMqpoGpD6T2CktIMDP%2BH3H7kIk%2F3I4oqNCkDAsHLv2HsGcGclu12ay5m9zojIpLnOFdnWnzsqNqjoEBfrD26uXxXyffFqIJZlTxe%2BTJyYiL%2F%2BQW4rLrL8V%2BEwDvGVOVBbFZUDH2r4sPqYIVtI1GpSznfo4u5H8%2FbzR1NQCnU6AUmn6talTZy%2FjQnklblTXI3%2FnYTTf%2Blls%2BJeWVSIifJBkx%2BqMb0ZwfzOrPa0RkMqWOmsH6GGmzv2WbXiNLZNZgTls%2BYqldE8PrDBErjRAdTEKoVolYlnGcSzPNJb3lIeAjO%2FOQe1IR8TFhop3c4eLzmLsw7Em8%2Fxn17eIiRrSodHO22Q8mi1%2BeYpkjrTXS4OjohGlUWAdKzyOGS2PWe6gSoczYWpcyge0puzZ3t9s%2BZG3Jza0tGIOCyzpggL14BHMmrgMhQhthRzxVCGGi4bt7BVL6e3LEA9QjTL2lX%2F2RERgSYAn%2FsLq5qIRsUg7fgYHHHXl9fb3wdwXkvHqXzchd91CxD44RFx%2FTn0Na7P3ImtFOnbtOYL1WX%2FA6IQo43Z7C47irZXb8OqfJrt09cbs%2FwSryvKZH1fXt2JCaSl%2BNqQVWwgyZvydye4mV7A7y8XmRNZeXPmWRGNDukn0J7AsPlqsQvPZlTPGXhHMFpZkpsLLyxNTpi%2BHv783tFodBBbgp6Ul4evDp%2BHZywOj4iM7bMMb94uWbkTR0bbDrq5tQEh0x7dG83IXicuP%2F%2F2V%2BDHA%2B9HUJX93uLB4xOLCEgS8UHIOe2zYxKq%2F9evMikyhD4O3WCHrWSErTBViLb0L1ddrbJHEQn6P9jLyMN7V15y5qCqu10KlVCJ4UJBTRJb2rzn3dLXIbLSfLQ6xcpfZkLdb%2Fub9Ylxk7MDns%2F34ipGL3e3db6kQa%2Bk2V0vNeK%2FRBxkjHsLw46fxvSMdqVIpMSTkHre42%2BP2Zq3xocz%2BE23J311%2Ft49k%2FLey3UprG901X11EC7setyp1mApCMkR7M7uL9rddJN3GsL30D67Z3QkLuYnkckn7qRK53SUXtdQ7ZI3K06xOjiKXSwe3N7e77MXl0ySGzP7kcknpr7e7vMVVeFWs973J35Lirbe7vMXV1gSQz1%2FWXadmlP5xEr2JSpC4CBIXQZC4CPsjmyGU5Db8EEUuJ4E%2F5JXToGkkLoJwl2rREMHIpRS5CBIXQZC4CBIXQeIiCBIXQeIiSFwE0ZPIohNVTnP%2FGJBDhzDN%2FeOEyOUhPFWLThyNXT0ik7gIEhdB4iIIh4uL%2Fl4mHQ75W5kjxdWSOJj%2BGCsFeju3uJO4qpr9XX9Me1dAb%2BcqtxEXi9FqlQIPkevtD7czt7fbiIs1Agr5YLzkekmMPU60twNwSA%2B9TolPlDp8%2FngYlto6IFlPseajveLYp5wFv%2F81Hn80Dtt3HkZFZS1efuk3HfJOT1%2BNZa9Px%2F2hA%2FCPTftRcPAEspbPRUhwP2Mew%2FpV78xG6OD%2B2LG7CFvzD4lpvj69MGJYOObOTEafPr6S25nZ17tRwPPM3iluE7n0Q1aebPTBn6Xe91Pj47FowURU19SjurpBXHflWjXUpRWd8hYVq9F0s037ZZd%2BFGfg%2BDD3M2N6Y1Mzsv%2B5H98dU%2BOWPt%2B1ihrotDpxH9NSk8RBetNmrRTHvpcavX1POmqIUIf1c6kE8Gm%2FMuOjMUHK%2FfKJChJHRcPPr%2Bs3q89OegS79xWLU7xwtmz7GpMnjIHijgkTgoL8xX1wIed8kMFEeQU%2FnL8qqX31ds3U2xluJS4%2BXLhOgTSFApv5KM8REfBy9uZLYIAfpk56GNkbC9B6W4OP875E%2Bqzxlu%2FWWm5DEARxeHJJLh5mR25PblduX0cOy%2B7QtyL4hAd8XHo%2Bo0OAJzLiY0zP6OBMzHvxSSRPegP9gnrjsbFxuPeegE55amubUMi8yqfPW7%2BhQJzHMTxsoF2Ox8KMJWOOnXWcsBwuLkMEY4vxfDhrpQA%2B%2F8kfdSpElsUgNEGiXnwlu8wFE53YPOLcOUfQwAF98atxI7D8%2FR04tO8dk%2BWdL6vAqrWfwsfbU6waZ894otvHZu3NiLK23vdL7CjPM2sVsmiV4uhh2J1GXHc08r%2B3hwNM3rFq%2F79J30B%2F1sBv6NgYbmzG7VYNggI7z7O4cN7T4nxA9w02PY796JFRyFnTM00dV35p0K0eXPP2D4dPzlnO7v5CQtq6FJIeiUXx8VIUl5w35l2Xsw8PRgZj0MC%2BncoJu%2B9ezJ%2BTAsJFIpcUzJqfJYqqru4mpj6TiDEj20Ys5%2B2h5W%2FMxMx57yOwjx%2Bam28jIMAX2VkZpJC7QBZvJtg69w9vQ12tqBHv%2BvgMZnfC7wCvV9XBQ6UyGbGkwp5zAFHksteVxBrulub74TOWuct8QNTmIkhcBEHiIkhcBImLIEhcBImLIHERBImLIHERcoXm%2FiHshkoOJ1FZjTf5J7g%2F%2FiY3B%2FHzomqRIAhCKv4HzYyIi4%2Bc2EMAAAAASUVORK5CYII%3D)
+
+```
+call_type
+ ::= CALL
+ | JUMP
+```
+
+referenced by:
+
+* call_stmt
+
+**call_target:**
+
+![call_target](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANUAAAB9CAYAAAA1DyYAAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAE6FJREFUeNrtnQlcVNUex3%2FDsO8qqCgGbgi4IJCCkYjgAm7hQu5JuIuiaebTzJdmvSx96lMT62laphnupqk910xEc0FxQxRIBRVREZF1Zt45BxjBUMAYhpn5fz%2Bfy13OuWfO5fx%2F9%2F8%2FZ%2B6dAxAEUaVItOEiPF2goKbUDk5f1nyb1NeWxvjjtzVkkRrO6x3DtOI69KgpiZoWdWh65EGiIggSFUGQqAiCREUQBImKIEhUBEGiIgiCREUQahOVVyvUe1mm8tI1icEjF%2BH8xaQK5Y3a9jtycvNq5HXcS8vA3v%2BdIQuuQv6unRefL0SVL0OKpwt%2BelGh5aVrEv37dEA9W%2Bty8ykUCkyZuRqPH2fXyOuIT7iNBUu2khKqkFe18%2FYu6OvpipsFMiTyffHsn6RQXCEyGUt0wTZ9KSbFxOFu8UnlpWsS6Q8yIZEUPrO578BZWJib4Oq12zh49AIcXrPF9EnBsLIyQ9T24yJP5Jq9MDczRmBXD7i2aFRu%2Bb%2F8ega%2FHjqH%2FPwCeLVrgZDgN2BkaIDjMVewIeoonmTloItfGwx9u5OoR0ZGFtZtPIRu%2Fu74Zt1%2BpN3PwPBBfujaua0oLzMzG1%2Bz47yO1pZm8PVxRc%2FuryNqx3Gkp2fi38t3iHyjQ7uJa3kZuXn5WPP9AUSfvAIrS1OEDgmAp3tTJN9KwxZ2vaNHsDIsCsvgXlAuV6BHN0%2Fs3HMStrZWOHXmGmJOxaNtm8aYNLYnjI0McffeI%2BzYHYMBwT5iLZPLMeqdrhopqsraOReTTIL%2FyBSwL%2FlgVak%2BlaJQZLzQW2Uptrx0TYCL5M69h0pRhYUvQ8qdB%2BgT1A4XLibjky9%2FEmm2NpZi3cCuNho1tIGZqVG5Za9cvRefLdoMf9%2FWCPBzwy%2F7TyMp%2BR5%2BO34JE6ZGsmNtMGJIZ%2Fy49Rg%2BX7xFnPPocRa%2BWLoNs%2BZ%2BD3e3Jmjn0RyjJ3%2BF2ynpIn3CtEikpD7Au0P9hTFz0Yr61bGEvoFU1I0v%2BswCymPUxBVIuJGKiWN6wq9ja4ROWIrE5LtwsLfFpas3Me3DwoeSz51PxKx569GmpaPY3%2FnLSYyJWIHc3Hz06dEevx6Mxcf%2F%2BlGkpd59KOofMmIBEhJThdA1nfLsvNgzyYCt4IJ6Dv1yChWKLS9dkz3XuLBATJnQW2zzuzQ3EI7fm63Euk9Qe9Rld%2BnyKCiQY2nkLmz4Zio82jYVx4J7eom7%2FXwm1HBmyH17eYvj9g1sENR%2FLqYxr8gxNNDHlvUzlB50%2B%2B4TrN%2BXjIYN6iDu8p%2BY1%2FdNdGjvLJYhIb7K%2Bh04ch4hfX0qdJ3nLiTieuIdrIucDD09Cdp7NseJU1exhwk%2FfHQPLP5sJIIGzMPSlbuwaevvWPbFaNg3rKM8f9rEYIQyYXOaNbbDkFGL8Nmc4WLfyNgA29bPhCXzftrEX%2Bxcgl8KgHnPe6YKiaoYOWsL5soCFeWkFxQgkX2oiUaO1Eifvb7DQ6J8Fli%2FCneZ9%2BOhWvHdXVk%2BM%2BDriXdFaFVM86Z2yGPhYSrzkCLsYGIqFhTH0sIUMllhPbjwps5aI8Tu0bYJwoZ1gVsrx0rX71pCigjV3ug6o9Tx15iXKr6hrFw8DoH95jJP1gM%2B3i6lQ6MSbzk1cawnwtgstnB4GFjVgqpJT6pzO2eX37NAgQFsLS%2BvYvoviC2PsxNvs3UXVuB%2F2fq9l6WzG%2B2CYk8VAkiTnOAg04Mry%2BjP8gxmeeP0FQhnoXy8Ki66JjQA73dxYTzKzIJNbctSaRbmxsh88mzAgxukTCaHGTun2DBfxDDW9%2BKDKzw03fPraQwM%2FRJnjy1WDqZUFP5ZTRvXx%2F7tH78wzxbWT2vt6sD6RicxPiwI1tZmZeZ7mPFECMm0AiHxq1LVLysyJ%2B9UIMEKVmgr9l%2FbyCzmoFSOS47xSI4CZGXZUUk7Z%2BtVzCGvyclHGHMkoxSsO1xW6PeXPhUvhI8kswJc2HKLhXUuZy5jannpJUM%2FXkHWl71x5gp%2B5mkZ%2BXBk5x1hHboT7q4I0JhOKxMIv%2FvyPkhF4IMbr7s3w1ff%2FKI8FnM6XngH%2F05tsHHzbyJE5Hz%2F42HhbZ4XX5mGvjNahIc8XJswMghZT3OQy1qW1%2B0OKzvraW6F6ufj5Yw%2Fb6ex0DJGeSz55j3ExiWJ7R17YnD4WBy2%2FvAP4aUmffC1CF2Lych8Ktb8ZrCCXWP3AHdIpZrxNSe3O25%2F3A65PXK75PbJ7bRYUBXRwfHziONrqRTN2f0siuXLZJlvvcxT8UK4ImNY%2F9eljD5SeellkpAA3urzPZxFqBjF7hjeqvJYVc3Y0O4IHb8UtWqZY%2FqkvhgQ%2FMZL8y9dMBJjJ6%2BE%2B5vvQaqvBxNjI0Stm46Icb3Y8a%2Fg030GrCzMhDDWrpxcoTqs23gQH326AU5NGyAx6S7mfDBQeBAuKrdWjeEVMB1SiR72bv0n7OrXeqnov%2F0qAtNmrsG8BZuEUPnAw%2BLPR4qRxdmf%2FMDqOgOmJkaY%2F9FQ9CjqX70X3kec%2F8NPR7BuwyFk5%2BSJUdCvl07QCEFxD8X6QFFMBO9wIVXglHLtvOjYVK9WWMB6CzOe91ySIrf3lBUSyQpZUFYh5aVXIkybzVa%2BzLV3q%2BrwT1Wv0z96lIU81mmsa2NV4XPu3c8Qd%2FE6tSxKHU9Lf4wcZpR8tK4yPHz4BE%2BYEPmIJA%2B7SvflHgkhFA%2BFV4Q7dx%2ByvqReha9p1KTl6NjBVQyK8NC1Mv%2BLylDydfqqCv%2BYbexnq6OsvPkVyPtKds5HB7m4WIXHsc8xFZ6KubfGLyukvPSKYpGNhZkmCHdvCbezFxGrCXe64n7F%2FoPn8PXa%2FS%2FMN2fG28pBihcZHR8GfxW4p%2BRLWdSrW%2FhF9qLlOxB98uoLy9j83QfK7fr1ar1SPbh4%2BaIpcDuDHK2Z3fWpSP5XtfOSnksZ%2FpVXUFUNlx9OQo6nKzboydGf7cZCg%2Bjm31YsNZVpE99SWdl8xLEiXyvUuJFdbmcSbOB2VwlxvDLF51d%2FT1OBg8zFdgChMbzh5YxmTew0rt7Czpi9VbuYq%2FsDWafxIos9nchUCVXD7Yzbm9aLyuSJcJG21ORENWBbZG%2FaLaroWyK%2BNab2JqoB4yJ7025RFYa62vFz04QmRIDV%2F7QNvflLECQqgiBREQSJiiCIV0drptLRlmlYCPJUNQL%2B8KU2TBZGkKgIgtDm8K%2FYY1GTEuSpCIJERRAEiYogSFQEQaIiCIJERRAkKoIgURGELqIVX%2F7WpN%2Fd1nboC3YdERVHVT%2BmSTyDHlqm8I9QUVRAkQGJiiBIVARBoiIIokaIikaRCK20L7WJqoM9%2FaAmoZ32pTZRZZtr3sz2hOagTvtSm6ikErSkpie00b7U16eSwF9bGzT1zkPk5xVU%2Bjw%2Bn%2B6t2%2BkqrRufCfHm7fvIyMjS9h6Vv%2B6JSoEhfo7a2a%2FqPWg%2BLl65Wenz%2BLShfF5gVcFng3zdbxrCJixD5Jp9WqsnYVfMvtT1%2Bep8TOlCpgneZ%2Bv5IKqFpZG78OW8UPQOaqfV11lkVxfYUl%2BnRCVVYKJMghN81voKzhpeJcTGJWHj5qN48PAJ7BvUwZAQXxgaGuDnvacwYVSQMl%2FSn%2Ffwv8OxGPVOVxw%2BFieO%2FXkzDb8eOgeXFo0wZUJvsb1zzymYGBti%2BuRgODSq%2B8zr3HuIjz%2BPQcL1VDGt6TuDOyvTok9ewYaoo8h8koOATm0wbGAnSCSVGwHmE2jv2B2DAcE%2BYi2Ty0Vd%2BcTfq9buY9eZCHs7G4wfFYjGDvWw78BZ3Ei6i2MnLuPa9RS8M6QzbGpbap2gmD31YqupzL68mX1d1anwj9lVvFyCEGZL3%2FFZ65s1g8pnaL6dko7BIxfB060pBvXvCCtLUxw9fhH16lohcvVexJyOV%2BZdyfZTUh%2BI7cO%2FXcCYiBW4nngHfYLas%2F04%2BAbNwp79Z9DFzw15efmY8o%2FVpT7r04WbUb%2ButRDU4hU7sWnrMXH8WPQljH8vEp1922AEM%2Byftv%2BOzxZtrny%2FjYWKXyzdhpARC5CQmIr09Ezk5Oah3%2FDPYaAvxZTxfdDCqSH6Df2ciTcbtazNoS%2FVQ53aFmjU0AaG%2Blr163Tg9sPtiNsTtytuX7oY%2FuHsJRxo7wzvAglWWBkg3MMFG%2FkcrVI5LjnGIzmK9d2r8vMSbtyBkaE%2Buge4w5IJyt%2B3tTJt0ICO%2BG7DIXh5OiEzM1vc%2Ffdt%2F1iZPmygH%2BbMGCi28woKsGV7NFYtGV94d3RrgqD%2B80p91rIvRqNtm8ZiOycnD5t3HMfAfm9i1bf7ET66B%2Fr19hZp3MC7952L9yOCK309RsYG2LZ%2BprgWzpad0WhoVxtTiybVbu%2FZHLv3%2FoHfmXcK7OIBU1MjBDAxe7o31XgRhbBgJ8kJDjI9uPJBCebnByuAOH3moU5fVp%2Bg1C6qYo%2FFVl3dW8JNT4F%2BbDtCLkXzGy5w8Kzib8U7eLVAm5aOaPvme2jp%2Bhp833DFuLBAWJibYPggP%2Fj1mI209McspDsJ73Yt4GD%2FbBZVqfSZU7cwMylVLj%2B%2FQPZi%2FTdtYofvNx0R24nJd0WYprzDsrQCWYHwioYGlWsOYyNDpaA4PKw7dSYB3gEflMqXny%2Br8nZT95PqNwonc0tmBnKNWUk0806BZy8itiYIvsbEAEX%2FkFhVNjA32nWRk0V%2F5PS561i5Zq%2FYXjj%2FXeExfH1cseGnI9i66wQ%2B%2BfDFg0eV7f88ycqGtbWZ2DY3M2bh2FNlWtbTXMhkCpgzYebl5v%2Bt%2F6GZqTELK1tj5b%2FHqby96GXFGtinUgcXLiXjSvxt1oeyRo9unuju7y4GLIoZMcQfy1btFtsdmRf7O2Sz%2Fg0nl%2FW31jMvxT%2BL49%2BpDTZu%2Fg0FBXKxv37TYbR2dYBtnb8%2FaNC1c1scOByLP84mKI%2Bdv5gkvCOhg56qOnianYuxEYtFyMRH7LiX%2BO%2BycGV6J5%2BWsLIyw7tDAyrtjZ5n6szVrAw9PHqcBR8vZ4wN7SaOTxrbE%2BOmrBTfR1lbmokRwLUrI6rk%2BpydGmLBvBEYGb6c9Z8MkcM8nwkLEdcy70xUH2px4Txcq8rwgZdXmdfp%2BVMLenoSNGCd%2BpLw0b1eA%2Bfj1KGFIkz7u%2FB%2Bkr6BFHVtrP6SxvtufACDh52qgD81Yc7CwVq1zKuszJKv02tC%2BFfVdkae6iXYN6xT5vFv1u3H28E%2BVSIozvOiLUl54d7wMUuQnZNXZppbK0d89MHbLz1fVWIlSFSVwsfLRQxD1wS%2B%2F3oKNQiJSvPR9sd3iOqBXqcnCBIVQZCoCIJERRAEiYogSFQEQaIiCIJERRDqQGu%2B%2FKVpXgjyVFUIf2iS3u8hSFQEQeGfZngsalKCPBVBkKgIgiBREQSJiiBIVARBkKgIgkRFECQqgtBFtOLLX3X%2Frnd1Ql9wk6iqjcr8mKamQg8NU%2FhHqMgr65JnJlERBEGiIggSFUGQqMqE9wloFItQJZIiO9MZUeV0sIcxtTuhKorsK0eXRJWWbY561PSEqiiyrzSdERXzyfFSCVpS0xOqgtsXtzOdERULdqPZH39qekKFRuYv7EwNqOWJCrketujJsdfPER8eTqq%2BuJdPKD39o3XK%2FbmzBqGl82v48JP1uHotRRyrXcscTs0aoF9vbzRxrK%2FM%2B0PUEWzbFfOXMj%2BbM0zk5zMfyuQyrFoyARbmJiLt8LE4HI%2B5grBhAZg4%2FZsX1qu4HkTVwOzKOFOBIczOAnVGVGcvItbTBRcyTfA%2B251fXZ9rb1cH82cPRUCfj%2FDzptlo1sROHOez1nt5OsHftzXSH2TiwJHz6N53LhZ%2BGoq3eniJPH%2FeTIORoT4mjulRqky7%2BrXE%2BtSZa2jYoDZWfbsP708KFsfu33%2BMy1dvwdraDNMm9hHH%2BKz0g8IWYvnCMahf11oca9SAphKtSors6gK3M50RlYh5FZgok%2BCEhzPOnbmCn6vjMw2YKLjhF4vByNBAmcYF1qG9s9juFdgOvYPaY0zECrRzb66cu9fW1kqZpyymR%2FTFlJmrETrUHza1n83pa2xkqDwvP69ArD3cmsChUV1SQBXD7KkXW01l9uWtrjqo7cvfk1cQL5cgRCLBd8xrzW7WDEY1qXG413JxboTd%2B%2F5QHktLy0A0q3jJJfNJtjLd2cke3f3dsSxyN1l3NcPth9sRtyduV9y%2B1FUXtT6lfvYSDrAbuHeBBCusDBDu4YKNUOCgVI5LjvFIjgJk6qyfYyNb3EpJV%2B5funITi5bv%2FEufyqKZiXJ%2FGgv9ur41B6NHdCNLVyEhLNhJcoKDTA%2BuRYMSgxVAnD7zUKcvq09QahdVscdiq67uLeGmp0A%2Fth0hl6L5DRc4eKr5qYtHGVlo2thOud%2BpYyss%2BdfIl57zmr0NQvr6MPFtF7Pdqwpdf1L9RuHTEsnMQK4xK4lm3ilQXX2oGieqkoMXbBVbUwwsJfUBC%2B%2BuYua0AZU%2Bd%2FL43ugYOBM2dSxV9v%2BilxVrLvRA7XNkZmZj%2F8FzCBnxBYYN8oNri0aVLsOWiSlsWBes%2FeEg%2FUN1EH1dutir125j%2BNglYrv3oE%2BxavF4eLRtKvanzlojFlMTI7RwaohJY3tiUP%2BOpc6P2va7WEqy68cPlWWUZHxYIL778RBZmA6iFSEED%2F907XV6Cv8o%2FCMIEhVBECQqgiBREQSJiiAIEhVBkKgIgkRFEASJiiBIVARBoiIInUVrHqilaWaImoJUGy4i9T7m8qWBLT7WlYbj10vmS%2BEfQRAEQVSe%2FwP8o%2BhF5LkMhAAAAABJRU5ErkJggg%3D%3D)
+
+```
+call_target
+ ::= int_const_expr
+ | symbol_ref
+ | IDENT
+```
+
+referenced by:
+
+* call_stmt
+* jump_sp_stmt
+
+**call_arg:**
+
+![call_arg](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAATEAAABFCAYAAAAiodELAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAEFtJREFUeNrtnQd4VFXax%2F9T0kgjjUCIUkJLTEIJHRQMEupmQYgr4ApLUaSIwCKWXQTWZRdRWFSEDxXFQouAqJQPJIgiJSTUQEyBJJCQ3nsyM3fPuTOJYR%2BSmQm5M0nm%2FT3Pfe7MLeeee%2B77%2Fu%2F7ntsAgiCIFoysuVREiHrB6ptz55fcjM9%2FPu5WYfe8wiqb7LyKeuvn5mKjsrezKnB3tTmdeKf8X6culEXT4SQIy%2FO3ZiFiJz4PeumHk3c3xCcV2U8MfgTD%2B7dD%2B3Zt0M7Ntt51snIrkJFVhjNRWTj04x2VrbUiKi2n7LnoGNwiEyUIy%2FE3s4qYIKyW73t%2F%2F95PdsdPfe5pHzw7sQusreRGl1NVrcGeH5LwyZ74ivJq4emo6%2BqjZKoEYRn%2BpjDnxv1cc%2Fft2Jsw9d03ByBkuBcUisZpKl%2Bvt68r%2Bge6K0%2F8kvash4sm9V42LpPZEkTr9zeziRgPaT%2FYGbuCN2hAT5cmKdPT3Q79A9zlh0%2Blhnq4CXczSMgIotX7m1lEjHcqvr878uSYEd7W%2FIzQlPCGLa9Uy2Ji8yd4eSCKnSESyYQJi04jW7m%2Fyc3RqPyqSGJKsT3PyaXgxWk9YW0tV2oE7A3yhw%2BZMWHJtHZ%2FM4uI3UzInzl2RMdGdSoaAi93YG8PftVCCTXeJTMmLJnW7m9mEbG420U%2Bw%2Ft7SrqNkCfEsNmODcP7PobeZMqEpdLa%2Fc0sIpabV2nbsX0bSbfh162t9ocMWXINppApE5ZKa%2Fc3s4hYXlGlzM3Zxqh1cvIqcTe9DAVF1QYt7%2B1Ze9Ac2DCaTJmwVAz1N0GA6GN8qKrSGLUNc%2FqbKGKD%2FNFgrKlvvrFo1ALkRtyjkpBSgqA%2FnsSTM34WG9igHdOVzw6MKxs9SqZMWCqG%2BpuMLbLpswT0Cz2Jpf%2B8apyQNMLfHlZXatYXRaxajXtBvthXX6H65kvNkrVXUVahxruvBSKgp7NR68q0ZwZPMmWC0M%2BGlYEI7OWMfUdSceLXTKPXN8bfGqsrA30xOcgPd1VqJPH%2FSt2GuZiFqdVspi8OKhVYfCEGmXUq1uB8Kfk5MgcXr%2BVhcB9XTApp9D0uCjJPgjDAUVhEtW65PybO%2BxUbP0nA6GGekvmbsbrCxUstw%2FsssPSG8Pt05X05sfZ%2FvYXqmy8FR09niOPpoZQREoQpGMQChq6P2iP6Rj4ycirQ3t1W0u3p05X6xOuBIlZfocZutCm5FlcojgcEupB1EYSJGBDggtt3ShETVyS5iNWrKzIcVQFr6xOvBkWsBg1whcV7YwU981UqJLGN2kmxY%2FkFVeLYzcXmocph9RPINAnCMNxdtf6WV1hlcn%2FjusJSzQkqAVPZWKOvIGU9uepZtmIaGz%2FFCvyEjZc2NN9KifXGRGLG7KCDg7aK5RVquDhZNfqgRMc2%2FNqhMJbHJ%2FdAJ7UcfmzJYLbwNFbJGKWAhZG%2FIZ7MmjAHA3uhh0qGLcwe%2FZk97maeE6HQ4GbneKSEA2qpBKWsTFu0vZ1SEn97UL3q6gob%2F5%2BtFXZUVGM2C5TmCjIUgkdk%2BkSsphBBW8gFKwV8uTixjS1taL6UB7FzR3tcvlGAmPhCeLWTLqwVDSIet9lPPvzQrRted7bCCpaLn%2B%2Frh7DLN3GSXIowJczuRrFUKpz53cbCakxMTERlzbyLEm%2Bb%2Bxun6yNtJN9PPbqybJA%2F1lersbI%2BMasrYuF6xCnclOJVQ%2FAQDxw8nob9R9MQMtx0d0roDObtfr3ElDmcnREHU0RGmDIC4wImCHj%2B0m%2F4wZTbTkkrQ1RMvhg09PJxknpzenVFN61eMau5Y7%2BcFZKqZIVcisWyBxSkb75kTA7pKHYsfh%2BRjtjEIpMbk86ANrKI7ENyLcJU6Oxto6kFjLPh4zjx7v35033EG2AlxChd4fP5cgoFurP6hfP1a0WMFdKloUL0zZcSG2s51v3VH9UqDRa8dRnFpSqTG5RjufhkfgA9SE6YJI3U2lmAzu5MCs96%2BI2uft2dMDuss6Tbaqyu1IgZX782nTREAZuy8vwRBWMePfrDqA744t0BKCyuRmp6GXy76Q9xS0qrm6y%2BPyWjIsgPu3QPtl4lNyOkRLQzGXZxuzOlv%2FHoi18KfH9VHwzt5yYGEIbSGH97WF2pWV9pjoPU1tFalVtYqfRwNbyjftyI9kZtIyG5iVNPARHs%2BL5CLkZIDbOzITIB%2FzG1v%2FHUccqYjo3aRpP7mzEibY6NOtpbFaRllEm6jcirOdoDI6AYBl6KbrCPQsANdox7kIsRUsPtjNubJftbsxcxNxeb02eipO1eO3HmnvasJkMWGz30xuxKxDI8yMUIE%2BChszeL9bdmL2L8C8KHI1JV%2FPt1UpCUWozk1JKaPeT3fd152DLPpYr9E7bkX4QJsNXZm8X6W7MXMf4JdGsreRT%2FAKcUvLY%2Bum4HQyk%2FUTRNV0Xz%2BGI6YQkZZdM9JtdC%2Fa15ixiHfwKdf0H4elx%2Bk5b7zvYY3EoprmnQ22wI0sixn%2FyCsGRas7%2BZTcSi2b5XVQtTFr11Xt1UDcsbdF%2Fds40MZ9gp7eLlG3RbBGHZtGZ%2FM%2BvLAtOyhAQ3F83doxGpoWWVallfP7dGfVqd5%2BTz3zyHMxcz64a1X7NGDWF7OC09C01y1Lw8sDo9B2vIJQgpkcrOWpq%2FGYrS3Afs0k181t9XI%2F9y%2F61te75LUg7u446xI7zRw8cJnbwcHrhOWYWKf4YKkVey8eOZe6xRS%2B5fQNugwTIZ%2FhLFzkDkFgTRev1N2RwaNioWn%2FZ7TEhTV6nDT0dmKtjQuHeT8ZychbTg70CTY2b0DRxrzgZF7zhrRelabMu56NPa%2FE3ZXBr2EmuAIH%2F0Eb8gLOBxpurpbLKzIIMr%2B29fz2olzHKyZQLiNTKUMUUYKAccBCWGXmohEVjULztIAVo4%2FR%2Bf3fIislbkb8rm1LDR2oaYzB%2BA1T2nGAIN03pZvY3qIAgoYA3Pv9wZKSiwJoo68QkzRtUtKSJrLf6mbI6Nq7u6wYdV5B4EQf7WEHI6hARBtGRIxAiCIBGzIOjRI0JqmvSRIxIx4n%2BpGOJND4ET0qGzrwpqCRIxqcgud4AnNQMhFTr7yqaWIBGTKpeMV8jwGLUEIRXcvridUUuQiEmCDDjHH6%2BgliAkNLJg0c4IEjEpEF8xImD6yM6m7xebNuc9XLuRbNCy4Qd%2FRUVlVbNsw6zsQhz78RIZ0wMQ7YrZF706ikRMMnQ3BV4vtsNfTb3tKaFD4OnRVn%2FKKwh45fVPUVRU3izbMD4xDev%2Fc4CM6QHo7Oo6vTrKOJTUBMahELBILcN5%2FmVwU37YNDevGDLdl0z%2F%2F%2BRlODrYIS4hDRE%2FX0enRz2wYvEkODvbI%2Fzbs%2BIy23Ycg4O9LcaO7ge%2Fno%2FoLf%2FoiUs4ceoKqqtVGDSgJ8ImDYWNtRXOXvgNu8J%2FRklpBZ4aGYgZz4wQ61FYWIqdu08hJLgvPt55HNk5hfjzsyMx%2Bsk%2BWocsLsd2Np3Xsa2TPZ4Y5ocJY%2Foj%2FNBZ5OYWY%2BOHh8Tl5s0KEfelISqrqrHjy5M4F%2FkbnJ3aYNb0UQjq64OU1GzsZ%2Fs7byYrw1FbBo%2FyNBoB40OC8N2RSHh4OOPipQRcuBiPPoFdsPjFCbC1sUZmVgEOHb6AqZOGiWO1RoO5z482m10xe5rIRsuYfQ0mL6NITFKYH%2FGHX8OYH38R5Iu%2FdesGG1Nsl4tSRlZ%2BrYjNXvgB7mXkIXTcAFy%2FkYJ%2FbNgnzvNw136T06uDKx7p6A77Nvqrt%2FXTY1j33jcIfiIAo0b2xtHj0UhOycIvZ29iwbJtbFogZk5%2FEnsOnMG%2FN2kznYKiUryz%2BSDeWPMl%2BvbuigH9umPeko%2BQdi9XnL9g%2BTbcS8%2FDX2YEi%2BLBRVKsn5sTlFYKsW58UCr1v9Ju7qItSLydjkUvTMDIxwMwa8FmJKVkopO3B27G3cXyN7UP0V%2B5loQ31n6FwMc6i%2F%2B%2FOxqJF17egsrKaoSOH4gTEVex%2Bl97xHnpmfli%2FcNmrkdiUroorOaA2w%2B3I25P3K64fZGXUSQmfVp5EycH9sJglQxbnK2wsJ8vdvPvUio0uNk5HinhJvhk1fzZY%2FHKgj%2BIv3kUwh1S7FcZ7i%2BOQ8cNRDsWhehDpdJg87bvsevjZejXx0ecNmnCIDGaeZsJ40ImHJMnaoMDby93jJuyBstZ1MextlJi%2F1crayPEbw%2BfxzUmqB293BATewdrJw%2FHENZQfJge9kRt%2FU6evoawycMM2s8r15NwKykDO7ctgVwuw8Cg7jh%2FMQ5HmNAunDcem9bNwbipa7F56%2FfYe%2BBXfPDOPHh3dKtdf%2FmiSZg1Q3stpluXDpg%2B9z2sW%2FVn8b%2BNrRUOfvU6nFh0ZyrCWDCf3AOd1HL46TrxpwlAjJJFYNGxJGAkYiaOyNhotPgGAAFPs98vaxToftsXnYJMcFd%2F3a858xSrurpxupnJojue%2BtVEL7XlM8G4lZQppmo1dPfpgCqWbqazCJDDxatGwDhOjm2gVmvrwYVu2Rs7RHHt16crZj%2F3FHr7dza6fgmJ98TUb%2BjolfdNf9Tbo1bAt26aj7FPr2GR2ngMG%2Bx733J1qoeunT3FtLi0VHsvKU8rm1rA9L0j7rb2bvwUVq0EZiXnWPQ1lvrASMTMG5X9%2FgaAJjd4U8D7zbgQFRSXwt3V6b55jg62KC75%2FQIBFwC1WgN7tk6NENTHc8%2BMEC9G8FT3yIlo%2FGnWBlw%2Bs0mcxy8%2BGArflk%2BX9jj%2B7ep6l9l%2F6CwC%2FDrh0OFIvDR7HNq2ffCbZPILS0ThatNGuh6AlvQqHuoTI5olXJB4dMH7kAyBXwzo37cbPvr4aO20C9HxYvQTPCIQu7%2F5RUw5OV%2Fu%2BUmMpv5X7B4oLN%2BdE9NNnv4tmDMOpWUVqKyoFuuWwcouLas0qH7DBvXCnbRslqpeqJ2WcjcLV2OSxd%2BHjlzAT2dicODr18QobPGr28VUuIbCYu2Xr7n4bmH7OGZUXygUZPYUiRHNmhdnjcGslzbDxcUBKxZPxtRJQxtcfvP6OXhxyVb0Hb4UCqUcdrY2CN%2B5Ai%2FPn8imf4RhY1bC2dFeFKLPty4xqA47d0fg7%2F%2FchR4%2BXkhKzsSqV%2F8kRkhcxHr7d8GgUSugkMlx7MBb6NDepUGR%2Feyjl7H89R1Yu36vKIy8o37Tv%2BeIVz7%2F9o%2BvWV1Xoo2dDd7%2B%2BwyM1%2FWPLV0YKq7%2F9b7T2LnrFMorqsSrtNs3LyADaW0nbmoC88HTSaleT11QUIoqlQrt3J0NXicrp1CMUtxcHO%2Bbnp1bhAomAvxqojHk55eghAkfv2LK07i68EiPC0%2FNrRGGkJGZDzmrn6H7NHfxh3h8iJ94EYGnwsa0hTHUfT01pZMUiRFNRE2%2F0PGIK9j%2B%2BfF6l1u18pnaTv36nJzfFtEYeCTIhwfh2U574%2B57Hx7Cuci4esv45otXa3%2B393RpVD24WPKBIBEjWiAhwX3EobmyfNEfJSubXxE15DYTgkSMIJolQwf1okawAOgyDUEQJGIEQRAkYgRBECRiBEGQiBEEQZCIEQRBkIgRBEGQiBEE0bqhm13NTN3n7giCMB4FNYH5SM%2FBGj54eWA1tUbrOabUCpROEgRBEARBWAb%2FBY6yiu7i22%2BMAAAAAElFTkSuQmCC)
+
+```
+call_arg ::= '(' int_const_expr? ')'
+```
+
+referenced by:
+
+* call_stmt
+* jump_sp_stmt
+
+**jump_sp_stmt:**
+
+![jump_sp_stmt](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAfsAAABFCAYAAABNPE9jAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAFqVJREFUeNrtnQlcVFX7x3%2FsoLjv%2B4YLuCLuS5qae2apmaapuOa%2BvGX5fysz317N3EqNzCjTXMI0c9dXSy13cd9XFHdQAREVhvmf58BMgMgMiODg7%2Fv5DHe49865d85z7vk9z3POvQMQQgghJEtjlxkH9fGEkVWfOvafSD9bsf7ZLtgubN9ehKQGx8w68L7t%2Fqx9K6nV2Jf1T9guaC9C0ow9q8A2kKiLkRdhu6C9CKHYE0IIIYRiTwghhFDsCSGEEEKxJ4QQQgjFnhBCCCEUe0IIIYRQ7AkhhBBCsSeE2AYR96IQeidCv4%2BJNuDK1VBWCiEZhH6CXt0qKLT7KG48aSdL258lX3%2B7Blv%2FPqbfDx3QFk0bVcEvK%2F7G1Wu3MXLwq4n2fbvfNEz86G2UKVUI3%2F24ERu2HMTMSX1RrGg%2B8z6m9VM%2F74NSxQtg%2BapdWBSwTW%2FL5uYM72pl0bdnC%2BTMmc3iuUmH5ffDBqxatwdh4feRN487fGp4YECflihRLD82quPMVccT3FydUMWrFPr3aqn3sxW69Z2KD0d3QrXKpS3uG6Ds8mrb2nB1cX7uvsfNW2EIPHQOrVvU5FWfSSxZth0HDl%2FAnGkDERR8C207T8Cp%2FXMsfk4chF17TqFdq1qZct6Hj11ErMGIGtXK0Igkw3la%2FTV9Xkf2SrOu%2BnjiF1mZ3M6Wtj9L2rxSE2OGdkBIaBhCQsL1ustXQnD67NXH9t219zTuRT7Q788H3cCxk5cw5%2Ft1iSKLufM3Ys%2F%2B07gfv59EF7GGWH2Mbp1fwq59p9Gl1xeIjbX8kKtxExZi3ab9GD%2BuGwJ%2Beh8fjOqEiMgo7FbnIdy4eRfhygmQsnu%2B9TKOn7yMDm%2F9Bw8fRdtMQ%2BvUoT4KFchtcT%2Bj0YiRH36vvm%2FUc%2Fk9Tp%2B9gskzlrPnsEGCgm7i08lLM%2B34q9fvw4rVu2gIkimkVX%2FreOJ1Hy9cjjHggjmyt4tL53cxGNRGT6xwdMCwhJ6Epe3PEo%2ByRfQre3bXVH%2F2zY4NsUJF7iMHd0CBfDmxcOlWvN6%2BHr79cUOi%2FfLmdUf9OpX0%2B0b1POFZZyhOnQmGZ8USKZa%2FccsBTPr0HdSvXVH%2FL9H8Sw0rIyYm1ryPZAhMZb%2FcqIouO%2FDgOfO6553Q2xGws4v77Y4Nmw8gh7ubqpsr2LLtCEqVLID3hnVErlzZEfDbDr2Pn%2F96uCtbtVZOmpeF%2BhPWbQrEpj8OIjo6BnVVPXbp2AAuzk7YsfukzriI89aiaTW8%2FWYTfR5hYZGYv%2FgPtGzmje%2BU43YrJEw5Uk3xyss14hy6iDiHTs4xd87syh5eOiIMWLkDoaERmDZrpd6vf%2B%2BW%2BrukhDhl%2Fgs2Y%2Beek8il7Ni7e3P4eJfTUemv6vtKliZHjrgy1v8vUDuIbVv64Pe1e1CgQC7sDTyjHT%2BJCIcNbKczHuIArlyzG51V25SlITYW%2Fd55xfY6oEcx%2BGnpn7otu6t6bN6kmrJJDfy18zhWrduLW6HhyJc3B9q3qo0mjSo%2F1bF%2B%2Be1vhEfcN9uu99vNcf3mHfz8y1Zdn9mzuaJp4yr62hbOXbiunPZTaNa4GlZv2KfbY7fOjXEpOAT%2BC%2F%2BHs%2BeuoY5Pee2g9lFlmbJ4IuhrN%2B6HQTn%2Fr7Wrg9fa1sXFSze1HWPUOjl%2B3jw51PGbUYFIhpFa%2FRWRN9jhK4MRxRM%2BmDnRmL0xTvyl0ODkPAlL2583cisR6qTEY%2B4PG3TntECJRL9eKXesUQ8e6U7AxcXJYvkVKxTXwnPkeFCiTICjY%2FJTIR4qQYtWlfc8prmfhIi3dKwmsfcd8jWuXr%2BNDm1q48ixIHw25Re9rUD%2BnHpZtEhe7fRkz%2BZisexvvl%2BPz6cuQ7OXqqJ50%2BpYpzraiyqK277jOAaP9lPrqqFX95exZPlfmDT9V%2F2Zu%2BGR%2BGLmCoz7dAG8q5dF7Zrl0X%2FEHPP47%2BAxfnqIp4%2FqkEVkxZnQ56ecPUcnB31u8nJUV4wl%2Bg2djbPnr2HogHZKTKqi9%2BCZuBB0Qw%2F%2FHD91GWP%2BL%2B5HYw4evqCzPKahjt%2FX7cGA4bPx8GE0OrStg01bDmH8f5fobddu3NHn36XXZJy9cE07ILZIP%2FX9%2FlAOX6fXGqBypRKYMy8ug3b9xl11XRRDr27NdH0MGDFbXx9PQ8H8ubS9TLZzUu8ly1e0cF6djWuinOiJUwK0k6Gzehev63bVY8A0BF8JQYhyPGQo4LVu%2F4G9chh9e7bQ5X359W8IU06EMPObVfhJXcsi%2Fj26NsGXX63UTpur6gfcs7tph0GOXbhQbhCSGVjSX1MkbwCWQ4Q%2BCY4WCtWehKXtGRnpp5aBKoJr0fETHWU0Ud6%2FdBxJuX37no7eZNzdz3%2BDEp9qKFu6sMWyp07sgw%2BV6LR%2F8zM42DugsldJFV3U1RGgvX1cNCxpfClbIlT%2FhZtRo0oZVK9qu2N%2Fg3xbm%2BdKSFQrwiXIXAqhQ5s6KFggl8VyJPsx028VFn03GjVrlNPrOrarq52micqBGKIE1hSpFS%2BaH206fYoxwzrq%2F52dHPHrwrHmjMNva3bhsHI8ZG7G0ROXMOH1RjpzIq%2FuXV4yn9%2FmrYfR5fWGVn3Pg0cu6Ahxvt8IbUuJBHftPaUjvyH922L6533RpvMELRJLl%2F%2BNr7%2Foj%2BLF%2FpkbMmZoR3ME6FGmCLr3m4rPP%2B6p%2F3dxdcKKhR9aNS%2FkeUTGsPeoaDdw2zS4ucY5rj26NtXLzsq5lrks4sg4OzvAo1wR7QxV9SqV5uOJ7cThS2g7yaDJS5wxye74KMdv%2F8GzeFU5oUKeXO5YE%2FCR2bGeNXctqqtr7%2BOxXfX%2F4mB%2B8VVc232knHBxVrav%2F6%2B57cocD4n0xVnzrFhcO27Wth1CMkj04%2FTXDutigAlJI3mrxN5ErOrzVIza2mhhe0wMLqiDumXUlxXv3JjMt5KI3CSyJgoXyoNWzbwxacZybFv7ebLlnTl%2FFVNn%2Fa4n0ckcgT49mlt1HtK5L5g7EvejHuo5BCIG02b%2FroV9%2BMD2ep%2FLV0N02S7Ojkp8KuqUbdJzTA2Z%2FYtZ9g7%2FnLuktqNVx54Wbty8o1PuSSf%2BSd2cu3BDp8hNlFeCIR3yteu349Jayv4moRdy5sgGgyHuPMQhGD3OXzshNWuUhW%2BPFqqTL53q8zuj7Ckp4gavjE20vqSK6k2OzjfTB6H1G5%2FqiaMN63kmTr0lMHHZ0oV0m4iMnyciApTeQp%2BR7eLMuWvaJiahN9lN%2BDlgK6bMWIHyHkWVk5ZPR9WSFk9vZBjp%2FY9%2FRBEV3XuUKYzzQTdRqGCeBG3CLVEGTTIyItrJIdG%2FXMMynyYh1dLQbmzlOia2j%2BivuuraxRjRWS0tzjJLVuzVB3eoD15RyxaqwHlqOSql7SrQmpyayD4tDV1mw5rIk9tddyIJEeEQQcibO8djn5XxUumcShbPn2zZdWtVwLyvh6a50rO5uaCGitbldefuPRw4dN68rXKlklj20%2FvpZuD9J2CXFToaSYuKYN%2BNiET%2BvDkTbcvh7qonU5oQoRTBkHkbJsF8Ej3ebKInFcoQw9pN%2B9G19xQc%2BGu62Rm0FjlWOSUiG38b%2F8R9fl25Q0esK9fswbu%2BbZA7d%2FZk97sTdk8LTzYrhjZsoV2I7cLC7j%2B2XmymJ60u%2B9g8X0OGM54WaSdJbTf2k%2Fn4ZOxb5kh%2B8vTl5sm5ySFtKmmf8c%2F3iYtTNq%2F67InDT6lpO%2Blhry6Aw8UKKGWwh5fas5nauZs6g6OORgzZcxKnKXVZgzqVUCHGDrOVfaso%2By5WV%2BAWh1gcL30aQQGAIbnrMqH%2BquW3Kkb1fxANXxV49zPaISy5FL52yJMWohYBqgBP9Qp2dIBn4AmMtrT9WaXwZfxckPE28cyLxadJZdLV3gNn9cQZE7PnrUXF8kWVp5%2FnsXJKlyyo08%2FpTc8B03Ho6EXz%2FzdDwvDHtqOo5e3xwjVa6ZAlWpW0qjXIpD6ppznf%2FXO3xO79p3U03axJNSxett080XHBkj91dJ7UKUhWgH%2FfqdP8knYf3LcNIu8%2FwEN1Jci5XVdlR95%2FaNX5NaxbCZeu3MJva3ab1wVdvmm298q1u%2FHnX0ex%2FOcPdFQ%2F7P25ieZtmMaCxUmZrb5jq%2BbecHDIGo%2B1qKec4%2Bs37uiJldoRV9979fq9MKqlQdlMJlgKMrntVDJ3zaQWsZ3Mbbh7N9K8TubguLo6mfsH6Q9SokXT6nqy3t%2B7Tuj5FjJeb4iJywZJ6l6G1qbMXG7OQsixtv51zJw5kiGdjEQ6%2Br2ncT7wJFZLHxsWjdKq%2F91qsMMuby80B7F5xI5iT7Gr2FfsLPYWu5uE3hp93nEYR2Xp4IDyyicNUPtFqJ2DU4rspRDxFHY7qUKSEXBL29OdXoPiJkTJhdfptfq6kxFkPH3SJz3Rc%2BAMPeM6KuqREo9smDtzSIYaK1%2B%2BnDpydFIVIjOCb6tOp7uKLAf2af1CNt6BvVuh97szkSePO94b9roev02JmZP7YuCIb%2BDdaBQcHO3h5uqCgPnvYfig9mr9HDRsNRa5cmTXgv3jNyOsOof5i7fgo%2F8sQoVyRXHh4g18%2FH5XHXGLYMiYbd3m78HBzh7rl3%2BSrGOY0Bn5Yc5wjPnQHxMmL9UOhIzbTp%2FUV8%2F0%2F%2FdnP6tzHauzOvJsh7bx4%2FejhnTQn5eZ4vMX%2FaEdVoly584cnGXsLHXjN%2BNdPVzi5rIY4ZFR8FZi2b51bQwb0A4tO47XEzZlgqxJ%2BJ8GybDIjP6GrT%2BAs6Ojvs117KhOGDTSTx%2FH2dlRCXbKE%2Bca1ffCv4Z11JkHGXLo%2BkYjvXSKn6jpN%2B1d7bBVazgCudyz4U54JEa%2B%2B6o%2BrszM%2F3HRZtRqOkYPC65e%2Bu8Mr%2FOzZyFe6sSalfTQaYCKCOsxwrftiN6ghFmJ8zsi8Nb4f5b0N37d6LpVMDnagLFJI327%2BDTBfVWInyok2XS8pe1pSRfu2%2B5vcT9JnQVfDdWdRnK3SYl3f%2F3WXTgqlyaljvtZE3wlVM8hKFQwtxaF9KZWY1%2Br03%2FpWf9pQRyzRzExyU6EfBKSEZGoN1%2BexEMwcvvWAyWWMgs6Ndy5cw%2F3lIMgQpD0zgfJHIhAm26ZswaJYu3V%2BVn7nfoNm4XGSlxkQpekllNTF7bWLqTti6Od8PoMuR2urk1Dul%2BTMmlO5r6Is6GzJ2GRCL8XpecGJJzDYQ2SdWjZ8RMc3zM70d0zt1XbuX%2F%2FYaLJlqYMjdyF8jTXeHrZS9lJvI2XVBktKZu2ibKhPG1tm7LhRCv2TZP%2Bymx9EX3V0Aap42TTrVY5t2VSKsTS9meFXMApdfRO6sJPrRBYy5qN%2B%2FHDws1P3D7x391RqULc0EjSjuFFxjRunfDpgcnx8dg3zZPzniSGcrtcWpDMQp4nPKVQOmth6qyV2Lnn1BPLSDjPQqK5tCBOhbyyMsm1fWuGWxLylu%2BXiZ5NkZDa3h4qin8jrp0kuctDRN8k%2FNbQ%2BZ0v4FG2sE7Ly4Ny5JbKpLfJytMtk3vCpTijz6qvSS05ovBlhBuGeFdG9QPHcIi9jm0hdkMsqio7drBm%2F7Tqb8JIX5eTYKWlD71QtGvpo18kbcgDVuT1vDJm6GvPrGy5A8Ca2w9JHEv8%2F5UhxxncrzXOnb%2BuH5Ajt0rKA5JskT8v4oGPFxbZx6KT%2Bpdib2Nou9lhkdgxFaKdZkyfd2TVE5K%2BNKhbiZXwHCLPz5BXlsCILUZgJK1qi6ZDfTsjZmS4k8GqJ4QQ28JgxDE7oAJrwvYQu4n9KPaEEEJSxO2eTs0WYE3YJAXi7UexJ4QQ8mR2BuvxXlfWhE3iGm8%2Fij0hhJAUkSc42bEabBK7ePtR7AkhhBBCsSeEEEIIxZ4QQgghFHtCCCHkBSDTHqqT8DnRhPVP2C5I5vI8%2FPT180p6%2FPbECyn2popj48rchsv6J2wXJCHP6gey6ABnPkzjE0IIISkgDrCtO8GZ%2Bmz8rJAayQqRHCFsF4RkbRjZE0IIIRR7QgghhFDsCSGEZDR8ZK7tkSmPyqXYE0KI7fKgfnH%2BGI4tEW%2BvB5lxbIo9IYTYJrei3FGI1WA7xNvrFsWeEEKIVRiB0w52qMyasB3EXmI3ij0hhBCrsAN2qj%2FNbOV8I%2B5FIfROhH4fE23AlauhL6LRmmm7UewJIYRYQ6w9flXhffempW1j3H7Jsu346LNF%2Bn1Q8C00e%2FWjF8pe2k7KXtpuFHtCCCHWcOAYDqnFkQg3%2FIu18fwTb6cj8XbLcBxpAkIIsU0cjBhqsMOumpVwMPAkVmfUcaMfxeCnpX8i8OA5uLu7oXmTamjZrAb%2B2nkcq9btxa3QcOTLmwPtW9VGk0ZPN63gXuQDTJu1EjdvhSE6xoDKniXQv1dLuLk6IyYmFl%2F5rULfni2wfvMBPTQwbEA7xMTGYt78TdgbeAalShREyeL5Ua9ORVT1KpUpdlL2aa8Wo5W96mVWW6HYE0KIjbLnJE57e6GLPRDg44lpYdGYcvYsHj7r4%2FYbPhsGQyx8lcgGXwnBnHnrtNhfv3EXFSsUQ9vStXAp%2BBYGjJiNZQvGPpXIRiqxd3R0QJuWPnBxdoTf9%2BtxOTgEUz7rjRhDDKYqR2D1hn2oXqU0smVzgdEO6D9stv7sO91exu07EZg%2B53dkz%2B6a4WLv4QGXXE54T4Q%2B1g5d9p%2FInMl5FHtCCLFxDhzH5jqVUC%2FGDrOVsAyp6YnFMGKLQyyOlz6NoADAkJ7HO3zsIvaoiDlw2zQdXQs9ujbVy84dG%2BjJd2cvXIOzswM8yhXBwcMXnkpkCxXMjXFjOuNmSBjOnb%2BGpo2rYvmqxHPcvp0xGOXVsYQjx4MQePg8DmyfppwDJ71u7cb9GWKLLoDDxQooZbCHV%2FxkvG5G4KijiugzU%2Bgp9oQQkkUifLV4xbsyqtsb8YZ6PzzWAeXPe6KUTzo%2FZe%2FMuWtaWE1CL9jbxx3i54CtmDJjBcp7FEXxovkQEhquMwBPw%2BUrIRg06hsd4XtWLIGIiKjHyiyYP6f5%2FfmL11GmVEGz0Kcnln757nzc0%2FGCVG2cUbW%2BU0XzrTNrjJ5iTwghWTXKjxOWNImLtT%2Fh6p7dFWFh9x9bL7fWjZuwEOuWfQwvJcrCgOGzn%2Fo7zZizSpcnaXthp%2FJsPhi%2F4In753B3007Gs8CWfxGSs%2FEJIYRYTb1aFXD9xh1s%2BuOg%2Fj821ojV6%2FfCqJaGmFhzRH3x0k2cOnv1qY8XHR0DF5e4MmWIYPPWwynuX7tmeeV4PMC8nzbpKH%2FJr9tx6MjFF95ujOwJIYRYTa5c2eE3412MHucPN5fFCI%2BMgnfVMmjfuraeCd%2By43gUyJ8TudV%2B6ZFKH%2BjbCt19p2H9%2FwJhNAI%2BNcqluL9E9t%2FPGoqJX%2FyC75Xgv9SgMkqXKggHhxc7tuUvJhFCCNFp%2FH3b%2FVP1meAroUr8s2mBNRFyOxzRjwwoUjhPup3bg4ePcCskHPnz5Uw0V8AaJPPQqNWHmD7JF3V9KqT62LUa%2B5rf23Ian5E9IYSQNFG8WL7H1uXPmzNVZbzl%2B6W%2BXz45ant7YOyoN%2BDq4owSxfJbXeb4SUsQGhquIvpC%2BHvnCRQtkhd1apZ%2FoW1FsSeEEJJpLPFP%2FwcAdunYAIEHz%2BuJeoP6tkazxlVhZ%2FdiJ7Ip9oQQQrIUlSuV1C%2FyD5yNTwghhFDsCSGEEEKxJ4QQQgjFnhBCCCEUe0IIIYRQ7AkhhBBCsSeEEEIIxZ4QQgh5keBDdQghhGgSPgeeZC0cWAWEEEKuheBTeRUtgPGsjSfXka2eO9P4hBBCCCGEEEKILfP%2FjM3JwNSc4lkAAAAASUVORK5CYII%3D)
+
+```
+jump_sp_stmt
+ ::= JUMP_SP int_const_expr call_target call_arg?
+```
+
+referenced by:
+
+* basic_stmt
+
+**from_stmt:**
+
+![from_stmt](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAcMAAABHCAYAAAB70CykAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAFThJREFUeNrtnQdYFMf7x79XAOlKsYBdqWJUwBZrjFGsiGhEY0wkxm5MNDGxpBgTfYzlH03MTxNDookllhijpseuCIIlIlUBURQRQTood%2Fuf2ZMTFDwOODiO9%2BOzLruzO7M3O%2B98552Z3QUIgiAIop4joSwgCMPGyw0C5YJ%2BEx5FdXFtI6csIAjDJ%2BxEEGWCnuLdJ5AyQQ%2BQUhYQBEHUvvdOHjyJIUEQBEGQGBIEQRAEiSFBEARBkBgSBEEQBIkhQRAEQZAYEgRBEASJIUEQBEGQGBIEYWjcSsnA9eQ0KBRKygyCxJAgiLrB%2BNfW4L%2FLiVWOh4vfhClrMOzFZXhl%2Bjqk3M7Qy9%2BbkZGDA7%2BfrVIc%2Fxy9iJu30qnw1HHodWwEQajxH9kTTewbVjme0HNxSLx2B2ePrIZMpr9t7us30%2FDB8u0YMaRrpeNY88V%2BzJ%2FjC4dmNlSASAwJgjAE7qZnQyJRvTP6z3%2FPw9LCFDFxyTh8%2FBJatbTHO3NGwdra%2FKlx5OUX4vtthwFBwLr%2FHUCb1k3Qu6c79vxyGuP9%2B2D%2FbyEoKHyAaZMHIzUtE5uC%2FsTl6CR4uLXEVLavsZ21GM%2BOPSfg5twc%2Fxy7iIuXEtC3lwcmje8vxn0yOBKtWzbBu2%2BNhoV5A42%2Fi1%2FT5q1%2FIyIyCVaWpujh7YIxo57F7n2nkZdXiLVf7hePmzThOcRdvYXs7Hzcy8zFoT%2FDWDqNMX%2B2L4LPxmDv%2FtOQMnF%2Fc8ZIuDo74vipy7h95x72HTiD%2FyIS0fmZthjQtyMVpDoIdZMSBKFmY9AfSEnNUIth4KwvcDMlHSOZ53Tp8jUsW7VLYxzcE7RpZAGZXIYWjnaws7FCGhO9Vev2wX%2FSSkQzcU27m4X8gvvwm7BCPGfu9OFQKgX4T1zJhPK%2BSgz3HsfkWethbCTH4IGeWL%2FxAPoPXYzkm3fZ9XRDaHisWsQ0seD9LYiKuYFXJwxANy9n%2FP7POXG%2Fvb2VKG78OvliJJPhTGgMZs7biPALVzF8sDcuMCEeMPJ9bN99HP36eMDExAgz528Uz%2BcNA3599nZW4vmNNDQUCPIMCYKog0wP9MGbM0eIf1syj%2BozJmiaMDE2wrPdXBETm4yxfr3EfVEx12FkJMPPP7yr9ix%2FZt6UtZUZ3l%2Fworjdk50TzIToj3%2FOY9Sw7uK%2BZYsnYLiPqguTe4dWlo%2BOVyiVzLM7VaHfwT3P114eiGe7u4rbLz68rv69PfDdj%2F%2Bqr7MYX5b%2ByqWTxL%2FNzEywdsN%2BbNk4V9we2K8TPPvOE0W7k0drNGpoIXq%2BA%2Ft3ogJDYkgQhC7p0gGdpAJGQ0BPtunEllaoge%2BRSmWPkuDC9eCBotJxGRvLS3WxJly7DWcnx1LHODs5ID4h5VH60kedV%2BaPdYfyLtyiCs5SnTtjBN77aCs2fPMbvDq3x6TxzzEP0al877ZEuhbmpqXCLCxU2zwvGphUb35X4MsVPPwaW%2BLY3Q9WSvDz%2Bcu4SBZCYkgQBg1zlpyLJNggUcKD1YI7WFW4XqZEZOtYXNvNnKNqqmBrBT7Wx8fmSsK3yxsDLB7LLLGjwmlxT3PIC564HJmEv49eRMDk1Qg7tkYVp4bcqUgyvIu3OtD0kd%2BxTKcTndFKIYU72xzAGkh%2FeLohQi5gVmg0YsliqtDwoywgCD31Bt3xvEKCM6x2PJb5AK3PRWHeuWgcPBuL%2BIoKoT7DuyhPnYnCteup4nZiUipOh0Sjf5%2Fqn4Dyy6EQyCRSeHZuh5lThkAQBOTkFsCKebsZWbm4m5Fd6bitrc1wtYQ3q0v4fef3n5cDXh54ueDlg5cTXl7IasgzJAiD8wgVAnazOnsSr%2FgM8Te6ODli4Tx%2FDB27DE5tHRAXfxOL5o%2BBc3uHak9r7%2F5gsZvU1ak5EhJvY860YWjZ3E4Me6F%2FJ%2FTxWQQTIzl2BM3XOu7JLz2POe98jS3bD2PIIC98%2BO64GsvDK1dQyFafeLriAvNsdrNy04M8xMohoSwgCP3Dyw1%2FsdXx8Ch8Ug1xCWEngvT2t%2BbmFSKdeWa2NpYwMzXRWTqZmbnIyskvMx3%2BiAcXQ%2BtKzgblj27wB%2FgdHWy1Pte7T6D6b03dpBru8xK26sviGEQWRJ4hQdR5%2BGQZKNHRMh8j9fH6bqfew6y3vy43fNSwbpg4rn%2BF4zM3MxGXysKfC1y49Idyw18O6Affod1FoStP7IqfbawsXFx1KeQVgZWX1dmmmMXLD02qITEkiDqPVAl%2F5h9sP5qIAn28viaNG2LP1gV6cz1O7Zrp1fXUFry8eLlju1h%2BQGKotd1RFhCEfiEAPdl%2FhykniEoUnsNi%2BSFIDAmiriOBOHnmMuUEoS283PDyQzlBYkgQhoC9aQ5uUzYQ2vKw3NhTTpAYEoQh0CD4hn6OFxL6zcNy04BygsSQIAwBPr1eoGwgKoEAemSOxJAgCIIgSAwJgiAIgsSQIAiCIEgMCYIgCEJr6A00BFEPKPn%2BS4IgyDMkiHoHf%2FlzVV4ATRDkGeoIff3YaHVVPJRPtZtvZSGETTXaE3xmbmRsxqSYq5lO6Zn3Te6kF2hM07aRSZG5qdE9OxuTY1eS8lccCckLp2qDqO8Yoj3VWjepPn9SprLooivKEPOpJvKtJH9%2F7zXjzXW%2FrIpNyDIfPqAFRk1viaaNzdDYVvOzyal3C%2BQpqXl2J8NS%2Fa8lJ%2FmO7G8WlpyWNzE8AlepwUHURwzVnmjMUEdeL1U8tZ9vgvCRdNf6vT99tjFizMTR7fDZwq4wNtJuZIAbOF%2BecbPBlABn%2Bc6DCT0274yN8O4ojA67pPid7hxRb7xBA7cnGjMkDBZuuEE%2FxY1Zs6QrJvm109pwH4efz%2BPZ8HGPBmbGkgPe7qBZKQTZk4HYE4khYZDwrhzW4hyzapE3Oro0qta4eXxfLu0hk8ulm7uQIBJkTwZhTySGhMHBB%2FcP%2Fnt91UTW6qxuwy1pwBN820rkkGxiLdohlOsE2VPdticSQ8Lg4LPcrlzLNg8Y3kan6Uwb7wJjY6lcKeAnLw%2B0q876h%2B4iUUmq%2FSXvBmBPJIZE%2FSQyLuMVn36OVR7T0ASPv1sne177yKHA6mqMurB%2Fa%2FoMD6E9PZuL5aaA7InEkCAQE5%2FVrrd3kxpJa1BfB74yZUvvLh3QqZqivZtrQR9oJbQn3wK84N8heyIxJAjcTS9s4NjUrEbScm%2FfUPWHBKlSJfyrKdr4IiWc6U4S2iKToIMAxJI9kRgSBNKzCiW21iaVOvdmagGu38pDXoGiQsc3b6KuJCzY8kJ1XD%2BrzMIkSvSmO0lojQQDJEBwbdlTSprKfnLyiiqVli7sqaKID91390CTkAjcLu8gTeG6ZN6iICTdSCu1z8O9JT56LwCvzliPnFxV97itjSUG9nsGY%2F16lTo29spNrN94EOEXrkAikaK7txPenDUSrZqreqFSbmdg9jvfYGD%2FZzA90Ed93q2UDMxZ8A2e6%2BOBWa8P1evyn3DtNt55f4t6e%2BmiAHRwbYnFy35ETNxNcZ9NIws4t3fA6BE90LZ1U%2FWx23Yfw74DIU%2FEufyDieLxL0%2F9HAqlAps%2BnwlLC1Mx7OjJCJwOiUbgxOfFvCuP4uuoaZQKAVKZds%2Fuxybm4OX5oYhPyhW3N37iCf%2FBjppbkw%2FTEQTYSKrpJRaCBIdYK3U9%2B%2FNj0GQaooLwceZsAROUUvjUlj2NeyMEkXFZkLPjA8e2wafzO2jnnVXCnqqqT8Xni4k9UOCmlxv2ymWYU1akmsJ1ycWIBAwb5I2e3VzU%2B6ytzcV16Lk4LHjDDy5ODrgSn4Lla%2FcgJfUe5kwbJoZHxyZj1ITlCHx5IN5iAqhUCti26yiGjV2G33Z%2FgJbN7ZBfcB%2Fh568gjonmOL%2FeaNTIQjz3my1%2F4XJ0Elo42uq9ETRvZotPlryE50e%2Bj4M%2FLUH7ts3E%2FZcir6G7lzMG9O2Iu%2BnZ%2BPfYfxjstxSrP30VvkO7i8ckXb8DE2M5Zk8tLfjNmqqmUJ9leezoYINN3%2F2Jt%2BeMEvelpWUhKuYGGjY0x%2FzZI8V9RUVKBASuxperp6JpY1VXRwsHuzpTkazdHCsKYcDwFuLi0sZCywa52JI1rY5rOR%2BJI17ukHq7wz8sEnuomicqQrYp3uZmf%2F4yLtbWNaxb0gm37xZi7rIL%2BHpnPCb6toBbe6tKOLgVt6fK6lM3N%2FgpJFhfpACv5M3kDxPm3aVjFQr4sUj3PR6ppnBd4%2BLkyMTQtcww7iV6d2kvhmdk5uDoiUtqMVz5%2BV74DuuOBXP91Md%2FtHC8KJhrN%2BzH5yteE%2FeZNDDCiKFd8e2P%2F4gVflZWHg79FQa%2F4T2Qn1%2Bo90ZgxMSMC1axiJkYG6nDuDAW591wn64YMaQbpr6xAV27OMGhmeoce3vrcvOX8w5rcLy58Fu8%2BtIA2Nk8KtgNTIzV5z24r%2BoW8ezUFq1aNK5zFUlquuo%2BTw1og44u1pWNRlZdjXFmc%2FNY6%2Fi7zq4IuxCNRKrqiafh6YrhvCNNJqBHbV5HZ3dVQ7hvV3vs%2BytZFEa39tCpPWmrT8UiyBze5iX7XUqNGQoqt5RHeoNFuou7j9qE64qYuGQEh0arl8L7D8o8jndttmih6v7kXuCJ05EYPfLJssFF7tiJiFL7pk0ejB92HBW7XbfsOIIxvs%2FCwtzwZrdzL9HNtQUO%2FRmm3nfnTmap%2FOVLdk6%2BOtzVuTkGD%2BiCLzYeMtjKpHiMw8rCSC%2Buh3mEvwvMYFltcMLTHX2ouifKon17mLC6eIlEgq2sBTWWmW6sPlyXpYW8lF3VBJr0iYuglzuuK4CfwYXwMeQaIhWVVlO4rj3Fg6ziPh0ao97%2Bau00NLZTtd537j2B46cuI%2BX2PZwKicKOoLdVN4FV5rwLtLjLriRNmzRCWnoWBOFRs6CFox369%2FHAN9%2F%2Fhd2%2FnMbBXUuwMegPgzSg1qzBcOPmXfV2ZPR1rPny11LH8DFDy%2FaPeinmM4%2F5Bd8P8PorgwwmHxSsaZhwIxfHz6bhv%2BhMPOtpi5YOZnpzfecisdzLFYkSAXs93RDG1j8pZThrnYv4o4nV%2BywZUTcYy7ylRGe0Ukjh%2FnCyzHhWi0XImUcYHqUfQsjh4%2B07fr2ODVuvwq6RCZxbW8CmoXFNi6JKnyT4nUnyx497ghUSQ3VfDXCBuY4%2BgobwoiIksERNdfXj5s%2F2xbDB3uWGFymU%2BPlAML5YNVUcB%2BSYNjCGVCpBVnb%2BE8dnZ%2BfB3KwBJJLSg8IzpwzBIL8PMfml58UJJ1VBn79FeC8zF%2B3aNFNv92ONgOIu4%2FLg%2BconJ6358hf06u6ms2uryXzjXTg9xxxRdet0s8O2td0gkejn9bPLGsL%2BGyJVimNDPB2iHhL%2FqDyULBtNFRLE6FOZ4A3LHeu6YcJboRjx%2BimMHdIcX33cpUbtiesTy5thRQLGsLVSU0TycgzvNDsxma0Hsgg3s%2FVbTws3kmOlNp5hdVYYAf59xDHDDm4t8dbCb9GqpT3cXVqI42gebq3ErtKO7q1KnXPyTBQ8O7d9Ii4%2BNvnWTF%2BMG131We3V8SkiXVSsN2%2BlI5h52Qvnj9H63LkzRqCPz0LY2VrpzIhqMt%2FsWEv12xVeOBV%2BF0F7EvHuZxFY936nWr9%2BgtAnKlMP8dnZUxefQxPbBpg9qR26d7LRmT09fn0l9YmtNzUwQlDBAwQyx22KIEFmWV2kHOnjkbDVbhaBG1tuyGVwOxeFeZrCa%2Buxi5IMG%2BSFma8PwaRpn4uPS3D4DMn1mw4i%2BOyjLtYjJy5h85a%2FMWtK2Y9LvDlzhHompSGRzTzkvw5fwNhXPsPEgP5ig0Fb7JkIBk4ciO%2B3HTaIPDE2lmLkQAesfLcj3NpZYvuvSeJzhgRBVI3vWOMy%2Fd59LJrpisAxrdHByUrnaZanT6f%2FQwRfy2RwEgTsZsdls4NvPM0z5JFwJQ0xYpGUIXCawmudN6YNx9X4FLwyfR1%2B3rZQ7FrNzMrDtDe%2BEj1FpVIpHrd2eSB69TCcfiY%2Bwehl1gjgjAj4FJv%2BbwbzfFXvueXPafLFzNQELs6O4kxb7k2XurH7TolLSQ7sXKyOoyQzAn2wdecRgzNeOxsT4Go27mXeh0Njei0oQVSFDCaEHNsaGiesiD493DevuwdWPlDg3cc9xWIxzOdK%2BhSR0xSuM%2F79dVm5YZEhXzyxb93KKaW2J4ztK1b%2BybdUE0b4RJmStGnVBNFnN5QZ%2F6JKdCXWBrx7N%2FTwqif2%2F7pjscZzF84bIy7lER1WOm8sLU0REbz%2BieN4YyM5OqjOGq%2BlucoU%2FjhxGy5tLSGTUW8nQVSGW3cKEBah6p2zspDXRJJa6dPjosgsfbpaDJk72eZpkWgK13f4RJrHRZAgSvL6uDY4euYOVvwvWlwq%2BgYagiAe0W%2FCMfENNBw%2BKa2Le0Odp1lZfSopimox1BRRXRZCov7BX%2Bmk7SvZenvb4fzBgYi6kq3ytiv4Bpqc3AeU4QTZ00P4G2hy8xUwN5WpH8DXhsrYU1X1qfh8Od1qwtBoaGlcdDezUG5vo93Yn421MXp5aff6vbjELMpwguzpIZ2r6AnWpj3RVysIg8PS3OheckpejaQVelH1EnmJAO5SKij3CbKnumlPJIaEwWHbyOTYybCa6dn%2F%2B6TqqyCCBKlsRcMJBNlTHbUnEkPC4LiSlL%2Fi0OEbRfcfKHWaTsKNbCTeyCm2JP5ykCTKfYLsqW7aE4khYXAcCckLNzaShu08mKDTdN5bGf5oQwD%2FEOLflPsE2VPdtCcSQ8IgSU7Lm7h5Z2zBpZgMncT%2F2dcRuHotu9hw49nipZRiL%2BU8QfZUN%2B2JxJAwSMKZbd1%2FIPjP%2FvCMoroNmBvurpKtZAlOSoCztflRVYIgeyIxJIgyCbmk%2BC0nv%2Bj1aQtPC19sjUJVxzz4mMa4OUdLG66Abez%2FwYIMCyjHCbKnumtP9JwhYdCci8R33m5K6Q97r27c%2BWuCvEdnO%2Fj0aw7ndlZo5fD0B%2BvzCooQE5%2BF0At38M%2FJm8x4c0ofwA2Xf1NOgslhrOVMuU2QPdVde6qVFzDq87f%2Bqq1bQU8%2F4VQf8q0sPDvAB0rxjfUytlm1b2%2FyMQ0JTrK1D2vBvnLuMv4AQdQjDNGeZLWR6K00LOWLgz0%2BMtTCwn8f5VPt5FuZ8d7BFYem2MUMrh1b7FnrM54ZciEzQt47ounV%2Bjns2GSpgFBBgkushdJKKsEddmYAM9yzVDUS9Q1DtCfqJiXqj9ep6nrx69IBnaRK%2BLO%2FB7HWrYT9M9dwqoUg4B4zXP6uqVDWel0aRpNlCLInsieCIAiCMCT%2BH8FXwwPn47YZAAAAAElFTkSuQmCC)
+
+```
+from_stmt
+ ::= FROM IDENT '{' in_from_stmt* '}'
+```
+
+referenced by:
+
+* statement
+
+**in_from_stmt:**
+
+![in_from_stmt](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOcAAABRCAYAAAApZ7FIAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAEOlJREFUeNrtnQdYVFcWx%2F9T6L0JIlYQATWKoEGjgh02lhghlhjd1RjjGqOrq65ZN6tZv2Q10WRj2WiwxESjoCZGTbFr7IJiQRRFsAEiRTrCMLP3vgEXFBgGZ5jC%2BX3f843c985r53%2FPuffd9x5AEIReIjKGgwjwhYIupXaJTdCuryhi3jHZcfrMzGuJORNuJOW2z84tNXuUXfLcNp0czGRWFiaPnR3Njt26W%2FzJkbNFscZ6zqXGciAxv28gBWmJwD6TtGr%2FwKaAabP%2B8%2BOnicl5VkP7t8Rr77aCWzNLNHMyf27ZjKwSaXpGkfOJmIxRdx7cHTE8xDLmQWbR%2BNirSDK28y4xhoNwd8GidyaNIBVpiXUbdwvnmE9pmVissWipWCT2c8yKWrkpYe6QEA%2FTJXO6IcjfBa4uFrCyrDlu8L%2Fz8u5dnDF6aFuxXAGPKwk57zRzFl1IzVDcMqbzLibXI3RF1Jc7t2%2FYfjN8%2BcLumDDSE6Ym6rkjX56vt%2FqjIHNLU9GeQD9MInEShAZS2chtieGffhCIzh0cXsgWX3%2FV4iCJVCqO9DcigZI4iUaHd%2F7sPXTv0%2FEs6r2oMKsKdNyIdiIpRGtZBA0jcRJEA%2BC9srfu5FuNGdpWo3anju0AU1OxlLVDtwd0gieJkyDU5NrNnImhwS3UbmPWpw3ao4sLv%2BcjRTk%2BI3EShJrcuJ3n2TvQVSu2B%2Fd15zMLNvX274guJE6CUIOs7CfmLdwstWLbz8te%2BUOEDLEco0icBkRqWjbKSmWkEB2SnfdE5GRnphXbHq5PRW%2FNpkEGL86XO6HOHENVuSERNuojJN5O1Zi90jIZwicsQ1Jyulb293J8CuIuJzd4%2FcKiJ9ix%2B5ReXQN5uQJiiXZGA1baVSjgyGatdHF8L6qXyvUFcZaVIzXAF1G1GVVV3pSRiMUYPfIVONpba8X%2Bvt9isGvP6RdIIfMxd%2BGmJnddRMrIqRN%2FbaheevhiZIAf7snKIdTG0ooD4SKNKC9nhb74QSrBjLNX8bDKgdZZbmikpedg%2B84TSL7zEKGDuuHNiGDh77dT0rHxu8N4%2BOgxzEylCOrRAePC%2B0IkUtbGPAIdPnYFUqkYPt4emDiuP6wszZD2MAdi8f8jwb79sTh4JA7l5XIEde%2BA8Nd6wdSk7mHMPPJu2qLctquLvbCOvZ0lzsXeRBm7WitW7Yajgw3%2B%2BGZ%2FbP7%2BCLq%2B1BY%2Fs%2B3EJ9zFoH5dEcEqiPWbD%2BLM%2BRvw9nLH3JkjYWFuiugfT0KukAvrc94Y2RseLZwM5lpFRiXjUkIuQvu64dV%2BbmrXnTqqGNTSCxdluQhfsoTCo%2BojHNXanAqlWLnR%2BzUpX1W5ofCvZVHwcHfCwJAuWLpiF37Ye0b4e05OIVycbRHBhDG4vz%2FWfP0Lvt12VCj7bvtRrNu4XxDNkIHdcDMpFffuPxLKvlizB4%2Fzi4TfK9fuw7Ivdgm2%2B%2FXtjD2%2FnmfLZapMPUeM%2Bxjt2rhi%2FBvBcG%2FuiENHL8HczBQ21hbC1LKFM9xclZ0d3zBxvj1jNaytLARhfrxiBwYM%2BxDZOfkY8YceOHz8Mv4b%2BYuwbDNnO%2BYtImF9PpmZmxjUtToZk4Vte%2B%2Fhyo1cg%2FMzVXqpjJTlwC5wYT6DVIVRQfmqyg0tkq5ZMRUdfZTNkfyCEuz48RRGDg1CgL%2BnMKXczWDRNRsvB3ojNi4JE8b2w1UWoTq0d0e%2FPp2ESPrq4IDn7MpYPrNq3T5EfTMPXTq1Ef7G7crldT%2FR9iA1C0WFTxDGoribqwP6vtLxaZlvBw8UF5cKkbEq%2F140Af2Z%2BDmnWbRs3645Zr%2BnHPyfyyqK4yfjhd%2FBvTuxGlj03PqGQod2NsjJK0UrdwuDTbGf04sIv8iAj56NlPUS59OGOxDHQmuoQkW5TIZktlGDPHuebd1Y5FS26c7GJmLW%2FEghffTybI5bSWlo21pZ2f2RpbCT%2FrwSnXq%2Bj8CuXhgW1h3hI3pVs5XK0lseBTv7ta7eSSGuu%2FOjPdvWiFd7oOfA%2BawCaIFXgnzx7uRQuDjZ1tnWrcTGqvqpt7WxhIx5gjZo7Gdn%2F%2FZuB4PaX1V6Yp7wqkyBcDaXq9oxaS058ym24gM2H8gMRrL5X%2BoqZ82ppZWRM4L5TYo3WpeL4ccW7M%2BWGcuWvSpVYPq560jUN4cpKCiGva2V8Psf%2F9qKaZPDhEjJWbfxN1yOvyP85m3MUweXIuHGPZy%2FcAuL%2Fr0NDvbWGBD80lNb1lbmUCgUyMsrgr29Vf3bKCwSf%2F7JZHw4bzRi4m4JbU9eSWyJnF3Z86hi%2FeeuX7UyhQY7RjXx0LU61ys1owTJ9wpZBSTFSz52OtnfaqmoD7xlIqxmRjuxg%2FieHclhiRzX2iTiTjRQXtPxVdULm69lLYsNJWWYxKrXt9m1ya0ppX1OnJVGFEojZ00k8OWiYxv7S13lVW0IO5iI27x%2FhU17vbywwM4Ec1mD94y%2FHyIuXsMhXddgJcVlyvmTUmzdcRxhrA0p9LKxFMDc3FT4zQXG00UrS%2BUDvweOxKFHt%2FYszWwpCDV69ylkZ%2BdXs%2BvoYA3%2FLu2wZv0v%2BGBO%2BNOUk0dnoe1XCzyNzszKQ6C%2Fl9CGzMsvRuQ3B4QyO1ZxVFYQDcGWtVd5un2XtXtbeTgbXGazfH0iNu%2B6gwXTfBokTk3C%2FHcAS0WjmQ5W5JZh6K1beFJZdr6OIFeLXmazNuhSdmnm1ybSquKMrkt09SivkYoDWNLNR0iBo1nNE6StCFpfZsxdJ4SUnNwChLA22aTxA4W%2F%2F3XGa5jJIhbv2RSz8rZtXJk4levEJ9xj630tdNpkMlHy1HU4S0WfZeWyKZg6879CL6mYpZ48mkZvnlfn%2Fshk5fjznLXCNrnAs3Ly8Z%2BlU4Sy4WE9sHHLIQSGzIFrM3vsi%2FqHWsdqZ2eFseF9MHjkP4WKZtVn76Bn9w4GI87fz2fC2lKKSeFtdLofPGJyYbIsZsKF69hbj1VU6qXib7WKVFQRhouYka%2BYkaU1GVFVrkY6s5DN%2BrJUY7Cm01p1X1PCO2FMTKXPRbR8FrUe5xXC3c0REkn1AVQ80j7KzGPOYg4Hh7rva2Zk5grrO7H2a31JZ21WftuE96pWhd%2BSSU3PFsSp6pZMbWRm5zHxiwXxq0vV15RoKq2N%2BWmYyuXupxfDf9hBTH%2FLE4ve96v%2F%2Fg7fo%2FG0lu3zfjY7zuwtqceyDdIL783lImU7%2FC7bjvJdEFIJ2tZlRFV5fbEpxmf5FpjOByRfjMclXdaELdxrvtdnY2MhTDXBb208K5zaqCp6fjtm98%2Fnau89Xj4VzVzshJ7aGjt%2FmMjru93acHa0NbiU9kRMJn8EDNPebKfbdJYPoJejM%2FPf4fVZvqF6qRpJn6a1qgxp6jbJ0RSUBPhha8WA5EtoIrw1JkSYCCV8iF19hvCFBbshJMgFrjW86KvWDr7CMs3vL%2FdXEbZy%2F1VDZA2mcv3GH%2FiuwGEW8nuSizZd7G1MZVm5T1S3l21M4OZsrpbtmyl5WnBZ5q%2FMbxu9EmvsDbIKM57Vl97kok0XGyuTxw%2FSi7Ri%2B9wl5WgskQK8K10jN3u5v3K%2FNXpxWhQIIduFXLTp4uRgduxEjHYGlB04oXziSCFCBptpaiMuFX5r3OI8fV%2FI283JRZsu%2FE3t%2Bw7fl5WWyTVqN%2Fl%2BPlLuF1R6Nr%2FPfldDps0r%2FNa4xalM4Y3jMxBEw%2BCfUDA1Ecds25usUbt%2FWxpb1csKeSDVkGlRhd8avTgJAvwTCpHbEkuu3MjRiL1l664i6U5%2BpTBvsylALsZOQz5HJE5CJ%2FBvm5SWKUa9988z5S8qUC7MqKpRWIQTLNSd1%2FW9dBInYbCcvVL%2Bc0GxbMrUBacUKzcnQN02KG9jjp5xtLowFdjC%2Fh2ikGCeoZ8fKbkIoUsuXMPGQF%2B5%2BNudSV9t%2BylZGtTVGaHBHvD2tEVr9%2BpDDYtKZPy1mjgX9wgHT6QycRY825uxRXgSSoQ%2FxRjBV8eMRpza%2FkwdoT1iErC%2BW0fFg%2FLS8uhj5x5K2KTes8G8jclSWfBnj8WYGBuPX43hvBhFWssHN2v7466EliMoE5RIgq7s529MbFnsYl5l0z12VQtrWLyAlSWLFWxZ4AcFYCa80EuKXheMRJiU1hL6VckqU9GRfKB5xfjrwZAzeYrw7JPr1goFHitE4C9VOsfal4tj4o1vrLZRiZOip3FQ0cvKpw%2Bb8nmg3lqCIHESBEHiJAgSJ0EQJE6CIHESBEHiJAiCxEkQhoZRDELQp%2B9h6AoagEHi1FvUfam0MUGD%2FimtJfQ8e6AMgsRJEASJkyBInARBkDgF6PWYhKGgk9di6lKcJT096MXShP5T4aclTUmcj4qt4UqXntB3Kvz0UZMRJ8sREiUidKRLT%2Bg73E%2B5vzYZcbIk%2FjR%2FhaE%2BnHz%2B1eh7DzKRlp5DnkjU5Kz9BX9tKuIUXpOvwLiQNo3f7hw7eTkux6cIv%2Fmn4fuEfoDxUz7HlJmrG2wz%2FvpdxF5s%2BGtS%2Befso384SULQMwT%2FZH6qq8866GT4Hn%2BBU4AvruRb4K%2Fsv0sac9ujhveEq4u98Dtq10l07dwWa1ZMfSGbvx28iIcZjxHg79mg9fPyijFrwXqEv9YLIhF1YusLFf55RVefddDZ2FqJAu%2BVi3Cmmw%2FiLlzH3sbablZ2viCApOR07D9yEaZSKVas2o1eQb4ICqz7m74pdzOw8btDSHuYg2Yudnh9aBCb2%2BPUuRsoLCwR7NjaWuLtCYOwJfoYOvq0wv7DcbjCInVIn84YPzoYG749hFNnE9CujRvmzXodVpZmiKqImitW%2FyT0248a0ROtWzYjdegQ5pdD2Ww289MgXe2DzgYhnLuORLkIEUwnm1kUXejlBbPG2O5XG35FekYOLMxNYW1lDgsLM7Rs4Qw7m7pfMv6ktAwjxnwMD3cnvDU6RFjnwNFLMDM3gR0TpBWzxf%2FW3M1RWH5r1HFMfm8VzFn5kAH%2BTHi7EfKHv7MIm4PhYT1w8ux1fPnVHmFZLnQOX59P5mampA4dwf2Q%2ByP3S%2B6f3E91tS86fSrl4jUc6uGDIJkIq%2B1MML2bL75nOf5hiRzX2iTiTrSGPhteE%2B7NHeHt6Q4TEykiRr6icvl0lrY%2BzitA2KAAeLRwQp9efk%2FLOvq0FNLaZ%2B0sWfgmW76b8DsmLoml03ZYMDv8qdj3%2FBqjbNv07iTMIyitbXQiWBKX4o3W5WL4VXT%2BjFUAV6UsYsYm6E6YOhdnZQRls0HCW74VeJ39fl8uQfvbvmgdoEejiFp7uGDM633QJ3QBvL3c0fNlH0ybFArXZva1p%2B6S%2FycmNlbVI7MNi9SyMpnG95OeTFGP28rRP3eYo91k3naaRctQffl0oN48z1nlLd9665BLP5qID%2BaEC1Fw8%2FdHMH3OWuz4dr5QplCxB88GRJGW6h166Np4oIHv9YTfCz0Tkwg7OysMCH4Jb7AUNvux8hN0%2FG9JyWkNts2jqFgswq3b6XSiCf2LnPqOnIXGWfMjhbmLk61wj%2FTzj5VvIBg6JBBfb9qPgOA5cLS3xoHdi9WyzTunJo7rj2Gjl8Da2hzLl0xCcG8aQNXUMYoUiKe1jfWaEt7xU8rairzXtmrnjVyuwIO0LKHn1czUpEG2s3LyhbmTg41a61V9TQmltRQ5jY5tO3%2FHjt21j9L64pPJQi9tbR1APC3lt0FeBHVFSZA4mwRjRvURJoLQF6hDiCBInARBkDgJgsRJEASJkyBInARBkDgJgiBxEgSJkyAIjWA0I4ToM3iEsSExhoNIy8RiPrm7YFFTv6D8PJBbU1pLEARBEE2P%2FwEqtBzigdMgZwAAAABJRU5ErkJggg%3D%3D)
+
+```
+in_from_stmt
+ ::= basic_stmt ';'
+ | if_stmt
+```
+
+referenced by:
+
+* from_stmt
+
+**mode_stmt:**
+
+![mode_stmt](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPkAAAAlCAYAAACAs0%2FEAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAACtJJREFUeNrtnQlYjWkbx%2F%2BnokjFUPYRxkd2hSjblKRMjX2fT1KWyFIX4fumocHIWCZrWfoYu5RlqD5Lxq6MbI3dxKBFQzUtaJ3nfnKOSnVO6Sj1%2FK7rvU69y3Oe932f%2F33%2F7%2Bc9pwCBQFChkZTFmxoZILuiX9grt0vv2laG61VZKM1xoShqZXWyv531rbA3snNPe3G9BB9lXCiCirj0ynMrIgMLysO4ECIXCCo4QuQCgRC5QCAQIhcIBELkAoFAiFwgEAiRCwQCIXKBQJAH%2Fok347aoGxqB2MJ2krddmbjM90VS8iv4%2FOQEFZV3nwicNW8LXrxMws8%2BM2Xrfrv6AOs3B%2BHWnSeoWlUNvUzbYKaTDep8ps233%2Fj9ETw89%2BWcuJoKmjTSRbeuLWFj2QVqVVT5%2BoyMLIy0X%2F5ePzq01ce3c4aX%2Bxs6asIKzHMZgvZt9OXu63fgPGysu0BDvWq5O4%2FncYkIv%2F4Q%2FfsaVlpxfqjupMdzkadnIsrIAP5qqnAuqFF525XJ9YhIRMXE40jwZdhad%2BXrwq7cR%2FDJq8jOfvfBobMXbsF%2B6hrMmTkY380dgdTUN1jjEwjb4YsR5O8OHR1NJCam4t79Z%2FDxmoJ0dlK37j7Bau8j2LozBDs2zYJWjWrIzsrCxbA7WLt8Iurp1ZS1X5Md%2FykwxLY76urWlLsfXbuZLFD27tEWGrrlT%2BT3HjyD508BlVrkJdVdVwMMypRgdUYmarNfq3ORS3Js%2B7DMTAxijR7I36i87crGbpQZE%2BxR2Fh1gUQi4dl6%2FBhz%2BO44IdtnoedezJhiA8dxFrJ161ZMhM3Ixdi8%2FQRcp33N11VVV0P3rq34z5TpJ4zti1EOK%2FHDSn8scR8rO9awQzM0aaz3yQ0Mcjd0jYj%2Fs0BIgesuC2whZ26iyee6mO08kAc8v4MX%2BD7evsGooamB%2FhaGaN2ysdz2g46H4%2FipayxIZsC4S0sMG2gC9apVcCH0Dnb5nUFyymv07dMeY4b35v1ITEzBtt2n0M%2BsEzZtO4a4vxLxzcg%2BsPiyI28vKekVNrL11Mea2prsnrTGAMvO8Dt0AS9eJGHl2kN8P0e7fvxciuJNWjp8t5%2FkQVpHuzrsRpvDqFNzPH4aB392vo7jWBtaOW0EnwhHVlY2rPsZ4XBgGHR1dXA5%2FD5CL99Dx%2FZN4TxpAHc4sc8TcOhoKIYONOWvmSwJOPzb4qPcy%2BLqTiruzGw0yv3B2Tw1eXaOfadGn7JG91G6L852ZdHTpDW33ydP32ARPgrPol7AvFf7PNbuNsvKg2265b1IbJANHGCM0%2BcjCm27CmvXeeIABBy%2BmMcZhF%2F%2Fgw8W6ULtfwqQaGOex8tETu4mKuYlbFmAvPn7Y3z%2FY065olsnp4RpUP8zNG5YB5rV1eW2vWFLMJas2A%2BzXu1g3qcDgo5dwaPHz7mLcnLxZuvaY9zoL7En4ByWrvLnxyT8nYJlXgcwf%2BF2dGKBs4thCzjOWM%2FvIeHk6o2o6JcsaJtxcVEQ4f2rrc1LKOobLWpqqnL75zBtHR78EY1p7H726dkOdk5eiHwcy8sycm2u%2F8n5ks%2B1G5GY77FDVtIcDgrDxOnr8OZNOneLx0OuY8EPe%2Fi26Nh43v9h4zzxIDKaB56PjTzdkbiNWuNJJhAAEnhBNXkRjfIIIm%2F7x8jsUx2tsdrnCJrr18PUidaQ5PrC3nOWHYi6eu%2FbVLLccXGJRbatr6%2FH636y89LBvoVl%2F9y1ak5N3hifGpPt%2B%2FN5CYKyGA1Yog%2Bz6YStVVfosSwmD5qr8PL%2BBbs2ucCwY3O%2BjgIoZcNFLHBMZcIa9FVOkG3UoA6shiyEK3MN3D1VUYP%2FDjeZwzh49BJusIDTsEFtRNz%2BEx6DenB3RcvoYb1k%2FaOgPmyQqULnee1mJB5GxmCb9ww%2Bd9PVqAUuXb6LQBaIaOysWjIBVkM94LXhF%2BwNOI81yxzRqGFt2fGu0wbCjgUa4oum9THaYQVzdt%2Fw39U1quDAjnnQZu6gLHlPdxIEZQAe%2BTO3QiKXksWuHUv1%2FbPlbM%2FIQCR702rKPEGqzahGuxz%2BAMsXjcd1dlOlkN0kkplQdfLVzknJr6GpWXTX4uOTedao8bYm51af1eSlYdfL%2BptoKqrvoiFZWJqLKAmxzB2Qtc4%2FoUeCehgZy62wlBbN6yON2flo5iCkjkqSKypra1VHZmZOPygQ0OQqBR%2FDjs1gz8onCqjF5T5zeGStTSzc8qz%2FnGVxaYDbsGoy%2Bg9eyDK9NUy7GeRzfe9%2BbqZfl5cdKWwhKNiXtsA%2FZFyQ7lh3B2RkYyh7zZLXkFohtcAFduAz9tqXNbiZvc4qajsL1J7FyeQlOUEaTDShRhlFVVXlvRtZu5YWzjDbSHV7bshKGjGbWBRk1cn%2B04x7elpWqd7M0vgjAeXhK6sUSEmoCUkpsqcVUrRqaHAnJIUEkpmZxYKrhkwohTGW1e40WUilRODxKxhh9yOunlslmxxUFHqv5k3r4djBBYXu48%2Fq%2FHatm7DaOgxT7K1Qs2bBk6nxiclc2NUVKGGUOS7y3%2FfcumOvPsxg%2BL5Ohz1Tg0O2BIkFWfX3anJqhL34sQYM2PKU2XCD8Ntwkbf9Y03CmTEh9jPrWGAAcHK0gseyvbhz75ls%2FR7%2FszgWchUOubJMnuj%2FMBoLlu7BgSOX4O42olLN3JJgKTtRDasI5JA6d%2FoC6zcFydaFXrnHs6dZ7%2FbYvf8sD8DE9j2%2F8mycPxgUKDwWYMnOk712mmCFlNTXeMNGLvUthrWdkvpGof6ZGrfCn8%2FiWCkQKlv3%2BMlzXI94xH8%2BFBiKX89FIGDnXJ7Fneds5KWGlMSkVP5KwWkdO0dL807vJZMyu1eF6O7CDUTQq6oqWrB46Mf2S2I7Py0qk1MjFCFCmXM1KEC48raXKZPGWyItLQNfj1rMI%2FSr1DQ%2BUKhGI%2FsoJTomHg1b2csmnXp2b43A%2Fe58cic3JhZz8%2Fzeu0cb7NrsWqGEPsnOEnZTvFCrVg3Mdh6EoQNNitzfy3MCJs3YgE49ZkGVuZ5qGurw2zYb0yd%2Fxdavh6mlG3S0NLlQt26YoVAftu0OwbeLd%2BFfzRsg8lEs3OeM4PeP7l2Htk1hbD4bqhIVBAd8h%2Fr1ahUZhP63fjpc5%2FnCw3MvDxw0kbZq6QQ%2Bc%2F%2Ff73eyvrqhejV1LPp2DKzf1uezptry43fuO41tu07h1es0%2FpRho5dTeblNcnX3dp2LcVt4smrMLX9ml7y1BamsEW%2FWSIG2W972kthPZf05o3Qm9Ji4BKix8FbUoFAmuf%2FMT2nZdWVdr4SEFKRlZECvjo7Cx9BEJ2U5KpFyE%2Ffib7xmIskfMOVBcyLJLDDQjH%2F%2BD%2BaQUyBhSh99KUJMbDxUWP8UPScH57U82NMkH5UaxbkWyhwXJdUdzb6T2NkbTGbvk%2FOcnKX%2FpkU1Im97eYIeiRV3kFVmpHXpsZBr2Lj1WKH7ubsNl026FSYCeuxVEshJ0FIQ0icmK9YewsWwu4W2sf%2FnObKf69UtWXCnYEJLeaGkusud2WV2XV5Dn4rABSWH5joKmu8oL0g%2FzKQMaEZfkceIH5sP1Z30eDUxvAWVHRPjVhX6%2FMS30ASCCo4QuUAgRC4QCITIBQKBELlAIBAiFwgEQuQCgUCIXCAQ5KHMPgxTVv%2FG9VNFXC9BSVEtizeN%2FgsLaWmgiwUV%2FQLTeYrrJVDGuBB2XSAQCASCysA%2Fcglj6wu8a3IAAAAASUVORK5CYII%3D)
+
+```
+mode_stmt
+ ::= MODE int_const_expr
+```
+
+referenced by:
+
+* basic_stmt
+
+**message_stmt:**
+
+![message_stmt](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAT0AAAAlCAYAAAAwaT7fAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAADoBJREFUeNrtnAdYVEcXhj%2BkCAhiAVTsXSxRwV6wYMMOdo0dxa5gL3801pCIJvYSEBsaO8ZCFKLGKKKCNZbYomJXbAiKlP%2Bcwb0usLCINJN5n2ef3b1zd%2FbeuTPffOfM3QUkEonkP4ROVnyprTXiZNP%2FOwi%2BnH59SPYL2X8yA72sOtnTR73kFf%2FCqdFwgOwXkmzVf1JDDtn0ks91Z9KhSb6k%2FiNFTyKR%2FKeQoieRSKToSSQSiRQ9iUQikaInkUgkUvQkEolEip5EIpFI0ZNIJJJMRvwio3ZlFAi6iEfJ7aStXJJ%2BRL6Nwp79p9DFsb5sjBQIex6OBUt9cezEZURGRqGIVX7UqVUeQwc6YKb7L7hx66HGz7VoUhV29Stj2uyNyrbSJQuia8f6sK1eWrz%2F68odTJ%2B7WSmfP7sfShSzxJjJngi99wyL3J1hVSifKLtw6Ta8N%2F4Ojzn9lf2vXruHlWt%2BQ8i5G4iJiUOxIuaoV7sCena2Q968JlrPrf%2BwRZg4xgkVyhVJsH25px8CjpwXr4sWzo%2BObepg8aq9ydaz2XMsps7agBv%2FJBy6RoYGWL9qDK7deIDJ367%2F2A4lCqBzx3qoaVM2SV187mFhr7Fm2Sjo6n70SguW%2BNL5WYjPZTSfq0OqzwvRex%2BD%2B7bW2K6ni5GaKtVWLkk%2FXr58A9cpXlL0UiAuLg7d%2Bv2AsqWtsPiHwchtaoxzF25hw5Yj6NA6DL262uHNm7fxgrVoF0qRqDm1qyPeF7DMg2c0eC%2BSWK1ZNhJRUTE4cfoqOvV1x55fpqGydTGUKVUIk107oX2POTi0ZzYKF4wXOP6OHDl04EEDXSVyr15F4NzFf5RjO3T0Aoa6rsBIlzYYPqg19PX1cPb8TazbdAimJkbo06OJ1vM7deY6Xr2OTLK9u1MDEvvXQpQn0fHlIPEZO6L9B6G%2BS5PAbnguHq7sr6uXA%2Bf%2Fuo3GDSvDrl7Fj9t1dcVzeHikOKd1K0fjPQ3yoOC%2F0YXa1ddnCqpWLqHsf%2F3mAxw8dBbGRjlxNPASGjeo%2FFHgr9%2BnNsmcgDGtOlTLGo4xOlgUHYP89NZYiJ5OfJjbJSYGjlTpzsSVaivPSFZ4%2BdHMXAlbdh7DTZq9Hanz2tt9hdXrDuI0dQ7baqUxZmh76OnFN%2Fzde0%2FhSWXcCb6qVAJDnVvBPF9uUcaz5B6%2FU3j77r2Y3fv2bAqL%2FLnFzLxu8yE8efoKBWlQdO%2FcEBXLF0XwmRvY6nsMj5%2B8RN48JmjRtBpa2ldXji3k7A1s3v4nHj15gQZ1rPGeWnWYs0P8BYqKhtfGABwPuqJ09lq2ZbWe75Zdx5QZlOnYtjZ%2BJefXo4sdLM3NxLbo6FgsoRm%2Bf6%2BmeEaD4PjJq7Cigbl5%2B1EY0CAbNshBHD8TExOLjSQGPBh5APaketQ77ZdI6P1nuHT1LjZ6uiltwm6qnUNN0TaqvsDky2eKolRWt1YFZRuLHguCalujBpVwLOgyjh6%2FJEQvp4E%2BChXMK8oKk4PUN%2Fj4E%2FVRQ9pi4jfryFG2EuKoTjSNynHTvDFtQld83bWRsp2PrX3rWsKdfg7sEs1y5yKnllOIN8P9V4UBDUz181TBk4Om7fEC%2BLEdeJwFBl3FH8f%2BSiB6230D0bZFDZiZ5aLXx7Os%2F3yqDqnEjsx2EfUfuiWQ6Lj4cJcrDaVKt7Ad%2FJTyjGD5z35wGb0cVgXyomG9Shg31Rvtus8Rg7kDdSQWQ5%2BtR8S%2Bjx6%2FgGOveShVoiDGj3IU2752XiicAXfoSTPWCdHq2KY2wskJnKcZ%2BsWLN3Dq%2FR2sKZTo1aURLC3yIOBwfAjBYlaqeAH07t6YLH8ZuE31EuEUc%2Fb8LfQavBAlilsK8fzn7mMs89yvHPcQtxW4RMLLs30zCqmcRyzB3zQrakM1iIsWNhePXMaGwkms33xY2cfPPxj7DgSLTniTQpepM9cLwePOaGZmjO795uN1eLxTmELhCwuey4BWcGxbB64UppwMvvZFix4PeBaARSv24Da1e4J8jd6nuw4Wq6dPXqFYUYtUXZ%2B%2BPZvg%2Bx93JCk7c%2BGm6E%2FdOmp26flSEdpmBNdu3EfgySvKI7nrzxPGk2fcDuYJXPWOPYFw6lBXuGU%2F%2FzN4E%2FEua52%2BFh1isbOtiLsxwA6w4GnK6aVQqVBUbeUZ7fyWLXBBlYrFxevfAs4IsWMhYm7feaKEF94%2Bv6NtyxpKCMFCVa2%2Bq8jvcEhQ1MpcuESeuVWOjT8bQxe7ZTMbMWvyrK%2BidQtbIa5s7w1z6otjCCZ3V59c3XJyoIP6NFecnRU5A999J8Xry%2BRCONcTeNBdyX9wR9v722mUK9M%2BxXNVzaLq4W0%2FElXOqYwe0k4Mam%2BfQxjQ214pr1i%2BGFb9NEx5z8J8%2BOhFcf67ydme%2FXOhcC%2BqY9u9%2F2SqXGd2hd2s15KRmD53E9ZsCICpqRFsqpYi52uP5k2qpaqOt5HvFTd94vTfsK5QFC2bVk%2FVZ4c7t0bdFhNxlkJDdXjStbTIrThDdvu79gYp5dXpGBO7w8xg%2F8FgnAq5niSnx7x797EdToZcI8NQAG2a11D2PXHqKjksHdSyKQsdHR0UL2aJfdSPs0P6JYkO6WB%2FNDAzsbNLleipiCVDQ0O2VZyW8uho3KIvNcqok%2BM8igpTE8MEZSb0%2Fv7DMGVG4w7Ms5FygY0MxMzELmfXniBUqTcaVauUpMFRlcTEXgiZfaOvUKvxOJE4blivIoaQK%2BJZ2XdfEGbM24ySxQrQxbbAvfthQgQZDrXZMWqC8xxPKVSu32JSgu1d09hR%2BJhMchmS4IeIQXP1WqgIe5ODne7DR8%2BFWEdEvkMjh6kJk%2FlNq6X7Ncrsf8pg0d6%2F%2FRvhrC5evi1yTQPJTfv87IYGdSumuh5Oh%2FBEEPDrrFS7xNy5jTFsoAO%2BW7gdIwe3UeuLRnj%2B8o1wRywQ0bGxOE7OijlCIeNoCo2zQvRG0WSpymkmx70HYWKiDvCdCT19XWX7NgptOT2wbddxZXLftjsw3UXvc%2FoP6xApRJvoOHSm51htFeklEzsfpw%2Feo%2BdmVOHP9OyaUjlNvO6f4vQ%2B5wS5MyX3PhcJA8%2F2Y0d00PhZvx3Tcev2I5Gr81iyS3x2YO9mWOrhInJjvH312gOY8I03Vv44DOOneYvVKnZ2zMRv1qqJrxGeUiigCS7jEOHw3jnpk8ug42T3unbTIZGL7NHZjpynQbL7c%2B6Iwz%2BTXEYwMzFGoL97knZLb9LjzyDT0i%2Fy5MklRI4fIeduIuT8zVSJnqGRPtw%2B9BO3KV7oN%2BQnbN8wSbig1DCA%2Bo3nen8htoqTo8n03dv3IpXC%2BTGua%2BG8gaKsx0CPbOmac%2Bb82A56FJX0pXbYsXEychnnxNt3Udh74DSaNaqqiDfnSHf%2BGogHD58rec%2FM6j%2BJ%2B4e6DtHzSkN9eFHzD6CpyzlOBy81hbZJcnpcCT1tpQqs6RFKYat1yGW4aSvPLiu6rextRNJePc9z%2BM%2BLYkWUOyK7n5LF45flbaqWFithvGzPYUr%2BvKbCAbGDCgsLp9kaYkWLOwVz%2F8NMqKI57evtEyC2naHBtnT1vgQuhHMjW3ceS%2BAoeD9tmJoag%2FUp8S0X3RwbiFVATiT36Z5wBZA7J4dSqtD2CjnBJnZVRFLeyNhA3D6hghdl2A1%2FyfD1mjJzg2hTFZy%2B4MWrmtXLfHJ97jP6iJXJ4WNXIjY2dbrLguY6rD081%2Fkr2zjH6jKgpVh950U29esT%2FmE1OTsz539fi3MY6rpcRDQHAs6KlNCS%2BYOFePPjR3rUtCmHnXtOZNlxJqdDx8%2FjIj%2Fr6qIsjd%2BttN9r2jk0JafHlbBiBpG7tdYgZNrKsxyH5jZCLFo6fYt8ZiZ4%2FSYShQrkw9a144XgDRq1VNxTxPfCcfg6c1pPkYdxHrkEBnp64oK%2FeBmOpfNdRKgzYYwTuvWbDwvz3OQicwonqYLzeVyny6hlwm3YN64K%2FcDLitPzJofoOtkLcxdsE%2FnAiIgoeMztr%2FUceIbtTaLWpsss8X3cyTi85bxVq2Y2IlwtUjh%2Fgs%2FwrNvQYQr5%2Bji8jYwSx88iLvKcdBwjxq8WC0Jc98vwCMyc0vOLFj1eYQ8lweNz5vPkvGkktcsUt07JrlKmBOfgVi8ajrbdZmPm97%2BgfauacKGBzzRtNw3rV7qiXBmrJJ%2Fr0amhuLtAnQmjncQKKy9csbvmSfMFTbp1a5X%2FpDwqL8ipwzls7lcbt%2F6BqHfv0dPZg0L5samqa%2BT4VeKhhOHUr64GL0sa9tHAXv3TMGqHOZg%2BbxPu3H2iMY3C29Zs8Ffy2T8s2ike6umVo35zM%2Brya9WhD9vcaleGO%2FmWiYmdn84H2xhBlaygSjSGqdrK0xLGZOTfgvNq3IPHz5GHRIw7SuLthjRLqy%2F1q4SDZ7fEgsKhYkREUqFJDN9WwuHOLp%2FJSZLb3PktLcw%2B6Rw43OYEsmrFj4%2BtQctJ8JgzQNzoqsL%2F8Dl4LPYV%2BS2%2BcZYFQT0no4KdJ59%2FeoYk6n%2F3nV7h7af0C3a3D5%2B8EK95pTu7wdFBTGysuPaqhSRJ2vtPWnWIV3dZ%2FOgLhtD3xN%2BnR%2FawZEqVaCvPbvCg1zQIktvOJCcGLDqabjW4E%2FoU46atQYWyhYWo8SKJJienup9KBYdQjyjE1ATfHvP9rL7itcqpKflI%2FxAYk1NTF7zEpCTMiUX%2B3wA7tOwodipUv9pQZwY5qIuX7yaTCzYUOWRJ%2BuqQuvNTwlttFclfYSSFb00Q9%2BfdfiRCmJ0%2Bk4St1wYvmqQFcwqxVUlxdfgm5LEjO8gL8oUwY3IP2Qhp5HN1SPV5PdmUaYNXT9u0sM2076ttWy5ZN6HJUUgkEs3If1mRSCRS9CQSiUSKnkQikUjRk0gkEil6EolEIkVPIpFIpOhJJBKJFD2JRCLJOLLs5mT1391JJLJfSDIL3az40gdP8S0%2FrCwwQ16Cfwd8PWW%2FkGRl%2F5HhrUQikUgkEsl%2Fnf8DpCYXBOiq5ukAAAAASUVORK5CYII%3D)
+
+```
+message_stmt
+ ::= message_type STRING_LITERAL
+```
+
+referenced by:
+
+* basic_stmt
+
+**message_type:**
+
+![message_type](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALUAAAB9CAYAAADk6CJwAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAECxJREFUeNrtnQlcFdUex3%2FsoCIBIigoirigKIKpuGCm5AZqWFiW%2BpRMRAUStzL1VWpuaUpuqfGs5%2FP1NAKLktxaXMBdXFBQEVxIExdABJTlnXPuIrd7WUUuzP1%2FP5%2F7uXfOnDlzZ%2F6%2FOec%2Fc%2BfODyAIiaEnhY3o4oJiqQTkxAVpxESbGEplQ44fiKjz2%2FCiVwApshrQp11Q%2B0YdKY08JGqCIFETBImaIFETBImaIEjUBEGiJggSNaFriF8Uu7vC9sg53C6tUnnz6wpX025j5ryvldMfz3kTHdo1x4cLtiLpUjqWfDQGzk5NxLwrV2%2Fhsy%2BisX7lJDE9e%2F7XuJKqugvatm6KRfNGi88xscewZduvuHEzA%2FXrm2LY4K4IDBgIUxNjUlkFeVadKZYXon5SiPQuLog0NECwpkbLm19XcGhijYVz30b%2FYfMQ87%2B5SgGfTUxDTk4elq36HhvDp4iyh2z6ZMIV5bJnzqehr5cr%2BvRsrywzN68n3jdt2Y01G3%2FGJ3NHwcOtFW7%2F9QALlm1H3LEkbNs8Hfr6dDtHRaiqzrq5wK9QD%2BEFhbBmk%2FWEqPVkaYh%2FYSH8WKNRf2%2B0vPl1BSNjQ9g3tRKfm9hZwsTYSDlv0vhB%2BGjpt0g4lwo31xYal2%2Fdqil6dGunUpb9MBfLw6PEwdC3t6soa2bfCFs3TkPPAbOx59fTGNjfnRRbASqrM4WYC4vhUPLGApUbmopl06U2Wt78uoyFRX0EBQzG4pXf4duIGRrrXLqSjrijF5XT7m5OOHbyEkxMjJSCftqLm8G7rxt%2BO3iORF1JytNZaWLWKOrSGq3sSusq74z1RsTWvTgYl6hMLUqya88JJuLLyunwpRNwJyMLto0tNbZnx8ovpaSTSqtL3HrYVQB8UpqYyxS1giLgNBsPBhWXM7%2BgAFfZSs3q%2Bk40MzXGtMnDsPjzSHw6f4za%2FJBJQzFiqKdKWQN2Upj98JHG9rJzcsVJY1WgO%2FVUdcZSE5%2BCYrzO3ovK2zGGpeQ2h9mCN9m7N2twM3ufVtZ8I0MsVfTU%2FoBBahs4FuqjPavYj9UZxeqeMyzGFDZyJz%2BPja5OAYx6zQsbImJFr1wR3FxbIv3Pe0hJvQWnFnZPe5niYhyKv4CA0d5V%2Bh5S%2B7MAOxVpU6CHtWyjXFmw%2Fssitt%2BgCIktkpG2AyjUFMeSOmPvX5oaISLvCQJYRzqhWA%2BZ4D12eaJWNFIsa%2BSIkQFcuFjZyqaVNb9kG%2BILJiOFfeSvGGdnfGBhhJksB4p3bw%2F%2FU4nYV5t3viHbqJmhfpg5dwusrBqUf0XF3hqv%2BnRH6PtfIWJtMGysG6KAncbz3p5fQfH7W8%2Bui7C492cpww6mn5WZT%2BB7%2BTLyFfOOldGplqKzsO6uWMp28ezSxF1S1DvKEmsF5mtEvgELPdqJVGUHO2I9n1ePXR5Jl25iTOAq8Xnom4vw5edB8OjcSq3e8CHdsG7TLmRm51So3WULxmH%2Bom3o6T0b1lbmeJCVg7bO9uKEs0EV0w8p9dBc0GzgGnvyImIqsEi5OpOXlSpuPXm3%2F4g1soE1slRTI%2BXNr0SaMJe99WFD64DqTj9qw9%2B5ch7l4979bJiZGaORVcNKL1%2Fy71xSST9YbHaztz%2FY9iysQN0q6Yz%2F6MLFzXbYJLYe2XVqQwO0LKuR8uZXFPNcfJZthinuHeB26jwSpNYr1a9nIl6EPO1gcWZneR1Z3IdVKPWros5K9tx8Wr9EYXkLPTO%2FpSKP9T%2Fb9IvwGoVc%2Bog4s3iLuFdcnFVGsXzN39DEznrZENODQi59RJxZvGv8YKrpFbKThvMs92lDIZc%2BPM483pIXtdlDMUTYUMh1Aht5vKUt6rgbIr8ypXjrBKbyeEtb1LJUix6tpTsZSM3%2F3E%2F%2FfCEkB4maIFETBImaIGoYyTzKlx6DS0iqp%2BY3%2F9DDyglKPwhKP%2BpKj00hJainJkjUBEGiJggSNUGQqAmCRE2QqAmCRE0Q2kQSP77Qc%2BeqDyn8gEXe5IQSqdwURukHoTbq1fWRj0RN0IkiQZCoCUKHRE23iUobPZ0TdQ8HeqCNlNFmfLUm6twGsKXQSxdtxldrojbQQwcKvXTRZny1l1ProR%2BFXtIZtdbiq71fFIvxVt8W%2BLCiD%2BSuDn4%2FeB4%2F7DqKFYvGK8sWfbYDDc3rITjQR1k2MXQdwqYMQ7s2Mn8c7rQVMOUL1DMzwdoVgSptcq%2BXxKQb4rNFw3ro6uGMgDHeMDaS7drYvSex%2BZu9GDLAQ8WpK%2FT9zQgKGCTWMWve10hJkz0ctE%2Bv9ggJ9MX%2BP85g3eZYDHjZDRPHD1QuN2PuvzB21Mvo1KGFmH78pAD%2F2roPv%2Bw9hfRb92BjY4G2zk3h79cL3bto54nJLK6m2Sy%2Bunj142y2GWbU5ApbONrgu52HhPUyp6ioGNu%2FP4TtUYeUdbh93J79p1ndxsqy%2BGNJuJh8A3t%2FS2ACvq7S5rnEa0xgjpg%2BdRgTbhfWfhzCPnj6kz33Kb97LwvLVkfh7v1sZfnpM1eRmS3zX5wePFx4OHZk7Ywe2Ve%2BXCbuZGRi5dof8NedTOVyCWdTkZUlWy7%2F8ROM%2FMdy8b1mTRuBHd%2FMwoI5b8HK0hwffvIfrQVWHtezupdTF2MqewvzaAffmlqnY7PGaGpnJayXOReSr8OlnQNy8%2FKF%2BDhxTMBd3J1hamKsXI4L9bXhPTGYizb6sFq7rZzshGf5a8N6YFaoH349qBrPNs72rMftjPD1ms2pbBu%2FgHr1TGDBRgwry6c2d04tbOE76EUm7J0al9u0ZY84QLdtCoPni22EJ3rnTi0xZ%2Frr2L5lplbiKo9nmDy%2BuiVqbjtXpAd%2FPT18w127nJ1RIw5AvXu0x6F4mb943NEk9OjaFj2ZIOOPJ8nLLsKrh4uyfl7%2BY%2Fy0%2B7gQ7AhfT0TFxKOwsKjU9v9kKUBze%2FVnys8I8cO3kQdwM%2F1upb7v9KmvIurHeKRd%2F0ttXuy%2Bkxj1uheMjNWzyJIHR03A48fjyOPJ46otW0Ht5tQMbhTKfRW5E6qFEaZ4uGh2Qq1OvJiouaOtIq14d9wA0VMePpKE4UO6C6G%2FudRLWf%2BXfafQqqUdWjraormDTKwH4hLRt7erss6e%2FQm4ffsBsnPy8CPL2detmKS23uYOjUSe%2B9kX0fh88TsV%2Fr5N7Czx9siXsGxVlFo%2Bz0cX%2BybWymk%2BAqWmycTP7aN5OvS8KMPZ2PPEBe0JWuuiVvTY7O0Vbk%2BmX4wR7HNIkQFap7jAsctz%2BFWqF%2BuFg2dtRGZmDk6fvQr3Tk6ws7VkJ2W7WC97Hxl3s9DZteXT1CM6DnaNLbFDnne3aN4YkTsPq4haARc0z4m7dWmtcd2hQUPhNfADBL0zuFLfOXiiD3oOfF8tnzdvYIb7Dx4qpy%2Bn3MLRE8m4xcSedu3OM4m6vDv1UmQPU09jAbrEohTHeudBtcVGsNbcTy3fIQnPIwAlsWYnUW2dHbBl237hJc6vUjiyHpifdO38%2BQgTZBth5czJYCd43F98uE83HD4qS1ma2Fohdu8pYQSq8Ex8pZ8b3vZ%2FCQO93THi7SVo29oeg1%2FxUFs3t3geP7o%2FO2n8vlLbZ8lSicBxA7F4RaRKeVeP1vh59wm85d9HTPNUhL9%2BPXD2mU8U6%2FKfBXTyhqberLfe%2BPVukU8r4Hn1hq9iVfLp6Jgj8OzWRqQLite6lYFo2sQKu5iY%2Fk6Hds2xeukEhM7eJEYBTUxmvXT88eRK59Y8TTpzLhWp157m1pPfHYzjpy%2BLy5L8oFSQkZEFXUYnRe3Vsz0ePMhhglUV9R2WevQqIerInXHw8%2FFUW%2F5Vn%2B747ofDGtse5O0h0ozxQeG4cVNduObmZpgyYQhy8x4ry8YGrsL%2B38%2Fgyy2%2F4KMl32psl48KIUG%2BeJSb%2F%2FRqDhthvt%2F6vjiA2ncNhmf%2FWXDr%2BR5Wb4gRI4KuopUhhqcL1Tm81RZvcm2SnZ2LB1k5VfZF51S3N3p1x7nO5dTEs8FHAP4i6E8CBImaIEjUBEGiJggSNUGQqAkSNUGQqAmCRE0QJGqCKAvyJieop66NkDc5QekHQelHXeqxKaQE9dQEiZogSNQEQaImCBI1QZCoCRI1QZCoCUKbkDd5HYd%2BcJKoqDm6%2BDAbuomL0g9JIgUvcRI1QZCoCRI1QZCoqwTPAemsXdroyeOsM6LOI29yaSOPb54uifoOeZNLG3l87%2BiMqNmYlEze5NKGx5fHWWdEzZKtOPIml3xG3U%2FEWQto5RfFIn1E6hchtqa9yTlhcyJw7UaGSllDczNErA3GhaTrmLfov8pyZyc7vOHXG%2B5uTsqyiSFrce9BjvjMDThf9uqIN0b0hr7%2B0%2FPelNRbWL0%2BBsdOyJx1u3ZpjdAgX%2BEGxuF2zoGh65X1HeytMXxIN9GWFFB4k7M4D9KZnlpuL1fj3uSchHNX0bNbW%2BElrngFvSPb95nZuTh%2F8Zoo496FlhYNMGL0EhX%2FwuOnr2DAy26izku9OwiL5RVrolUE7TNyIRrbWOCbje%2BJFzcfHeK%2FAFeu3hJ1HucXCGfdyRMGY9rkoWjt1AQTpq4VHuNSQOFNri1fRa3d%2B8G9qwv1EO%2FRDqdPXkRMTa6b%2BxxyL3FNGBkYKOdx0f4Rdx4HDyeifdtmyjodXJqLOvz1KCcf0T8dwcwQPzFveXg0BvTrjA9n%2BCvrc6%2FwvzIy2bwobPg8SFnOTUQb1DdFL08XnL9wXfgfevd1q9OCLuFN7qmt76Bz3uScpEs3RU%2BpeHH7Y00UPCnE3bvZaOZgU2pb6bfvs%2FmNlNO%2FHTyHEb491Opx6zo%2BrzRusXaal7Ge2g55kyvSEC14k3NifjmOw0eTVHJq7h4rLkXlPcbKNTvFZ16nYwdH0fOWZHv0IRw5nix639%2BZUP%2BzOUyWVjwpQFbWI5Fu%2FB072xeELVxJE881G38Sjrs8vSksKhIe5HUF8iYvp8dGDXqTc6ZPHQ6fgS%2BWWefazQwksx59X8wCGBioD2hchFE%2FxmPJx2OVJ4BGhgYwMjZE9sNH6nnmw1wxj4u4JJnsINj%2F%2B1nsipwvUpGqUtN36pE3ecVPHhO0HVAzU2OEMdFz3vvgK4wLWo3If8%2BGqYmxss7IV3uJPNjDrRWCpq1HS0dbdO7YEnps7HVn7wdYDq7o%2BRXwMo%2BOTqKOgqnsZJQL%2BQWL%2BmI9P26fW2VjT%2FqzQC3IqesCyz%2F%2BB0yMjBA8cxOKitSPm%2F4vdRIniOMmrVZaNnOhboiIFSJWcDAuEeu%2F2oWpgUM0rmfalGHiABkXFI68%2FMe046XSU9ckE0PXqUzz681n48LVr4SwdGHzmqnw9V%2BAhcu3Y%2F7sN9TqvDtuAC6n%2FImxk1Zh57Y5Quif%2FnMMQmZtgp782nVRYZEo69enU6nfaeXiALw%2BdhlC2AG0YdVkleveROWQxJ6rjd7kxcXFuJEu670dmlqrpB3VRXV7iVNPTZTdWzARN7NvRDuCcmqCIFETBImaIFETBImaIEjUBEGiJggSNUGiJggSNUHUKsibnJAcBlLYiD8z8DF%2FNbXBR7oaSL79JGdKPwiCIOoG%2Fwcsaz5Y2Aj63AAAAABJRU5ErkJggg%3D%3D)
+
+```
+message_type
+ ::= INFO
+ | WARNING
+ | ERROR
+```
+
+referenced by:
+
+* message_stmt
+
+**keystore_stmt:**
+
+![keystore_stmt](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAfsAAABRCAYAAADVew%2FuAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAH9NJREFUeNrtnQVYlFkXx%2F%2BEAYKAIhgo6ioC6qqALXaLYhd2gI3Cmqhru67rGit2Yseqq35ru3Zii93dqCgYxHfPhRlnCGdIifN7nmFm3vvGnfuee0%2Fcc18AhmEYhmHSNTrp4Uc42iGCbyUTG2eupg8ZZ%2FlPO3LC94NJjeOSfnppPP%2FDS1iCGDWcnLtlmN%2FK8p%2B65ITvB5PaxiVdbnomvXu97GkxLCdMRpc3VvYMwzAMk85hZc8wDMMwrOwZhmEYhmFlzzAMwzAMK3uGYRiGYVjZMwzDMAzDyp5hGIZhGFb2DMMw6ZD374MRGPghzvKHj18hPJwfFcDEjnyCXvkSsDx5Gc%2Fj2klTeVpi6K9%2BaFTXEVUrF1duG%2F%2F7ehgaZoF3P1es%2FfswNv5zPMZx433aYf6y3ahTo7Q8XsGde88weuIazJ3eC9kMs2LJyr3YvO0EXr8JgqlJNpQqWQjuXeri9NmbsZ6XMM9pjHnTe8vPm8SxK9cewJNnb2BsZADXRuXhIY7PlDnyYYcbNh%2FFOvEisoht9rb50b1jbeS2NJPbHj95Dc9hi2Nco17N0ugpzhMXrwOD4OE5N87ykb%2B0QumfC%2BHu%2FeeYMXcbTvvflNudHIrAs3dj%2FFQot1btv3n7CaxafwgtmlREu5bOyu3uA3zhM7gVbt99hi3bT2LW7z3VjouIiECP%2Fr4Y1LcJStgV4J7LKOVi45ZjaNKonOgPmdL1b13ktwfPX7zFlHGdY5R9%2FRKKCrWG4NLxWchhZsSCkY5IrP5VHC81yNcwPHG0w9%2F6eugf20k1laclLgXcQznHosrvE6auxwn%2F61i3dLD8%2FuDRK%2Bjr68Kzl4vacVZ5zdGgtgOGjl4O5wp2yJ7dUG4fNmYFqlS0k4p50rSN2HfwAsYMa4eC1hZ4KM61dccpHDx6WRoJ1vlzyWP2HriIA0cuY8LI9lFKO3KQmjVvO5at3i%2B2u6FkcWup8MdOXgv%2Fc7ewdE5%2F6OjoSOtdvMFLKL33QSHCgDgG1%2FaTcHjnZGTOpI%2BQT19w%2FNQ1bPQbolZ%2FSwvT77YL1d%2B7XxPl91adp2L6pG6wypdTfi9YwEIq%2BoatxsOtVVX4LRgYaXxsOYpGrcdj%2B7qRKFI4j8b2f%2FzkDQLfBom22gCX%2Bk7yuoT%2F%2Bdv4GPxZGkdd%2B%2F6Ffu6NYFMkr%2FK402dv4fSZm7Atko97P6OEPNmBwxejetWSyJUzEzcIk%2B5IqP4tZ4dmYTqYFRoGGsQNpbLXiQzntwoLQzNx0s3RT6qpPK0ye8G%2FQukGYOPyITDKllW5PVfO7KhYzjamd1yrjPT8p8zchImjOkgv%2FNXr9%2BjTrYEs373%2FHHp3bwDnSvbye%2F585qhU3hahoeHSgKDvxN37L3D2wm21a5BnPWPONqxZ6o3yjjbK41cu9EKlOkNx%2BNgVZTTCXKV%2BVSraw8ahN27efoLitt883gpli0njQFvIUIj%2Bm0nxqipcn%2FErUad6KYwc3Fq5bbhXS7x4%2BQ6%2Fz9yMBTP7aHWtMj8XlpGPeUt2YvCAZmplOc2MUb1yCRkdGTqouXL7pm3HZZRDP5Me9%2F5EQG1OcrR%2B81HcufsMzRpXQK2qP2Oh8BrJqHQs%2FRMG9m4i5ZUg43KxKAu49hA%2FFy%2BI3j3qwzxHdmmYzRfnalTPCfOX7kLQhxB071QHVnlyCg90N67feoKGdRzRsW11reoVKka0RSv24OiJazLS1cWtFkqVKCjLjp28hg8fP%2BHFq3fYs%2F%2B8NEAH9mki%2BykZm%2FJ3Ld6JbIZZ0KCOA%2ByK5U8z92PVhoPwF4bsu%2FfByJsnB7p1qIXCBb9FydZsPIyde8%2FCIpeJ7DP0mxXcf%2FgCcxbtFP3vLUqLvqoK3V%2B6X89eBOKsMKRd6peVfXnXvnMyuvbp01c5nimia8Ehn7Fo%2BR5cvvoA2Y0N5PjR0rWSLKPIyf5Dl6RM2NpYiXtTE4YGWTT%2BtjPnbmPF%2BgN4I%2BrtXKm4%2FG16err49PkL5izcgZ6d62L7Ln88FU4NRey%2BN17dvP1Uymc1Ibv%2FE8eQs%2BXaqBym%2FfWPjHZ8Ek4O1c29az3lWD7dd6uUz5XrDsiIIX1uLxwVBXS%2BdZuOyPGrinDgwsLD0atbfVn25WsolqzYK2XPRFyrc%2FuacCpT5IfISHz1r0LJh0XASvWBvGpz9hGRYX066SNx0vXk%2FsenPC2xcv1BeaPXCuVqappNreylUODkHau%2BgoQXTYz3cZPCT8p3%2FJR1mDK2k1IB2Qivkzrn%2BYt3pYJXoBg4v8eJU9dhbp5dqegVUEiuWpUSMhIQG8%2BeB8rr57HMoX6%2B09fV6k%2FTDYnlwNHLUjlEp3njijh0NCBe5xo2qAUWi8706s37GGU0yNCARCFahSKgQaGFa0XW1olkrlAONF2T19JMDsC%2F%2BCxD47YTERYWDteG5aSSWC0UEEGDaDO3yVL5KIyyDj2my%2FvyMfgTps3%2BR06LkVIuUigPOnvMQKdeM2BpYYa6NUpjnOgfNH2lDd6jlso%2B1bNzHZR1KIr2PabhyvWHsuzoyavo4zUPV8V3FzFgP3j4Sk77EKQECVKUZBwbqhjtaYEXL96hnOjzPYShRAZ3c7ffpKIhZs7dJgypnbI%2FkNNAyl51jGrSZpJURB3axDSo1ouxrXPvGcJQ24sgYShRxM9vzX%2F4U9yzti2cxfVqS2W2fPX%2ByPb3WYprNx6ji1Bq1P5kYBAr1h7AgmW70bJpJdSr7SCdCmp%2FTdAY2LnPTFQSDkT3jnWw57%2FzGDFupSz7FPJVyk5TIVukcF%2BJ3xWhIdXg1p2nmDhtAzoKGXv89LV0sug8JLd1a5ZGW2G0%2BJ%2B%2FJSOvCv70%2FQe9veZK%2Ba0tnJQxk9fghP8NpSFC56Lpx87ta%2BDO%2FefSYFTgPmAOrt98LCOMNYQx3LXPLFmHH4km%2FUtK3tEeD8OEbwRS9NHQ13BSaUloKk9rnj5ZhnsPXJDzwuSlROfa9UdCGLeqbaOQu62xlfQqBvRyQQeP6WjbrIrsGMp9RrnBRwg0DZARwhyzF5Zm4wbl0FN0ZE0eKVmXcYXa81iaSuFWcOPWY9lpQ4Wgb9txGj7Cu44%2BTxe9%2FjRnX7hL7gS3GSnct28%2FIncsdaR8AfLsaEAxyJpZq%2FMVK5pPehaz5m7HOJ%2F2amV1a5XG4NHLZOieplz%2BO3IJOUyNYngvTMKY86cHStpby8%2Fk6ZGSV3jg9x%2B8xIXL9%2BRnmlIi5dqpXQ35vaxDEZSuPEh6SYpprI1%2BQ5XGLHlxZPwq%2BgQZqHQu1T4Sl%2Bxv%2Bd9JnD80HWZRckxTRqSopk3sKr%2B3alZZRtMUEbaSlQbIqEO1yiXktibiN6h6vWkF8mgpakGKpFa1n7Fs1X6hTF%2BiYH4LzBXKZ%2F3ywdJDl21y77k0wIjVwlkp51QUI7xbyu9VK9rL6JoqPYSSVeTpkIHWpddM4dz8Ivse8cuApvIa5LVeufZQeMV1pVFBtGleRb4HXHsgPOZ8qOFcQnreqvlK34PyC8hwaC3uG2FXzApla3hjuDDyFSybO0AZ7dQGivr9u3GUWm7G6KFtpMNw684zUcefZRRKFb95A5Evb06l0UhRjgpONpi7ZAd6Cy9e4clb5DLFjt1n5OdLV%2B4LRf8IR3dPga6ujhyDTgoj4d89ZzDAw%2BWHy0wM%2FauDHcI8HBfdk9dK2SsQvul50Y3rR2goDw3FXXFRg7TSwSiJjTwVsjTti%2BVXC1UTFIb%2Fa6p7nMd7dKknOtYmdGpfQ227hbkJFs7qi89fvgqF%2FASnztzE7AX%2Fk4p61JDW360ThZ6CgoJjLaO5%2BWyxeCwnhfdOHk2PzjET7zaIQSI%2BYXxNkLFCnez9h5AYZVRvRXl8%2BKV%2FU9RuMhruoj1VofOQkqHQPXU0mi5RhBQTCv9HM5Vwnu43uTA2UpcrI%2FGdckUiQ6dPpCe0c%2B85ZbmBQWYZwlcoe7VzRZNRyscIDQ3TWJ97D15Io9tMxWAtViSfDHHHBl07hxj4KaqVN3eOJG2blJQT8kpHjF2B3cLrLVWiEMxMs0mlTFHBx8%2FfyOiJwiiL4ZAIr1NhBMSFhYWJ8jMZ6jQNQpEXHZV%2FpW5dwEK%2BU5LtiHEr4Dv%2FXziU%2Fkl6u2SkdRaGXve%2Bs1Gi4gA4lS4inJeyWvVFiiSSUaasSy4TGBsb4v6jl7C2yqUWldEWuu%2BqYwzd%2F16D5smIR3G7%2FAgJ%2BSJD8eqyrqsuj2FhSmOydbMqsV6Hxu7nL97J6VNVVKcAUoO8kf4Vd7JRaARaineN6zD045gjOCYOfCzea4sTLhLvg75XnkkfUxSefStA754NrMN0YS92rCn2aSf2vawfgb6nruFGcnSa%2BDYYzetQNvh7oaQ6Cg996xofjQls0RUfZcnpxqFMSSCpk9Lr8%2Bev2PvfBY3nLFOqsOggz6UhorBEFQMCheG9%2BzVVbqPpAq9%2BrtJqd203SYanonvHyUGZnwvJUGv0qYbDx6%2BgTMnCagO%2FNpBVTx3uj9lbYpS1EANKzwG%2BGOrZXLafj3erRNX9zFXoIBVSzhY2oTrwFZUrIYR4jZDk%2FXrhuFLwBu5vELc%2FuQeM6Aah6ncyMLu61ZKrVGJ440JxaD63dnUgA%2BOj8G5J0Smu%2F%2F5DsDCAY%2FcfSBnStBopfMX%2BERFJo6OTQk60vR8HjwbgvyOXcWTXbzLfgNhzIHKsyCrGEEo%2BJK9fkcSqNsZkySSjadpiYJhZzpdvWTUCeXKbxShv3rgCGtVzxOWABzLq2bbrNPgf%2BEPmPxzbO0VOoVCk7Vcx1piZGskoxPfvqYG8h6r3LPjjZ7XcqMTiu3AH8glnZ8vq4fI7TR309PTVStZJtl6%2Bfhen41WooCX2bR2X7P1fG3mLLk%2Bq%2Ble8z8%2BaCUs%2BfUU3Ydb0iNDBu9hC%2BNLwiX4ScgrFCezE65G%2BHuzOXoWXpnLVED4NUKdv4M7Za9hOZe%2B%2BoqA47mCYDk6UsUet1DTQUgisbJmi6Og%2BQ3aqxNKj%2F2y1OUpaE0tzVbQ8TROUyU4Z%2B55DF%2BFN1FpaWk4zauJqIaS6cGngFOMYGgSWz%2FOUS9VoyV9y09e9EeYv2aU2P08JLHMW7UA%2F94YJOqdnHxfs3HNWeh6qUKiNBsAhvy6Xc8KKVQHpCeoP1C%2Bof1A%2Fof5C%2FYb6j7aKPjmpX8sBq9YflIlgCig0%2F%2B7dxyS9DnnxJiaG2CzkmKAELsqLUVUotMZcwcLlu6VHWlgMyGRgUj%2BgqYW0xpcvX6En6q%2BYBjkijOaPHyLHIXI%2ByANWJCBSAu8plbGlnPC6%2F919Rjlu7YiaY4%2BLrFkyyykPikjSlBxBx%2B47eFF%2BpmkUPTHOOJb5CX16NEBoeJiM4ND4RfeblD5N9RSytpQJd5qoWbUk1m86qsw%2FWL%2F5iIxC0j1LsvYT5yajR2FM7Dt0UetjaQ5%2F6cr9MiGRQvuUMKiA8gyePg%2FE31u%2FLZWmiAQZEz%2BSuPTvsYu4TO96eigqbN4NYr8gsfOj73n2dBKyFE4Kx9Uuljl4TeWxcusWPou3CQ62MuS%2FQbRjheTy8BPi1dDysg4eM%2BAuLEK%2FuZHLyShsTC9VNq8arrZkLzZo7rpLn1lRIU0DobSD0MylArz7u2pVH8ohoLBe%2BZqDkTOHMd6KTkZryilDnzprXN7xYt9%2BaNdtGgqIwaFgVFjOyq672n7UUX8b0ylR7UUd%2BLexnaRBoiMGKWo%2FGjhoqSB1noRA4dtuHWvLZKTo94YS%2F2g54h8TuqY7RU8efZjomKJzdiIFnxrrSJntpETrNR%2BLHCZGCPoYIhNBaYooKSGPc84fveAxaI6cc33y9A2qVimulsl%2F%2FPR1OFbzRlhomEyoXTirn9JT8%2BhaTyYHmgqPc%2BjA5jJqlxagVRCL%2FPaijLOX6N%2BZZLZ35szfhmTqa%2B6ec6QHq3AIFLRyrSRzjxycB0FXtF%2B9mmU0Xu%2FPyd1E312IkpU9YZY9GwLff5Tz6mRUkXE1bIwfbItaydyAQb2bSAObjI3%2BgxdKJU1JgWR40zMNNNG9Q22Zr1Gx9lBY5jKRSXg0xZmUU4uU1Nim61Q4VI30R8s72Wh9LM3XU65IT%2BGgUYSounMJnDwTqZaMjQ2wxLc%2FvEcskUuzKVJL2f5%2FTu7%2BI8VFo%2F6N2uZVvgSmiGF5aHRPXycqTBAsTjJPnGRKbCfRVB6P8NZI8Vb1zFXUTcpWoDCH%2F%2BElqaYT02BFc0e0RE7bhDVVyOIOfPtBPuiHklJSGxQyffTktfycL0%2FOeIfvUwon525JGp5NYpndLd4OiXpNSO3yTwbd0xeB8iFRsYWUkwqasqJ8AXo4lWrC6dRZm2W0a9zwdnL6QHWaSwFFhr6Ehsq8mR8tJ%2FG9HzR1Z2CQJdaH4dCSOJqTzmNhFmuS79NngdK7jc%2BDdMhTp9yb6H1XsZ0cDdWldRRpefnqPYzEfTGL5wN7KCIRHPw52cYJ8u4paTF6neOLfNjXuoPYuEJ9np7yAsiYSohcJZW8JVT%2FUrY%2BKX1xgV7iOpHr7PX1UOh7J9FUri3GIfgjyAB9yxRHqXMBuIB0CoWrEgPNGRklwxKiURNW4%2BqNR7GWmZoYYtFf%2FbSOiMSWRUvLWSZP%2FzvO4%2Fr2bIAaziWR0SH5RzhKiv7QJC3Ul5RMfLKmo0OJdpu3nYyzfPbUnjIqRh7%2B965DT5GMTdFL%2BY22fDYtEddvIkiBGeaLW4nFNv%2BuCRNhtNFL2%2B0UVVS9L2QUdO8f99w4JebREkqCnBVNDgsZNJ08Zn43okhTC7FByxUTIpuUFErLRotFJWfTVOiMKT1i7Kd4MukP7X8J1L%2Bqnr48j8pGTQclmgP38MnRHqt1w0HrL9Ktsk%2BtjB%2BZvEl8NN8X%2Fcl9TEyk%2FOtgNfWHjPB73VpVk6%2BE0qCOI758%2FsqCk0oggyAp%2BzkZNCk9blBORKe21eUDzrJmzYR%2F1o6Q%2BQipkcTqX8Xx%2Bile8wjsjwAGcpdhMipC%2FivqRGAGt4R28P9CYJIaml6lJ%2BplKCcjpS8YFoEAHcCGxY3JqJD8Uz%2FglmAYJt0qe4MPMqSQi5ueycDkiuoHDMMw6VPZH38k5ymzctMzGZisUf2AYRgmfSp7yCnL1Pk0M4ZJIXSi%2BgHDMEy6VfYMwzAMw7CyZxiGYRiGlT3DMAzDMKzsGYZhGIb5EQ%2FVSSZUnzfMMBkNln%2B%2BHwyT7j17%2BmcCqfX%2FlTMMyz%2FfD4ZhZc8wDMMwTPqD%2FgUktwLD8s8wDMOePcMwDMMwrOwZhmEYhmFlzzAMwzCs7BmGYRiGYWXPMAzDMAwre4ZhGIZhWNkzDMMwDMPKnmEYhmGYpCZdPBufH1LCJDf8%2BFOGYVjZpwL8Dy%2Fhu8kkC%2FxPTRiGSetwGJ9htICiRxxBYhiGlT3DMAzDMKzsGYZhGIZhZc8wDMMwTDpR9jT3ydnNTEZEJ0r%2BGYZh0r2y%2F1TRClm5%2BZmMRpTcf%2BKWYBgmIyj7lyFGsOTmZzIaUXL%2FkluCYZh0r%2BwjgBt6OijOzc9kNEjuSf65JRiGSffKXgc4Lv7U5OZnMhxC7qX8MwzDpCA%2F5Al64br4WzccO6sXhM%2BBeyk7fzn0Vz80quuIqpW%2FBRbG%2F74ehoZZ4N3PFWv%2FPoyN%2F8Qci8f7tMP8ZbtRp0ZpebyCO%2FeeYfTENZg7vReyGWbFkpV7sXnbCbx%2BEwRTk2woVbIQ3LvUxemzN2M9L2Ge0xjzpveWnzeJY1euPYAnz97A2MgAro3Kw0Mcnylz5K3asPko1okXkUVss7fNj%2B4dayO3pZnc9vjJa3gOWxzjGvVqlkZPcR5NdPKYgeCQL2rbqom2cu9aF249piu35bE0RcO6TmhQx0Ft37Pnb8N30Q4EXH2AzKJ%2BzpXs4dm7MSzMTWR5wLUH%2BHXSWrRpVhmtxEvBZbH%2FmMlr0dK1Itq2cNZYT8V9at%2BqKpo3rqDc3rnXTEwZ2wnnLt7F%2FkMXMXV8F7XjwsLC0aX3LIwe2gZFf8qTonIv5D1rUATaC%2Fmvz0MPwzDpXtmfC8AFRztcCjLAL%2BLrhJS89qWAeyjnWFT5fcLU9Tjhfx3rlg6W3x88egV9fV149nJRO84qrzka1HbA0NHL4VzBDtmzG8rtw8asQJWKdlIxT5q2EfsOXsCYYe1Q0NoCD8W5tu44hYNHL0sjwTp%2FLnnM3gMXceDIZUwY2T5KaWeS77Pmbcey1fvFdjeULG4tFf5YoQD9z93C0jn9oaOjg4ePX4l3wKtvE7wPChEK7xhc20%2FC4Z2TkTmTPkI%2BfcHxU9ew0W%2BIWv0tLUy1ap9TwigZ4dVSTRHmEoqalCSdl4wSMk4uBdzHoOGL8TH4k1DQleR%2Bx05ek8p28ICmQpm2RogwGnwX%2FosmbSZi59%2B%2FwtQ0G96%2FDxaK%2Fb5o55doKgwZhRFD%2B5EhoHpvvge1Q%2BDbIHn%2FyOAwyJpZWX9qg1IlCsJj4Bz093BBAStz5XFHjl%2FFtZuP8FOh3Cku91Hyfonkn4cehmFSkh%2B2zl4vAv3Em5eDLVx%2BVB1mL%2FhXKN0ArFrgBaNs3xYH5MqZHRXL2aq9jI0NUK9WGZQpVRhTZm5SeuGvXr9Hn24N5Pfd%2B88JL76e9Gbz5zNHpfK2%2BG1MJ3RqW1N%2BV5yLFE12cT7Fd4fSP%2BF1YBBmzNkmIwQN6zrK%2Fcs72mDlQi%2BcOH0dh49dUYkERNaP6jPjtx549Pg1bt5%2BovbbKpQtplb%2FwgW1V24l7AqoHVuk8DfF7yB%2BP21z71oPTV3K46AwWhSMm7IO%2FdwbyjLr%2FBawtbHCrN97SkNj%2FrJdyv3y5s4hr7FBGCrE%2FYcvZCSgRpWS8bp%2FlcrZwaZIXixZsTdGWd48OVDeyQZbtp9Q275p%2B3E0c6kAXd2UXfkZJedeUXLPMAyTMZS9cBJvhOuglfBS%2FYSXP7JIEWRJyeuvXH8Q6zYdwdql3tLjVOWlUODkxaq%2BgoQXTYz3ccPGLcek8h0vlBuFjPUz6ckymyL5sGbjYZy%2FeBehoeHfwif6mpv5xKnrMDfPLhW8KjnMjFCtSgkZCYiNZ88D5fXzWOZQP58wEFTrT9MN2kIhddVj4%2BLZ87fIbxUZrSBj5dKV%2B2jWuKLaPhSNIOV66GiA2vb%2B7o2kN08Rg3lLdsGjWz3o6cVfAQ8b1AJzFu%2BQEYPoUMRh07ZvUyfk8e%2FccxYtmlRMMTkjuSb5JjkneSe552GHYZiU5of%2B17tzV7BPOIkVQnXga5IJfR3ssAYR2K8XjisFb%2BD%2BBiAsOa77v13%2B2HvggvQ6zXNkj1F%2B7fojTJu9VW0bhdxtja1glS8nBvRyQQeP6WjbrArKOqhMCYxyg8%2B4lWjmNhkRQm%2FZC8%2B2cYNy6NmpjtIgiIsXL9%2FFGWqn%2BXGKICi4cesx%2Fpz9D0KFoty24zR8vFpKo0CV6PWnOfvCXbTz7ldvOAQjIwPl9%2FXLiik%2FL%2FTbg%2Byi7M695zI%2FYPqkyP8I91LUn8htGfM30O968eqd2jaKkOQRHv6Slftw8EgAxo5oJw2e%2BFK6ZCFUFkJECp8UvyqN6jnJ%2B0FGSEl7axl5KWRtiWJF8yWbTLcC9O7ZwDpMF%2FZRyXjtIoT9pB%2BBCmeusqJnGCYDKnuFhy%2Fe6pQpjlK6EWguPg8I10PRO3awdkymp%2ByRkho8oBlGCEVgXyy%2FDAWrQmH4v6a6x3m8R5d6%2BH3mJnRqX0NtOyWhLZzVF5%2B%2FfBUK%2BQlOnbmJ2Qv%2BJxX1qCGtv1snmkYICgqOtYzm5rNli%2FkMopPCe6dwdY%2FOMRPvNiwfLL3qhDBpdAc5tRAXwSGfsX23Pzb5DYVZlJGhqF%2FQhxDkNDNW2%2F%2BD2GYUS%2F0p5N%2FRfTpGDW4t8w0SypCBzeHSegK6dagdo01pqoMSJknZb9p6Ai2i8gsSiqb%2FfHcn8ul490XL3xTSe1x48%2FV5jp5hmAyv7JVefuSAmKBBMb7%2FepTmlCmU%2B14o147CQ9%2B6xkfrBDbZaOSlC0WqG4cypYQ7Ui70%2Bvz5K%2Fb%2Bp%2Flnkaer8Jbz5c2p3K5IjPPu11S5jaYLvPq5yux613aTMGbyGozzaZ8i94miFFQ%2F8sq795uNbetGymiHldhGxg6F6ylsr8rh41fgUCqm8VC9Sgn0FIaKW5vqiaoT5RSQFz99ztYYZaTcfxm5FH16NpDJeX9M7JqoawnvnB%2FzzDBMmiND%2FyOcEd4tUbZMUeFdzsCHj4lfAdij%2F2y5xE5BYOAH7PnvPJwcimilsChj33PoIrwRxxFfv4Ri1MTVwq7QhUsDpxjH0AqA5fM8sWX7SbnkLyWh5X716zigc%2B8ZMp%2BBogh9ejbEhKkbcPX6Q%2BV%2BlN%2Fwv11npFKPDVoCl80w8ekatGxy09bjcl5elaqViiNcGEzDx6xApfLFZPIlwzAMe%2FYZCFJQNOfcwWMG3D194Td3oNxOWfb0UmXzquEal4XRWvcufWZFKuJsBkJpB0kv17u%2Fq1b1oRyCEWNXoHzNwciZwxhv332UWetrlnoja5bMsR5DWfuLffuhXbdpKGCVCwULWMjtVnbd1fbr2La6XBmQlFCyIkVG3AfOwYr5g4RCr4NPQtk2c%2FsNJiaG%2BBTyFUZGWeWyQVubfMl6L2k6o33raliwdJe6gOvrylUDC5fvge80D%2B7xDMNkTH2XHn4EhfH9Dy9JNfV58vQNwsLD5RI5xfrv%2BEBRhsC3H%2BSDfqLPf6cFKCLx7OVb6OnqSiWc1nFy7qb8zGF8hmHYs2eUXmZioMSy2BLaEsuoCatx9cajWMtMhSe%2B6K%2BkWQJOD8qhiENCoRyF6KsJVKEHCtEzDBiGYRhW9kw0xo9snybqSQ%2Ft2ejHypxhGCap0OUmYBiGYRhW9gzDMAzDsLJnGIZhGIaVPcMwDMMwrOwZhmEYhmFlzzAMwzAMK3uGYRiGYVjZMwzDMAwre4ZhGIZh0gvp5gl6qs8vZxiGYRjmG3rp4Uc8fYWx9MqbC2P4ljLJLWvcCgzDpDU4jM8wDMMwDMMwDMMwaZn%2FA0nbVqjwLzi6AAAAAElFTkSuQmCC)
+
+```
+keystore_stmt
+ ::= ( KEYSTORE_TO_NV | KEYSTORE_FROM_NV ) mem_opt address_or_range
+```
+
+referenced by:
+
+* basic_stmt
+
+**mem_opt:**
+
+![mem_opt](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQkAAAB9CAYAAACxrJYHAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAF05JREFUeNrtnQdYFEcbx%2F%2FHHb2JgIgNlCJgpaiosQQVsffEGg222BONMRo1MYkmxhjjFzWaYkuMGOwlMRpbNCoKNggIqIAdUOmIwHHfzAAXMCBF4I7j%2FT3P3t622dndef%2F7vrOzOwBBEMQLkGjCQbg7Q1FTLlhQmGZcM6L6INOUAwk8vVHjL5ZHJ18qsUSVo0WnoPp5TTXJcyJIJAiCIJEgCIJEgiAIEgmCIEgkCIIgSCQIgiCRIAiCRIIgiKpCtLhs1xxWASGILW6lkpZXF6JiYjF30Rbl9JIFw9HMqRE%2B%2BORnhEfeF%2FNqmxnB0b4eBvfzRBPbusp1t%2Fmfwp4DAf9Jc9ni0WL9MZO%2BhjxHjg1fT4Wxkb5YdvJMCM4GXIfv6G6YPvf7YvOVnw%2BCqEhe1m7ztxcikSXHfXdn7JJJMaOoREtaXl1oYG2OTxeOQrf%2Bi3Bwx0LYN7EW84NDY9DO3RFenVvg8ZMUHDt1DT0HLcGXS8dhQO92Yp3bd%2BKhqyPD9Em9C6VpXddMjC9eikT9erWxYdMfeHfGQDHv0aNkhIXfRa1ahpgzvb%2BYl52dg%2BG%2BX2LNl5NQt04tMa9hPQsq0USFU167beuMQXIJ%2FpcthzmbNBAiIckNO4bJ5RjEEt3zfKIlLa8uaDMj54acb9y6OtrKZVww2rd1Ev%2F7%2BrRBv15tMWnmWrRxdUA969xtLC1NlesUxdyZg%2FD2%2FB8xbpQXLGqbKOfr6eoot8vKzBZjt1ZNYNOwDpVkotIoq93mi4NcgQYFG%2F4XesFLkTtdbKIlLdckuFfh7NQQh%2F4IxMRx3mJefHwSzl24Xmi95i42yvDCybEBenq54pv1h1gIMYJKKaEWlGS3xYlDkSJRXKJl3ammYNvQEnfvP1ZOh16%2Fg5Vr9v%2BnTsLYXl85PYeFGj0GLMbEsd5UOgn1FgsJfmd%2B7cfFicMLRSKfHOAK81d8FCUsz85GFNupvqad1MSkNNg1tlZOd%2BnUHF9%2FNv6F2zRqYIFhgzoyMdmLju2cKy1v9CYoUV643bJQpE%2B2AkPZOKekgiQrJpY5yza8x8bdWYI%2FsPE7L1quLcPyfE9iGCCNdoSNXAsubEUvts4Itm6ITIFpzFOPqC4Gc%2F%2FBExZahGP%2BnKFl3nbWlH7o5DMfFuYmlXah6eMzNZu2TnDMlmAtKwTNWeHfzizguDQHobYRiPEH5EXZRUG7ZeMNetrYmJEFX3ajn6CQIAncoyhJJPITUeQmEqAthTM3frazd160vGAaIoMRuMX%2B8uGgvT3mm2pjLot5zru6YNjlUBxT55OfkvIU5y6GY8nnfhg9vCtcmjYscxqWTBx8R3fH95uPwLNNUyrRRIXC7KgbCxH8mT1%2BlZSFvjdu4Fn%2BsosvuOkXY7ez2zXH8iw55hUnFgVFwv9Fxl%2BK5UWSdwCfujmJ0MSfKaBnZXkUJREeeQ9jJn8t%2FvcbvhQbVk2BW2u73DO1YKMYDPR10dSxPmZM7oPhQzoVPgF7%2FhZDQQ74faBMoyBTfH2w1e8ElWiiwj0ILhAKBd64dB0HS7FJiXabN69YsZDkuSXpLJH1LJHlRSVS0vIyhAUL2agzc5UrtFaPu1U17fN1FG7UTFhZP8JGf7Hr%2F2kp1i2X3fJGVFwsWAF7i%2B0nt52ETIrGL0qkpOWlxfgpvkzRxzTXZmh1%2BR9cpUtOEGUIM5jdIActmB31L8365bXbgp4Fn9YqMLOkjV6ak9HIYPe%2FX7RyMIQuOUGUDWE3zH6EHZXe2MtN%2FvZV%2F4KXAseZC9SeLjlBlNV0mN0w%2B6lycarqHcoV%2BIfFOo50yQmibHC74faj8SKhnypcGEu65ARRZizz7EezReLcXRFP6dH1Jogyo5dnP5otErmhFT2%2BI4jyRRxV3xyfvkxFEASJBEEQJBIEQZBIEAShCmSaciAF32sgCII8iULwl53ohSeCIJEgCILCjZf3KOiSEgR5EgRBkEgQBEEiQRAEiQRBECQSBEGQSBAEQSJBEARBIkEQRHmQaeqBKQInae88d35WaETCG%2BE3kxyeJGXqxj%2FJKHNjK3Mz3WxDfe1Ei9q6p27cfvrZiYD0oMrOO%2FXzqTloQgM%2FjRSJo5vdp7y9eu%2BKiKhkw75eDTHwrUaoW8cAdczL%2FtW8uMcZsodx6RZnAuOGxNy7PaB%2FV4PAe4%2FSRweF4GZlHkNN6GxI09GUlw41SiQUio%2B0fv3frh1frA8ZOnqwHb6Y3wY62i8XUXFh4UNL59qYMNxR5ncwyvMHv4gQjxaKwYHB8t%2FJFIjSeIXV2aPQqDoJLhAbd0QOXbmwDd4YZPfSAvE8PD2e7tqPPfUMdCQHPFxA76cTGo%2FGiAQPMdgdfuiKBR5o0dSsUvfF01%2BzxFMqk2n94EpCQZBIVIMwI3CS9sFjd1aMZnf5yhaIgkIxckATiQySDcyj6EVFiSCRqHgqLEbjTzFuxKQYDu%2FbuEoPYPKIptDR0ZLlKLDDvTnsqDgR1cFeqo1ItG9QcR30hEYmjPXpUr%2FC6yBKgu%2BvbStLfvVkkONLKsdEdbCXaiMST41gVVFphd9KtnvFw0olx%2BHduR4f6bPhFdE1PEGoub1UG5GQStCsotJ6%2FOSZXv26Bio5Dhf7WvnOYJzoGp4g1Nxeqk%2BdhAReFZXUk%2BRnEnNTXZUcRgMrpTgZsaEHFWdC3e2lrKiuMZUCI7va4oOT0S%2FfAWqOXAEtadnqdY6djcPP%2B27jalgS9HS00M61NqaOtoODjVHZVDZvvwoFaktUcD5HjF%2BJ%2BbOHoGUz2xLX9d%2FzN%2Fr1bgM9XR21s4G4%2BCRcunoTPt3dSBCeg9mJXgqzl5rnSQDBKfp4VxU7nr8iBFMWXYJHczNsWu6Brxa2goWZLnq9eQaH%2F3pYTqEXnkSVx41D%2BreHlWWtkjWZqdjb839EcvJTtTSEiBv3sPzr3aQIRZBnJ8E1zpOQKjBdLsF5NydcuXQdB6tqv9sP3MHuP%2B7hj82dEBKRjI07o9HQWh8P4zOw4v0WTDwu48JuL1ialyt8kVb1eXz8JAUSSa4388exyzA20kd45D0c%2FysYNo0sMXfGQJiaGsJ%2F71mxzvqNh2FkqAefHm5wadqwxPR%2FP3oJR09cQVZWNtq1aYphAztAV0cbZwOu4xf%2Fv5CaloHuXVti1GtdRD6SktKwZfsJeHu54vstRxD%2FKAljhndFj1db5xb4lKf4js3neaxlYojOHV3Qp6cH%2FPedxePHKfhqzT6x3sRx3uJYXsSzzCxs%2FOkYzl24DlMTA4wb2Q3urnaIuRuPXex4J45laRjnpnH4z0vIyVGgt7c79v92AZaWprh4KRIBFyPQumVjzJjcR3hYsXGJ2HcoAEMHdhRjeU4OJryhuiiS2UdfNprN7MWT2Ut4jfIk2HWNyJFgGCtXW92dsdDeHlVSqbB6SyRmjbPH5bBETFgQBEN9KROLJPgdvIOO7hZo5mgCv0N3qs1dhhv9w7gEpUj4TvsG9x8%2BQf9ebRD8Tww%2BWfGrWGZpYSLG9axro2F9CxgalHy6v%2F3xMJat3Amvzi3QrWsr%2FH4kCNExcTh9NhRTZ69n81pi7MhX4bf7DD5ftUtsk5ichi9W78GCJT%2FBtVUTtHFzwMRZ63Dv%2FmOxfOqc9bj%2F4AneHOUljJOLkMifuQlk2lKRNz7IZCXr7YTpa3Hj1gNMn9QHXTu1wLipqxEVEwubBpYIDb%2BDOR%2FkviR35VoUFnz8szIk2%2F%2F7BUyauRbPnmWhf%2B%2B2OHr8Kj76zE8sexCbIPI%2FbOxy3Ih6IIRLFXB74HbB7YPbCbeXmlcnwbgcimNtneCZLcFaU21Mc3PGdihwXJqDUNsIxPgD8gq96yZk4mZMGrq%2FYoX3Pr%2FGRMEcy95tjqN%2Fx%2BLQidwww6OFGa6FJ1Vb1%2FQtXx%2B8PbWf%2BM%2FvorzAi7j2leZi3L9XW9Rhd9GSyM7Ower1B%2FDL97Ph1jq3ndjAPu3E3fhTJjzTmGEO6usp5jeoZ4FeQ5ZgDvNaODraMuz6eZ7Sw9l76DyuMcGqX88cIWG38fGgV9CeXXg%2BjBzWWZm%2FY6euYdigjqU6zivBUbgZ9RBb1s%2BClpYEbd0dcP5iOH5jQjZtYm%2BsWjYevYZ%2BjNXfHsCO3X%2Fjmy8mokF9c%2BX2c6YPxLhRuXWB9o2tMXLCSixbPEZM6%2BppY8%2FP82FiUnVPzIYxLzTaETZyLbjwSkp25kYogBAZ8yCCwlQnECoXiXyPgo168DYGWgoMZv9n5kjhcMsZNu4V3MosPSNXc7j38CQxEy72Jv%2BNF1iBy8rKKfc%2BVP0tiIIVuNwFz8oqn87GMu%2BEhwbPV4hyg7wZFStc%2BXwc7KyRycKRB8yDEfUzTBzyBYJjYmwAuTw3H1xIZi%2FYKMTLrXUT%2BI7ujlbNbcucv8gb90Vo0KHHvELzGzEvIl8gv131FnwGL2GeRm909HQuXIdUoGQ1sbUSYVNaWm4dOg87KlogSioXtyCWx7BsRbJSf455Dz6X%2F8FVdbjxqM2r4nkn5GplGqaVhS4rAFLhTdg1MkIw8xgymSDEP36mXCf8VgqcmhiX%2Bzgq4pVgdfjoDK%2B34IaemJIGi9qFxdTYSA8pqf9WgHIDk8tzYMi2yTe04hj9WhdR2cpDod%2BOBuH1cStw%2BcwqZeVqaeH7smtcF0f2flTsOrv2nUULFxvsO3QBU3x7oVYtwyLXS0hKFcJgYFB5ES%2B9Kl5N4M2ovTtZYdPOaLz9pgMexGfAweswlvwvTCz3HntaPBrt1bWuxh07N3h%2Bd%2BQxfGnglZ0ervZY9%2F2%2Fn8wICIoQd2%2BvLi2xfedpEZJwfvI7KbyB58WkSMPdf06EIzw8mDq%2BF9LSM%2FAsI0vk7SFLOy39Wany17GdE27fi2ehTIByXsydOFwNiRb%2F9%2F0WgJNnQrB72%2FvCi5jx3nciVMonKSVdjLm4rWXH2LObK6RS%2BpqjWnsSVcWiaU7owcSgcUND8RTjzoOncLIzxqOEZ0pjalBXXyOPffK4nhg3ZTXMzIwwd8YgDB3Y4YXrr14%2BHpNnfQvXV96BVKYFfT1d%2BG%2BZi5lv9WXz16Fjz3kwNTYUhr7521mlysOW7cexaOkvcLSrh6joWCx%2B73Vxh%2Bci0ap5Y7TrNhdSiRYO7%2F4Q1nXNXihim9bNxJz5G%2FHx8h1CeHhF5KrPx4snJws%2F2cbyOg8G%2Brr4dNEo9M6rn3hnWn%2Bx%2FbZfT2HLLyfwNCNTPOX5bvVUUoPibjCq2Cl3pyvS%2FeLpBe7vV%2Br1w26mYNYnV0TY0aKpCW8IhbAbyTi30wvmZmVvaOTR%2F0CFhxuV9fm6xMQ0ZGZno46Faam3iXuUJO6y5maFw7D4x8nIYEbGn0aUhYSEVKQyYeFPXJ5v2MU9FW7Y%2BY8uS8PD2ARosfyV9pgmzFiDTu1dRCUpD5XKci7KVC4KfL6uosqFKsKWGudJcJyZ53BkcydERKfiBhu0tSWwttSHmam2xh97flx%2B5PgVfLf5SLHrLZ73mrLSsjgj4o8tywP3ZPhQZL1RndyGYSvX7MO5C8U3C9i59T3l%2F7pW5fuGCBcjPhA1QCR4jX55mmY72hqJ4WVITcuqlufM26u1GNSVOdMHVFra%2FIlKaR4DExokErWMdbIfJz2TWdau%2BlfuI6OTqRRVMzq0c6KTUJabsCYchLGhduK9h%2Bkq2feFq4%2FEWKIAb5onpyJFkEioIeZmuqfOBMaqZN9Hz9wXY4UEcWwUS0WKIJFQQ3jPWoeO383OfImWkuUh6m4Kou%2Bm5p%2FJW%2Bz3NhUpgkRCDeFd7%2BloawX6HYyq0v2%2Bv7xAj38KpHHHgooUQSKhpvCu937wi8gIDk%2Bokv198V0Ibsak5AvELTa452hhFxUpgkRCTeF9c2ZmKYZM%2F%2FC8vLKFggvErwW9FgnOSICL6vJCDkGQSBRDQLD8t9Sn2RMnzz%2Br%2BGZrGCq6joLXQbw%2B42RhgVBgG%2FvtqZDiPSpOhCaicS0uL4Vik4dzjtZPu26u99sfJfNsbQGfLg3gaGcCm3plaziVnpHNP9ePC1fi8eeZ%2B0wkUguvwAWCv%2FsvwZuBldzLOEGQSFQggWH40a2Z4p48U%2B5%2F6kKslA0V%2B8YWr4NgIQb756PQwtigf3C4oo9BU7qtJyjcUF%2BPghmuRAre7vgPZtSPJUAIG%2B4w404rR3KpbNsoLQVLC9ijAHTFh29l6HCpEgSCv8RTnb8%2FQJAnUW0Iyg0BBomvXuV2nOONHGZ8EhiWMSkjhQKJCgn420cXFFIsCaRKSoJEQnMo8NWrxdVK5MibICjcIAiCRIIgCBIJgiBIJAiCIJEgCIIgkSAIgkSCIAgSCYIgqgyNaEylDt3iVTXU0IogkSgjldWZjTpCL38RFG4QpfKeaqIHRZBIEARBIkEQBIkEQRAkEi8Jj6Wpdp4gSo8kz25qjEhktG8APbruBFE68uwloyaJRPxTI1jRpSeI0pFnL%2FE1RiSYzxQhlaAZXXqCKB3cXrjd1BiRYMHVOf4perr0BFFqo%2FESdlNTREJ0h6fAyK62mlsvEXT5Jv65Tv0HEy%2BPsBNmL6rqRlIlIpH3YdrgFH28q6kX1n%2Ff3%2Fj96CUq4cRLk2cnwarqRlJl725IFZgul%2BC8mxOuXLqOg1W138ysbGz86U%2BcDbgOE2MDjB35Ktq4OYhlO3afgaNdPRw%2FHYwr126hc4dmGDvKC5t%2FPobT58Jg08gS894eDGMjfaSlP8OGjYfRs7srftz6JxISUzFmeFd4dW6J8Mh7uBYSDQN9XXy1Zh%2Bs69ZGY1srPIxNwMA%2B7ZR54XlITEpDb293sgSiSJh99GWj2cxePFWVB5U1prpwHRE5EgyTSLDV3RkL7e2hWxX7nTxrHa4zI54%2BqQ%2B6dW0J32nfIPLmA7HMb9dpMS2TasGnhxu%2B2XAIXXotwO17j9C%2FVxsRQqxkRs9JS88Q%2Fxd%2F%2BgtaNbeFWys7TJyxDiFht2FgoAtDQz2YmBigYX0LWNUxRS32%2F71Fm5GS8lSZl8XLttPLF0SRcHvgdsHtg9sJtxdV5UWlb4FeDsWxtk7wzJZgrak2prk5g1vNcWkOQm0jEOMPyCtyf7yOIDT8Ds4d%2FQJaWrxtigMCAiPw25FAzJrST6zz0YLhGNA7925%2FLTga%2BszgP3p%2FuJjmBr1951%2BFw4qt8%2FLSAm5EPcDeg%2BexcO5rsGtcFxbmJhg2qKNy3RYuNiIM8R3dHQFBEUhOSYdPN1eyCALDmHMd7QgbuRZc8iopR7DyFiJjHkRQmOoEQuUike9RsFEP0cuWAoPZ%2F5k5UjjccoaNewW3ygyPvI%2F4%2BGR06DGv0PzhQzr9GwZp%2FetcGbGwQp7zb8%2FkPMzIyi5et5rYWCm9kqIYO9ILq9btFyKxedtxvDH8VUilL%2BfM0ZugmsGt3HtQDCvwkazUn2Peg89lNeklTm2%2BJ1Ggl61KMxRjIz3Y2tTB8QOflCpdieTF08%2FzJCEVtc3%2B7blcoSicrd493PHhZ9ux91AATvwVjKWLRr%2F0eaOPzxAaWyehCjw9muJhXCJ27jurnHf77iNcvnqr3GkmJ6cr09nHjL93Tw8xbWpigJtRDwsrsrYUo1%2Fvinc%2F2CQqKwsKCkGoK7KadLDGxvrYtG4GZs%2FfiKVf%2BkNPVxtPn2Zi5bLyf%2Bmp%2F4ilyMzMFk83Zk8fwITIUcwfOqAjho5ZjrZec9HE1gp%2BG3Of9r42qKN44uE7pjuVPoJEQh1p5%2B6Iv498jljmUUhY%2FFDH0lS5bM%2B2%2BYXW5RWQBfHp7iaGgpw8tBSPniTDyFBPPPLMx8HOGkGnVuJBXAKs65gp55%2B%2FEI627g5o7tyISh9BIqHOWNWpVWFp1bEwLfrksvCCPwItyHebj2DG5D5U8giqk9B0TFjo8vVn45WPP0sDb4A1aZw3ent70AkkyJPQdPR0dQq1gSgNhga6Zd6GIMiTIAiCRIIgCBIJgiBIJAiCIJEgCIIgkSAIgkSCIAgSCYIgqgaNaUzl0cmXriZBVAJSTTiIB4%2BwhA%2F1LPFRTbuA%2FLipGBMUbhAEQRAEoZ78H43xP44Ns%2B1FAAAAAElFTkSuQmCC)
+
+```
+mem_opt ::= IDENT
+ | '@' int_const_expr
+ | empty
+```
+
+referenced by:
+
+* keystore_stmt
+
+**if_stmt:**
+
+![if_stmt](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAkMAAABnCAYAAAADm0aSAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAHWJJREFUeNrt3Qd8FFUeB%2FDfZje9QULoVQgp9CSEgPTOgSJNioAHooi0A0TurAeHeCBwJyqHShFUioAioiC9SSgJnQRCGiGhhQAppO%2FuvTcpJBBIApuy2d%2F389nsbmb2zez85%2B38582bGYCIiIjIhKm4CIhMi7cH9FwKJSMwmL%2BpRMZIw0VAZHoCDq3kQjAwnw5juRCIjJQZFwERkWHIVje2vBExGSIiIiJiMkRERETEZIiIiIiIyRARERERkyEiIiIiJkNERERETIaIiIiImAwRERERMRkiIiN2LDAEF0Niijz%2BYf8ghEfeKHffIyziBo4cu8iAEjEZIiIqnh82HMC%2BQ%2BeKPP43q3fB%2F8Slcvc9%2FjwajBXf7WZAiUwc701GRI915nwk1m06iDt3k1C7pjNGDOmI1LQMBF2KRmxcAlJS0lC3jgsG92%2BH79bvx8kzYYhPSEatGs54bXR31K9bFYGnwhAeeRO79p7BzZv30LhRTfTr3Rr3k9OwfPVOBJwKRRVnB4x7tQeauNdVprvq%2Bz1o7e2Krb8fR%2FClq%2Bjdwwsv9fUTicsuHDsRAk%2F3Onh7ykuwtDBXxr95655IuHbiXFAU3ET5b47tjZo1nJCZqcOSZb%2FihT6%2B%2BHbtHlyJihXltMHgl9op32n3%2FjO4cjUWi7%2F4BRpzNaaM78egE5kgtgwRUYFirsVh%2BGuL4N2iIYYN6gBHBxscPHIBtjaWykO%2Br1OrClycHZXxb92ORxufxnhtVHeo1SoMGjUfmRla2NlZwdrKApUr2SrjOzvZQ6fT45VxixF3JxGTRQIiPzd0zEIlqZFWimRo3KQvUMnRFt07t8Ccf29ArwH%2FRGJiCvqLZGbH7lP4etVOZdx79%2B6j%2F%2FB5qOZSCTMm9Vc%2B8%2FJfP1USIa1Oi0Ui0Zk44yuRJNVC5w5NMeujNTh9LgLmGjUqV7ZT5k3Ol0zgiMg0sWWIiAoUGn4DlhYa9OrWCg4i8enasVnusHp1XODhVgdDBjyf%2Bz%2BZiCQmpSBMfE4mMKvW7kXMjTi4udZCjeqV4ePVKHf8A4cvIDU1HXPeG6G89%2FV2xd4DZ7Fr%2FxmMfLmT8r9FH4%2FB834eyutD%2FkFo0bSBSJz6Ku9lEhV4OlR5vf6nQ2jr64bX%2F9ozt6yffj2KMyLhadokq6Vp%2Faq34SQSH2nfwXM4dSYcLZs1UBK9pKTUfN%2BDiJgMEZERaNUELcz0GAg92oq3rjI%2FEQ%2BVIafRto0bmjepj5btp6GJZ110bOepHH6yt7N%2BZFytVodZH63GXpFotGhaX2mdkWTrTEFCwq4pnZf9ur2T7%2F85yY9kZvbg69iJaapUD97b21nllh0Seg1%2F7D39SFmpaekPysr7WXtrZGp1JRqfIty5Xg6%2FIh6XRdT8dSr8dOoCznDNJmIyRESF8HVH40wVvlTp0FRsTdeJTeoStQ5B9UNwZaPISQy0oVZYmGuwetlU5dBV4Okw%2FG%2FlDuX1wrljsrbm%2BgfF7DlwVumMfPiPT2Bjban8b%2Fuuk%2Fm3%2FnmmamdrhZbNG2Dj6neebkHkSW5kWUP6t8Psd4c%2FMlpaekYBH1U9NF96g8cpMPjJiekQQB3ZGPW0ZvAUb7uKxHaHlwfOa%2FSYePwiQrimE5Uu9hkiMhKtPNFNq8JRsZU9EJ%2BB%2BieDMf3kRWw7EYLwoiZCxXEu6Ipy%2Bny1qpXwl57e6NW1ldLpWHJ0sEVo%2BPXccdNF0qFWq6HRqJX38jBYSp6WGdm%2FSLYE5ejSoSlOn43A3oNnc%2F93Oey60lm6uHp398KmrUfynep%2FNCAEt2LjC%2F2sPPwXGXVLadkqTTJeMm4yfjKOMp4yrjK%2BMs5c24lKF1uGiIyAbBHS6rFRr8douQEtjWkmp6Rh%2FJT%2FKAmD7GSsnP31%2BURl2LDB7ZVOym26zYSnWx189dlbWPndHrTqME05w0t2iNaYqXPLGjm0M0a%2F%2BV9s3xmo9OlZsuB18ZkJeOfD1bktNbKFZtl%2FJhR7Ptu1ccfbk17CwFH%2FRiV7G2U%2BnZzssG7FjEI%2F261jcyxZtg0%2BnWZArTFDwP5FZRLf0FCkiae5Xu44LfZQN4p4%2B7GFiKj0qLgIiMo%2Fbw%2FIU6cOBgZjrgHK0gccWlnk8aNj4pT%2BO%2FJU9bwy0jNxI%2FYealZ3glptljuujY1lbmflvOQhK9laI0%2FRz3uo6tr1O7Cw1KCKk8MzfS%2FZunPtxh04ioRIJnDFIedbJlA5h%2Fiehk%2BHsbmvCztMVkh83hdPHUUZPbnmE5UOHiYjKudkZ2nx1Mw%2BBQvLYvq1azk%2FkghJ5hYa5ZT0nEQoZ9yCEiFJthjJ8R%2FusyPLftZESJLzIcsvbiKUM9%2FPkggZUnacm2XHnYiYDBGRmQ6DoMLa%2FZFI5dKo%2BJQ4i3grcSciJkNEpJyD3Vb82cslYVJB36vEnYiYDBGR0rFPdp6%2BwCVhOmS8Zdy5JIiYDBFRFhfrJNzkYjAd2fF24ZIgYjJERFms%2FKPZX8iUZMfbikuCiMkQEWWRp1%2FpuRhMih689AkRkyEiIiIiJkNERERETIaIiIiImAwRERERlQjeqJXIBOW9jxYRkaljyxCRiZE3EX2WG4kSEVU0ZdIyJO%2BaXR42CBXp%2B1TEDXZJlq8PeMN8k%2F%2FRqUEhd0dfCot3vROfbhl7J7XQaTpXtsy0tTa%2FV8XJ8kBoVMon%2B44lBzJaZKxYD4jKMBmSAg6tLLMvXRKHCMry%2B1Q0JX0IZ9e33hP%2B9tmWT0MiEmz7da2Dl96si%2BpVbVDVufBr3N2KS9XcuJVc5XDArUFXYqL6v9jZJiDmdvLIwPMIY8JJxoT1gKgcJENlLac1hxsE04mPXv9Psx%2BXbN6wYNn5wSMHNsSCf7SGhXnxjhTLDYV8NPdwwrhhjTXrt0X4LV8fct6nmX5gwDntdkaOyjvWA6JHsc8QmQy5AVi54fLgRe%2B3xugBDYu9AXiY%2FLws58s5flY2FqpffTzBXsnEesB6QEyGiMoneUhA7LkO%2FvRdHzRzq2zQsmV5X8z2U2s0ZstbcUNArAesB8RkiKi8kZ1Et%2B25%2BulIsfdq6A1A3g3BiP7PqTRQfSX2jPtwqRPrAesBMRkiKjfk2TKhVxJth%2FVrUKLTGT%2FcDRYWZhqdHhu8m6KhIbdjjKLJMfjNeStAPSBiMkT0tIIu3321d6daz9w3ojCyfN8WLnIrpoEWCw1YdFrn%2BrBiJE1H29pKvFNZD4iYDBEZxKXwhIbtfaqVyrR6dqwpn6zFo32rJmhhoGLj7tvBhZE0HSl2kCtsLOsBEZMhIsNkEnfSrGpVtymVaXk2qpT1QoVbZjoMMlCx4Zk6NGYkTYdahSZ6IIT1gIjJUIV07fodZKRnGrzcGzfvIj0jkwu4AHcS0lTOjpZPF69bqbh6PRnJqdoijV%2B7Wu7Gxk48ehhi%2FsVGMUClQ3tG0oSo0FUF%2BJdVPbhxO2u9T0p%2But%2BUkqgHRCVJuehim6aoduw8bj5upMKGl5SIKzcx84PVue9nvzsMTdzr4r1%2FfY9Ll6%2FlG7dhg%2BqYP3t0uV%2FgfQbNwdqV05XvYUiDRs3Honlj4efDBoSH6bR6mKmLd%2B3GkMgkjJpxHOFR95X3y%2BZ6YVCvWoXvXWRPR6%2BHk8pAFzXVq%2FCb2GtZIl7OATtTV3iyf1iiHiN0ZuhdVvVg6JRjCLqcAI0Yf%2ByQBvh4RpPi7WWXQD0gKon8JOfzykqaocU1bw9s1qgxuaBCCxteUmrXcMbc919Btxc%2FwLYN76PRczWU%2F58LuoI23o3RtWOz3HFtbdm%2FlAxn8fIQJREa1q%2BO8nBrYFfMHXtlj9jaEPNyKgj7vD1h5uOJQQFB2MToVGyJ1nhb%2FsyduoAzZTUPn73fAjfj0jD1X6fx9fpwjOxfBx6NHIpdjiHrAVFBnjY%2F8fXAAK0KSzK1cBZvbTTZK6w8XDZEq8UAUejPDxda2PCSYm6hQa2aTsrrGtUrw9LCPHeYTIza%2BrobZfCu37iLDZsPKy1fvXt44ZUhnXKHHfYPwrpNh5CckobuXVpgxOCOUKmy9rKiom%2Fjm293IjTiOlo1fw4TxvaGvX3xf2dS09KxYs1uHD0RAqfKdhjzSje0bN4AkVG38POvRzHu1R6wt8sq9%2FedgTAzU6F3dy9s%2Be0YqlerjGMnLuF44GW0avEcJo%2Fvq8RFfqdtfwRg4It%2B%2BEWMJ40d2d1oK9itO2nK8xvDGqCZm%2BPTFqM21E69WAOmi73sVS3dEXD6IiL5E1gxebmjn3iartbDryzno6VnVp%2Bfjq1d8PPOGCUx8miEsq4HRAUl3MXKT3KSIK0etfO2s%2BfrM6TPas6UhUaLQn%2BUzUfFGV6aQsOvw%2F%2F4xdyHTB6Mxb8W%2FIjaNZ3RvXMLzF%2F8E37edlT5%2F96D5zB55jfo2a0lRg3rgh82HMDCz7cow%2BLuJqL%2F8I%2Fh4uKAKSIBkX2Eho9bBJ2u%2BEdNxk78HFeiYpVEpkM7T4wc%2Fx9ciY5FvTouOHM%2BEu98mHVoMuBUKD74eC2aN6mvvN%2By7RjGT1mKDJFKv9CnNXbsPqV8F0n2hfr0s58wZPQChEfexO24RKOuYDl9JRzszMvF%2FAQEYbteVGCxVTnk5YkO%2FAmsWBo1gqX4TX1f7PesEZnvEPGTFlIe5sveTpOvPhCVV4XlJzIJ8vbEVS3wE2Qi9BBNIYUqmVZhw0v78Jm0c%2B9pnDobkft%2B8byxqFvb0iiCtnTx%2BNw%2BQ4lJqdi05QgG9PPD19%2F%2BgakTXkD%2Fv7RRhtWoVkkkQPMwbcKLyjgyKZkyvp8yrI2PG3y7vo2jJy6hXZuit5AFngpDdEwcfvhmutLi5OvtisNHg7Fj10mMH9MLS%2BaPQ%2B%2BBs%2FH5V79h3caD%2BGLhG6hZwyn38zOnvoSRQzsrrxvUr4Yxb32uHMqUrCwt8Mvad5%2Bqtao80IpdhYjo%2Bzh44jbOXoxHOy9n1K1pU27m72QQ5nm7I1Klx2YvDwSI5w06NU443kf4%2FkjDXpOGStYQQB3ZGPW0ZvDM7iw9XPyuntfo4RcYXD4SIUn2k1u39Sq%2BXBOGKpUt0bi%2BHZwqWTCAZAxJUVZ%2BosJ2kcrPebglqEjJUA4dcNoM6K0vZHhmJiLEREt1C%2FjWuD4YOvDZT7DJuTt6WZEdv3%2FelnXSiGxRcXOtmTuscaNauJ%2Bchpux97KHPejAKw9duTasKf5%2Fo1jJUEjYNcRcu4O23Wfl%2B79bo6yyHRxs8OWi8eg3dK6SmLVt7Za%2FANWDDpjP1a%2BO%2BPj7ua1y1jYWBk%2BESjM%2B8lBA28H7lNcdfavgh8W%2Beb9uuZp%2FMVt9xJ8%2BZjqlj4mcDhmR8AdxzBvT6loVLpWnWModgnWf%2BWLEtON44fU%2FMaRPbSyd08rofmfJ9Mj8RNSpvpl6DBbPhR5D0Tzmh%2FaI%2BGCMeO4uClwunqc9abi5BvOL0zJUniqG2AtTPWsZz%2FJ9kpJSUMnBVnltb2eFhMSU3GGJ4rVsvbGztVIeCYnJ%2BT4r39vZFS%2F5kOXIhOv3TR8%2BdpxNW4%2BgmWc9bPn1KN4c00tJkApy504ibKwtYW1lUSHiU0Xs8a74xBt%2FBsZh5aZIzFpwHp990KLM55%2BorHYs5FmVb7x3EtWcrTBpdEO0aeFUIvXgCS1lE8vLIUMqfb7uaJypwpdifWgq1od1Yg3eq9YhqH4IrmwEtAWt13nzE%2FH8lZU5VqZmYKwZME6vQnxBh8iUBoaHCxFPG0UBHuIRrVHD42Qwphc2vCxOuzdmqSkZWc9p6Vi76SB6dcva0%2BrasbnSeVqr1Snv12zYB6%2BWz8HR0RbdOjXHH7tPITYuQRl2%2BlwELodew%2FN%2BxduNlOPLVqZtO07k%2Fk92nD57IVJ5vXmrv3Lobcu6f6C1jyumzFoOvf7BupaQkJWQZWbqsHTFdvylp3duB29jZ2Fhhhe718T8Wc3g0dAea7dGKdcZIjJVq8ROwZ176Xj3LXeMHVwfTVwdSmQ6csN2IgThJy9im9ymxGegvvhVOaBV4WgrT3RjJEyPjLuMv1wP5Pog1wu5fsj1JCcRKkr%2BcuQszstntRquYlO2UYyXKEaOflLLkCxEZlLHzEUhBSQ4hQ03uEuXYzBq%2FH%2BV1y8M%2Bxhf%2FWeCSA6M%2F75%2Fk2d%2BrRxuuhufhM7tm%2BaedfW3t17E%2BKlL8XzPvytnc6WmZWD1sinKMHkobOSwzujc9z24PlcT4RE3sHDuGLg4F%2B%2FHSZ49tuKLSXj7%2FVX4cN46WJhrkJaegSXzX0fwpauY%2Fcl6bP7%2B70r%2Fn3kfjkKfQbPxxde%2FK52tlQRt3T6s%2BG43UlLT0dSjrhKTiqiKkyUQloh78emoWZWXbSDTdFckQpJzKfcTCg2FPPY%2B18td6Yqx0dcdfmwhMq0WIa1IXETyMlomQEXJpwvLT7L%2FN71NU8zP0GLWwy1FOclQisyknpDkFDa8RMg%2BMsf3fvrI%2F7eue89og3zmSFZyF3MtTrl0QNUqD07btrWxxPffTMOt2%2FFIT8tE7VrO%2BT47Y1J%2FvPFqT9xLuI%2BqLo75LjXw585%2FF6t1yH%2F3AuV0eI0Iat6E6qz%2FZ%2Fnm5%2BD2efk%2BO0kkRbKz9%2F3k1Hzz7t2qIY7t%2BbTCVEZ726yqsePQTbg9Zw%2B1mke7yLRcj01FwPm7ymsHu7K5bqLcEHp7YLFWhS%2FE256MimnIjvfiIiZCxcpPHk6KxC%2F7m7nJkEaNBk8qpLDhVHy1ajo%2FdljeJOORjbS99RM7KS%2F47GflGkAFkZ2uf%2Fx2Zu57ee2mpyGTJPmoyF4f2gD7j8bik%2F9dVB5FvQI1UUXQacQB5QrUkjyZoFX2dYfKZMckBQsTrTFR3vC1LC9ESaVDubGvDs1E3F8syvhPm5%2FkTYpyk6HCCmIiZDzemTqgxMoeN7p7vtPsjYW8NUBxb8nR3qcKTm3rjuDQrOslFfUK1En3M7gSktHXA3kF6vspWthaq3MvwFgchqwH8rIR3p5Ym33DVyZDFX09lXFWYW1RLxfyrPlJzud5zxgqeoLQ1tMo57uSvUVmXHyaxsWpeH1%2FnBwt8Ly3c7E%2BczkygSsKGX09aPmMLUEGrwd67NUDf2MUKz4R57YqPf5b6kkYFz1VdPa25vdibiSXyrSOn7mtPIvKLJuUtFz6xHrw7PVAq8cFFcC7UJsAGWcZbyZDRAbmXNnywOGA0jnSu%2Bvwtay9GxVuiSceXibWAwPUA%2BskpQwXRtEkuGTHm8kQkSGFRqV88tve6Mz0DF2JTiciOhGR0Uk5NUteZDiKS59YD569HvhHK%2F1HeI0L02CVHW8mQ0SGtO9YcqCFuVnA%2Bm0RJTqdv88PfPBGj%2FtyB5lLn1gPDFIP5JVfeX0L06DKjjeTISJDi7mdPHL5%2BpDUc5fulkj5C74%2Bj7AriTk%2F2%2BHi4a0zw2YueWI9YD2g8o%2FJEJmEQPEbnZ6hHzTpo6NaQ28I5Abgx7x72yocFrs2J3hNFGI9YD0gJkNE5cqxc9rfk1IyXx%2F%2FjyP6z9cE41n7Tsi%2BEUMn78%2B%2FAdDjB%2FG3l16Nd7jEifWA9YCMA68zRCblZBBW%2BXjozL7bHLZs%2FdYIjV%2FLKujdqTYaN3RAvZpPvrBicmomLoUn4PjpWOw%2BfE1sBJLyjyA3APKO2yqMCRB74FzaxHrAekBMhp7Ip8PYCrUgK9r3qcgCgrHCq4k%2BRpuu3Xjg%2BE21eFg%2FU4Gyb4QKh8Wr3nozvBp4ATu4lIn1oHzXA2%2BP0u%2BkW1EFBht%2F53ZNWS64irIyVrTvYxJ7xuKH2rspWkKLhSJqHcRe7HXxb0e9Ck7ivW0hH08SAY9V6RGiUyFZBN3XDLDTa9DuJPeEifXAaOpBwKGVXAnYEFB2yRBRuUhis36wB8gbA2bf96gndCKxVRW6EbDT63FPbDDkPQuO69WYHcBOosR6wHpgonIaAoy5hahMk6GK0LRWkb%2BPqcg%2B20U%2BPuTSINYD1gMyPTybjIiIiJgMERERETEZIiIiKr94S46Kr0xuxcFkiIiIjEVq29q8WWtFlh3f1LKYNpMhIiIyBrEpdqjGxVBxZcc3lskQERFRAfRAiFqFJlwSFZeMr4wzkyEiIqICqAB%2FeZuP8jZft27HIzkljQEyTJC7KnFmMkRERPQonRk2Q48RneuXr35Db01bhl37Tpf6dBMSkrHlt2PPVMbeg%2BdwNeZ2uViOSlxFfJU4MxkiIiJ6VPZFIc8lWuNtLg3g%2Bs27eHfO989UxpJl23D2fGS5%2BD7ZcT13qoyuYs7bcRARkVFQ6zFJq8JRL3ecPnkR20pruukZmVj53W4cOXYRDvY2eHVEF7T2cn1kPHm4bPmaXTgfFCXGs4afjxsGv9ROGRZzLQ7LRRnng66gqWc9THitN6pWcSx02qlp6VixZjfOiKTF3s5aTLcRhg3qgI1b%2FkRaagYWf%2FGLMt4rL3dCVHQsbsclKvPx6%2FYTqF3LGTMm9sfJs%2BH48ec%2FodfrMXVCPzRxr6t8l2s37mCrGO%2FS5Rg0a1IPPbq0LJO4inj2E0%2FTRXz9ymrdYssQEREZheMXlZvCDlGpsMbbA%2B83agTL0pju%2BKlLcVEkDJPe6ItunZtj7MTPcTns%2BiPjvfPBagRdvIq%2FjugKX%2B%2FG2L77pPJ%2F2a9owMh%2Fo26tKpg5ZQAszNUYPnaRkpwU5r05P%2BD0uQi8OrwL2rZ2w%2FZdWWXKRMrMTIU6okz5MDfX4MTJUEx6%2B2v4iwXVt6c3Ll6KRo8BH2HV93vQoZ2nkqC9Pnmp8nkHBxsxHxpUcbZXPl%2B5kl2px1PGT8ZRxlPGVca3rNYttgwREZHROBWEPb7u8MtU4UtHc0z08sA66LFXrUNQ%2FRBc2QhoDTm9CxejEHTpKvx3LVCSD8AVxwJC8PvOAEyd8EK%2BceV4Y17phnZt3JX3Lw94Xnn%2Bfv1%2B9OjSAmNGdlPe%2B3q7YtMv%2FrgYEg0PtzpPnn5wlNK69Lyfh%2FI%2Bp6WpU%2Fum%2BO%2BybRiSPY0cfXp4YeHcMcrrypXt8NG8dfj%2Bm2nK%2B349fdDEbzLi4%2B%2BjqUddkQg5oJ1YmH17%2BZRK7IYA6sjGqKc1g2d2Z%2BnhIh08r9HDLzC47BIhJkNERGR0slsQerRqghZmegwUr6fo1HAN90A9bwNfpfrS5WuIjU1Aux6z8v1fHqp6mDwENeujNVi6%2FHd4t2yE0cO7KIlPSNg1HPIXWdz%2Bs7njmmvUSElJL3T6k9%2Fsh5kffItvVu%2BEd4tGGDWsE9r6uj92fLX6wQEfOzvrfMNy3mdotSUSl5y71z9OeNbVpa%2BIAF0WUfLXqdC7rPoIMRkiIqIKIXtD%2BlQb08I23Dns7axQv15V7P31X4WO2%2F8vbdC7uxcuBEVh1%2F4zGDZmIU4cWAg7WyuMHtoFs6YNLPZ8ysNdslUpKPgq9hw8ixGvLcbRPQugUqmKdJitMDqd4e5%2BERhsvLdLYZ8hIiKix5CdoG%2FcuodNvxzJ%2FV9U9G2cOhP%2ByLjyVHe1ygxeLRvirXF9lGQl6X6qkiCt33wI4ZE3csc9dCQId%2B8mFTr9X34%2FBpXIV1o2b6B0ujY3VyMhMQWODja4L8q%2BKebtackywiJuMMhgyxAREdFj2dtbY9XSyZj%2Bj5X4eOFGWFmaK4e3Fs0b%2B8i4P231x9%2F%2FuQburrUREXkTk8b3Rb3aLspj%2FNhe6PvyXFR2sFUSpKpVK%2BHHb2cWOv1tOwIw60NRZuOsMseO6g7XhjWUYS%2F28UXnfu8r87Rq6ZRif7dXR3TFhGn%2FUxI12TH84w9GmmyceQdgIiIyOfIwWcChlcX6jGyFkYenqro8%2FpR42Tk5ISkFzk72sLHOf7JbZqYO12%2FeQSWREMkkq6jkBRbjE5PhVNketjb5y4yNS4C5Wo1KlWyfajmkpKYjLi5ROQ3%2Fafh0eJAUGvNhMrYMERERFUG1qpUKHcfR0VZ5FLjB1Zgpp7HnuHL1Fma89%2B1jyxo2sL1y9pg8DV4%2BCuLi7PBM38nayuKpE6GKhMkQERFRGahXpyo2rXmHC6IcYAdqIiIiYjJERERExGSIiIiIiMkQEREREZMhIiIiIiZDREREREyGiIiIiJgMERERETEZIiIiIqqQeAVqIiIySXnvq0WmTc1FQEREpub6bcyWj5ou%2BCeXhuGWqbHOOw%2BTERERERERERGZqv8DpsSTS4J%2FPPAAAAAASUVORK5CYII%3D)
+
+```
+if_stmt ::= IF bool_expr '{' statement* '}' else_stmt?
+```
+
+referenced by:
+
+* else_stmt
+* in_from_stmt
+* statement
+
+**else_stmt:**
+
+![else_stmt](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAYMAAABzCAYAAAB6gW6%2FAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAF8BJREFUeNrtnQdcVFfaxp8pNKmCWAAVY6NYARVb9NPYEhN7jK4xq8Y0TdNsssnm241%2Brtls1GSN7pqN0STuGiOafJZNsbdYQcQCgoBYUETpSJ%2BZPedSxIIUZ5yBef6%2F38ydmXvPuXfOec%2F7nPecWwBCCCFWj4pFQBo6wf4wsBRMQ0QMfUhDQcsiINZA%2BP5VLAQjE9J%2FOguhAaFmERBCHiTqYuRFMSCEEEIxIIQQQjEghBBCMSCEEEIxIIQQQjEghBBCMSCEEEIxIIQQQjEgxOo4EhGHs3HJNd7%2BwKFoJCalWNz%2FSDifgoNHzrJCCcWAkLrw7%2B%2F2Yvf%2BUzXe%2Fouvt%2BPQsViL%2Bx%2B%2FHo7Bl2t2sELJXfDeRIRUIup0Er7dsA%2FpGbnw8fLA5AmPoqCwGNGxl3E9LRv5%2BYVo1dIT40f1wZp1e3A8KgFZ2XnwbuGBGVMfg2%2BrpoiITBBRwTVs3xWFa9cy0aGdF0YO74GbeYVY%2BfU2hEfGo4mHC55%2FbggC%2FVop%2B139r53oEdwem388ipjYSxg%2BJAijnwgVjns7jhyLQ4BfS7z12mjY2doo219LzRSCsw2noi%2Bio8j%2FpenD4dXCHSUleixdsQVPjuiJr9buxIWL10U%2BvTB%2BdB%2FlP%2B3YE4ULl65jybJN0Npo8NqLI1nphJEBIZVJvpKGSTMWI7hrWzwzrj9cXRph38EzcGxkp7zk95beTeDp4apsn3ojC71COmDGs49Bo1Fh3LMfoaRYBycnezjY26Kxm6OyvYe7M%2FR6A37z%2FBKkpefgVeGAZbqJ0xYpTl2ySojB87OXwc3VEY8N7Ir5f%2FkOw8Z8gJycfIwSzvznHZH45%2BptyraZmTcxatJCNPN0w9zZo5Q0T%2F%2F2Y0UIdHodFgtHP2vu50IkvDGwfye886dvcOLUedhoNWjc2Ek5NnlcUsAIYWRAyB3EJ6aInrcWwwZ3h4tw%2FIMe7VyxrrWIBvw7tsSEMX0rfpOOOCc3HwkinXTgq9fuQnJKGjq290aL5o0REtSuYvu9B86goKAI8%2F8wWfneU0QBu%2FaexHbRU5%2Fy9ADlt8V%2Fnoa%2Bof7K5%2F2HotG1UxshHE8o36WIRJyIVz6v%2B34%2FevfsiJm%2FHVqR1%2FdbDiNKOPxOgaWRxrrVb8FdOH7J7n2nEBmViG6d2yhCl5tbcNv%2FIIRiQOoN3QPRVW3AWBjQW3xtL%2F0zjPw8jt69OqJLoC%2B69XsTgQGt8GifAGX4xdnJ4a5tdTq96HF%2FjV3C0Xbt5Kv0ziWyd34v4hKuKJO3oYPfvu33cuevhOnqW3%2FHSexTpbr13VlEG%2BV5x8VfwS%2B7TtyVV0Fh0a28Kqd1dkCJTm%2FS%2BqnBnUvl%2BgvidU7U2iG9Ct9HnkEULZtiQEiN6OmHDiUqLFfp0Ul4k2%2BFS1mq0SPaNw4XwoRPNpKjUrC10eLrFa8rQzcRJxLwj1U%2FK58XLZhW6s0Mt7LZKXr1cjL2wC8fopGDnfLbT9uP3%2B79Ku3VydEe3bq0QdjXb9etICo5d5nXhFF9MO%2B9SXdtVlhUfI%2BkqjuOy%2Fh3nK7uITcTAE1SB7TWqREgvg4Swv5zkD9Oaw2YdfQs4mjp5odzBsRyo4EADNapcFh4mb1ZxfA9HoM5x89i67E4JNZUCGrDqegLyumjzZq64fGhwRg2qLsy6SpxdXFEfOLVim2LhNPVaDTQajUVw0D5lXrmcn5BRgLl%2FE%2F%2FTjhx8ryIJE5W%2FHYu4aoyWVxbhj8WhA2bD952quvh8DikXs%2BqNq0c%2Fkq6mKpENg8TWV%2By3mT9yXqU9SnrVdavrGdaOyMDQqqMCHQGhIlO7FTpQB7GPvPyC%2FHia58oDlNOsipn%2F3w2S1n3zPh%2ByiRtr8G%2FQ0DHlvj8b69g1Zqd6N7%2FTeUMHzkhrFVrKvKaMnEgpr70KX7aFqGM6S%2F960yR5mW8%2FcevK3rqsoe%2B4pOXa32cfXr54a3ZozH22b%2FAzbmRcpzu7k749su51aYd%2FGgXLF2xFSED5kKjVSN8z2Kz1G98PArFYkGQH06IHmmYqO9QRgjmhc8vJRZJsD%2FkqTP7ImKwwAh5GWrz2MvLyWnK%2BL08VbMyxUUlSLmeCa%2Fm7iIqUFds26iRXcVk7Z1DNrK3Lk9RrTxUc%2BVqOmzttGji7vJA%2F0v27q%2BkpMNVCIIUsNogj1sKSPkQV12o%2FNjLB3kWsqif98XiUZHHUFq%2B%2BeAwEbG84aFAdBWLzs75WGSO%2Fft4e9wlBBIbW61ySma5EJRvey8hkMiIQW5%2F55i9zPtBhUAij0PmX1shKD%2FuBxECY1JWz53L6p1QDAgpM0o9xol%2B5to9SShgaTR8lHoW9a3UO6EYEFKOAegt3naxJKyq0ncp9U4oBoSUo4IyeXyGJWE9yPqW9c6SoBgQUhlPh1xcYzFYD2X17cmSoBgQUhn7Q5c5X2BNlNW3PUuCYkBIZeTpNwYWg1VhAE91pxgQQgihGBBCCKEYEEIIoRgQQggxO7xRHbEKKt9HhxDCyIBYIfImag9yIzVCGBmYiJo%2BbKS%2BOJr6dLyG8BdsNhw6%2FHp0XMbU2ISs9ulZRXbX0wuq%2FA8eje1KHB1sMpu42%2B2Nv5j%2F4e4jeRFsNqS%2BQvu3MDGQ1OaWwhx6MA7bvwp%2B%2BY2%2F%2Ff%2FHceezHUcOaonRL7VC86aN0NSj6mt9UtMKtCmpeU0OhKeOu5B8cdRTAxuFJ9%2FImxJxGgkUbkL7bzhozLFTL0988ML0UfW%2B8P65epPyX%2BTr6g3Ms9jekOEDdYB72vrPvor53bCBPrYL5gYhtLsnmnk6wLHR%2FfsDcr3crkfXJpg4so1ab4DPqZiMF5o2UR2%2FkmqIN5V9WHJ5EtP5BVPUe32zf3PBOQMrYP3Sjd%2Bt%2Bu7c%2BMXv98DUMW1ha1O3apfpZPrl80PtG9mqtoQEgLOyhPZPMSD1JTReuS5u%2FMfvhaBzx8ZGyVPms2xeqEarVa%2FsTkEgtH%2BKAbFs5GTZ1p2XPp4iejPGagiVG8TkUY%2BotFB9LnpII1jahPZPMSAWijxrIv5CjuMzI9uYJP8XJ3WEra1aqzfgu%2BBOaGvMdszaszqMfnPCemz%2FFANiXKLPZTw3fIB3ncdIq0Pm27Orp2zFWuiM%2BrziwoG%2BvJ2xNdHbR6nvAto%2FxYCYgNjE7Lb9QpqZdB9DH%2FWSCwfx6mfEB5qn3XTig06siXwnSEO9TvunGBATkJZeaO%2FdvJFJ9xHQzq08yE814gPNE0v0fASiNaFRIdAAxNH%2BKQbEBKRnF6o8XO1qleZGeiEuXc1DZnZxjbb3aVbR2JzEa4gxjls4hXCVHv1Yg1aECoNUwCFz2L9BGJy0efkqKtLXah%2BmsH9zoVxx0asTmh05XfUzZ6tbb0rmvLcKFy%2FfuO03F2cHrFr%2BKmJiL2HRZ5vw5bLZd6XT6fRYtWYHvt9yGBmZuXBzdUS3Lm3w4rRhaNO6GfYfjMbfVmy9K90rzw%2FHoEe7NIj2pdcZoNbU%2FKLbcxdy8diUfbCxUeOHf%2FSGm4tr9b2JsvxFg3JXGemKdoMK%2FxG9lKXi43xwMrnBI%2BeHcgyYrFdjuDnsXyU2%2BWT1Oaz54SKeftwHy%2Bd1r3lv2gT2X1se1D%2BXp1cOvliHK8H%2B2KjV4NV7ZVrdelMSdfo8nhgagt49O95SMG3phdNZOfk4FnHunukWLApTHP4Hv5%2BI1q2a4uKl69j841HlNykG19OycS01E3%2BdP%2FW2dG3btLDaRvn6%2FCjkFejwxf92Q%2BeOrrVKqyrtGTkY4zgio7E7OADqkACMC4%2FGBrrLhk2OA94Si1ORZxBlrmP4%2BJ0uiIrJwvofL2P0UC8M6dvMbPZfW%2Brqn3v6Y4xOhaUlOniIr6XXYqtKh4sm6HQYIzL94c5Mq1tvajq29xZi4FerNNt2RuLNWU%2BhX%2B8A5XtL7yboG%2BqPkpJbYaCTo32t822o7Dt6A8dOpiO0m7vSGOqIsW5vohc2N0f0tlZ380P4ibNIYg01TIL8MFIOAGgMCDXncWhED3%2Fh3E4YOfNXLFl5rtZiYGT7r60Q1co%2Fl4uACJx8Ksfdt4U1htLvVWZa3XpTEXsuGe6NnW6LDHoEtb9vGr8OPli7fh%2FaPdICnfxbizTqsrS3pklybxbg0NGzd0UGTT1dra5R%2FrQ3RVlOfqqVRRyPiAh%2BCgrAUuEk9ovl5OPR2E%2FX2XBo1w52rjb4nRQCofwTImKMO3lcp%2BES0RF6pJUjIs5kIOVGAZo3qV9nN1fnn6sSgXuKQVWZ1nanxmbrL%2BE4eDS24rucM6hODBb%2BcQrem%2F8vjP7Nh8r3wI4t8dTjPTHj2SEVgpB6PROLl22%2BLZ0yZ%2BDZxeoa58nYLGXZo0tjizkmIQALg%2F2QpDJgY5A%2FwsXyO70Gx1xvInFPknHPSSemZYLoNSd1QGudGgFlk8WThB85rRURgSUIQTk9OjdG4sWbOB2bXe%2FEoEr%2FrMJPJcD8qkTgvmJQEasDJ4TbHG6oZn1JCc6LnZpsvGzu7FF4YlhIrdI0a%2BqmTCwXFBYhLv4KjoSfw9%2B%2F%2BBHpGTl4d854ZZtHfJtjwzdvG%2BUY6%2FszGjIyi5SlR2M7iywH4TxGiLcRar0yxiz3Q%2BoRibfqsXKdNhc91VhLqssm7qX2n55VVO%2F9gPTPooyfKDFgvFjqqzswbRUN76BImCyWj4kMV4rlm%2Fdbb6PFR7WJDB5mgdnb2aJLoK%2Fyyi8oVCaQTUF198q%2FT89o1tGzpukZ1aacnZxKTSG%2FQIfGLjYmKwdCHhZ18TN5eTpl6eigtQj77%2BmHDiUqLBeZdhJ%2F5lvxj3Zp9Ij2jcOFMEB3r%2F9Z2T%2BL5ef2NlhVUIzpouP%2BvEGFLMgIoToxKM%2FEUJrJERsN%2FKWTFzt7837rLdEQpr2yFLNnPoHg7qW3DEnPyMWOPVHo28s83RCl4uKUDpJ8bW3XDu%2FKMVPRMzrcPQATIqOx05zl5evtiMgzmTgdlwWvprwTBLFOpP0rowYtG5n9WIRfGKwzIEz43SVZxRgZH4%2FC8nXH7tOJr8I%2Fz%2BnVCR8V6%2FBOVaJQWQzCqnHyYeYSgRde%2F%2Ftt3%2BVk8qlDS5XPaRk58Pa7%2FS6ya1fOVYaJnn3pU%2BUcYmdHB2V4aNyoPsoZRuWcPJN0V9pFC6Zh0vj%2BJv9PZRW7IMhPGWoLEz2AUFNFCDVhUG9P%2FLAtGRt%2FSsbQfs3oFYjVcSE5D%2BGnM5TOkF9bF7Mei4wIpBAYDJh6%2FCy21qS%2FWZ1%2FLvutSlEoF4N8kcnl%2Bzj56tabjJ2b%2F6%2FKdaEhHZB89t6PzxzQLxB%2F%2BWAqkq%2BkQS9K1LOJizJkVM7YJ0OVl7mRFS0iryUiQlgmvg4113GMGeqNPy8%2Fiy27ruKN%2BGz4t3OhdyBWxcdfxCpXI780ua3SiTQnZf5gSQ2FoFb%2B%2BU5REH%2F1Jfm7clqNVoM2x2Mwp6qMqltvyXh7eSjXGFQWAkvDOV%2B542Fnc97oys5WjYVvdUJxiR6v%2FCkSOTdL6B2I1SCjYnnBWUB7F0yf4Gve4aFSP9C5zC9US139s9xeppPpKyKD6jKpjyJQn5CnSQYHYG3Zja6MdhWmvFS%2BNrekeHJwC3yzqAeycopx%2BWpejaKD3JvFrEBikdTU%2FmU0IE%2B1WfrHbugT5KF0jGqKKexf8QMqrK3p6dMP6p%2FL02tpMhaCAbuEPb5hzCzdnG1L0rIKtZ7uNZ8QHjGgea32cS4pm3VHLJKa2r8cEho3zLtO%2BzCF%2FQs%2F0FtlwKcPXTxpMpaB6MCcETZp1Ns2OzvaZCan5Jn0uI9Gld5EUBhvDspOdSPEEqiv9i%2F9gPQHFAMrxSFXCdWM%2BkAXj8Z2ew%2BEm3aEb%2FuBK6W9GRVSxYLDicRiqMf271nmDygG1sihy8r4oFFP8I%2B%2FmP%2Fhf3ZdLikq1pvkmM9fzkHS5dxyS5LXT1xkTRJLoR7bv32ZP6AYWCkGwLhXL%2B4%2Bkhdha6MOX7f1vEkO%2BPcfRVQ%2B%2Bpuyo8RqJJZCPbZ%2FFczwHA%2BKQQMn%2BUbelJXr4gpOxWYYNd%2B%2F%2FvM0Ei7klDeERPEK1quxkSVOaP%2F1E4pBAydC2GxRsWHc7D8d1hmrQciGsL5yb0uFA6Irc8ycDychhPZPMSDVcOSU7sfc%2FJKZL7570PDZNzGo6xiqHCOd%2BOqe2xuCAf8W78MMGrzNkia0%2F%2FoLrzOwEo5HY3WIv169ZmPCinWbz2tDuzXB8AE%2B6NDWBa29nO6ZJq%2BgBLGJ2Th64jp2HLgiGkPu7RvIhiDvwKrCtHDRA2MpE9o%2FxaDWhPSfTgt9yITH4MugQEOyrkgXtvfoNY141e0ZFHKMVITGkM%2B6UOO5iDP4maVLaP%2F1G7MME8l7fvO%2B92bqIQnDVWnQTXz8RRh1mqiE0%2BJ1SdTGzfskyxXbnFcbRBrgBwNgpzwAXIs%2BxykEhPbfIOAwkRUSURrSjpE3xCq7H9JQ6EVzUMGxiiROBgMyDSq4ic9HDRrMC%2BdkMaH9E2Ia6vujMwkh9dcP8GwiQgghFANCCCEUA0IIIRQDQgghFANCCCEUA0IIIRQDQgghFANCCCHl8ArkBgwvYiu99QktgRCKgdUTvn%2BV1f533gyRkJrDYSLS4KMjRkiEUAwIIYRQDAghhFAMCCGEUAzqIXJsm2e%2FEGK9qMr8AMXAyino7QN7FgMh1klZ%2By%2BgGJDr%2BU5oxmIgxDopa%2F%2FXKQZWjogN4zQqBLIkCLFOZPuXfoBiYOWogEPibZAlHItOp8el5Bu4mpLBiiHk4TmBQYofoBhYN3o1NorwYPJA34c%2FbzBpxmKcPJOkfE69kYX%2Bw9%2FDlJmfYObry%2Buc55mzFxERmVDn9AWFRQj74VcaBrEKlHYv2r%2FiB8wAb0dhQUSeQVSwP07lOOAt8XXBw9z3uKd6o5mnm%2FJ5%2Ffe%2FolvnNvj7khcfKM9fdkTiWmomgru3rVP67Ox8vPHulxg%2Fug9UKp5kRRo2Ze3%2BlPQDFAMCjQGzdSocDvLDieNnsfVh7TctPUdxuAnnU7BtdyRstVosWbYJfUL9ERrS4b5pky6mYvW%2FduLqtQw09XTF2JGhYumGg0djcfNmgZKPi0sjPD91CP4dtheBfq2wbdcJnBKRyMD%2BnTFl4gCsWrMTB4%2FE4BHf5nj7jbFwbGSH9WVRwZLlm5Xz7caN6o3WLZvSSEiDQ7T3kWIxR7T%2FUHMdA4eJLIyjZxGnV2GC8MvfiCjh%2FXbtYPcw9rti1c9ISc2Ag70tnBzt4eBgh5beTeDq7HDfdIVFxRj1zEL4eHng2YkDlTTb90TBzt4GrkIAHEVe8rcWzd2V7deu34cZs5fBXqwfNri7cPSbMPDxP4gIIgNPjeiJX4%2BcxdIVW5RtpbBIZHr5srezpYGQBoVs37Kdy%2FYu271s%2F%2BY6FkYGFkhkNHb29ENoiQrLXW0wK8gf38KAXRo9on3jcCEM0Jlq314t3NGhrRdsbLSYMKZvtdunpGYiMzsXI4YEw8fbA%2F37BFSsC%2FRrqQwT3ZnPgvd%2FI7YPUj6Hn0hAM%2BH0350zvkJctvwcrnwe2K%2BTspzAYSLSQJgggv%2BkDmitUyOgbLJ4kgE4rRURQUSM%2BYSAYmDhEYJYDOkeiK5qA8aKz6%2FpNWif6I%2FWwRZ0lXJrH088M7Y%2F%2Bg9%2FFx3aeaF3Lz%2B8PH04mjV1qzKNRnMrIHV2vD3ycBaRSElxidGPk3cuJZZAYunVxRdEAz4nWvEhEQ0MN9ccAcWgvkUJpYZSJ2N5WA7wo%2FnP4b2545Ve%2Fjff7sasuZ9jw5p3lHWGao7gzg6%2FykQ6x4fcEHJ%2FOGdAHgh5LcLh8Di4ujpi8IAueHpMX6Rn5irr5G8J56%2FWOW8ZJajVKsQnprCgCWFkQCwZvej6v%2FHOSmXp6eGiXKPwycLSJ4yNHBaCL77ahuABc%2BHu5oTtm%2BbVKm85mf3c5EF4cuICODnZY%2FGC6RjQjxdoE2IKGDo3YOQw0cN67KWcKC4qLlHOKqo82avXG5B8NU05M8jO1qZOeadl5ChLj8bOtUpX%2BbGXHCYihJEBeQDWbdyPDZuqvjr%2B0w9nKGcRVTVhLId55GmhD0JtRYAQQjEgRuaZcf2VFyGkYcMJZEIIIRQDQgghFANCCCEUA0IIIRQDQgghFANCCCEUA0IIIRQDQgghFANCCCEV8ArkBk7l%2B%2FMQQkhVaFgEDZerNzBPvrw88QHLAvNoEYRUDYeJCCGEEEIIIcB%2FAZrKlCcV2%2FcTAAAAAElFTkSuQmCC)
+
+```
+else_stmt
+ ::= ELSE ( '(' statement* ')' | if_stmt )
+```
+
+referenced by:
+
+* if_stmt
+
+**keywrap_stmt:**
+
+![keywrap_stmt](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAl8AAABHCAYAAAA5pSLCAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAHZRJREFUeNrtnQl8jMcbx3975L4vR8SROnI4Igkh7qKOUkdRpIo6W3W00tJbqVJVVUqpthRt3ZS2%2BFP3GRLEFYlEgoRIJOQ%2Bd%2Fc%2FM2tXIsghu9nE8%2FV5vdn3mHd25nne%2Bc0z874LEARBEARBEHpDQkVAEARBGBq%2BHlBRKeiGkDBq%2BysaORUBQRAEYYgEH1lJhVDOtGg%2FigrBAJBSERAEQRDE8wOPKlJkkcQXQRAEQRAEiS%2BCIAiCIAiCxBdBEARBEASJL4IgCIIgCILEF0EQBEEQBIkvgiAIgiAIEl8EQRAEQRAEiS%2BCIAiCIAgSXwRBEARRCQgKicCViLgSH3%2F0xGVci4k3uO8RFR2P40FXqEJJfBEEQRCEYfPHhkM4cORCiY%2F%2FefVenDgdbnDf49jJMPy69j%2Bq0CoE%2FbYjQRAEUakJvRiDdZsPI%2FleOlycHRAwqAOyc%2FJwOTwWiUmpyMrKQZ3aThjYtw3Wrj%2BIM6FRSEnNRK2aDhg9vCvq1amGkLNRuBZzB3v3h%2BLOnfto1MAZvXu0REZmDn5ZvQfBZyPh6GCNMSNeQmP3OuK6q37fh5a%2BDbFj5ymEhd9Ej5d80K9XayaU9iLodAQ83Wvj%2Fcn9YGJsJI6%2Fk3CfCbw9uHD5BtxY%2Bm%2BN6gHnmvbIz1di8fK%2F8UpPP%2Fz25z5cv5HI0mmFgf3aiO%2F038FQXL%2BZiO%2BWbIfcSIbJ43tTpVdyKPJFEARBVFribiVh6OgF8PWqjyED2sPG2hyHj1%2BChbmJWPjn2rUc4eRgI45PuJuCVi0aYfQbXSGTSTDgjXnIz1PA0tIUZqbGsLO1EMc72FtBqVTh9THfISk5DZOY4OHnDX7zWyGiOCuZ%2BBozcQlsbSzQtZMXZn29Ad37f4G0tCz0ZeJp939nsWLVHnHs%2FfsZ6Dt0Dqo72SJwYl9xzmsj5wvhpVAqsIAJq3cCf2KirBY6tW%2BC6TPW4NyFaBjJZbCzsxR54%2FnigpGo%2FFDkiyAIgqi0RF6Lh4mxHN27eMOaCa3OHZpq99Wt7QQPt9oY1L%2BtdhsXPmnpWYhi53HBtOrP%2FYiLT4Jbw1qoWcMOLXwaaI8%2FdPQSsrNzMeuTAPHZz7ch9h86j70HQzHstY5i24Kv3kTb1h7i7yMnLsOriSsTar3EZy7aQs5Fir%2FXbz0Cfz83jB3ZTZvW1r9PIpQJrCaN1ZG09avehz0TWpwDhy%2FgbOg1NG%2FqKoRlenp2oe9BkPgiCIIgiCJ4N4aXVIVXoYI%2F%2B9iQ6yG2SMrzGv6t3NCscT00b%2FceGnvWQYc2nmI4z8rSrMixCoUS02esxn4mbLya1BPRJw6PPj2OiKhbYrJ76y7TCm3XiC2OVPrw61iya0okDz9bWZpq046IvIX%2F7T9XJK3snNyHaRU818oM%2BQqlTuvH14PVzNPh%2B6%2Bz5SqrtRNKCbaevYRQsmwSXwRBEISB4eeORvkSLJUo0YS13utYE75YpsTlehG4volpoHISBgJjIzlWL58ihgJDzkVh2crd4u9vZ7%2BpVg%2Bqh8nsO3ReTF4%2F%2Br%2B5MDczEdt27T1TWG0UuKqlhSmaN3PFptXTylYQBcQUT2tQ3zaY%2BfHQIofl5OY95lTJI%2FlSlXs9hYQ9XQgPAmQxjVBXIYUn%2B9iZCendPh64KFfhnVNXEEGWXnZozhdBEARRbnh7ootCgpOsVT%2BUkod6Z8Iw9cwV%2FHM6AtdKKrxKw4XL18XrJKpXs8XL3XzRvbO3mKTOsbG2QOS129pjc5nIkclkkMtl4jMfVswqEHni88N4pEvDi%2B2b4Nz5aOw%2FfF677WrUbTG5vrT06OqDzTuOF3r1xcngCCQkphR7Lh9OjbmRICJ3%2BoTXF683Xn%2B8Hnl98nrl9cvrmay97FDkiyAIgigXeMRLocImlQrDeYOtj2tmZuVg%2FOSFQqDwSeni6cQf3hH7hgxsJya1t%2BryATzdauOnRROwcu0%2BeLd%2FTzyByCfQy6UybVrDBnfC8Le%2Bx649IWJO1uJvxrJz3sa0z1drI1E8ArV84dulzmebVu54f2I%2FvPrG17C1Mhf5tLe3xLpfA4s9t0uHZli8%2FB%2B06BgImVyK4IMLKqR%2BIyORw1azfdxxTsq0Gavv1hQBKxsSKgKCIAiiPPD1AH%2B073BIGGaXQ1qq4CMrS3x8bFySmH%2FFX91QkLzcfMQn3odzDXvIZFLtsebmJtrJ7QXhQ4A8GsVfWVFw6O%2FW7WQYm8jhaG%2F9TN%2BLR69uxSfDhgkwLhhLA883F2yaIdOy0KL9KO3fxQ07FlM%2Fn7JVB5ZGN7L80kPDjgRBEMQzwyfXs1VTqyx8WxHXd6nlUER4cYyM5eIVDRrhpTn2ccKLwyNi%2FPhH51zxtJ9VeHF4Pnj6pRVemnw%2Fi%2FAqTx7Uc9MH9U6Q%2BCIIgiD03pgoMQAS%2FHkwBtlUGlUfUc%2BsvkW9EyS%2BCIIgCP2jAvzZf%2FupJJ6rSt8v6p0g8UUQBEHoHwnEZPtLVBLPD7y%2Beb1TSZD4IgiCICoGJ7N03KFieH54UN9OVBIkvgiCIIiKwfRELM33ep54UN%2BmVBIkvgiCIIiKgT8eqKJieK5QgV5ZReKLIAiCIAiCxBdBEARBEARB4osgCIIgCILEF0EQBEEQRBWHflibIAiCMEgK%2Fg4hQVQlKPJFEARBGBz8R5%2Bf5YefCcKQqZDIF%2F%2B1eir6Z78x6TJ9VfA4o80nTk65HHFveHhUSsPklFyTxOTsJ17Twc4k38LM6L6jvcmhyBtZcw8EZYaQHRFkz%2FrNt6HlnyDIDwxIfHGCj6wkiyojug7F7%2F3N9%2B13F%2F01PyI61aJ359ro91Yd1KhmjmoOT36XXkJStjw%2BIdPxaHDCgOtxN%2Fr26WQeHHc3c1jIRUSRHRFkz%2FrJtyHlv7IIc8Kwqap%2BIKuIizo74Ytxo%2FqSVZWRFau2izLky%2B27mFluvQvVF1JP%2B6SNP%2FwW9kH3Ti7GswN90NrbCdWdzGBh%2FnSdzvfz41p6OWJwb1epUgWXC2H3xlVzlJy5laCKJDsiyJ51n%2B%2BK9sfyrD%2BicqCreq%2BsflBSaM4XoWXj4i0bVm64OnDBpy0xvH99GBuVzTz4efz8pbNam5obS%2F5u4QmaNUuQPes53%2BSPBPmv4foBiS9CwEO7v6yPGDj%2F4xZo6mZXLmnydJbMbC2Ty6W%2FeNMNnyB7rpB8kz8S5L%2BG5wckvggxmfGffTfnD2O9Al0YekDfFyRySH5iPY2eVNoE2bP%2B803%2BSJD%2FGpYfkPgiwJ8iibyeZjGkt6tO0h8%2F1A3GxlK5UoUNvk1Qn0qcIHvWf7714I%2F09PHzR7n%2FmHoV8AMSX0TJuHz13ogeHWs985j6k%2BDp%2Bnk5cS%2BVQ4FvqcQJsmf951sP%2FpjTqR5MyQKfH%2FxdRH1nVyb%2FNZR2icQXgfBrqfXbtaiu02t06%2BDMV2ZsaefdGF5U6gTZs%2F7zrWN%2FTMqwhBNZ4PNDliW4wSZWNv81hHaJxBeBpOQc01o1zHV6Dc8Gtuo%2FJEiQKjGASp0ge9Z%2FvnXsj9fylWhEFvj8IJOgsQqIqGz%2BawjtEokvAsmpORIHG5NSnXM3OQc3b2fifmpeiY53qa51Jku2vESlTlS0PatYq8FtmC%2B5ucpSXUMX9lwWP9RwKyFbfI%2FMbEWF5Z8VZ7BEiXZkgc8REnSWACcqqj2Kv6u2%2B%2FTM%2FDJdqyLbJfGmslZNUD3oIu486aDi9uuS6TPWoFc3X3Ro21i77ctvNsLc3ASBE%2Fti%2FZYj2Ly9aN1%2F%2BclQ%2FPTbHrz0YnNxvrZrFhOPz79ah3kzh2PKh79ixaIJsLezFPv%2B3ROCrTtO4NclE7XHL1%2B5GzbWFhg6sD3mL96GoOCr6pqyMIV3M1eMGdENFuaFDSX4bCS%2BXrgVg%2Fu3xSC2aEhITMGEwJ%2B0n90aOiNgUAc0dq9Tof6jVKgglZX8JdJXr6ej67DDMDKSYtsyf9ha2xSv8h%2Bkzxo8e0kF%2FLLC0NEL8NHUAWjWuF6xx27adgyvvNwSpibGBnev4zZ0JjQKPbr60I3%2FGe1Zwg5ZuOoq1m67gddedsHSmd4l77XqwJ5L64eciJh0vBF4CtduZKjvV7N9MKB7rQrJv0qCf1lvfjH7cxZo8n2Vh8%2FvS1MhQClFj4pqjwZPDsLlq6mQs%2BNHDXLFV4GNS3WtsvjBs%2Bohzfki8pWnwC1fD2zkGx93cHH7dcmFSzFITErVfp49fyNOBodj%2FJvdxecbsXchl0uZEOtTaHFxdkRP1kB9MnMtUlMzted%2F%2BMVa%2BLVoiFrODriTcB8nTodr9%2B38XzD%2BO3gO128mPGyI%2FzqGak5qcREReQuudauJ9F99pTX2HT6PMZOWFMnzHxsP4X5KBlYw8VeQrJxcnDh1BZPH9xKLuZkJ%2Bgyeg0tXblQqp5syK1T0sL%2F9sBmautmU6lyJuoehdzsa0Mcf1Z1sSxANUeHdj35lNpNlkGUfERmHed9vpTt%2FOTF%2FejM0c7fBxp2x2Hus9PfTirJnDd%2F9EiGE15DetfHX8jbo2NKxwvJ%2F9jIOsASlLTxpWsHzQJoZ3udN9NlLCK2oPCz61Au%2Ff%2BcHG2sjrFh%2FDWGRqWVKpzR%2BUFY95OeB%2Fr6euJmvQLQ28iVRDz8OUijYTg9sk8swqaCyK26%2FvliyYicOHr2EzauniciTBicHa%2Fj7uRc5vnsXbxEZm7doK776bBi2%2Fn0Sd5mQmzBK%2FVqP9m08hRjSRMaCz0Wid%2FeWbFs46tauhqR7aYiKuYNWLR5OY6jt4qi9Vq2aDugbMAcKhRIymXoENys7F7v2nsG2Pz5E36FzcCUiFu6NXArlq7WfG4yN5CKadyUiDjt2nqrw6FdJOXzqLk6fT0br5vbo1825rMno%2FWetkpLTIJGoezn%2F23cWVpZmCL8ah%2F2HL6BuHSd8MKkfbGwsmNg%2Bro4grNwtbKzHSz7wdKtdbPq8zvceOIe8vHy0aumGQf3awMTYCMeDruDPTYeRnpGNrp2a4fXXOop8pDBxvnrdAXTr7I2fV%2B9B4t0UvDGkk4jUihtbWhZWsO08j7bWFsxWPNGrewts2n4cSUlp%2BG7JdnHc2JHdxHd5Gjm5eVi5dp%2BwdRtrc4wM6AJf7%2Fq4HpuILez7jh3B0rBSp7H7vzNQKlV4mfkEt0sn1vE4feYqgk5HoHkzV0xinQYeEeQdl%2B3%2FBmFgv7ZirVAqMWZ45RtNlrGe75zAJug99hgTMlfxUtvqlcKeNSQk54j1uCGupe4I6SD%2FSuZhU1n%2FZVVzd3Y7vYIYkihVEx939GarqTIVWldkPpp7qjvUHVo6YdueONxJyoFHA%2BjUD0qrh7joUkiwWKGCS8F4cKE5Xyq1GOOJxj5O2RW3X5f8vvEQNmw9ivWrAmFra1FoH4%2BM8Yal4MIbL86Xn7yOzayBOXL8Mr6ct0EMN8qN1GXcrrWHaBw5fDiyRjU7dH3RSxsNO8kaHK%2FG9QoJvYLcvpOMWs72WuGlabzcGtaCB2uwufjbvP34U79XVlaOQQ5vPVFkHIoX64A%2BdSrVzYKLqfiEe1rxNeqdH3ArPhl9erbEhUvX8eX8jWoh72gt1s417VG7lmORIeXHsezX3ZizYDM6d2iKLp28sGtPCGKuJwibmzB1OdvWDCMCXsR6Zr9fL9wizrmfmoFvFm3DxzPXwtvrBbT0aYixU35E3K0ksX9C4HLcup2MN1%2FvLEQPF3eajga3X543vsjlxd8vxkxcishrtzFxXC90at8UIycsQvT1O6jr4oTL4TcR%2BIn6x8nPnY%2FGx7N%2B1w7N7th1CuMmL0VOTh76vOyHvftD8cXc9Q9s%2F57I%2F6AR8xAZfVsIwspKK9aReKGOBUIu3RNzSCoTmrku1pZGBpGf4MvYpWINDbPKIz6eaE8ypWrRoAFMWNv%2FKes%2FrmFKexBraiMMIV9WlvJC%2FqAPitNDmkiXAtgKLrweQV5MokLZFbdf15Gwf8VwYCgWfzMWjvbWRfZfCY%2FFgiU7Cm2b%2FWkA3K1c4FLLAZPf6o1h4xdiSP92opHT0LaVO96eeht3k1OF4Grj5y6Wud%2BpG0gu4toygVaQoyfCkJ%2BnEBGuv1iPf%2B6MNwrt53PG%2BJAkp%2F8r%2Fvjgs9%2FwceAgSKUPx7BPngoX0Q8%2BbHk5Ihbffz2m0jjf%2BfAUsW7ZzK5S30TeGtUD7054Re24VmZCSHA6tWsi1n16%2BmmHm59Gfr4Si5b%2FjT9%2Fngqf5ur39PXr1UpEj%2FgQ%2BTtM8PTvrbYHMRQ%2BYCYCJ%2FUTn3n0c8vv07URub%2F%2BPYnzTAjyIfGLYTcwi9krj7Lyhc8N1ORv36HzheYSPo1zF6IRFR2P1cunCBv0823IOhXh2MkE4jtjX8bCOaPRc%2BAsLFr2N%2BvcHMMPzMe4z2gInNgPI5kAFDde15oIGLMAcz5X27yJqRG2%2Ff4RrK3NUdlp2dRODN9dDE9FDUfDflWVgnWho2MzcPj0XZy%2FkoI2Pg6o42w4dXDmMub4uiNGosIWHw8Es%2FUGpQynbTJw7WAMskFUGgYBsphGqKuQwvPB5PqhrP2%2FKFehdUiYYQgvDp%2FnuG7HTSxdEwVHOxM0qmcJe1v9BDWK6CEJdjEJOOvRSFeJxJcGJbt3S4EeqmL25%2Bcjml3UTFdfjkcDPpjcX%2FTK%2BRBQowaFh7v48OEP88c98fzxI7uzxnUrhge8WGg7H2Zq4lFXiKETQeEY1K8tqlezhamJkZhLxocfv%2Fwk4LFp8uhJjy4%2B6Nrp4atBEu6m4PDxS2jn7ykmbecrlELYHT1xudADA7yhk0iZNbu5YNeWzws1dqWFlbteJ7beu58r1g52Js%2BUjr7z%2FSgFJ3Tyobi8PEWZ0rmTcE9EWR%2BdyM%2BFTlT0HTGkp6Fh%2FZrIzcvH7fhk8ZmLLo3wEtELK3PWsKrzwQXa1I9XClHo0%2FwFjBrWFV5N6pU6f1cjb4khwjYvTS%2B0vY6Lk1Z4Llv4Fnq8OhMTx71cpLNRIHt4oV51MXyakaFuP3nEtryFV0XZhaO92p6TU3INPt98aMV%2F4AHxdwc%2FR%2FzxnV%2BhejKk%2FLNs9WT%2F9ZQqxRwhfh2iEnHtYT0WrNMaCgnCDakueQdk3SI%2FBLx3Cq%2BMPYZBPV3w4yxvvfoB10OsbHrlqzCQrZXFJSR%2FgsMcZyfGsXVXluAvbP3e0%2FazDvy80kS%2BSvsFx73ZXUyYTk3LxBvjF2LHuk%2BESCopYpiR3Z2kj7lDtfP3wLGgKzh99irmzRqhrshW7iLaduNmIlr4NChy%2FOTxvTGgrz96vTYbHkxAaaIS2%2F8JEnPF%2BDwvDY2ZWNyy40Qh8bVu1fsi6lEesN6H5FnTKE19WD4I72ZlK2BnbVRp8q0r%2BJA0F1D30zKKRGWtLE2Rlv5w4j4XLnx%2BoAU7RyNgnsSw1zoKm%2BdDojv3hmDwyPk4e3ShuqelKvnX5teq71oDe%2F764onHbNl%2BHE0962L7v6fw9qieRYb1tcI7JV0ILnNzE52VZ0XZRWamWvRamMkNPt%2BOrEf%2F61xfHAtJwsrNMZj%2BzUUs%2BsyrwsudICqqA8af%2Bh33yRlUdzDFxOH10crLXmd%2B8Gj%2BCuohtv7J1Agrs%2FMwSgqMUUmQ8rghR9FBfzQRttrEEvBgS6xcBo8zYZha3H59Tb7%2FOHAgWno3xBvjvhcNWXnQ3t9TzG2p5mSrnd%2FDhx5%2FWrlbTEp%2BkkjiIuvnxe9gxpx1Ym4Ph8%2Fveu%2BdPlg4d7R24RP9d7HGMzMrp0o4Rr1a6ob5YkRKlXR8LqR4NIfPkSoJPHrawrsBfvx5l3ZbUEiEiDZ17tgM6zYfEUOTnLXrD4ro1eOGzosIIibYue3xYcIJo3siIzMbOcyjed7iWdoZmSWzJz60fiMuUQyRa%2BBP84ZejFF3GHYG4eDRi9j6x4ci6jVp2goxZKohJU39pDAXjUvZd%2BTzGAvOcawqaOz5hdqGP4RqbCxFn67OmDe9KTzqW%2BHPHTfEe74I4nllFeuEJN%2FPxccT3DFqYD00bmit82s%2BSQ8dP4%2BLfC2ToSHrJ29ix6Wxg2OfFvniiXDlFmTEEnmMoCpuv14axoVzRmHY%2BO8xbspSrFn2rtjOn2LkS0G2%2FfGRaLiKoyU7JjsrD%2F4t3bTb%2FFmDdTc5De1aez71XH7Ol58GYCzLyzczR%2BBazB3ROBWET6Z2dLARE6YfjaJVRjr7q58q2bIrDt3aVa%2BSjsyHqUe%2BvQh2dpb4YFJ%2FDOzX5qnHL5o3GuOnLIN3u%2Fcgk0thZmqCTas%2FEHMNx0%2F5EW27T4eNlYUQUL8tm1KiPKxetx%2BfffUnGtV3RjSzq8%2BnDRYRKS6%2BvJq4olWXDyCTSLF76wzUrGH3VHG46sfJCPxoJWbN2yAEHZ9Av%2FDr0eJJyk%2B%2F%2FIPldbp47cnsz17Hyw%2Fmf%2FFOBIe%2FNmX1nwfEHEc%2B5M%2Ffi1fVuB6XieCL9%2BBczRTu9a0rVd7FcGlUGu6n5Ir8E8TziHY6jK3eHl4rVg892Da1VRPMy1Ng%2BqORMI34yuLK7Smiqrj9OmPn5s8LfTYylmPDqve1n6dN6S%2BWYm%2BwF35%2B7Hb%2BOoCo0OWFtvEnymLDfi1yLI90PcqQAe3FwuFPhD2O43u%2F1v4dd2VlpTby%2Ft1q4aulV%2FD3%2Ftt4NzIVHg0qR2N19shC7d%2FfMQFfSET7uePI7jnaz3wi%2FsiAzsjNz0c1x%2BIn3fMoKBdBfM4fjwo52Flp96356V3xNG42Ey%2F86cSC5zxqd7zDoIEPrd%2B7l450Jtj4E5iaJ2L5XDJu%2FzyyxgWT5hURxXUSjv83D%2FF37kHK8lfwO104sVj7t5mpMQ78M7vQuTzqxif380hzwfOaN3VFyKEFVeLGPf%2FncPG2%2B7cC6j%2Fz3Cl9Y2WhvoXvPnIHbi9YiVdnEMTzxO3EbNF54lhb6uX93aXSQ4%2BKMOahb2nFl1wG16clUtx%2B4vnBxFiKOe83wagPgzFhxlnsWNFW2wBUJTTznvbsP1fkZbkF%2BXz6a9rJ9k8SalzMlwUeebN78OsLj6KZ87hgyXbxYMiT2LxmmvbvGtXL9oQqF3l8qYrwKC5%2FwapnQ2uMGlSv0uV%2F7GBXHDyZiLnLroilpG%2B4J4iqQMeAQ%2BIN9xz%2B8Im3p63Or1lWPVRQhGnFV3EJkfCq2vAn%2F0rzkw6vdKmJNd%2B2REpaHmJvZ5Yo%2BpWekVcpy6Zb5%2BZiMVT4T2zpCv6EZUlet1FZ7ZlHu%2Fj0tsWfNxdPS%2FGORUnRhT2X1g857Vo44uw%2FXREWqX7PmpurZYXlnyD07Qf8DfcZWQpYmMm0L1wtDWXxg2fVQ5rz5VTVhK2VcX5SSo7cyb7kc0Z6dqxRqmtcjUmlgq5k8Kd%2Bq7I98yHGskaJdGHPZfFDjr2NMdr6OpA%2FEs9de9T8GSNdFekHUqpqwsrC6H5cfKZOr3Eq9K66wVOBd9EVVOoE2bP%2B803%2BSJD%2FGoYfkPgi%2BAtTDx0N1u3I8t6jt8RaJQH%2F1XIaxibInisg3%2BSPBPmvYfgBiS8CkTey5v67PzY%2FN0%2Bpk%2FSjY9MQE5uusTj%2B0uQbVOoE2bN%2B803%2BSJD%2FGo4fkPgicCAoM8TYSBq8%2Fp9onaT%2F4byQhx9UyOAdDip1guxZv%2FkmfyTIfw3HD0h8EYK4u5nDflkfkX0h%2FF65pvvNiouIup6mMfBrbPFVSrGFSpwge9ZfvskfCfJfw%2FIDEl%2BEIITZYm6easDEGScV5WXw3MA3Fuy9SHBUApw%2BewmhVOIE2bN%2B8k3%2BSJD%2FGp4fkPgitARdUOxMz8ofO%2F6j46of1oShrGPufCx98KSDhQ1chT%2FY%2F91VMkyjkibInnWfb%2FJHgvzXcP2A3vNFFOLMZaxq4aGUrt0StXz9jmh56%2BaO6NHRBY3qW6Ou8%2BNf4JiZnY%2Fwa6k4dS4R%2Fx29xYw8vfAB3MAl6CyR4M1g1qOhUibInss%2F3%2BSPBPlv5fGDCvkhMF8P9rWJciEkTDd16NMYPaAUv8guYx%2FNypQIH0uX4Chb92A9ixFnLmE32RFB9qznfFdg%2FgmC%2FODxyCriorfvYiZfnJ3wBZnVs5elTtJNRKRzDWxkBlqfLU6sd3CNGX4OM1oeLX3ST8ens2PipCqcUklwgSmjulIJEtkZQ5iBnyY7Isie9ZJvg8k%2FQZAfPB4adiSeHIVQh2L7ezeGl1SJAezvbqz3IWH%2FLJ5wiqVKhfvMwPlvPpxivYqZwTSZlyB71ne%2ByR8J8l%2FyA4IgCIIgCELD%2FwFHH2ep0wQ%2BywAAAABJRU5ErkJggg%3D%3D)
+
+```
+keywrap_stmt
+ ::= KEYWRAP '(' int_const_expr ')' '{' statement* '}'
+```
+
+referenced by:
+
+* statement
+
+**encrypt_stmt:**
+
+![encrypt_stmt](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAlsAAABHCAYAAAAwToK4AAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAHL9JREFUeNrtnQl8jMcbx3975D7I5Yj7lgi53HdRR6mjcf9RpY6qo2jprVSptqq0SrWNou6raFHqvkkQIiRykiCJhMh97O5%2FZlZWQiIHu9nNPl%2Bf15vd933nnZ15np3fPDPvLEAQBEEQBEFoDQkVAUEQBFHWeLtARaWgHfyvU1tf1sipCAiCIAh9wO%2BELxXCS6Z5hzFUCHqAlIqAIAiCIMovPGpIkUMSWwRBEARBECS2CIIgCIIgCBJbBEEQBEEQJLYIgiAIgiBIbBEEQRAEQRAktgiCIAiCIEhsEQRBEARBkNgiCIIgCIIgSGwRBEEQRAGc8w%2FBjZCYYp9%2F8kwQwiPv6d3nCIu4h9PnblCFktgiCIIgCP1i%2FeZjOHLiarHP%2F3XNQZy5EKx3n%2BPU2ev4fd1%2FVKHlCPptRIIgCMKgCAiMxMZtx5H4IAXVnR0wfFBHZGRmIyg4GvEJj5CenomaNZwwsF9brNt0FBcDwpD0KA3Vqjpg7KhuqF2zEvwvhSE8MhYHDwcgNvYhGtZ3Rp%2BeLZCalonf1hyA36VQODrY4u03X0WTxjXFfVf%2FeQgtvBtg997zuB58Gz1f9UL%2F3q2ZMDqIcxdC4Nq4Bt6f2h9mpibi%2FNi4h0zQHcDVoFtoxNKfOKYnnKvaIydHiWUr9%2BD1Xi3xx4ZDiLoVz9JphYH924rP9N%2FRAETdjsf3P%2B2C3ESGqRP6UKUbOBTZIgiCIAyGmDsJGDZ2Mbzd62GoTwdUsLXE8dPXYGVpJjb%2BukY1Rzg5VBDnx91PQqvmDTF2ZDfIZBL4jFyEnGwFrK3NYWFuCruKVuJ8B3sbKJUq%2FO%2Ft75GQmIwpTODw64a89Z0QTRxfJrbenvwTKlawQrfO7pj39Wb0GPAFkpPT0Y%2BJpf3%2FXcKq1QfEuQ8fpqLfsAWo7FQRMyf3E9cMHv2tEFoKpQKLmZB6d%2BYvTIRVQ%2BcObpg9Zy0uX42AiVwGOztrkTeeLy4QCcOHIlsEQRCEwRAafg9mpnL06OoJWyasunRsqjlWq4YTXBrVwKAB7TTvcaGTnJKOMHYdF0irNxxGzL0ENGpQDVWr2KG5V33N%2BcdOXkNGRhbmfTJcvG7p3QCHj13BwaMBGDG4k3hv8VdvoV1rF%2FH3iTNBcHerw4RZb%2FGaizT%2Fy6Hi7007TqBNy0YYN7q7Jq0de84igAkqtybqSNmm1e%2FDngkrzpHjV3EpIBweTesIIZmSkpHvcxAktgiCIAgCnk3gLlXhDajQhr1swPUP2yQv8x5tWjVCsya14dF%2BOpq41kTHtq5ieM7G2uKZcxUKJWbPWYPDTMi4u9UW0SUOjy4VREjYHTE5vXXXWfnezxVXHKn0ycexZveUSJ68trE216QdEnoH%2Fx6%2B%2FExaGZlZT9LKe62NBXIUSq3Wj7cLq5nnw49Hse0mq7UzSgl2XLqGALJsElsEQRBEGdOyMRrmSLBcooQba603siZ7mUyJoNohiNrKNM9LEgICUxM51qycJob2%2FC%2BHYYXvfvH3d%2FPfUqsF1ZNkDh27Iiabn%2Fx3ISwtzMR7%2Bw5ezK8u8tzV2socHs3qYOuaWaUriDziiac1qF9bzP142DOnZWZlF3Cp5Kl8qV56Pflff77wHQTIIhuilkIKV%2FayCxPO%2B71cEChX4d3zNxBCll56aM4WQRAEUWo8XdFVIcFZ1oofS8pG7YvXMePiDfx9IQThxRVaJeFqUJRY3qFypYp4rbs3enTxFJPKORVsrRAafldzbhYTNTKZDHK5TLzmw4TpeSJLfH4Xj2Tl8koHN1y%2BEoHDx69o3rsZdldMhi8pPbt5Ydvu0%2FmWojjrF4K4%2BKQir%2BXDo5G34kRkTpfw%2BuL1xuuP1yOvT16vvH55PZO1lx6KbBEEQRClgke0FCpsVakwijfQurhnWnomJkxdIgQJn0Qunh788V1xbOjA9mISequuH8C1UQ38snQSfNcdgmeH6eIJQT7hXS6VadIaMaQzRk38AfsO%2BIs5Vcu%2BGceueQezPl%2BjiTTxCNPKJe%2BUOJ9tWzXG%2B5P7442RX6OijaXIp729NTb%2BPrPIa7t2bIZlK%2F9G804zIZNL4Xd0cZnUb2goMtluvldjXJYyLcbquzVFuEqHhIqAIAiCKA3eLuCP3h33v475LyEtld8J32KfHx2TIOZP8aUU8pKdlYN78Q%2FhXMUeMplUc66lpZlmMnpe%2BJAejzbxJSTyDuXduZsIUzM5HO1tX%2Bhz8ejUnXuJqMAEFxeIJYHnmwu03CHQ0tC8wxjN30UNIxZRP5%2ByXUeWRney%2FJJDw4gEQRBEieGT4dmuqU06viuL%2B1ev5vCM0OKYmMrFkgm5Qiv33IKEFodHvPj5T8%2BZ4mm%2FqNDi8Hzw9EsqtHLz%2FSJC62XyuJ6bPq53gsQWQRAEofXGQwkfSLDhaCQyqDTKP6KeWX2LeidIbBEEQRDaRwW0Yf8dppIwqko%2FLOqdILFFEARBaB8JxOT4a1QSxgOvb17vVBIktgiCIAjd4GSRglgqBuPhcX07UUmQ2CIIgiB0g%2FmZaJqvZUw8rm9zKgkSWwRBEIRu4I%2FvqagYjAoVaMkoElsEQRAEQRAktgiCIAiCIEhsEQRBEARBECS2CIIgCIIg9Bz6IWqCIAhCL8j7O34EUZ6gyBZBEARR5vAfSX6RH0omCH2mTCJb%2FNfdqehL%2FkWkzfRVfuNNtp05Oy0o5MGo4LCkBolJWWbxiRmF3tPBzizHysLkoaO92bHQW%2BkLj5xL8ye7IciedZtvfcs%2FQZAf6JHY4vid8CWLKibaDq0f%2FMP7nfeW%2FvVtSMQjqz5daqD%2FxJqoUskSlRwKX7suLiFDfi8uzfGkX5xPVMytfn07W%2FrF3E8b4R%2BIMLIbguxZN%2FnWp%2FwbihAn9Jvy6geysripsxO%2BGD%2BmH1lVMVm1epcoM77dvY%2B5L633oPpC6mqfsOXHP65%2F0KNzddP5M73Q2tMJlZ0sYGX5fB3Oj%2FPzWrg7YkifOlKlCtWvXn8wvpKj5OKdOFUo2Q1B9qz9fJe1P77M%2BiMMA23Vu6H6QXGhOVtGzJZl2zf7br45cPGnLTBqQD2YmpTOHPh1%2FPrl81qbW5pK9jR3Bc1yJciedZxv8keC%2FFd%2F%2FYDElpHCQ7W%2FbQoZ%2BO3HzdG0kd1LSZOn89Pc1jK5XPqbJ33BE2TPZZJv8keC%2FFf%2F%2FIDElhHCJx%2F%2Bfej2tyOY6teGYQ%2FvV1cih%2BQX1pPoRaVNkD3rPt%2FkjwT5r375AYktI4Q%2F5REalWw1tE8draQ%2FYVgjmJpK5UoVNnu7oR6VOEH2rPt868Af6elg4%2BOl%2F%2Fh4OfADEltEwQTdfPBmz07VXnhMvDB4ui3dnbhXyqHAd1TiBNmz7vOtA3%2FM7Fwb5mSBxkOb6qK%2BMwzJf%2FWlXSKxZYQEhz%2Bq1755Za3eo3tHZ76zYFt7zyZwp1InyJ51n28t%2B2NCqjWcyAKNh3RrcIONNzT%2F1Yd2icSWEZKQmGlerYqlVu%2FhWr%2Bi%2Bg8J4qRK%2BFCpE2TPus%2B3lv0xPEeJhmSBxoNMgiYqIMTQ%2FFcf2iUSW0ZI4qNMiUMFsxJdcz8xE7fvpuHho%2BxinV%2B9ssZ5rNn2KpU6Udb2rGKtBLdhvmVlKUt0D23Yc2n8MJc7cRnic6RlKMos%2F6w4%2FSRKtCcLNCIk6CIBzpRVe3TvvtruU9JySnWvsmyXxEphrdxQ%2BVwgYgs7qajj2mTGx764FX0%2F33u2NhbwXT4F14Nv47OvNsLNpQa%2B%2BGiY5vj3P%2B1CE5ea6NHVU7zOyVbA98%2F%2F8M8Bf8TGPYRzFXu0atEQo4d3QeVKFTFx%2BgrcT0gW59rbWaNT%2ByYY5tMRUqkEu%2Faew%2FFTQVj81Vv58vD%2Bp6vx6ise7N41Me3D39V2yKywUYNqGDG4E6pUssPbU5cX%2Brk%2Bmu4Db8%2BymTuuVKgglRV%2FkeabUSnoNuI4TEyk2LmiDSraVihaxT9OnzVw9pIy%2BKWCYWMX46MZPmjWpHaR527deQqvv9YC5mamevfdFhefhIsBYejZzYu%2B6F%2FQnrl%2FLll9E%2Bt23sLg16pj%2BVzP4vdKtWDPJfVDTkhkCkbOPI%2FwW6ni9cr5XvDpUa1M8q%2BS4B%2FWW1%2FG%2FpwHmixf7uHz85JVGK6UomdZtUdDpp5D0M1HkLPzxwyqg69mNinRvUrjBy%2Bqf3KvFzdjWuSOtwu2y2WYUlCiRR3XJgGBEejdvTnatGz0RCHK1QvfJyWnIzzyHm7cjEb%2F3q3h0Uz9NENw6B04OtiqK1KpwuhJy%2FDwUSo%2BmTkQ1as5IjrmPv7YcARb%2FzqNyeNfg%2F%2FlMIwd2Q3ubrURERWHH1bsQXR0AmZPf0MIqgWLt2HHnrN44%2FXWIk3%2Bt9%2BlUCz8fCQib8fjzPkb2LZ2FustK3DsVCD6DJ6PvzZ%2BjJmT%2B2ryPJQ1%2Fl%2FPGYXaNdVTHOrWrmwwTjZtXoDoQf%2F6mQeaNqpQomsl6h6Eha7z7NO3DSo7VSxGtEOF9z76nQlsN5g76Z%2FYCgmNwaIfdpDYekl8O7sZAq4nYcte9p3R3RmvtqtsEPas6Uj%2BFiKE1tA%2BNcTWqI51meX%2FUhCOeLtC2twVPn5B2EbWVb5JtsD7bHf10jUElFUeln7qjtiETEz78jJWbQrHiH414FLftsTplMQPSqt%2FWrpggEKCZTkKOLCX6jXwJerhxEEKBQawRHc%2BnWhRx7UNjxa1adm4wGM21hYY8kZ7LPh%2BG7b88cEzx%2F%2FefwGBQVE4sX8hbGzUZVuDCS6eXlJSquY810Y1xHt8S8%2FIEtEOLrYsLcww7%2BPh%2BHDOWrza2V00zl8u2owVP7wDE9Mnwjg3fzwqdu3Gbfx76BITW%2F3y9KolcG9aW9zHkDh%2B%2Fj4uXElEaw970TiVEp3%2FLFRCYrIocw6vC24nwTdjcPj4VdRigveDKf1RoYKVENwiQuC7H9ZW5uj5qlex6mjfwYs4eOQysrNz0KpFIwzq3xZmpiY4fe4GNmw9jpTUDHTr3Az%2FG9xJ5IPb2pqNR9C9iyd%2BXXMA8feTMHJoZyHmxRcZ6zisYu%2FzPFa0tULHdq7o3aM5tu46jYSEZBGt5Ywb3V18lueRmZUN33WHRCeggq0lRg%2FvKqKoUdHx2M4%2B77g3u2t8Yf9%2FF0WH5LXu3ti99zycnCrgwsWbOHchRHRepkzoLSJ%2BPCK8659zGNi%2FndgrlEq8PcrwRodlrGe7YKYb%2Bow7xYTLzRKLrbKy51ziEjPFfvzQOiXu%2BGgh%2F0rmYTPYV%2BJqj8bwu3wDkSRJyidejdGH7WbIVGhdlvnwcFV3oDu2cMLOAzFCeLnUh1b9oKT6J1dkKVSonjfem2%2FOlkodVuOJRrNEt%2FDwV0mOawveAPGGI3fjjUFexozsirCIezhxOuiZa%2F87GoDePZtrGpe88Ma2IO7eS0TN6o6a13w40r1pHSxaukOIuq6sEW3dvPB5oWnpmayBMikXTrbv2D2xH963pkHlm4une3EPNGJrzLs%2F4g6r1769WuDqtSh8%2Be0WcczJUd0rcq5qL0S4lWXRcwdW%2FL5fRDu7dGzKbMEd%2Bw74IzIqTtjfpBkrhX28OfwVbNpxEl8v2S6u4ZHVb5buxMdz18HTvS5aeDXAuGk%2FI%2BZOgjg%2BaeZK3LmbiLf%2B10WIHC7mRP4cbCE3kYm88S03qvs83p68HKHhdzF5fG907tAUoyctRURULGpVd0JQ8G3M%2FET9Y96Xr0Tg43l%2FaoZad%2B87j%2FFTlyMzMxt9X2uJg4cD8MXCTWqfiH0g8j%2FozUUIjbgrBKCh0op1HOrWtIL%2FtQdiDoghkTtXxdZaP75f%2FIKwT8UaFmaVJ7xc0YFkSfmifn2Ysbb%2BU9ZfXMuU9SDW%2FIboQ75srOX5%2FEEXFKV%2FuMjydsVtBbADXGg9hbyIRIWSK%2Bq4tiNdf%2F%2Frh9PngzWv%2BZwt3ljlwnve0ye9Lhq29m1c8l0bG58kImNFsX33GTE0GJ%2FwCEeOX8Wfv07Pd%2FzLT4ejW9%2FPRaTryN%2Fzn7mei8DsbAUOHglgDW%2BsGMYqD1wJThL7Fs3sDPpzTBzTE%2B8xGxGOyuyHCwdO5%2FZuYt%2B3V0tUcio6UpCTo8TSlXuw4dcZ8PJQz7nr37uViA7NZwLuXSZwBvRRd%2F6qOzuil89czJzSX7w2NZFj%2B5%2BzNRG3v%2F45iytM%2BFVzdkDg9VuYN6C9Jro6fFBHTf4OHbuCQQPaFetzXr4aIToea1ZOE3MOW3o3wNkLwdjLBOG7417DkgVj0WvgPCxdsQebd5zCj9%2BMQ%2FVqDprrZ07uj9FM8Ikv2jpVMfztxVjw%2BUjx2szcBDv%2F%2FAi2tpYGb9ctmtqJ4bjA4Eeo4qjfS0UpWBc5IjoVxy%2Fcx5UbSWjr5YCazvpTBxeDsMC7MSIlKmz3coEf229WynChQirCj0YiA4TBMAiQRTZELYUUro8nww9j7X2gXIXW%2Ftf1Q2hx%2BDzFjbtvY%2FnaMDjamaFhbWvYV9TNNJBn9I8E%2B5jkm%2Fd0JKtYYisXJfvulgI9VUUcz8lBBLup1uYx8OE4PqTyPIb6dMRK339Fo5IXPjT0KDmtWPdRqlTYuecs5n%2F2P9SvWzXfMR5V4EMtfAinYsVnI2KLf9ot9m6uNbF32%2BeoUlk74oSVs04noj54mCX2DnZmBpXvp8k7AZMPrXFhXBpi4x6IIb%2BnJ95zYRMWESuG6HJpUK8qsrJzRKSUw0VWrtBSdxosWUOqzgcXZPxhEC4CvTzqYswI9RzCknIz9I4Y8mv76ux879es7qQRmiuWTETPN%2BaK%2BYrtWufvnOTJnphXyIdDU1MzNJ2aly20ysouHO3V9pyYlKX3%2BeZDJW0GHhF%2Fd2zpiPXft8xXT%2FqUf5atXuy%2FXlKlmOPD70MYEOFP6jFvnVZRSBCsT3XJOxwbl7bE8Onn8fq4UxjUqzp%2BnuepUz%2Fg%2BoeVTe8cFQZKuHwo4nx5IQ5zml0Yw%2FbdWIK%2Fsf305x1nHfZFJYlsacPR5XIpZk0bIBor3shp7uVRT0StZr%2FnIxrEQpVy3zbo2K6JOH%2FCtJ9Rt1ZlTeQiF1NTk0LT4BPkdQHrXUheNI2SlL%2F143BteoYCdrYmBpNvbcHFOxdMD5NTWYOdf2KmjbU5klPSNa%2B5UFEolLBi1%2BQKlsLgT7ByG%2BRDnHsP%2BmPI6G9x6eQSdU9KVfyPze9Vr04VHPjri0LP2b7rNJq61sKuf87jnTG9Cuw8CKGdlCIElqWlWbmx51zS0tQi18pCrvf5dmQ99t8XeuOUfwJ8t0Vi9jeBWPqZe5mXO0GUVYeLP5U7%2FpOLqOxgjsmj6qGVu73W%2FODp%2FOXVP2z%2Fi7kJfDOyMUYKvK2SIKmgIUTRIX86EbbbyhJwYVu0XAaXi9cxo6jjZbUsxNO83quFmCt17OQ1zXvDfDog8UEyPp2%2FHhmZ6l4sjzZs2XkKazceeSaNVzo0xezpPnhr0o%2FPLDlhjNSupm6IA0OSyuXn48KJR2v4HKfiwOf5Nfesj59%2F3ad575x%2FiIgmdenUDBu3nRBDjZx1m46K6NTToqxAAcQ6BHyYkQ%2F7TRrbC6lpGchkHszzdo%2BlnZqWWaz8tWvVGLdi4vHXP%2Bc070XdjkNAYKT4my9lcvRkIHas%2F1BEtabMWiWGQHNJehwF5iJxOfuMfL6iTFb%2BluPLtee6NfR%2FSNTUVIq%2B3ZyxaHZTuNSzwYbdt8Q6WwRhrKxmnY7Eh1n4eFJjjBlYG00a2Gr9noXpn9NXEMj3MhkasH7xVnZeMjs5%2BnmRLZ4IV2rnTFgiBQiooo5rjfHTfs73mq%2BFdfXMsgIbzg9n%2BGDEuCWa9%2BzYuVvXzMKHX6yDW6upYkkI%2FqQaX4frsw8GF3g%2FvgwEb3xHTViC3Rs%2FKRdzVEpLlzbqpz6274tB9%2FaVy%2BVnnDC6B0a%2Fs1TYygdTBmBg%2F7bPPX%2FporGYMG0FPNtPh0wuhYW5GbOxDzB1Yh8RFW3XYzYq2FgJwfTHimnFysOajYfx2Vcb0LCeMyIiY%2FH5rCEi4sRtz92tDlp1%2FQAyiRT7d8xB1Sp2zxWDq3%2Beipkf%2BWLeos1CwPEJ70u%2BHiseNPn0y%2FUsr7PF3EM%2BXP7a4%2Flb099VL1OyfssxrNlwRDyRy5%2FKXLV0Urmr76iYNPgFPoBzJXM0rmdrUHkXw59hyXiYlCXyTxDGiGZ6S0WdLddTpP55%2FN6MVm5YlK3A7KcjXbliK50rteeIqKKOa41Du78s9Bh%2FIvDY3q%2BeiUzF3PDN9x6ff8WH%2BR49ShM99wo2lvkE1IUjz%2F4m5cI5I595b9HcUc%2B8x4csn75fQUReWWWQRj2gezV8tfwG9hy%2Bi%2FdCH5VqTZOy4NKJJ4L7%2BwVj8h3jE9BP7F%2Bgec0nzvMFbrNyclDJsehJ8rVqVBKiJ%2B5%2Bkoj6ONjZaI6t%2FeU98ZBFBhMrfJ5f3mvCAlbmS2fn%2Bo80f3NR%2F%2BBBClKYQONPSOYusMqHrTevfl9EzrhAKuip2qdp06IRTv%2B3CPdiH0DK8pf3M%2BXtpFiYmz7zsAePqvHJ%2BHwINO91Hk3rwP%2FY4nLxRf3tr8FiNfmJw%2Bu98NwnXWNjpf7K3n8iFo3q2oilLAjCmLgbnyE6Sxxba52sl10i%2FfO06GIeOlEjtuQy1HleIkUdNxS4wDLmKFVpMDOVYsH7bhjzoR8mzbmE3avaab7wyxO585YOHL6MVX8cKPS8z2cP1kyOL0yYOTmUTpDyyBrfCoL%2F0gFn8U%2B7cCbPk7lPk3fuYGkf0uCijm%2FlER6l5QuaujawxZhBtQ0u%2F%2BOG1MHRs%2FFYuOKG2Iq7gjxBlAc6DT8mVpDn8IdFPF0rav2epdU%2FeUWXRmwVlVB5EFrEE%2FiTeSX5iYTXu1bF2u9aICk5G9F304oV3UpJzTbIsunexUNs%2BkrehXJfNvwJyOIsf2Go9syjWXx62rLPPcTTTLwjUVy0Yc8l9UNO%2B%2BaOuPR3N1wPVa9zVtwV5A3VHwlqj%2FLCV5BPTVfAykKmWeC0JJTGD15U%2F%2BReL6eqNj4q2pjmJCRlyp3siz%2Fno1enKiW6x83IR1TQBkbbVo3LtT3zIcPSRoG0Yc%2Bl8UOOfQVTtPN2IH8kjK498njBSFZZ%2BoGUqtr4sLEyeRhzL02r9zgfoH6SU6IC74IrqNQJsmfd55v8kSD%2F1Q8%2FILFlhDjYmR076afdkeGDJ%2B%2BIvUqCOLajYWiC7LkM8k3%2BSJD%2F6ocfkNgyQkJvpS%2F853B0Tla2UivpR0QnIzI6JdfC%2BKLEt6jUCbJn3eab%2FJEg%2F9UfPyCxZYQcOZfmb2oi9dv0d4RW0v9wUZ6fTFIhlXcoqNQJsmfd5pv8kSD%2F1R8%2FILFlpMTcTxvx26aQjKvBD15qut%2BsCkRYVHKuQYezzVspxXYqcYLsWXf5Jn8kyH%2F1yw9IbBkp%2Fsz2srJVPpPnnFW8LAPnBr0lb%2B9EgpMS4MKlawigEifInnWTb%2FJHgvxX%2F%2FyAxJYRc%2B6qYm9Kes64CR%2BdVv249jpKO2bOx8KHTDma36BVWM%2F%2B76GSYRaVNEH2rP18kz8S5L%2F66we0zpaRczEIq5u7KKXrtoet3LQ7Qt7awxE9O1VHw3q2qOVc8IKJaRk5CA5%2FhPOX4%2FHfyTvMqFPyn8ANWoIuEgne8mM9Fiplguz55eeb%2FJEg%2FzUcPyiTH9bydmEfmygV%2Fte1U2deTdATSvGL5TL20qJUifCxcAlOsn1P1nN48%2BI17Ce7IciedZzvMsw%2FQZAfFIysLG569z7m8s3ZCV%2BQWZW87LSSbjxCnatgCzPIemxzYuo%2FnBl6JjNSHv0s7KfVU9g5MVIVzqskuMqUUC2pBPHsiqHMoC%2BQ3RBkzzrJt97knyDIDwqGhhGJJ1EGdWh1gGcTuEuV8GF%2Fd2e9Cwn7Z1XIJdYqFR4yg%2Ba%2FoXCe9Rrm%2BtHkW4LsWdf5Jn8kyH%2FJDwiCIAiCIIyX%2FwMK5gDBa5fmHQAAAABJRU5ErkJggg%3D%3D)
+
+```
+encrypt_stmt
+ ::= ENCRYPT '(' int_const_expr ')' '{' statement* '}'
+```
+
+referenced by:
+
+* basic_stmt
+
+**enable_stmt:**
+
+![enable_stmt](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZMAAAAlCAYAAACH%2BAS9AAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAADy9JREFUeNrtnQdYFEcbx%2F8IxIoNsXdjFMVesBesSFSwxS6CvUaMon6JikYTTIhdUCOxxd6wt1gSg71r7GJXEEXEDgffvHPseUu7sxxF39%2Fz7LPH7N7s7M47b5vZA2AYhmGYD8QsJS5axRYx%2FOjVHL%2Fw8fqCny%2FLDcsNy0VyX9MipW722D%2F%2B3OOxVK3rxs%2BXYblhUq1cGEM6fvSpA%2FIK2TNkWG6YtCoXbEwYhmEYNiYMwzAMGxOGYRiGjQnDMAzDsDFhGIZh2JgwDMMwbEwYhmEYNiYMwzAMQ8g34O3tkOfwOQQndpKh46bEY4w%2Fbt0JVZVltcoI%2F9mDceHSbfwwaTnsbAth%2FOhOuuO%2FzQpAWdvCaNaokq7s4uU7%2BP7HZXBqWgU9uzbSlT9%2F8Ro9%2Bk3X%2FZ0lcwZUqVgCbt0aI3Om9LLs29EL0LFtXdSo%2BpWqHXfvPcLQUQvitbmZQ0X0dm2apgTBc%2Bwi3L4XioW%2BQ%2FGFpfaHETzHLca1oAcJnt%2B0YQX06dksyTo79%2FLBmzca7ef29dCmZQ0sXr4XG7cdlX1AfaHQ0e1XzPHphxlzN%2BPcf7cSrK9uTVsM7d8yyWtS%2FS9evkY%2Ft%2BaqcqX%2FFby9umPU%2BMWISeS1rr49myIqKhoLluyOd%2By7Ic5SFkgu7tx9JMtyZM%2BM2va26NaxAczN1T7ahi2HsXTlfgwf1Ao1q5fWlZ84dU3WP9unb5pTHJ3cfTDaoy3Kly1q8NzV6%2F9FyxbVkCH9F6nuPkIehuPE6Wto3rjyZ2sEPlS%2FK9%2BXWiNSg3tVbLHWwhyDE6rU0HFTcvpckFA6VcUgLPXWAoqGEOERL3H9xgNcvHIHzk41ULF8MVl%2B6eo95LLOqqpnpRDoJ%2BHP4ffHdrh2cYCZmfanazRRGhw8chHzZwyUCuHxk%2BfSGN268xC%2FTHTVtuFskFCeFeO17eWrN%2FK7axaPVJXnyZ09TQkTKURSeNY5s2L33tNoEavku3Soh%2BfPX8nPv87YgOLF8kqDYOw9TvFylQbFXRjmJg0qyLIbt0IQ9iQCE71Xoqkos%2FxCa7gOHbssDE8kOrjUlsaYmDVvq%2BiTLLIdRC7rbAavSfVHPHsZr5za%2Fv2I9nBqPxG7A7xQuEAueAxqDcWaDPCYKx2ASrEyVKJYPmzZcUze%2F1jPDqq6viqRX%2B5Pnbku5c6%2Baknp8Mzw2yzlccL%2FOqvO%2F33xLrx6FYklK%2FarjMmTp89x8vT1NKmA2raqiTw2hmUgRjxfMrr169ghg03qMyaXr96F97R1n7UxeV%2F9Xt0WLhozzBAq1Fr8mUmOZDNtuqu9RgMXUen6uJUaOm5qSpUsoBqE%2BlhlyYhv2tTB5N%2FWYNXCEQmeo9FEY8PmQ1gwcxB6DpgpFVfNaqVU51St9CVy22iV1bWg%2Bzh09JLR7ash6lKMU1pk3aaDMoorViQP1m48qDMm%2Bl5nzpxWKFQwV6L9kBAFC1jD0tJcGnYrEU0qNKpfAYdFHyxZtQ9uXRurvlOmVCGVA5BH9Mm7XDMxKNrKnzen%2FFwgn7U0YvoykD69JWxLFYx3rWzZMiV5fUU2a1bXKs7Z87epjpNxuXr9vnA4PNG642Rp6Ehm0zqPHkfoZH7HXyflPV26chd7%2Fj6LIoVtMGKws3h2mbF6Q6A8x89%2Fu4z6mzeprOrjxNi26wR27T2FyMgo2It%2Bau9cC%2Bm%2FsETg4YtYtvpvPBNGvnGD8sLRqC%2FbES4cxUUiKm3qUAnzF%2B3Ew9BwGSU2iXUCI4TjOU%2BUUxuzZ82MerXLwKlZVawOCMSjRxHSgSTIoTDUP6%2BF0%2BO%2F5C%2FpSGbLmgmunRuhSqUSuCkc0LXifnv3aKqT9%2B27TyA6OkaOqY1bj8BGyPPRE1dw%2BOhl6fwO7uskI7bgkCcIEA5dO%2Bfacq%2BJjkav7k2SpS%2FfVb8rRkQTg4L6P9iiisdjtGkvqvSOqHQVhS%2FvctxUkABQxykbdYY%2Bbt0ayXTMP4H%2FJfj9vwPPI6tVJlSuWAKtWlTH2oDAeOccO3lV1k2dv2P3SQxwdzS6fWR49NtHCiQtQQakjfA027SqgT37z%2BCJiM5Mzejh7TDDd7NMM6ZmwsNfqPqWtsdhzxI89%2F6DMBQWBjfus6XI2s62MEqWyIetO49%2FEt4sGYcHIWE6Y%2BI2cCbuPXiMVo7VcPb8TUz8ZZU8ZpNLmyHIny8nColoUEkdJ4Xvgu2Y7LMGDvXKoZGIXreJZ3bjZogc3wM8%2FERZefTo3BAr1h3Az1PX6qK8KdPXY4zXElSqUBzVKpdE76FzZCpaRp7D%2FXDv%2FmP07OIglTgZK9k%2B4ehYCIeH2kabkvVIil6DZksHYVAfJzSoWw6uA6Yj6GYwihS0wX%2BXbmP4%2F%2FxjI9cgjJmwVOeUbdx2BH2GzMbr15FSD%2B3acxrjf1qhlZ3gMNn%2B9j28cVU4s2TgkhtD%2Bp2MSJUyuK0R%2FifIkMTBwkCl0lIZOm7qSGXzjmMIPPI2UqA5ExIWBbLswwa0lIJVp6ZtfM%2BblGVseob2nXr5YNLYrtLTUZj7xw7hRVsgWkQxlPbZtfe09Djj5r8TwmfWRtXflKYp7po3TSiFU2eD8PTpC9StWUbeq13ZIlLou3dqaNLr0pxDOXGt34W3aGgeJCUhbzNu%2FypzJoqCoLm7MGGAd%2Bw5iYW%2BQ1QpHpI9n0luOtlbIxwZiqQ%2FNWiO6tsB2n4kr5wUI9Ggjp3ct3Ksrov8k4Lmqab7bcKy%2BR7S%2BSOcneyld%2F%2BjMFADhQJ3%2BVo7lgvmzwXHtl4YLqIgJfpcu9RTFzFt2HIIZ4RhK5DfGucu3MIElzqxUWRpOYentO8v4UC1d6lt9Hghx3WR31CkS2eG6lVKSmeSnISBvVtg6mR3OLabgOm%2Bm7By3b%2BYOaW3jNAVhg9ylml24sti%2BWQaePLYbtroOIMl1i8djawi2klJ4ul3M2yLAibEjUSMMiYK0eLZCVXaPMbA8agoBImLmix2Hz6otQxJk6Jj23rCW9oRz%2FOjcHi7iDT6u%2BeRE4F0LzFCMCn6IO9AgeZMFGGnkLiJ8zghzMXRuoW9wfatXjTio6W5kvuXPtcGHESRwrml0iMorbRmY6DJjQkxyqMt2nWfgu4dG6ZaJVleGLwV%2Ft8ZGnxYLxTXyCEuqhTOERFBB4eE4%2FbdUCl7byI1UvGQt0wK7mOS0r8cnM78rfxT6icyUvNe9QSLaIfGX9yJfVLc14KCZQpJgSK9N5FRIiJ8rE3XiDGoPw4pG6HRaNtBBocW85CRo3FN6dUKdkXfuX1Xrt6TKalaTTxV5YVFVKIYUt%2Bp%2FdC8jZeIXFqgdg21c6uvJooXzSP1kzIvSU7xxzYkHyIXpN9Fc52iYtBO7KMNVWSRSA4tUHzxrtg3FhX%2BLvbDkjouHALvd4lMTCH4FhbpMHKoixQWEjJd7lUYF%2BucVnJA00bYigFPHqK%2BMdGHBILqCLoRkuyD8mP8Uxtjn2%2BUGPCUn61Vo7SI%2FC5q7z1LRuzad1pOZBcVRsaUlC1dGA3rlMPMeVvSrEdOHrdjk8qoZV8aPfpOw5fF88nP0lBvOAjb0gVV829FCgnDvemQzJWnVbkxJTSvQgbhScRz5MqpXkRjlSWDanEFKWKaD80svqMo5MTo2qG%2BXDRAKbitu47jG9dfcPLAVF0EaSx0rRLF8mLnhvFJOGiBKFemiBhbR9DfzRHZs2dO8Lyw8GfSgGQyIvVnSrmI2%2B%2F6%2Bl3s54qAyf9VJNxE4NArxgzhCaW4pMGPWwk52qICW7HdsTCH7YkL8DB0PKWWDcelpSMtP7TE%2FgPndWVrhMfdt2czTP3JXW9zw%2F7A8wh9%2FDReHZFvomQO%2BOCRSzL18ymz98BZaTj9pvZXPZ96NcvKXH9yMPJbFzmhSqvq0jI0mU%2BruHoN0ebTaZJ2046j8PbqoXq2Q%2Fp9LZ5tID4XyDCQt03PxBho0p4Ww8zRW8hw%2BPhlGQ041C%2BP5Wv%2BkakwYsmKfTK6iGt0ElTwQp4pDUZpKZoPff7iFV4LDUlteyDqNnburrZwFG7dfShXP%2BpSobdDcPrcDfk5YOth7DtwDuv%2BHCWjksEj58kUnUJ4xAu5JyNIizVo4YsxqfRk6atE9HvgGZyjvbk5Sgq7u1qcFyFOvpNUZEKVkCU6bCkqScBAGDpuMvoMnaP6O2eOLDh7cEaCgkupk669tR4HTYiSIM726aM6j1Yt2QmvmDyH9q1rybJKdYfp6qBUxbSf3eUKDYXeQknoQ97oqGFttblbW3fVMVpF8vP47ql%2BoK8JOAiX2LkkfajsVxHheQxs9UHpu3qOY8TAC8UYr6UIffQUPTo7xDuHoh%2Fnr%2B2lYvhYkHGiTYHmxmhwK33Y2HkcFvkOkRGqIWjSt0Bp9X%2Buo5RoC713ZN6mWutKpdm9zzT0c28uU4Y08R5PbsYtxpnzWuVDczJx6w9YPkYq1E%2BFvq7N4Np%2FOnKIcTtisAvaOddK8vzp3u7oO9QXleoMg7lFOmTMkF6mkskQ9xW6oHYzT2SzyiwNAr0XZQyLlu%2FBD5OWyWXdQTeCMXbkNzJiIGNSwa4Y7BuNgLlZOmxfNw758uZI0tj9MWcIho%2F2xwTvldJA0YT6VKEvaKHQ9xP%2FFG31RKaM6fHjD13QInb%2BZJgYS8Sfq%2FZj0bK98rUC0jPzpg9ILd1kUL%2FHlnnY28E7UgPPuJGKWWyY80JU4icqSTBdZej4%2B4TT%2FO9B36L%2FbzY%2FVrqCny%2FLTWqSG1oh%2BCYqCrlzZTP6OyGh4dJrt85hpSp%2FKByTV0IZ0%2BqrdyEs7BmeCQNEK8zivkBJkQ8ZAP0l7IZ4EByGdKJ9xt5Tr8GzZLaDJvspRfcuz8KUcvG%2B%2Bp1We5FRERfoJ66jfc9EhDPFkqrE0HHm84OWVib0driC15iOck7kY0LpA3qRMTFGi0hRP5pkUg%2FKvMHOPacwb%2BHORM%2BjF0SVyffElK2Nddb3agNFRrQlhPISrs%2BsAJniTjSa13tBOW%2BeHO%2FVDjJatKUW3le%2F60cqujSXoYrYkDBxoXQNbckJLeNUlpoyaZOmDhXlllqhlaOmglaQGbM8Orn5UP2ufN%2BCxZthGMb0KKv8PlX4V4MZhmEYNiYMwzAMGxOGYRiGjQnDMAzDsDFhGIZh2JgwDMMwbEwYhmEYNiYMwzAMQ6TYS4v6vx%2FD8PNlWG6YtI15Slz0fii8aMtvg%2FHcBfGfDT9fhuWGSS1yYSyc5mIYhmEYhmEYJuX5P5OJYJjsR7ccAAAAAElFTkSuQmCC)
+
+```
+enable_stmt
+ ::= ENABLE AT_INT_LITERAL int_const_expr
+```
+
+referenced by:
+
+* basic_stmt
+
+**reset_stmt:**
+
+![reset_stmt](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHUAAAAlCAYAAAB8iqZLAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAABMtJREFUeNrtW3tMW1UY%2F3UtHd0G2%2BiKSik4Nx5laFQe3cBFjM9JMiFxZNmYS5aaoMhUNp0xc9E9ElEJOEYcc0GjMUZgPlhw0T%2B2ZMQhY7ANWWDrGIg8hcF0asbow%2B%2Fe0tJCy12BtjzOLzk5vfc733d6vt8533ncewGGWQeRNyqNUcM0Vxxc2%2Bh5H0u81dhzlcWzntDYtdu8Uu88FqzcH5U8HZkYqbMQjFRGKgMjlYGRysBIZWCkMlIZZjD4EyVNNO6qbkCPs0JCcnci%2B%2B1itLX38b%2BXLlmIhPhIbNn4GCQSc388Vl6Fr8sqx%2Bjt2ZWGB1bdi54%2FbyC34AdU117B4OAQQkMCyUYEMrXPQuIjRk7et6g5f3WM%2Fo6s53g9Zzicn4FlAf5T2tbJ%2Btmiz5M6ZEBnjBrHJGJkOTIqJHcnLja0IPmpWKwhIjhyC4oq0Nzajf27N%2FPyjs7rMBmN2Lk9xU4vNFiBodt6pG5%2BHwmaCBTlvwSZTIq6i9fw%2BVcnsSntUSjk%2FmjStWPF8ruRkhxvpx%2B%2BMgg7Xlk%2FXEc%2FXn3rKMq%2BeNMq9%2FdbMOVtnaif49VINYhwUG%2BAnC4X8KSKzGF4g8GAVDL63WijQnJ3IyJMSaRGUqL%2FIhLh40%2BO28nlAX68fDQaGtuoI%2FTiVMU%2BzJf6mMlWBRKBGhiNIyd3oSqFQ33LPV1zl921u%2BCqny1kGkwItj2ItDvQN5mvnRoVknsC3T0DCCESbHG9%2FyaqzjbZ3YuKUEEVJIfMV4q8wnKkpyUhWCk3O486hlg88vDk9z96x%2BjHx4RTGe8sOYT87IxMh6Q6M%2BpqpVON8hM1uKzrwMCNf%2FHTyfMoLsyyk3MjKfdQucM59dOCTOz7oIQP24sXL0TcQyuhfeFJrE2Ispat%2FOUSmlu67fS%2FPPIaZGKpVxc8Y%2Fwswgk9sNcZmeOSaoERuEB99RmTgFyvRwtVKnN3I7%2Bv%2BJXmuRREq0Ps7q%2BOC8eRg5kOdZIeieZT%2F8A%2FqL%2FUilOnf8MmbS5%2BLNuD%2B6NC%2BTLpG5PwsnadW%2F%2F7ZJ7UcH6muJKsN%2BF5yo1ChiROYvsZUuyg%2FAkyeJTy18eT%2B0iQ48pIdbWB69fFIfnpWCSuUWPLi3kIW3EPElerXXJMwNJFVoKrzl7GhfoWK6mewJ08LB%2FtF1s%2FU17k64PiW0PYRgNJaxLhL3AjVmifyhmhrJQMqCm1U1hV1zUiW0juqXlVQ%2FPcgXfSod1eiCtXOwXLn6awuv%2FDEn4etqCmTofWth48%2FOB903af6czPZ%2BrRwOViMcJMJpRSuZtUuH28kcoZ4XpENW3f1A6IEpJ7BBtSE6G71oWtGfk4XrKbv1fxcy2UkfZvGXzz2U5%2BQcWtgDWPv4FAxRJ%2BxWuk7U%2FO3q1YFTkSwg98VMonWzSdK4TfIpk3mijo5%2BF72bQvzaFt0K7RI1c0POz%2FIyOHub24IyNC8onML558neXW4G309v2NebTqVQbJPVav7essdxh%2BJ%2BRn7tCBI5cqyKB6zPtUGt7LxzMiJJ%2Fu8J0vhUq5bPof703Qz7Yj1zqnChmayYTOJEzWzxZ9dqA%2FC8FIZaQyMFIZGKkMjFQGRiojlYGRyjCd4LVPGb31md9cgNgblXb14T0uBSnw7lxxNNdeFn4ZGBhG8D8CEQbUUILllQAAAABJRU5ErkJggg%3D%3D)
+
+```
+reset_stmt
+ ::= RESET
+```
+
+referenced by:
+
+* basic_stmt
+
+**ver_check_stmt:**
+
+![ver_check_stmt](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAbcAAAAlCAYAAADBTqcXAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAE1pJREFUeNrtnQd8zPcbxz8ZRkKsiBG7VikxgiBW7dXUpmZqNwSRamoWpTWKWglilBqtWZQoNf6o1YGi9myMWEnElvD%2FPk9yP3eXO3eXJgTP2%2Bted377%2B%2F0%2B32d9n7sAgiAIgvCGYfcqbupZAs%2Bk699O%2FjyefDInciTjK7x9cmEtjq%2BqsX%2Fsmi8j%2FpZRoXpXkSMZXxlfkYuXgr10vfCyo3bxyGV8BZELMW6CIAiCIMZNEARBEOMmCIIgCGLcBEEQBEGMmyAIgiCIcRMEQRAEMW6CIAiCIMZNEARBeJPhXyjxKoWc%2B48iwtxBlvanFGO%2FWYF3CubCR62qG2w%2FevwSpsxch7nT%2ByB4bhi27zqa6Nzgyb2QJXMGtO82WduWO2cWNK5fAY3qlde2PXj4GNNnb8DmbYdw9%2B4DZM%2BeCZUrFENP3wbI4ZYZ%2FoPm4GpEFB%2FboE459OhSjz9fi4jEtyHr8du%2BE3jyJBYe7xVAn55NUKZUQe3arbtMQPp0aRE63Y%2FfiU2%2F%2FoXjJ8MR0MfHqj64e%2B8hQr%2FbjF%2B2HkT0nXsokD8HvL1KoHO7WnBxcUYb34mYPqEHcufKqp2zYs1v%2BPfyTQzs%2B6H2HM%2BMvj5ZsnhejB7anj%2FHqHbr7hET8wAFCuRAtcol0KltLWTK5MznT%2FmqG%2FLmcdX6LHDIAtSrXQbNm1aWWSS8cj7qNgmDB7ZU87CgxWNpfnzQuKI2J1MT129E46%2FDZ9Gwbvm3diz%2Fq73Rnc%2FG7UkcrniWwCpHB%2Fibuqil%2FSkFKfLQhZsTGbflq3fDNasL7OzscObcVeRURqhj25oGx2RWSjku7in2HjiBkMm94aaM1pFjFxEwZB7uKYPRqllVPo6M1x2l0MeN7IScObLg1Jkr%2BFFd%2F%2Bjxi6jt5oGhn7ZG30%2FnwKtiMbT%2BMP6cm7fvoGnbMahR9T2ETuuD9OnTYOPmP9Gq03gsmTsQlTyL8nF7D5xE8aLu%2BG7JNvTu2jDBKEbh1NkrVrX%2F%2FoNHaNFhnHquzPj6i05seE%2Brc2cv2Iz8%2BbKjaYOK3L4HDx8ZnBd%2B5ZbBPfb9fhKTxnZFvgTjRJDRIu7df4Tm6h55cmfD%2BFFd4OrqgpOnL6t7%2FIKCqv%2BbNKjA7aBnIWKVMPTwnwnXbC74sLGXaFUhVdDSp4rSA1ksHvdMeXkDBs9DzWqlkN4t9Rm3U2cuY%2Fy3q99q45ZUe1OpBJrH2WFabBxI0TmzcbOLT0%2B2jotDc3XRNcYXtbQ%2FpfhAKdYRY5bi2IlLeO%2Fd%2FPHKNfYp1m08gNnT%2FLTj8ri7okqldxOdTxEGUb5MYY466JgL%2F95Qkd4RNm4k6Fu2H8LKRUGoUK4IH5svT3bUqenB9yFy5cyqjFdaFQVmRJYsGXhbyNxNKFQgJyZ%2F9fw30%2Fy6N%2BIIaMw3y7Fu2VBte9CAlhg4dD46tK6pIi0nm9q%2FYPFWxD19igUz%2B8ExjYP2fLVreCA6%2Bp5N16KIsnjRPIm2z1u0BfbKSZg3wx%2BOjvYGfUBRnD5Pnz6Df1AonJzSctvt7e1emwlz%2BOgFLFu5E7cj7yKvkpf2rWugyDu5ed8G5Zis3bCfI%2FDG9TzRurm3dt7%2BP09hzfp93BelShbARy2ra3JgKToIU1F62rSOaNO8mhqz0rz9xKlwdrIqVyqOMHXfbMpJaJXgNJnj1x2HVZSRBucuRCh5PYx8ebNjkH8zZM2aMcGJOqGecT%2BiY%2B4rucyBjm1qaVH2cvUcFJGrIeb76CvNbTuPYNOWv5SD85Dlv02LasjgnO61VIi3bsews0tQe10yOrGTRm0skN%2BN%2Bytz5gxY8dMePmbW%2FE3ImCE9GtYrj5LF81m8fpjqJ9IVJCNeFYujtdIf6dKmwZ79J7B0xU7OsNSt5YEObWryc9D8XLhsO%2BrXLscO%2Bo2b0ejUrhbqvV82Plui5GmO2k7PmCVTBtTwLsmO5Iq1e3DrVgwmz1jLx%2FXwrc9teRGPHj%2FB%2FO%2B3shyQU%2B%2Fbvg48yxXGxfAbWKXa26NLfU33UOaI5nHj%2Bp6sR91UYPD7X6ex%2F%2FdTKOtRCP69mnBEG3E9iudEq2be%2FE56qHvnei9lLG21NzqjFvcMefV%2F4Mtgze1ZfJqSLhquLrqcwjtb9ic3JIwkMKvX7dO27dp7jJVrpfJFtW2XVaRCA6v%2FogE3xdVrt5E%2Fr1t8JyohLFo4D6fkTpy6bJivdTS%2FHLlj91G0%2BKBKou207eDhcwZGoVyZd%2BDlWQwhajLZCik1mkQ6w2bcNzoO%2Fn3eoO2UkjSl3PWPIYeB2EL3UMrcuL3UN7roTsfgUd9z24K%2F6QUHh9dnuZbkg9JWnsrJaaeMEymAnXuO8b7QhVsQHLqRU7CkFGiclq3cpSnJXv2CUbZ0ITRtWBHHT%2F6LvSoKtsSMORsxR8kUKbqmSmF9NuI7Vo5s3JQy%2B3LCcnzsNx1XIiJZKVtiy7ZD6NZ3Bi4qx8ynUUWcOBmOkeN%2B0FL0vfqHoHrVkiwrdurfAaWsiK8mrcSqdXuVUqqLtspwjfz6B2z939%2B8jxTy5yMXoWrldzlNv2vvPzh2%2FNJr6%2B2Tsbp2PVIbt659VP%2BquU79Rc7ElxOX8z7K4BDuubOxE2eNMQ%2BZt4n7khyUOrXKsFNy4eJ17NrzD%2FwGzlLbPNCl%2Ffv4YfVujJuyis%2BJunMPE6auwRA1Z0gHVFT6qkf%2FYJZFdoYDZ%2BHK1dv4uENtNio6%2BXBzzcTznZ6NXo6ODhafr3vfmZzB6tuzCWpVLw1fv6k4fzECBZSe%2B0fJbODQ%2BB%2BfPqT0xJDRi7XU7bqwA%2BjZbyYePXoCn8aVlJwdZhlhPalkk56%2FdZfxOHP%2BKhvcl40le0NGzbMk%2Fo0DVoMMmxGOFi7KltPS%2FpSM5Foqb3Pol4s5PUiRAnnRLXyqaF4a8fvBM4i4EW1wHq256TyeuYs2I5OLM3u%2B4ZdvcYpOE9zJvfn69ZqNYI%2BltPLO27TwZiVojps373AK05hcObOwV0RpS%2F0oLWhAC%2Fi0G4uPO9axqe0R16Phniub5QhvyVaD9YNwZdxowuizcOk25RQ8n8i6NbfrN6J4olti4rQ17PVt%2F3kM0qR1fK0U35lz15SX7chrpmSwdVEUjdXUWeuxYfkwFMiXg7cFxPhg8fL%2FcSr82%2BD1GKLkrk1CJEdGgM6xlPaatWATFgb3Z%2B85Pr38WBnNMG2tN4eSnbAVw23qx%2B5d6mFQv%2Bb8mVLHI8Yu0yJBSlfXfb8MnNKnVc5gmfjI4O4Djvz%2F2PGN5ghdCr%2FJ84ei8skz12LCaF%2BtL8h4W2rb6wQtAwzw%2B4A%2F01wkRU3UqlaK330aVeI1dUtQBodkZGnoQJQvGz%2BezZp4cV%2BNUQaT1tl168553bOjUctRCFRRIpE2jSNWLQ7SdNVPG%2Fbhb2VoKdNETsloFdFTNolelEnQPR85IPrZgxdx6Mh5nD1%2FDQtn9Wf9SEsitAxByyR9ejTmtfJGrUZjash6%2FLj6N16fz6u3PBHYtxl8lYElihTKjfbdJ%2BGrEZ34%2F%2BnSp8GaxYMTObmv0MjF2xs7hMUCo40jNauMm5aGUn2n%2FPOGzyzsj43FeXVTp5RoWJ0aHvhUeRYUbZBwkVcWtmqEwTEkbEMCW5lNS8YrmEfY8MsfnILMlpDOIYoWzo3l3w3itAIpCkozjBi7lMNwSiWagry9mLv3E23XRWwZMqQ32F6siDunP6aF%2FIzChXJZ3XZKm9yJuW%2FxuGnju3PhjQ4qtjl5xjASpTSiqbQk3%2BOO5XuQB9m6mTd6KE%2FvpyWDDSLHpPAyfyG8ildx9lbLVgvAeyXzo4aKckj53b%2F%2FCJGRd9HW9xuD44sWdud3Wt%2BkQiF9LKVio6Lu8TWLFXU3GH9yrHRQoZOtDoKD%2FfNImZy2ODXTiQa1y2Hp8p3wqNKfn5U8954f18eFS9c5e9GgxSiD61A6lGT96rVIeJSyrW2pdXxNYe%2FwvC0UqT95Epek60SoaJDmtXGhCvXV2fMRnPLT1yWPn8RydkiX%2FdB3wsnB1o0bGcCBQ%2Baz0S1f9h107VjXoBjNWk6fucIpxKr1ggy267JTZNhDpvRGQyUHfXs2hnflEkYZmuef3ymYk2WDahIIcpiT27D9F7kge6Met0nsM7RS7xZdMUczOc896sTL6r2uuuBc9R7wov3KQRlvS%2BRmSwMpRKeQebXyOG%2FcuoOiSlHoK3KrvN7O9dlbyZPbFd39Z2D9j8MMvBedkqd1B3pdCr%2FB6UVzxo3SDJSSMC6ooNQOpRJyZE%2FsEX6qPKQ6PsM5VWV1PynPn6o4O7atlWJKwLNMEV5LMC7aMSbAz4f73feTqZzyWbbgU%2FZMk0py%2FPFCa%2BWInpM8W1ICfx46y6lH%2BvzF5%2B1Y%2BWxYOZwLlIwhIxJlheHXx8k5LadsSSHqMgf82cjhSS5Iea1e8jmnoqnKbtqsn9mRozSko4MDdoV9lciQUlEQzavo6PvIni1TijzXyxzflIT0AslIVMy9RH3lkjE9R8g6yDBQERs5tzoDYY6OSg9QEQylTDdu%2BVM5WBNxcPcULfq3FroXOcybfxpp9phVa%2FdwRmrthgP4pGsjs2vGkdF32aA5p%2BC6qzVyYTzu%2BvZGvc9WAeX8h0%2FQVbl73Z%2FZIdpUSpIdEOOLqLcV6gIl1CtcOesl%2FjqOgZb2p3RxSSufqtiw%2BQ9eC6HPSYXSgo3qe6Jz729Z4dyKjEHvgBCO2HSQktiz74RWYGKKXl0b8DrgTxv2a9sozfD1pJXsHZmCjCmlOr%2F%2FYYfVz9vTtz6nGKbN%2FlkrcCHFResLuhz9f4W8%2FJ2%2FHcPM0I0G96D%2Fk2E1jN7sMXuqH6fZ%2BgfNtWkSvkqO%2FHOR11QplUwL6RTtUGEJGR%2FyZCdMWa21neSCCo44a1DLg9djYxO8%2FtNnr%2FK624sg5VDV6118%2F%2BMOLfVJac7aNT1SpG1UDHDx3%2BvsVJGzVb1KSdy%2BHYMC%2BdxQqGAOTA5ep40Tyftu5YCRYatZ9T3Mnv%2BLloqk9BYVILzp6NaSaY3KGihDQbogODRM20ZFRuQc0ZiSTtLJDs1tir6scRhoLZScLkoj%2BnVrxEU9j5TGpme7pq5NVczW4K1k7dLlGwa6iOSB1tiJtRv3c40AOUAk6%2F6fzTFIP0cnZIbIKM9UbaTUfWpZTzdnb%2Fb8jaP0rny3okq0V6jjYtTB4S%2BK3OgiZBn3K9kvYcJgWdqfYlCk5OaamYWK1siMIUVML332bZ2A7K6JhezLoe3RsecU9Og%2FE6FT%2B8Dezh5N24xhD42qIiOj7iqF34A9XzasnSdwFHfwyDlEKc%2BG1j0oRTF3Rh8MG70EX4xdxrlpSh9SdPOiKMu%2FdxP8sGqX1e2misyl8wIxdPRinlyUzqIChArli2DMsLI29WHtD4YbpqcqFMOqxZ9zxSDdY9iXS%2Fj7frp70KQjQ2AqJbtozgD4tB3DhREjgtqmeoVGxrpXvymsOGhdihQHfUdSl9L1%2FywUHt79kcXFGZF37qGXbwO8X700hg9qg76D5qBM9QHInNEZD6kqbYa%2FxfvRWhZFuJu3HcSDB0%2BQxz0bJo7ukiJtIyPd5ZNpyJ2Tvuf4jOV5frA%2FK%2FG50%2Fvy8y9WhtYlgxO3bXBAS1RTBnCCep7eAbNQ1nsAR5tUiLJsfiDeBmh8aXyo2nSQf3Pta0HmmDq%2BGxftlKsWAAfl4DmlT4cVCwehX%2B%2BmanswvBsEIbNLBjZQ34X0t%2BoZFi7bhuFjl6JYYXecvxCBEZ%2B15YiKZLRMqULwqjMIDmosN63%2BwuA7rKaM74LgfggcPB%2Bjx%2F%2FIBpMKRKaM68aVmDSvVywMgrNTOowZ3gGNE9bfdN%2BzXaIcr4VLt%2FMSDlWNzpnql1qGyaK9Sdg20KsUxiv%2FM8g4krNLCAPvq4vMUhcxmV60tD8p6YbU9OfjyZO5fDW%2Biil3jqwmqxPNQRVPtD5n63lJUWI0ebJldUmxcm3y7Gkdir7D5uyU%2FPfQ%2F3PzyZW2skWOqJiI1kpMFdDQWlnMvQf8NQH9dRJO16i%2Bp7UUU0VEL4Iq49IoZWNN4UJyyC8pNlPPSOP6UEXbVMhgDBU%2F0fmmUumv2%2FjaAo3349hYm9p9%2FWY0RzXGKWxaLnmojANFz7ZAcnVXzWmq4DT%2BQjlFhjQHbfn6EP2whL16PmvbREs0FOlT8QqlVJNDBpJDLpJqb6iakoycukFvdZ%2F477mpcK%2FQiy5iaf%2FrDik8WwVThzWVhqagFBeV1pujU7uaBmt6VASjXwiTEtCkNbX29KZgvM6qD3nN5tYisur1O6V4qNTfHJ8HtNBS2qaMiTFUwDR55jqz%2BwP7%2Bpj8Dqct8stjasb5T6k1t9SObqwp9U5f2zDHiKA2WjGJOeXv5pq0PiS5ympmTuuclEkz1vKPKJhj5aLPtM%2B5cmZN0nOQEU0JZzapJNXe6EdyWlrS0oXeZMP2qqDKKn3BFF4PqFRbV06eHND6HL2EV0P92mX5lVoJTPgJvZSAKjRTOquQFP6rvdGd7yjiLQiC8PbxpjtV8lcBBEEQBDFugiAIgiDGTRAEQRDEuAmCIAiCGDdBEARBEOMmCIIgiHETBEEQBDFugiAIgvAqeWVf4tb%2FvTFBEDkSZHyF5MThVdz06k2Mope7G0bKELyd0PiLHMn4yviKXKQUkpYUBEEQBEEQBEFI7fwfdbpPk2oXnaIAAAAASUVORK5CYII%3D)
+
+```
+ver_check_stmt
+ ::= VERSION_CHECK sec_or_nsec int_const_expr
+```
+
+**sec_or_nsec:**
+
+![sec_or_nsec](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJkAAABRCAYAAADB5wRjAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAACcJJREFUeNrtnQtUFNcZx%2F%2FLy0UEREAUUUxFA0I0SMLDE9sEayrGaDVarU1jItqoqEdprdZ4lCbGxEeJEnxVpYkatUHUKNXa1FalBqwPRBEUESSCj4AKqAVhYXvvhV13XZYFhB129%2FudM2d2d2bu7Hz3v993753Z%2BwEE0cbIzOEigvygNLXvfDbbPGzfFGzM5ULOpCSYzHd9acgUi%2FJkVuTMpfO%2BpuiBSWQEiYwgkREEiYwgkREEiYwgkREkMoJoGWLEPyQAHqcycUffToa2mxL37j9E7LpvcDItGxUVVfDydEVo8POYERkBh44dsG7zIfw7JVPnuPWx76Orm7N4fegfZ7FrzwlcvXYLrq6OCPDthXcmvQZ%2FtjYnnrXeVccLkVXX4GaQH5JsrDG7oUINbTcVlEolJry7Cn37eOLzVb%2BBk2NHZFzMx46vj2P0iHvs8%2B7IzbsFD3dnvD3hJ1rHOjt1FOs%2FxX%2BDnYknsHTBBAQO%2FBFKyx5hf%2FIprFl%2FEJvjosxKZC2t92A%2FjKmRIU5RA1f2tqMQmawubI6vqcEYVui%2Bpws1tN1UKLx5F1lXbuCrrdFqr9TLyw1vRrwMhaJWvV8P5t3Cgn11jv%2B%2BsARxm5KR%2FNfFeKG%2Ft%2FisZw838bqMic3caG69q8RVo4SX5g0zrRvkyrr3egs1tL2949G1M1xcOiFuYzKmTR4G755dnxjC5knztIiJMfW%2Fl7WOHfRiHxxLuQi%2Fvl5qgWl5OmcHs21TGap3feJqUGT6Cm3uSdsrdrY2SIifjaXLd%2BEvO47C0dEeg1jIe%2B9XQzHstRfV%2B51Oz8Wd4jKdNtntH0rh2b2LxTbgdepdhsMK4EN94mpUZCpYADnPft%2FDlQa2KxTIZye1NwVDBQf1xeGkJSgtfYTM7AKkpGYhclY8dm6Jxith%2FcU%2BP38jBIt%2BO07n2E4O8lYPi6b4JAavdxZK31AoMY6taw1dgI2eWPwdO7CIrX%2FKCtzC1vMa284cxAqVJxsPWF%2FvB%2B8aK%2FRnO4azfX7J9s20USKKRaCctrjollRU584OQlR8OZeRh3MX8tQi03uewD5YHbcfxXfL4e7q1CrfXaqHF1mTs59ChnXs5AHMeLuYBf9lXYus3jkoSARqGrKrZr2z9Sa5LRIqqzGFOZqpShnKwD2aIZGpClHWFXLK1hp%2BXDzsZPMa265ZhviCOchjL%2FmS7OODPzjbYj6L2WmB%2FTE%2BPQtHpfoFnmc9ya%2F3ncSMyOGiwc65dPl7ttxAdNQow13yoH6ibTZj7gYWPqejq3td5%2BHEyUs49p9MLGE9TlOA1cNQFuISWX3GllVjZG4uHqubCo04HT31Hh0SgBWsJ7pAn9g0RZbYmHiasL1B6i9g2SBfEVoT2S8otK08miG6sYZ%2FYVEJhkQsgquLI6ytrVBR8RiLot%2FS6k3ysTK%2BaJJ2dKUQZkL8LCxe9hVCh%2F5eiOzBowq4OHfC3JlvmoTAuAfjAlMq8c65y0huwiEG673%2BM71iU4msghVS2Ih4DG03CL8g5hFjmUeLZ29fl0RkHi7YtmkuqqsUuF1cqh6C0OSzTyLFog8np46IWzkNKz%2BajOKScsjldq0WOo1Bvf1jmyiwZtX702JjHnC6WmSsd%2FhcY4UY2t5UHCuw%2BoE9ogL9MTD9EjKkMrStnY2OuJqLvIPdM5dh9DDJ7M5a7S%2BwehjVlP1bWu%2BaYuPvrTQ%2BNHTQM3PsOipZgN9pVYu3QBgdYXdmf1EPTRdLi1Edb%2Fwb5KwXw1xwGFW5JONcYdz%2BRhe30dsESlxisbofVbnx4Xbn9jd7kdk%2FFC7UnapcEtzr7W%2FeIkstFO0BOdW3JMjr7W%2FeIqtrGljOX%2FTbX8Q0%2Fm0sejKWIJERJDKCIJER0mM2U0dZ2nRM5MmMDH8my5ImlSOREYS5hkuVR6MqJU9GkMgIgkRGkMgIgkRGkMgIEhlBkMiI9ohZDMaac2YPcxhgptxK7RhzuelP4dIEvLSpe2oSGUEiI0hkBNFuRUZ%2FizM%2BkvwdTkqRVYZ50R98jUm9vSstSWTFFZ3gQVVvPOrtXWwxImM%2BO8daBn%2BqeuPB7c3tbjEiY42DVD5pMVW9UY0eLuwuAZKM%2BNdaIcmqFn9%2FtTc%2BaOqEbK1F9KIEkVlk7aeRIvMIh09OvHXbPxG7vG6EveReOWLjD%2BC7U9morKxGTy83hL78PKKmRYgZFtduOIiU1GydsjevnSmSUXAOHj6N3UkpuJZ%2FG25uTgjw64V3J4XDt5%2BX0e3N7Cx%2FoMQkZvfhFiMyPpVnkB8uPrDH79jbZcY8d0Zmvliv%2Fny%2Fem7Y8vL%2FqT%2BvqanFLyavgr9vTzHDtYODHOcv5GH77uMYNzpMZDHhibt6eHbBxLGvaJXN5%2FnnfPpZEpIOpCJm4UQMCOiN%2B6UPsfdgGuI2%2Fk0knTA29Xa%2BKNUUqpLdu7RWYhafdp3Pit3ESXJbjdnvj8TCpdswc%2BoIkbRLk4IbP%2BDK1SLs3b5QzPXP8fZyx%2BgRIVr5l7z05F%2FKL7iDDVsP48jeGLXX4nPLDvDvLUn%2BJWbfkdyBM3uHSlXXkg3G8mnWa2UYL5NhG%2FNqi3180MFY5%2BbJu3iqmxVrknS2de%2FWRcxwvWbDARQUanfGNPMvFdbnX9Jc%2BKzaR49fYN7ruQbDojHzL3F7crty%2B3I7SzWtvaSeTITNLBzl8%2FrzzBjOtoga5NdwZoy2YObUCIS9voCFwnytz%2B3ldmKu%2FphPdmPzl98KwQUN7IMpvx6K8B8PUO%2BXdvoKim7e02mT3eH5l7oZP%2F9SI5lgQs9mSycwyUWm8mhsNYxP%2F22lxFj2ek6tNfrm%2BcE7qA3vCvDkXVEsXC6P3YN5TyV64GHwyL4YkX%2FpYlYBjp%2FMxOTpa7Fn%2BwKRlYQzbvRgzJ8zRqdckX%2BpvPXDoqEnMfLqRvMLmMGuMqulMu81XMpp7NuVyDQ7A7xd3hYVoI%2F33g7Hlm3fMhE1PFcvb5MNGdxfLGfSryE9I08tMn28FOiD%2BD8fwv37D9U9zdbAlB9etOgb5Hw4Yl7UKDF8oeJMei6WfLxT5Lx80iO9jss5hUJAhhgc4gt%2Fv16YHr1RDIWo4LmXPl6daJF2toGFM3HsEGxKOPKk4e%2FhInqIg3%2B2UKSzkbGWc9VjBZYunKglMp4Omi%2BanDsRKxK3frF%2BDj74aAeCX52vzr%2FEczlFzxptkTY2iycheLhs7cevq6oVohGvGoJoCRWVVSi5Ww57ezu4dWl%2B%2FiXNx69NOVxavCfTB8%2Fy%2B6y5k3hP1dTyL1GbjCCREQSJjCCRESQygiCRESQygkRGECQygkRGEA1DuZWINsfaHC7iVgn%2ByBdPd8SYa0Xx66NwSRAEIRX%2FB%2FX8000nZItoAAAAAElFTkSuQmCC)
+
+```
+sec_or_nsec
+ ::= SEC
+ | NSEC
+```
+
+referenced by:
+
+* ver_check_stmt
+
+**const_expr:**
+
+![const_expr](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAN8AAABRCAYAAABSQ3OEAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAD8dJREFUeNrtnQlcjekex3%2BnvbQgWbIlotJoEilriLFmG2OyzaA7IWU0YwzXdYeJuRlm7sS4lgnX1hgiM5nBMC5mlC0iUpIiYZKlRes53ed5qlMpOjXpdI7%2F9%2FN5e5fnfZ93%2B%2F%2Be%2F%2F%2F%2FvG%2FvAQiCUAoSdTgJRxsU0q18vbgQo%2Fq2q6UuN%2BP8qc1kka8J3fpMV4vz0KBbSahqtKPqEQ%2BJjyBIfARB4iMIgsRHECQ%2BgiBIfARB4iMIgsRHEKqHeMOlhx2anYnGgxetVFW5KvHocSa%2B%2BvYA%2FoiIQXZ2HlqZm8LZqRNmzRiKZQG7cfPW%2FUq3G9zfHn172WGx%2F075svbtmuOd0b3g6NBezF%2B9fhv%2FXPG9vHyV%2F%2FuwaNMUHy4MQvLdNAQGeMK8RWNRduVaErbu%2FA2rl0%2BTrx974y42bDmMyKibkEoL0aZVE%2FTsYY2Jb%2FdFo0aGVZ7btNmBWPDhWFh3bFVu%2BX%2BCDuHYictiunVLU4we7ow1Gw%2B%2BsJ7vgz7C3z%2FfgZuJ5W%2B5vp4Otm%2F8EDdu3sPCpdtLr4NFM7w9uie6d7WqUBc%2F90ePMrBlnS80NUvb%2Bq%2FWHmDnZya2UzX%2Bqh5Kthfiy5cixdEGIVqa8Kms0qrKVYXCwkJMeP9LWLU3x5ovP4CxkQGirtzCjh9OYNSwR5j0Tl9kZeUUCScwFJZMXGNHOov5Zk0bIo0ZUTQTzZZ1PsjLkyLifCzGvReAsN2LYWfTBh0sW2DhvHFw91iO42H%2BaNm8SGh8HxoaEqxmBlcitvT0Z4iKTpQf2%2FFTVzBr3nr4eA2H99%2BGQVtbC5cuJ2Bb8HEYGepjqkf%2FKs%2Fv3MV4pGdkV1j%2B7tjerNHJEI3Dp%2Bz4NJgIPprjXtxg3GGN0Y8IWuMtX19TSwOXrybBtY8d%2Bva0LV2uqSnGmZnZ4py2bZiLfGYcZy7EYTy7rgd2LYK9nYV8%2FfiEe%2Fj1%2BCUY6OviVPg1uPa2K21o4lPYNVHNwKumenCywRipBIEFUpiyWQMhPklR%2BDleKsUYVun%2B5yutqlxVSE5Jw7XYO9gZ5IemTUzEMu5dRg7tjoICGbS0So2hcWMjtGZlLk7W8mVcfNwwS5b1690Zf5yJwanT14T4dHW00aJ5I1HWknlUbZ3SV2d9Z47AgiXbmIcdIkRalgJ2Nz9evBWLP3kHk9%2FpJ1%2FOj819mJPw1n8F7jVNjBswz6UrGhGOmamxvFyH3dCy51kCb6QqW14kxNLr0LdXZ4SficXJP66WE1%2FIgXCMGNwNJiYN2PTpcuJTZaqrhxLRsWCmVdkX4so1PYVFYSivNJlV%2BgN3j9Upr%2B9ww%2BOGGLg%2BDEl3%2Fiwff2tVvxXmonmYmo42rc2qXJeL%2Fb2J%2FbHy3%2FsqlF28koAnT7IwgYWwldFYgZDzVXDjZgrCz16XD2cv3Kj8OrCGKzWNX4cm5aKMfWHhGDvKRUQPh45eRNazXLXK2arSAxedoy3uSIF94MKrLOd7SaVC2VWVq4on1GGh3Oa1PiwvC8aWHcdgZKSPrvaWmDZpIAb1f1OhOnKy80W%2Bwok4Hwcb69Z4a4CDQtt6ew6Dy%2BAFuMRCtrI8%2BPMJmpoZyz1lfl4BQg%2BekZc7sGN83lvWBb%2F8egHnIuMr5Hyc3NzS63A28gYsWd43fFA3%2BboR52KZh5DAieWBEokEbVnu%2B%2FPh8xg%2FppfadZxU0IMEvxQAy573dAqJrwQZcIn5gyGFVZQXFOAW26m%2BKlwoJ0cr%2FBKyRHia6JgkkYvMmLMWu77zQ28XW4XruXP3IWJYCHvsp88V9prGxgaYPWMo%2FvV1CHw%2BGC5fbshyusdPs4S34IZaIJPhNPM0nBMslJvLQlZliM935kh5zvsi7t57JDqPjh1YBi1tTfnyvSzk5GH73tDTYt6cheN7fwyvdfHVp%2F9s4HpgIenwgkK8zcayqg5M6wUx7Wm24V02dmMVfsfG815WzhxKQInnG8%2FSgcSOaCvVgC1bcQBbx4OtG61VCG9mT3Gv4qRrcgMaNmwgxMaHyKgERF5OUEh8evra8JszSkz7LdqM92d%2Bg5AdnwqvoAjTp7ghaPtRIXq5Z3ujHXJz8kXuyPMnXtfXX8wQZR4zVtfLRkxXt%2FQ6aLH87z12HfbtXIgGBrrIyc3DwSPn4dbPXt6I8Bx6%2F0%2FhuHf%2FsTwvrg1q%2B59qWRrbsUCCb1mldsyogpll%2FaYpwzWLOCTtAaSV2VtZPbDxBj1tbGa3czprkj0LJXhaWchZIefjlbDRHlaBDRuSWThpExkDv6rKy4ac%2FADPxSEh8jrCeNnTfFiw7U6whDPCwRYDlWkwPNxbtGyH8Fol8B5A3uPX3aFDtesL%2BGyq6Mnz%2FmgDZDLF9M%2BFNW%2B2O4K2HZUv4x0SXtPfwjwm5vMXS8M8bsSZxb2v9Znl%2F5gszmHWvP9AKpXhyLFLaG3eBGtXfSAaET78mw3du3bE%2FrCIense3D65nXJ75XbL7ZfbMbfnEuEpopfTlxHNx5qasGLBzB62XgZbOfllno9XwpV7hkUPNpXkcFWVV0p8PHiW7d%2FVWoSoe1jL4vyqPGBVNG%2FaEMlMeH2GLoJpIyPRY5ednYtFfuNe2Kv3MniOtinQGyMm%2BGPZyt1wH9IdXswAOQNGLsb2DfPQsYN5he08xvXB%2Bs2Hyi37ZO5Y0SPpyUJgHnpyz%2FKEhaIuTp1EqKwoYyZ9UW5%2Byruu4lHFzj0nkcfytImeq1mI%2FZFCdfnM3ygGeXjcQA%2BxF9ZVDJ%2BYQWz6Zja7Dsvxzy%2BCcftOKkaP6FFhPb5sy46jmO05VMx%2FGbhfDCVYWjTHqUMrlJOOMI%2FHcrQ9TCxTueAU2KRKPRQv8%2Bthh4B8KRY87wklxW70GatkPaskoLJKqiqvRni4mPdMs1BhcG2HndX5jATv0Lif%2BkRMt27ZpN61wCksj5KyvK%2BpmYl4fEGUp%2BxnJGor7GQ2dISNTrL6%2FBVYt0Z64L2hXITsgGey%2FRQ952Pust3LKqmqXFGMsrEqQx%2FeDp1hf%2FEqopR187jHqo%2BiK6HkLZiyfMY8SnTMncqvq6GeeIOEqGG4yewRMrzB7NNdkfVrqoeynlAedlZVUW09RvhfInIcbbFLQ4ZxbDaKbrvifLbQgy7CK0LYowS7uH1WQ0Q1pmT7un%2B%2FpxC%2FMZftQrecqC8Ie2R2Weeir%2BsdsqT2Kot5O9ItJ%2BoL3B65Xaq9%2BPQzhcs1o1tO1CPMiu1SvcUXniziaj2630Q9Qq%2FYLtVbfEUhtnp8pp5Qp8iz7l9To%2F9kJwglQeIjCBIfQZD4CIKoA9TmJ8LU5WejCPJ8KgV%2FuVYdfiyRIPERBEFhZ%2FU9IN1SgjwfQRAkPoIg8REEQeIjCBIfQZD4CIIg8REEiY8giFeFWjxkr0%2Ff61cX6IUFEp%2FCVOejucTLoZfUKewklBxNUERB4iMIEh9BECQ%2BgiDx1RD6fCBRX1DKZwOVKb4cl1b04VxC%2BRTbYc7rJL7UbEM0o1tPKJtiO0x9bcTHfHycpgSd6dYTyobbIbfH10Z8LMgOZ38GKGPf%2FFdf%2BS%2FT1jb3HzxGXn4BWbPqZXwDhD2%2BLuKTaSCEub%2BJrhZ1n%2FcNHbcMcQkptV7vuCkBiIxKIGNWIYT9MTsU9vi6iK%2F4J6GvZOjjYzIBQlkU298VZf1EudLe7dQsxBypBBFdrXEp8jrC6nLf9%2B4%2Fxu6Q33Er6QGGDOqKSeP7yct%2BD7%2BG4L2n8Cw7F2797THx7b6QSIqeitxOfohNW48g%2FtY9OHSxxKzpQ2BkpF%2Ft%2Fefk5iFo21FEnItD40aGmDZpIN7s0g6Jt%2F%2FE%2Fp8i4PneIBgZFtX785EL0NCQYIhbV4QePIPmzRrhzLlYnL1wAw72lvDxGg5dHW1xTmGHz2OsuzMOsPU40ye7kcJeALO7EWzkx%2BzQWVnHoLSH7GevI04mwXhm19scbbC4Qwfo1tW%2BP1%2F5A1qZm8LN1R4BX%2B3D%2FrAIsfy3k1fgM38TBg98E1Pe7Y%2Bdu09g1ZpQUZb2OAOjPJbDzMwYvszgeY7n4bkaMln1HxFN916DpNupQjh9etpistfXSEpORdvWZoiKTsQnS%2F4r1jt%2FMR7%2FWL4LXTpbiPnQsDPw8l2H%2FAIpRg7tjkNHL4pzKcllv%2FxmH8ZPXYmExAd4mJZBCqsEbmfc3rjdcfvjdqisY1HqfzVcvIZjTtZwLpDgWxNteHe1QTD%2FbWxNGa5ZxCFpDyB9Fftd95UXOlu3KQo9MnOwN%2FQ0xoxwxsathzF31kiMGtZDlLVo1pAJbgXmzXIX63AR%2BHqNEGU9unWC04CPmfeKRc8e1grv%2B8LFm0i%2Bm4adm%2FyER3VytMLvETE49GskvKa9hcAATwwZuxRrNhxE8J6TWLvqA5i3aCzffv7c0Zg8wVVMt7Nohmmz18B%2F8SQxr6ergwO7FtXIG6sr41mQldgRbaUasC3uXPFgzWW0FvN4F2KUJzyli6%2FEA7LRIIfOsNcoxFg27SvThFWCDdo61sFbMO3bNWeer6izi3uMTlbm8rKOHVoi61kuHqQ%2BKS5rWRoysFDQqr05W36%2FWuKLu5mCuymP4OK2oNzyTh2K6jY2NsC3q70wYoK%2FaAhcuncqX4Gk9JJYWjTH06dZIkTm6Bvo1LrwVP0%2FGxKK3l5JYlftBrOmcObthigrx6t34nuuEyaqrg0kMzMbDY0biGkjQz2kZ2SXJuRsmnsnwwZ6YkjPeFZuWz5vaFg9Y%2Bf1cIH%2FvHfJC9fZ%2B%2BNpvGHbFqEs%2F5vJvCEXZGU8epQBA31d6OvpvLL7Qv9Uq4Y5nzLJyc6Xd3zs2nsSbw10EPMD%2BnYRnS1SqUzMb9t9HF3ftISJSQMM7NcFh1mOlZqWLsouXbmFG%2FEp6OVsU6198%2FW5Fw07dE6%2BjHe0XL6aKKZDfgwXoWxo8EJ072YF3wXfobCwtG1JTy9qAAoKZFgX9AuGDXaUdwgRqoXW63jSPvM3ivDt8dNMuPa2k%2FcKfjjbHV5z16HX4E9Fb2NObj7%2Bu95XlPHQcvK7rnAd%2FndYWbJw89Z9rPKfBjNT42rtm%2FduBq2dg48Xb8GSFcHQ0dZCbl4%2By%2FX%2BhpjYO1j6xfcI2fGpyN9WLJmCoeOWYu3Gn0XnjGgQgo8jaPtRZOfkwc6mDTZ8PYusWEVRiyaTh53V%2FYzE3ZQ0aOtooWkTkwplfz58irzcArRqaVqhjIeiT9Kz0NTMRHTx%2FxX44wEtbU2FBfz%2BrEDx%2BIN3DmU9y6n02GuDsp%2BRoLCTPF%2Bt09Lc9IVlLzNq3qHxsk6Nld%2FsF8%2FgKo3xNST4Yet8%2BXyL5o1qdOwNDHTFQJD4iDJ8MnfMK6vbc6pbuccOBImPqCN6u9jSRVAj6DMSBEHiIwgSH0EQJD6CIPERBEHiIwgSH0EQJD6CUD3U5iE7%2FawVoWpoqsNJ3HuIpXwwN8NndEtr%2F9rSVaCwkyAIgiD%2BOv8HL63kC7zL%2BWcAAAAASUVORK5CYII%3D)
+
+```
+const_expr
+ ::= STRING_LITERAL
+ | bool_expr
+```
+
+referenced by:
+
+* option_def
+* option_list
+
+**int_const_expr:**
+
+![int_const_expr](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGsAAAAlCAYAAABF7RcQAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAABIlJREFUeNrtWwtMU1cY%2FgotLY8OnQGSSQS3IFYIWQa6acT5xEXmMkUSJW5Mpoz5IhINPmJU8AFGHJuGRbMwnTMxoiAqbuJjRl1ZY51IcIL4ihaYgkaQWGx76c692Kat0Aul7V3N%2BZKbc8%2F9z%2F%2Bfnv87%2F3%2FOPTcFKDwGIiE6jVXA6OmOu3rT%2Fb4TCzVY9aVijyUqLj5NkH69aHJxPDu4O0NQsjwIlCxKFgUli5JFQcmioGRRsig8h6wPoxFirxGfnMI%2BBuo%2Fkz5Hlp5BE3kbP9ybUT45hX046r8xCsyKHYWHBgb32Dp3NijqJi2ZYYhQgTKxN5apavHIpMQndyV0egOKD5yFUlWHt%2BR%2BSE2ZhNEfREDT%2BASHyy7j6y%2BmIjDQn2tbeb4aetI%2BcXocKk6r8fbgAKiv3cFfV%2BoREx2O5Rmfwlfmg8etbSg9XoW5s%2BNxrEIFnU6P9AXTXTaG%2FvqPJYkR4QfGiFDLAy2rNcvYTR5rVNPTTOCTuwLfZBahrqERS9MTMWViDNKW7ELDnWaEDh2C%2BttNWLG2%2B0C45sZ9ZG%2FYj%2BioMK5%2B4vcrWER0X2hf4rMZY3DhUi3Wbz7IyVoIWdsLy5D0ZR6x0YjWp8%2FdEmF8%2FjNFEgOUgiXKBmIeo9xM4JO7KtJu1D3AP%2FUPUXVmO7y82C8SEVCpb%2BFUpRqZ385EwZYFSEzOxc7d5Sg7qULhtoUICw0y62dmzMSi1Gnc%2FcgRoUian4f8Talc3UcqRumB1eaodCde858IvxmAHNtI6hNZJnQB1ST0PjHyyA0G3COd%2Bjp7UPUNTWhpace4adlWz%2BcmxXNlgL8MP36XgYTPNyL9qwR8PD7KOv1YfHF6NzwE2k4d2tpfcHWpROIUogZy8s76j%2FzERIMRc0jZxWdI3EuOVRLFRlJOJQZ%2FIuUKe3KJGPn9iay%2BDlAeIEN4WDDOn8jttc3R8ipEK4ZxaY9Nlew61ROePuuAxEcMOSG42YkTqi8fIW3Ha%2Bk%2FUu6RSVDcqUcamfgLjSK09ZQCX1uzWCOkKCEGFOTSkPSm%2BPsmsvjkrtpsfBQXiX8fP8ORcqX52QNNK65dv8vdV1RexZk%2FqnH019WYPCEGS1buQZfF%2FGx%2FFUUM04WivaeQMOl9jjCh0Jv%2FlDWoZUtvb0QYjSgh7Z6Txhp7kcUaYZlWSYiRHgjgkzsdcrkvfi5ahqw1xdiyowQyqQRarQ4FW9Nw%2B24z1mz4BYf2rYS%2FnxQ56%2BZhxpxcFOw%2BhlXLZ3H6h0ov42DJRXS%2B1CHyvaHYu2uxkDt4Xv%2B9epZFNh75ZLufbRtpJrK0LNN2SOCTu%2B6FMnYE%2FqzMwyMSYSKyCAUHBZplNVXfm%2B%2BlPhKcO55jpcuuYynJE9DR0WmlFzVyGK4rC905jH75z5Y0EmkZZrJIOA63Z4RP7g6EBA9ySM%2FPV8pdQsJR%2F1mSZiaLz5DQRDmC1JTJGDJY%2Fr%2F4LQP1n0lfjDcUY0dHvpkHuRSULApKFiWLgpJFQcmiZFFQsiicBsFeioX624wnw1uITptbsYm93gnCRk93IDsOmgYpKDwZ%2FwGTVeBry0x1AQAAAABJRU5ErkJggg%3D%3D)
+
+```
+int_const_expr
+ ::= expr
+```
+
+referenced by:
+
+* address_or_range
+* bool_expr
+* call_arg
+* call_target
+* enable_stmt
+* encrypt_stmt
+* jump_sp_stmt
+* keyblob_block
+* keywrap_stmt
+* load_data
+* load_ifr_stmt
+* load_opt
+* mem_opt
+* mode_stmt
+* section_block
+* source_value
+* ver_check_stmt
+
+**bool_expr:**
+
+![bool_expr](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAasAAAI1CAYAAABoldXDAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAIABJREFUeNrs3Ql8FOXBP%2FDf7G42J0cOSATkCgQSDiEJGJQCRYHwloIQ%2BAuUQrUoWPGoVSu%2BvCq%2BVgtBW0FatKiItYZLeTWiFkFpU464ATEhkIMckGAIJCEHOXd3%2Fs8zCRg0kIO9Qn7fz2cys9ndZ2afOX77zMzOAERERC5OYRX8WEQoVNaCbSUdb1%2FLmmq63237gYOPpKaXLEw7WTqwuLTW%2FVxxdYs%2Fg7%2Bvu9nb0%2B1CgJ%2F7vsxTVS99eagyiUsB1z%2Buf21n4Gxsmunfb7ESbCTyJ%2Fe2q%2BndvSnigUdf3Rmbnl3mPW3izbhraW8EdfdCd3%2BPFpdRWFRtKCisDEgwFcbk5p%2BaMX2Clyn%2FfOWCpBSc5BLB9Y%2FrH8OKXPzbsit%2Fw1PV53Rb1%2B7YsnpDyuwFs4KxevkoGN10bSpLBpvshof6YfHcEENcfHbUxrj0lMhh6ixTsuVTLhHE9a91dJyNRPVkUL21JWP2yytGYeHM4DYH1Q%2FJcmR565%2BP8vAyKh9HhuFe1jYRw4qo1eSuP9HymR37dCSGDfK1yzhkua%2BtjNIbDLqNIxlYRAwrotaQJ1PE7zkdu0C0fuwVVI0Da%2F6M%2FooByuuihTWVtU%2FEsCJqEXnWX2Zuuffcaf0cMr4l8wbBaNQZrCq2RAxFMOcAEcOKqFmpGSWLosf3tNkxqubI8Yy%2BpZs80m2ABWs4B4gYVkTNSssqCx4bGejQcU4e10P2PEU3duQQ3MK5QMSwIrqmouIaj55BXg4dZ9iArvUDCgp1VsRwLhAxrOzqzHfFqKs127zcgrMlqK0zs4IdoLisRvHv4u7QcfYKvByOPqKbxLnA9Y9aEFa3DsU194E093xHNjXmeaRnnbF5uTG%2FXIXDR7NYwQ5gtajQ6R37W8lL41NV%2BIleb84Frn83quvNj0vv18KqzoIzEaHYerVCm3ueqKM7kVWOp1Ynw2xp3WXtlPqWFdcrumG1NT9Gh2JmRBhOmy3Ilo8NDSuMDK05Fot4MhQfGvR46FAKzjZaoa75fEf3XUEJtuxIQHbuWURPCscv5oy%2F%2FFzCgVS8v%2F3fqKyqwZ0%2FvQXzZ4%2BDotR%2Fqz6Vdx5%2F2%2FRPZGZ%2Fh5HD%2B%2BOBe6PRqZNnq8dfXVOLNzd%2FgYNfp8PP1wf3%2FOIOjBjeDzmnCvHhxwexeNEkdPKpL3fXP5Og0ymIvjMcOz85hKBAXxz6Og2JSRkYeUt%2FPLTkZ3A3ummfKf5zE2ZNj8L%2FiddJ9y64kzO78UpotuLTrwrw5rYc7D9cBINoLf3vY0PQhutD61mbXP9u1PWvtfkhQ8qiYK343ter8SWNrzhmpdaHlyw0r6kkbO75jup%2FV29Frx7%2BuHPCLVj1ygf4MP6g9v%2B9%2F0rGQ0%2F8DZPvGIFfzv0p3tuyD2vW7dSeKyopx4x5f0C3bp3xsFhA5T7yeYtfhtXa%2BgtO3%2FvgOuSeOqct6D%2B5LQwLlvwJuXnn0OfmbjiakoMnn3lHe53pSCb%2B5w%2F%2FwPAhfbXHO%2BMPYcnDfxEbXQt%2BPnUUPvviiPZZJHksIPbVDzBn4Wpk5ZzF%2BaJyzugGBeerser1NIyctge%2FXp6ErFMX8fjiEBz%2B%2BE64GXgYmOsf17%2BmNJcfl1pSFuADyKD6AUMzhWpJ2NzzHb2l9ZdXlmDI4PrDDuUV1di%2Bcz9mTovCG5s%2BxyMP%2FBwz%2FutW7bmbAruKFeRF%2FPaB6dpr5EL78JJp2nO3Rg7C6ImPi29nabjt1sEtHnfSkZPIyy%2FCe397TPvGODpiIBIOHsdnuw9jyT1TsHbVYkTPWol1r3%2BC97f9C6%2BtuR89bvK7%2FP4nHrkLC%2B6eoA336xuIe36zDi%2Bs%2BIX22MPdiP%2F7x9Nt%2BrZ5o1oem4J3PsjVWlUTbu2GP%2F5%2BKKLHBWmtKuL6x%2FWvVaFVnx8KPjUDz%2F%2BwJdWisLrECnwjvidGq808bzYjW4yUWzQhuF%2BQ%2BGZ3QBuW34gGDexx%2BbmQAT1xsbIGZ89daHiu5%2FdNXJ2CgcE9xP8LWrWypJ88g%2FwzxRhz5%2B%2Bv%2BP%2BgAfVld%2B7shfUvL8G0u1%2FQVtwxowb9oI3%2B%2FUa2f98glJZe1HaZSJ5eRpuvKO39XkWpmWVaUPl1MeK2cH%2BMHu5nk6DiPZy4%2FnW09U%2Fmh%2Fj0PzOrmC36zbZpDVfZx7hfvDFf9O8UBW4U%2Fd9e63k3A1ZdalnNAfQ5Iehj0SFMvHCieM088doUg4oHE08gvbUfyNbl2XuGVlRUoWtnb224k48HysqrLj9XLoblty8fbw%2BtKyuvvOK98rGPT%2BsWTlmOXCF3bX%2Fmqq%2FZ%2FtF%2BDAvrg50fH8RS8W1PrkBNKS4uh5enOzw9jHZbQJu7RYGrz%2B8dfxmjHad6a3sOXvzrCcT%2BLR3R4wPxq1l9MW50gN3qxV5GD0aIWcF6MfKhohLeFzWxV29Fat905G4DLM4oj%2Buf89Y%2Fe8zvH87Pxvkh%2Bq97uOGt6jrcKxo%2Bi1UFpU3tAtS%2BUPywENHbJgoIFV2eQY%2FQw8fxWHPPN94FKCfw63RkHT6BePlcaR36ivftsyg4ODIMd7S2Mmxdnj1UV9XV92tq8Y%2Ft%2F8KUO0ZqjyeOG64d3LVYrNrjzVu%2BRPiI%2FujSxRt3jB%2BOz784gnNFZdpz3yRnIyPzDG6PCm3VuOXr5bfE%2BM%2B%2Bvvw%2FeWD322M59RvXjw5ouzZ2vr8coyIH4uHfb4Sqfr%2FslJXVr7Bm0Vr4y5uf4r8mR1w%2BAO0Mrj6%2FZSvq53fchA%2F%2FOgYJWydg0aw%2B%2BOrgOcQ8eABRs%2FeKed1%2BGkiyPmW9yvqV9SzrW9a7rP%2B2BJWty%2BP6d2MtP1fLj%2F3fIkX29XoMFFWzTbyuXLw471otK1mITLpDbqKQJo5BNfd8kzIzIdu0L4QP1nYZbhNJHHU935BtXZ4tPPTEG1pzvqS0AhPGDr181s6jv5mOJY%2F8BbdPfko7G6i6pg7vbHhYe07ualgwdwIm%2FOy%2FMbB%2FD2RlF2DNC%2Fegm3%2FnVo1bnn305mvL8PiKt%2FHMi%2B%2FDKJq5NbV1WLvqPhxPO42VL8Vhx9%2Bf0vZ%2Fv%2FjMLzE1ZiVee2OXdjBYW4Hf%2FxJvvvsFqqprMTS0N17%2F0wMutUK44vy%2BvKunXye89MRQrFg2GFt35eHt7bmwWFXo28HxK%2FmNWOTqNrFxWCg3MK5WHte%2FG275aTY%2FGv732K1DsarOgt%2F%2FsKWlNDTTKkUhG0Qhq5oqpLnnW7G7ZYXojRNN0ck22n1j0%2FIa74Zo7W21888Uwc1oQPeALj96rvB8KWprzOjV0%2F9Hz8ldExfKLqJ7ty7aKavXQ57uahAzqaUr3K8eWKudzisPRl%2BsrG5y2m2h8W21r2c3hF3n90c%2Fd%2FgKHzn9Y6ftBhSf%2BZ%2Bi9y8x3hdcrTyuf665%2FrV1frc1P%2BTZgjK0xAQvFePxMtTv2kC%2FaxXS3PMt1akKa8o98aC8cOeRYzjqauVdj549%2FK%2F63LUWQnkA9VoHUVe%2F%2BqH2G4wm9%2BHqFGzd9MTlxzcFte1eTN5e7lrn6lxpfrdn2oVzrRgm6nO6K5bH9e%2FGWn7amh%2BNW1qXdwM2V5CtTkv%2FKgfVEWH4R8OFO4%2B6Wnmu6MlHZtqt7MUL77ziNFpXZ6%2F5LS995OhLLlVcrHNaPWr1p%2BAfsj5dsTyuf66ttfP7evPj0vsd%2FwtGFXtFk3CMy5bXgYwdE6adLtuu2GF%2Bd%2B1kNBeV1jj0Y2TklDmxCkX9iXp01fK4%2Frn6Kuic%2Be3wsBJfYI%2BJ768hrloeuTZ7zO9O3m4X8gsqHfo5Eo%2Be1%2FqKCnlpAosjxy3rT9ajq5ZHrs1Z89vhYeVZoTXpurlqeeTa7DG%2F%2FX3d9yWYHHsBlt0J9VcKVxUUip6jr%2F7SraEeXbU8cm1Omd8OD6sDedp%2BTg9XLY9cmz3md%2Bapqpc%2B2Ztnrq2zOuQzZOeVIyev4tIaKO9DccrB1ejRUI%2BuWh65NqfMb2dcdVMFbHqarq3LI9dm8%2Fn95aHKJKObzhQXn%2B2QD%2FDUqqTGn%2BaibGg5uA6Vhnp01fLItTllfvMS0URC%2FvnKBRvj0quT00rsOp7Vb6TgZG75paDKEl2EVYcdnANEDCuiZiWJDKmtU2OWPXvQYq%2FAkkG1tXHrTUGC%2BIr6NX8zRsSwImqxQ8mWXRVV5vuWLN%2Bvrtt8HLY6hiWPUd390FdXBpWK98TfKaoeT7LmiZpnYBUQfe9wKt6ODLXq3t1xckPcR9mGqBEBiB7fCyHBndGnh0%2BLyqisNiMtqwyJ35zDFwlnRFhVXPkCGVTyivIK7jGJFh1rnYhh1WaNr6dFHYvpON4MH6LmW2ot2%2FYlntWLzjY3FZLHqBQkQN4jTodFScfwGWub6x%2B1DHcDNkFe7NFZ9xciF2lhiSBR9BghBj8XIVMkFoYU0Z0WS8XFVhRTId6TrVNFGcCHKuAuHvuIr4i3HWZQcf0jtqyIbLLRrN9FN1NeuLPheoSTYRUbUQXeLSzCR1VxQVXQVQwnqnqsNPFkCiKGlT2%2B4bEWqOFsPdk9w9rg%2BkfOwd2ARETEsCIiImJYERERw4qIiIhhRURExLAiIiKGFREREcOKiIg6Ov4omKgJqul%2Bt%2B0HDj6Sml6yMO1k6cDi0lr3c8XVNv%2BRqr%2Bvu9nb0%2B1CgJ%2F7PnnHYnkjSNY%2BEcOKqFm7N0U88OirO2PTs8u8p028GXct7Y2g7l7o7u9h83EVFlUbCgorAxJMhTG5%2BadmTJ%2FgZZI3gkzi1diJGFZETbam1Od0W9fu2LJ6Q8rsBbOCsXr5KBjd7LunXAag7IaH%2BmHx3BBDXHx21Ma49JTIYeosU7LlU84Vono8ZkXUQAbVW1syZr%2B8YhQWzgy2e1D9kByfHO%2F656M8vIzKx5Fh4H0yiBhWRN%2BTu%2F5Ei2Z27NORGDbI16nTIsf%2F2soovcGg2ziSgUXEsCKS5MkU8XtOxy4QrRpnB1XjwJo%2Fo79igPK6aGFN5VwihhVR%2B2SzM%2FPkWX%2BZueXec6f1c6kPuGTeIBiNOoNVxZaIoQh2tXojYlgRNWNML9js1LzUjJJF0eN7OvwYVXPk9Iy%2BpZtMFwMsWONq9UbEsCJqRpUPAm1VVlpWWfDYyECX%2FJyTx%2FWQPU%2FRjZV3LHaleiNiWBE1Q69giK3KKiqu8egZ5OWSnzNsQNf6AQWFOitiXKneiBhWRM1RMNFWRRWX1Sj%2BXdxd8mP2Crwcoj6im%2BRK9UbEsCJqjor5E%2Fra5viL1aJCp3fN8w4uTZeqwk%2F0el9PWVp9iXrjwkMMKyLHSS73xOOuMjEnssrx1OpkmEXw2achqbWsrut4U0N9JXPRofaIl1uidkmvYplFwcHwwfjm8AnEO2Ma6sxWfPpVAd7cloP9h4tgEK2g%2F31siBYtNbVWmJJLrvreQf18EODX6l2P%2BrZOq6inaaL3mKi3KFFvaVyCiGFF5ACJJ5A%2BMgxzdMC2iFC8UlqH2MxM1Dhi3AXnq%2FHOjly8%2B%2BEpnC2qRlCABx5fHIKFs%2FrAzVC%2Fs6LgXDXuWrr%2FqmVseCEcMVN62n1aBwyAexc3PCGDyqpgTtJxpIv6ImJYETnKkVTsGT0YUWYF68UG%2BcHwULwPFXv1VqT2TUfuNsBi63Euj03BOx%2Fkaq2qCbd2wx9%2FPxTR44K0VlVjAX5GrHt2xFXLiRxqnytlzBGtr5wQ9LHoECZPphBTNU8FUgyiRSWDiksNMayInNTCEr1J8jdIOhWzxPDDVj0GZoWiT4QdrtaQmlmmBZVfFyNuC%2FfH6OF%2BPwoqyd2ox%2B0R%2Flctx9%2B3bWcfilbRNQ%2BKZUF7PldMUYb49AdEayr6yDEc5ZJCDCsiV2hl1W%2BQ27RRbi4AGtvxlzHacaq3tufgxb%2BeQOzf0hE9PhC%2FmtUX40YHXH5dfkEVIu%2Fac9Vy2robULSOeLkkYlgRUTMrjGhF%2FfyOm7QuLbscm7bnYssnp%2FHxnu8Q3Mcb%2F9nyU%2BjFa7p0csOT9w%2B6ajlhwZ1YmUQMKyL7G9SvE156YihWLBuMrbvy8LYILotV1cKqa2c3PHFfCCuJiGFF5Bq8PQ24J6av1hGRffBHwURExLAicvmVQK9ol1xyRRUX6ziDiBhWREDXTkZzUWmNS05bRk4ZZxARw4oI6OTtdiG%2FoNIlpy3x6Hmtr6gohx1%2B5EzEsCJqJ%2Fx93fclmM665LTtTjij9VUFhaJ3lnOLGFZEHVTmqaqXPtmbZ66ts7rUdGXnlSMnr%2BLSmpol%2Fp7i3CKGFVEH9eWhyiSjm84UF5%2FtUtP11Kqk7x%2BouCgbWpxbxLAi6sDyz1cu2BiXXp2cVuIS07P6jRSczC2%2FFFRZoouw6rCDc4oYVkQdWJLIhto6NWbZswctzg4sGVRbG7fyFCQowNe8IC0xrIgIh5ItuyqqzPctWb5fXbf5OBx9DEseo7r7oa%2BuDCoV74m%2FU1Q9nuQcoo6Ml1siauRwKt6ODLXq3t1xckPcR9mGqBEBiB7fCyHBndGnh49Nx1VZbUZaVhkSvzmHLxLOiLCquPIFMqjkPakU3GMSLT%2FOHWJYEdFlpuN4M3yImm%2BptWzbl3hWLzpPh06APEalIEEMRas6LEo6hs84V6ij425AoqZaWCIgFD3krX4%2FF%2BFRpAApojstQuSiHUZXIcrO1qliXMCHKuAuHvuIr5K3HWZQEbFlRXQtSfW73mZqdyG2IkYMT4ZVxJUCbxuPykdVcUFV0FUMJ6p6rDTxZAoihhVRazS6C%2FEzrA0i5%2BBuQCIiYlgRERExrIiIiGFFRETEsCIiImJYERERw4qIiIhhRUREHR1%2FFEzUBNV0v9v2AwcfSU0vWZh2snRgcWmt%2B7niaqWl7%2Ff3dTd7e7pdCPBz3yfvRCxv8MhaJWJYEdnM7k0RDzz66s7Y9Owy72kTb8ZdS3sjqLsXuvt7tLiMwqJqQ0FhZUCCqTAmN%2F%2FUjOkTvEzyBo9JvHo6EcOK6LpaU%2Bpzuq1rd2xZvSFl9oJZwVi9fBSMbm3bUy6DTXbDQ%2F2weG6IIS4%2BO2pjXHpK5DB1linZ8ilrm6h1eMyKqIEMqre2ZMx%2BecUoLJwZ3Oag%2BiFZjixv%2FfNRHl5G5ePIMNzL2iZiWBG1mtz1J1o%2Bs2OfjsSwQb52GYcs97WVUXqDQbdxJAOLiGFF1BryZIr4PadjF4jWj72CqnFgzZ%2FRXzFAeV20sKay9okYVnRjU2xVkDzrLzO33HvutH4OmfAl8wbBaNQZrCq2RAxFcHutNyKGFVEzxvSCh63KSs0oWRQ9vqfNjlE1R45n9C3dZGoYYMGa9lpvRAwromZU%2BSDQVmWlZZUFj40MdOj0Tx7XQ%2FY8RTdW3om4PdYbEcOKqBl6BUNsVVZRcY1HzyAvh05%2F2ICu9QMKCnVWxLTHeiNiWBE1R8FEWxVVXFaj%2BHdxd%2Bjk9wq8HI4%2BopvUHuuNiGFF1BwV8yf0tc3xF6tFhU7v2PMOLo1PVeEner0dMU6tvkS9ceEhhhWR4ySXe%2BJxR4%2F07R05%2BOiLM6gzW23U0NFaVg45jtRQX8lcdIhhReQgehXLRO%2Bx8MGY5sjxpqSX4dfLkzBy2h6sej0NBeerbfJx7D3dDfX0WEO9EbU7vDYgtUuJJ5A%2BMgxzxLetbRGheKW0DrGZmaix93j%2F%2BMRQjIsMwKYPcrFmYzr%2B%2FHYGoscH4d7ZffGTUQEuV08DBsC9ixuekEFlVTAn6TjSRX0RMayIHOVIKvaMHowos4L1YoP8YHgo3oeKvXorUvumI3cbYLH1ON0MOsyY1EPrMnIrsGl7LrbuOo34vd8hpK8P4tbeiptv8nJancwRrbScEPSx6BAmT6ZQgHmqaBAaVETJoOJSQwwrIie1sERvkvytkk7FLDH8sFWPgVmh6BNh56s19OvljTHhfvj2xAUc%2FKYY2XmVqLhoblNZorWj2mKasqCVkys%2BeIb49AdEayr6yDEc5ZJCDCsiV2hl1W%2BQ27RRbm1QfHeuGps%2FyMXfd57SjlkFBXjgyfsH4Zcze2vDbSFaPbwMEhHDisg2Xn0nE3%2F86wmYLSrGRgbgxceHYuqEIBj0zBoihhWRiyg8X4NfxfTFr2b3waB%2BnVghRAwrItfzh9%2FxakVEzsDfWREREcOKyOVXAr2iXXLJkSou1rHiiRhWRC3XtZPRXFRa49BxZuSUseKJGFZELdfJ2%2B1CfkGlQ8eZePS81ldUlMMOP14mYlgR3WD8fd33JZjOOnScuxPOaH1VQaHoneVcIGJYEV1T5qmqlz7Zm2eurbM6ZHzZeeXIyau4tAZmib%2BnOBeIGFZE1%2FTlocoko5vOFBef7ZDxPbUq6fsHKi7KhhbnAhHDiqhZ%2BecrF2yMS69OTiux63hWv5GCk7nll4IqS3QRVh12cA4QMayImpUkMqS2To1Z9uxBi70CSwbV1satNwUJCvA1LzRLxLAiarFDyZZdFVXm%2B5Ys36%2Bu23wctjqGJY9R3f3QV1cGlYr3xN8pqh5PsuaJmsfLLRE1cjgVb0eGWnXv7ji5Ie6jbEPUiABEj%2B%2BFkODO6NPDp0VlVFabkZZVhsRvzuGLhDMirCqufIEMKnmvKQX3mESLjrVOxLAiajXTcbwZPkTNt9Ratu1LPKsXnadNCpbHqBQkiKFoVYdFScfwGWubqGW4G5CoqRaWCBJFjxFi8HMRMkUKkCK60yJsLraimArxnmydKsoAPlQBd%2FHYR3xFvO0wg4qILSsiW0iq30U3U7sLsRUxYngyrCKuFHi3sAgfVcUFVUFXMZyo6rHSxJMpiBhWRPbQ6C7Ez7A2iJyDuwGJiIhhRURExLAiIiKGFREREcOKiIiIYUVERAwrIiIihhUREXV0%2FFEwURNU0%2F1u2w8cfCQ1vWRh2snSgcWlte7niqsVW4%2FH39fd7O3pdiHAz32fvGOxvBEka5%2BIYUXUrN2bIh549NWdsenZZd7TJt6Mu5b2RlB3L3T397D5uAqLqg0FhZUBCabCmNz8UzOmT%2FAyyRtBJvFq7EQMK6ImW1Pqc7qta3dsWb0hZfaCWcFYvXwUjG723VMuA1B2w0P9sHhuiCEuPjtqY1x6SuQwdZYp2fIp5wpRPR6zImogg%2BqtLRmzX14xCgtnBts9qH5Ijk%2BOd%2F3zUR5eRuXjyDDcy7lCxLAiukzu%2BhMtmtmxT0di2CBfp06LHP9rK6P0BoNu40gGFhHDikiSJ1PE7zkdu0C0apwdVI0Da%2F6M%2FooByuuihTWVc4kYVkTtk83OzJNn%2FWXmlnvPndbPpT7gknmDYDTqDFYVWyKGItjV6o2IYUXUjDG9YLNT81IzShZFj%2B%2Fp8GNUzZHTM%2FqWbjJdDLBgjavVGxHDiqgZVT4ItFVZaVllwWMjA13yc04e10P2PEU3Vt6x2JXqjYhhRdQMvYIhtiqrqLjGo2eQl0t%2BzrABXesHFBTqrIhxpXojYlgRNUfBRFsVVVxWo%2Fh3cXfJj9kr8HKI%2BohukivVGxHDiqg5KuZP6Gub4y9Wiwqd3jXPO7g0XaoKP9HrfT1lafUl6o0LDzGsiBwnudwTjzt6pG%2FvyMFHX5xBndnq4Iak1rK6ruNNDfWVzEWH2iNebonaJb2KZRYFB8MH45vDJxDvqPGmpJdh8we5CPT3wC9n9saimD4ICvhxA6%2Bm1gpTcslVyxnUzwcBfq3e9ahv63SLepomeo%2BJeosS9ZbGJYgYVkQOkHgC6SPDMEcHbIsIxSuldYjNzESNvcf7xyeGYlxkADaJwFqzMR1%2FfjsD0eODcO%2FsvvjJqIDLrys4V427lu6%2FajkbXghHzJSedq%2BnAQPg3sUNT8igsiqYk3Qc6aK%2BiBhWRI5yJBV7Rg9GlFnBerFBfjA8FO9DxV69Fal905G7DbDYepxuBh1mTOqhdRm5Fdi0PRdbd51G%2FN7vENLXB3Frb8XNN3mJVpMR654dcdVyIofa50oZc0TrKycEfSw6hMmTKRRgnioahAbRopJBxaWGGFZETmphid4k%2BRsknYpZYvhhqx4Ds0LRJ8LOV2vo18sbY8L98O2JCzj4TTGy8ypRcdGsPedu1OP2CP%2Brvtfft21nH4pWkXqt57OgPZ8rPniG%2BPQHRGsq%2BsgxHOWSQgwrIldoZdVvkNu0UW4uAH7ou3PV2nGrv%2B88hYLz1doxqyfvH6Qdw7p0%2FCq%2FoAqRd%2B25ahlt3Q0oWke8XBIxrIjo2l59JxN%2F%2FOsJmC0qxkYG4MXHh2LqhCAYfnDqe5dOblqAXU1YcCdWJhHDisg%2BCs%2FX4FcxffGr2X0wqN%2FVA6drZzc8cV8IK4yIYUXkeH%2F4Ha9WROQM%2FFEwERExrIhcfiXQK9oll1xRxcU6ziAihhUR0LWT0VxUWuOS05aRU8YZRMSwIgI6ebtdyC%2BodMlpSzx6XusrKsphhx85EzGsiNoJf1%2F3fQmmsy45bbsTzmh9VUGh6J3l3CKGFVEHlXmq6qVP9uaZa%2BusLjVd2XnlyMmruLSmZom%2Fpzi3iGFF1EF9eagyyeimM8XFZ7vUdD21Kun7ByouyoYW5xYxrIg6sPzzlQs2xqVXJ6eVuMT0rH4jBSdzyy8FVZboIqw67OCcIoYVUQeWJLKhtk6NWfbsQYuzA0sG1dbGrTwFCQrwNS9ISwwrIsKhZMuuiirzfUuW71fXbT4ORx%2FDkseo7n7oqyuDSsV74u8UVY8nOYeoI%2BPllogaOZyKtyNDrbp3d5zcEPdRtiFqRACix%2FdCSHBn9OnhY9NxVVabkZZVhsRvzuGLhDMirCqufIEMKnlPKgX3mETLj3OHGFZEdJnpON4MH6LmW2ot2%2FYlntWLztOhEyCPUSlIEEPRqg6Lko7hM84V6ui4G5CoqRaWCAhFD3mr389FeBQpQIroTosQuWiH0VWIsrN1qhgX8KEKuIvHPuKr5G2HGVREbFkRXUtS%2Fa63mdpdiK2IEcOTYRVxpcDbxqPyUVVcUBV0FcOJqh4rTTyZgohhRdQaje5C%2FAxrg8g5uBuQiIgYVkRERAwrIiJiWBERETGsiIiIGFZERMSwIiIiYlgREVFHxx8FEzVBNd3vtv3AwUdS00sWpp0sHVhcWut%2BrrhasfV4%2FH3XAZqkAAAgAElEQVTdzd6ebhcC%2FNz3yTsWyxtBsvaJGFZEzdq9KeKBR1%2FdGZueXeY9beLNuGtpbwR190J3fw%2Bbj6uwqNpQUFgZkGAqjMnNPzVj%2BgQvk7wRZBKvsk7EsCJqsjWlPqfbunbHltUbUmYvmBWM1ctHwehm3z3lMgBlNzzUD4vnhhji4rOjNsalp0QOU2eZki2fcq4Q1eMxK6IGMqje2pIx%2B%2BUVo7BwZrDdg%2BqH5PjkeNc%2FH%2BXhZVQ%2BjgzDvZwrRAwrosvkrj%2FRopkd%2B3Qkhg3ydeq0yPG%2FtjJKbzDoNo5kYBExrIgkeTJF%2FJ7TsQtEq8bZQdU4sObP6K8YoLwuWlhTOZeIYUXUPtnszDx51l9mbrn33Gn9XOoDLpk3CEajzmBVsSViKIJdrd6IGFZEzRjTCzY7NS81o2RR9PieDj9G1Rw5PaNv6SbTxQAL1rhavRExrIiaUeWDQFuVlZZVFjw2MtAlP%2BfkcT1kz1N0Y%2BUdi12p3ogYVkTN0CsYYquyioprPHoGebnk5wwb0LV%2BQEGhzooYV6o3IoYVUXMUTLRVUcVlNYp%2FF3eX%2FJi9Ai%2BHqI%2FoJrlSvRExrIiao2L%2BhL62Of5itajQ6V3zvINL06Wq8BO93tdTllZfot648BDDishxkss98XjHaUhqLavrOt7UUF%2FJXHSoPeLllqhd0qtYZlFwMHwwvjl8AvGOGm9ufiXyCqqaXplEK%2BjWEX7acE2tFabkkquWM6ifDwL8Wr3rUd%2FW6Rb1NE30HhP1FiXqLY1LEDGsiBwg8QTSR4Zhjg7YFhGKV0rrEJuZiRp7j%2FedD3KxbnNmk8%2F5eBmQva%2F%2B97sF56px19L9Vy1nwwvhiJnS0%2B71NGAA3Lu44QkZVFYFc5KOI13UFxHDishRjqRiz%2BjBiDIrWC82yA%2BGh%2BJ9qNirtyK1bzpytwEWW49zxp09ENLPp%2BmVyfD9XvUAPyPWPTviquVEDrXPlTLmiNZXTgj6WHQIkydTKMA8FUgxiBaVDCouNcSwInJSC0v0JsnfIOlUzBLDD1v1GJgVij4RdrhaQ5%2BeXvDr6tbkc4ry%2FejcjXrcHuF%2F1XL8fdt29qFoFanXej4L2vO5YkoyxKc%2FIFpT0UeO4SiXFGJYEblCK6t%2Bg9ymjXJzAdDY2ncyW7QbML%2BgCpF37blqOW3dDShaR7xcEjGsiOjaxt8aAE%2BPps9zcHP7Pke6dHLDk%2FcPumo5YcGdWJlEDCsiO4XV6G5a15yund3wxH0hrDAiG%2BHvrIiIiGFFRETEsCK63pVAr2iXXHJFFRfrOIOIGFZEQNdORnNRaY1LTltGThlnEBHDigjo5O12Ib%2Bg0iWnLfHoea2vqCiHHX7kTMSwImon%2FH3d9yWYzrrktO1OOKP1VQWFoneWc4sYVkQdVOapqpc%2B2Ztnrq2zutR0ZeeVIyev4tKamiX%2BnuLcIoYVUQf15aHKJKObzhQXn%2B1S0%2FXUqqTvH6i4KBtanFvEsCLqwPLPVy7YGJdenZxW4hLTs%2FqNFJzMLb8UVFmii7DqsINzihhWRB1YksiG2jo1ZtmzBy3ODiwZVFsbt%2FIUJCjA17wgLTGsiAiHki27KqrM9y1Zvl9dt%2Fk4HH0MSx6juvuhr64MKhXvib9TVD2e5ByijozXBiRq5HAq3o4Mtere3XFyQ9xH2YaoEQGIHt8LIcGd0aeHj03HVVltRlpWGRK%2FOYcvEs6IsKq48gUyqOQ9qRTcYxItP84dYlgR0WWm43gzfIiab6m1bNuXeFYvOk%2BHToA8RqUgQQxFqzosSjqGzzhXqKPjbkCiplpYIiAUPeStfj8X4VGkACmiOy1C5KIdRlchys7WqWJcwIcq4C4e%2B4ivkrcdZlARsWVFdC1J9bveZmp3IbYiRgxPhlXElQJvG4%2FKR1VxQVXQVQwnqnqsNPFkCiKGFVFrNLoL8TOsDSLn4G5AIiJiWBERETGsiIiIYUVERMSwIiIiYlgRERHDioiIiGFFREQdHX8UTNQE1XS%2F2%2FYDBx9JTS9ZmHaydGBxaa37ueJqpa3l%2Bfu6m7093S4E%2BLnvk3cmljd8ZC0TMayI2mz3pogHHn11Z2x6dpn3tIk3466lvRHU3Qvd%2FT3aXGZhUbWhoLAyIMFUGJObf2rG9AleJnnDxyReTZ2IYUXUqtaU%2Bpxu69odW1ZvSJm9YFYwVi8fBaObbfaUy6CT3fBQPyyeG2KIi8%2BO2hiXnhI5TJ1lSrZ8ytonujYesyJqIIPqrS0Zs19eMQoLZwbbLKh%2BSJYry1%2F%2FfJSHl1H5ODIM97L2iRhWRM2Su%2F5ES2d27NORGDbI1yHjlON5bWWU3mDQbRzJwCJiWBFdizyZIn7P6dgForXjqKBqHFjzZ%2FRXDFBeFy2sqZwbRAwrurEotipInvWXmVvuPXdaP6d8kCXzBsFo1BmsKrZEDEVwe6k3IoYVUTPG9IKHrcpKzShZFD2%2Bp92OUTVHjnf0Ld1kihhgwZr2Um9EDCuiZlT5INBWZaVllQWPjQx06ueZPK6H7HmKbqy8M3F7qDcihhVRM%2FQKhtiqrKLiGo%2BeQV5O%2FTxhA7rWDygo1FkR0x7qjYhhRdQcBRNtVVRxWY3i38XdqR%2BnV%2BDlsPQR3aT2UG9EDCui5qiYP6GvbY6%2FWC0qdPqWnXfw%2BEvf4q6l%2B7H2nUzbrogN41dV%2BIleb3tUmVZfot648BDDishxkss98bijR5qRU4H%2FJBUh77sqOzV8tJaVXY4rNdRXMhcdao94uSVql%2FQqllkUHAwfjG8On0C8o8br5anX%2Bt5e%2Bsv%2FO55ZhuLSuiZf39nHgGGDurT649l6ukU9TRO9x0S9RYl6S%2BMSRAwrIgdIPIH0kWGYowO2RYTiFZEVsZmZqLF%2FWBmu6EvPv3YcX%2FynsMnXjxrmi11vjXVaPQ0YAPcubnhCBpVVwZyk40gX9UXEsCJylCOp2DN6MKLMCtaLDfKD4aF4Hyr26q1I7ZuO3G2AxeZh5aG%2Foi8tnd8fM%2B7s0eTrA3wde%2BLGHNEqywlBH4sOYfJkCgWYpwIpBtGikkHFpYYYVkROamGJ3iT52ySdilli%2BGGrHgOzQtEnwg5Xa%2FBu2A3o1Wg34JABndH%2FZu8mX280tu2wsGj9qG15Xxa09%2BWKD54hPv0B0ZqKPnIMR7mkEMOKyBVaWfUb5DZtlFsTDFPGBckbKWLUML%2FL%2F3vo%2BW9svhtQtIJ4WSQihhVR23xXWH8W4BnRHxrSWRuePbUXwoc0fQHcHt15dSMihhWRg7330WkkHi3Goll9MHls%2FRnmMVN6smKIGFZEruOTjbezEoicgD8KJiIihhWRy68EekW75JIzVVys44wgYlgRXV3XTkZzUWmNU6chI6eMM4KIYUV0dZ283S7kF1Q6dRoSj57X%2BoqKctjhx8xEDCuids7f131fgumsU6dhd8IZra8qkD%2FYOsu5QsSwIrpC5qmqlz7Zm2eurbM6ZfzZeeXIyau4tEZmib%2BnOFeIGFZEV%2FjyUGWS0U1niovPdsr4n1qV9P0DFRdlQ4tzhYhhRfQj%2BecrF2yMS69OTitx6HhXv5GCk7nll4IqS3QRVh12cI4QMayIfiRJZEZtnRqz7NmDFkcFlgyqrY1bcwoSFOBrXniWiGFFdFWHki27KqrM9y1Zvl9dt%2Fk47HUMSx6juvuhr64MKhXvib9TVD2e5Jwg%2BjFebomokcOpeDsy1Kp7d8fJDXEfZRuiRgQgenwvhAR3Rp8ePm0qs7LajLSsMiR%2Bcw5fJJwRYVVx5QtkUMl7Tym4xyRaeJwLRAwromaZjuPN8CFqvqXWsm1f4lm96DztMiJ5jEpBghiKVnVYlHQMn7H2iZrG3YBETbWwRHAoeowQg5%2BLUClSgBTRnRbhcvE6iq0QZWTrVFEm8KEKuIvHPuIr422HGVREbFkRtUVS%2FS65mdpdiK2IEcOTYRVxpcC7jUX6qCouqAq6iuFEVY%2BVJp5MQcSwIrKFRnchfoa1QeQc3A1IREQMKyIiIoYVERExrIiIiBhWREREDCsiImJYERERMayIiKij44%2BCiZqgmu53237g4COp6SUL006WDiwurXU%2FV1yt2Ho8%2Fr7uZm9PtwsBfu775B2L5Y0gWftEDCuiZu3eFPHAo6%2FujE3PLvOeNvFm3LW0N4K6e6G7v4fNx1VYVG0oKKwMSDAVxuTmn5oxfYKXSd4IMolXXydiWBE12ZpSn9NtXbtjy%2BoNKbMXzArG6uWjYHSz755yGYCyGx7qh8VzQwxx8dlRG%2BPSUyKHqbNMyZZPOVeI6vGYFVEDGVRvbcmY%2FfKKUVg4M9juQfVDcnxyvOufj%2FLwMiofR4bhXs4VIoYV0WVy159o0cyOfToSwwb5OnVa5PhfWxmlNxh0G0cysIgYVkSSPJkifs%2Fp2AWiVePsoGocWPNn9FcMUF4XLaypnEvEsCJqn2x2Zp486y8zt9x77rR%2BLvUBl8wbBKNRZ7Cq2BIxFMGuVm9EDCuiZozpBZudmpeaUbIoenxPhx%2Bjao6cntG3dJPpYoAFa1yt3ogYVkTNqPJBoK3KSssqCx4bGeiSn3PyuB6y5ym6sfKOxa5Ub0QMK6Jm6BUMsVVZRcU1Hj2DvFzyc4YN6Fo%2FoKBQZ0WMK9UbEcOKqDkKJtqqqOKyGsW%2Fi7tLfsxegZdD1Ed0k1yp3ogciT8KpvZJxfwJffHfX%2BWg%2BnqLslpU6PQtO%2B%2FgQlkdXvrrCSSYzqOqxopeQZ5YMq8%2FfvbToB%2B99p0PcvGPj07hXHEtfLz0mPKTIDxxX4g8aaLl3yYbpktV4adc5%2Foq6sujXNQbFx5iy4rIcZLLPfG4o0f6%2BB%2B%2FxVvbc9DrJi8siumDA0eK8OvlJpz%2BruqK1%2B36qgCPv%2FQtcs9U4rf3DERFpQV%2F3pSBN7Zkt7FBpLWsrut4U0N9JXPRIYYVkYPoVSwTvcfCB2OaI8d7SoSPFDG0Kxb%2Fv77Q6RRYrarW1GssN7%2F%2BdQFd3TF%2F%2Bs0YMrCz9thiVa%2FrY7f1jQ319FhDvRExrIgcIfEE0q0K5igKNkeEYsWAAXDIQaeHFw2AQa%2FglbcyMPs3ByHGjyfvH6S1fU5%2FV4naOqv2ujlTe6J3Dy%2BkZZdj2uL%2FYPd%2FzmL0LX6YPvEm7XVyd6IjyHqR9SPrSdaXrDcuPdQe8ZgVtVtHUrFn9GBEmRWs7%2BKGB8ND8b5o4OzVW5HaNx2520RDxtbj9DDq4eNt0MLGlFKCudNuxu9%2BHYKet32COrMVe94dh%2BGDu0A2oLr5uWstMfm6noGeeHtVJJ5fl4otn%2BThwV8G47mHw2xeJ3NE6ysnBH0sOoTJkylEls4Tk5JiUBGVdJxBRQwrIqe1sERvkvwNkk7FLNn4seoxMCsUfSJsfLWGc0U1%2BPVTJlRWW%2FDacyPxh%2FXHERd%2FGjW1Vqiqqu0SlCdcSL994SiSREgt%2Fn%2F9cKawSjuGFX1PAm7qXv%2BbXNnqagvRSrrmfsSs%2Bv2RueKDZ4hPf0C0pqKPHMNRLinEsCJyhVZW%2FQa5TRvl5gLgktSTZVpQSZNu746fjArA3IcP4sN%2F5mv%2Fu%2FtnveDX1agNJx0r0frBvb3xwmND8PSaFO3EDLkLsJu%2FO2ZO7tmmzylaR7xcEnVIPGZF1EJhwZ3h4V5%2FjsOCxxKx79A5jBnp%2F32QpFy4fGLFyLD6H%2FOufiMNf9uSjZD%2BneDjVf%2FdsLS8DnsPFLJCiRhWRLYnW0Rv%2FjECPbp74OvkEjz8%2FDd4P%2F40lv0yGONHd0NmbgWm%2FjoBR4%2BX4k8rbtFaXiVldfifPx3DU6uTETHUVzu%2BZTareOB%2FDmPd5kxWKlELcTcgUStMHhuIyZ9MQl5BlXacKjDA46oXwP3gL2NQXFqLi5VmdPJ2Q9fObtr%2Fn1o6iBVJxLAisr9LJ1I0x6%2BLUeuI6PpwNyBxJdAr2iWXXFHFxTrOICKGFRHQtZPRXFRa45LTlpFTxhlExLAigjyedCG%2FoNIlpy3x6Hmtr6gohx1%2B5EzEsCJqJ%2Fx93fclmM665LTtTjij9VUF8lz3s5xbxLAi6qAyT1W99MnePPOl6%2Fq5iuy8cuTkVVxaU7PE31OcW8SwIuqgvjxUmWR005ni4rNdarqeWpX0%2FQMVF2VDi3OLGFZEHVj%2B%2BcoFG%2BPSq5PTSlxiela%2FkYKTueWXgipLdBFWHXZwThHDiqgDSxLZUFunxix79qDF2YElg2pr41aeggQF%2BJoXpCWGFRHhULJlV0WV%2Bb4ly%2Fer6zYfh6OPYcljVHc%2F9NWVQaXiPfF3iqrHk5xD1JHxChZEjRxOxduRoVbduztOboj7KNsQNSIA0eN7ISS4M%2Fr08LHpuCqrzUjLKkPiN%2BfwRcIZEVYVV75ABpW8J5WCe0yi5ce5QwwrIrrMdBxvhg9R8y21lm37Es%2FqRefp0AmQx6gUJIihaFWHRUnH8BnnCnV03A1I1FQLSwSEoscIMfi5CI8iBUgR3WkRIhftMLoKUXa2ThXjAj5UAXfx2Ed8lbztMIOKiC0romtJqt%2F1NlO7C7EVMWJ4MqwirhR423hUPqqKC6oCeROsRFWPlSaeTEHEsCJqjUZ3IX6GtUHkHNwNSEREDCsiIiKGFRERMayIiIgYVkRERAwrIiJiWBERETGsiIioo%2BOPgomaoJrud9t%2B4OAjqeklC9NOlg4sLq11P1dcrbS2HH9fd7O3p9uFAD%2F3ffKOxPJGj6xdIoYV0XXbvSnigUdf3Rmbnl3mPW3izbhraW8EdfdCd3%2BPVpdVWFRtKCisDEgwFcbk5p%2BaMX2Cl0ne6DGJV1EnYlgRtak1pT6n27p2x5bVG1JmL5gVjNXLR8Hodn17ymXAyW54qB8Wzw0xxMVnR22MS0%2BJHKbOMiVbPmWtE7UMj1kRNZBB9daWjNkvrxiFhTODrzuofkiWJ8td%2F3yUh5dR%2BTgyDPey1okYVkQtJnf9iRbP7NinIzFskK9dxyXLf21llN5g0G0cycAiYlgRtYQ8mSJ%2Bz%2BnYBaLVY%2B%2BgahxY82f0VwxQXhctrKmcC0QMK7oB80V0iq0Kk2f9ZeaWe8%2Bd1s%2BhH2LJvEEwGnUGq4otEUMR7KDRKg31R8SwIrKz6jG94GGrwlIzShZFj%2B9p82NUzZHjG31LN5keBliwxhHjbKi3ai5CxLAisr9zVT4ItFVhaVllwWMjA53yQSaP6yF7nqIbK%2B9IbO%2FxNdTbOS5CxLAisjMVSNcrGGKr8oqKazx6Bnk55bOEDehaP6CgUGdFjL3HJ%2BtN1h%2BXImJYEdmZAhwQfybaqrzishrFv4t7y19fWovT31XCYrny0I%2FVqmr%2FL75Q2%2BKyegVeDkkf0U1yQOVN1OqPiGFFZF9WHXaI5tX8CX1tc9zKKkJHp2%2F5%2BRp%2F%2FGsawqfvQcH5Kw%2F9lFaYtf8%2F8%2BdjLV8BG8arqvATvd72rDetvkS9afVHxLAisq8jx3BU9JLLPfH4DdRalC0rux44a6iv5Ib6I2JYEdmbXsUy0XssfDCm3Ugfy14FN9TTYw31RsSwInKExBNItyqYoyjYHBGKFQMGwJ218mOyXmT9yHqS9SXrjbVC7REvZEvt1pFU7Bk9GFFmBeu7uOHB8FC8DxV79Vak9k1H7jbA0tHqZI5oneWEoI9Fh7CGkynmqUCKQUVU0nEGFTGsiJzWwhK9SfI3SjoVs8Tww1Y9BmaFok%2BEDa9y4SiiFXRdV5fIqr86Ra744Bni0x8QraloHqMihhWRq7Sy6jfIbdooX29A2JJo%2FSicm0Q%2FxmNWRETEsCIiImJYERERw4qIiMjZeIIF8RubXmnVJZeWzu%2BPGZN6oJvvlT%2Ft6uRtwM4Nt6F7QMt%2F8lVxsY4zgIhhRdS8rp2M5qLSGkM3v5ZdarB%2Fb2%2Bt%2B9HKJMLu9gj%2FVo07I6eMM4CoJV8qWQXU0XXydruQX1DplHEnHj2v9RUV5eiAP2ImYlgRtZC%2Fr%2Fu%2BBNNZp4x7d8IZra8qKBS9s5wbRAwroiZlnqp66ZO9eebaOqtDx5udV46cvIpLa2KW%2BHuKc4OIYUXUpC8PVSYZ3XSmuPhsh473qVVJ3z9QcVE2tDg3iBhWRFeVf75ywca49OrktBKHjG%2F1Gyk4mVt%2BKaiyRBfBmyISMayIrilJZEdtnRqz7NmDFnsHlgyqrY1bcQoSFOBrXnCWiGFF1KxDyZZdFVXm%2B5Ys36%2Bu23wctj6GJY9R3f3QV1cGlYr3xN8pqh5Pcg4QXR1%2FZ0XUyOFUvB0ZatW9u%2BPkhriPsg1RIwIQPb4XQoI7o08Pn1aVVVltRlpWGRK%2FOYcvEs6IsKq48gUyqOQ9pxTcYxItO9Y%2BEcOKqMVMx%2FFm%2BBA131Jr2bYv8axedJ42HYE8RqUgQQxFqzosSjqGz1jrRNfG3YBETbWwRIAoeowQg5%2BLcClSgBTRnRYhc7ENxVWI92brVFEW8KEKuIvHPuKr4m2HGVREbFkRXY%2Bk%2Bl1zM7W7EFsRI4YnwyriSoF3K4vyUVVcUBV0FcOJqh4rTTyZgohhRWRLje5C%2FAxrg8g5uBuQiIgYVkRERAwrIiJiWBERETGsiIiIGFZERMSwIiIiYlgREVFHxx8Ft5Bqut9t%2B4GDj6SmlyxMO1k6sLi01v1ccbXyw9f5%2B7qbvT3dLgT4ue%2BTd6CVN%2FZj7RERMazsbvemiAcefXVnbHp2mfe0iTfjrqW9EdTdC939PX702sKiakNBYWVAgqkwJjf%2F1IzpE7xM8sZ%2BSbyqNhERw8ourSn1Od3WtTu2rN6QMnvBrGCsXj4KRrdr7zmVASa74aF%2BWDw3xBAXnx21MS49JXKYOsuUbPmUtUpE1Ho8ZnUNMqje2pIx%2B%2BUVo7BwZnCzQfVD8vXyfeufj%2FLwMiofR4bhXtYqERHDymbkrj%2FRIpod%2B3Qkhg3yva6y5PtfWxmlNxh0G0cysIiIGFa2IE%2BmiN9zOnaBaBVdb1A1Dqz5M%2ForBiivixbWVNYyEVHHCytVdIqtCpNn%2FWXmlnvPndbPphO5ZN4gGI06g1XFloihCObiRzcApWH9I2JYtUD1mF7wsFVhqRkli6LH92z1MarmyPJG39JNrt0GWLCGix%2B1dw3rXTVrghhWLXOuygeBtiosLasseGxkoF0mdPK4HrLnKbqx8g60XASpPWtY786xJohh1QIqkK5XMMRW5RUV13j0DPKyy7SGDehaP6CgsOFW6UTtllzv5PrHmiCGVQsowAHxZ6Ktyisuq1H8u7jbZVp7BV4OQR%2FRTeIiSO185ZuorX9EDKvmWXXYIZpX8yf0tc1xK6tFhU7fsvM1Hn%2FpW9y1dD%2FWvpPZsgpvKFdV4Sd6vbkIUnulrW9ivdPWPyKGVfOOHMNR0Usu98Tjjh53Rk4F%2FpNUhLzvqlrbGpQtq0AugtReNaxvyQ3rHxHDqiX0KpaJ3mPhgzHNkeP18tRrfW8vfZsmm4sgtUcN69ljDesdEcOqpRJPIN2qYI6iYHNEKFYMGAB3R4zXy9NwRZ%2FoRibXK7l%2ByfVMrm9yvWOtkCPcUFvYI6nYM3owoswK1ndxw4PhoXgfKvbqrUjtm47cbYDF5mHlob%2BiT3QjmSNa%2Fzkh6GPRIazhZIp5KpBiUBGVdJxBRQyr62phid4k%2BRsmnYpZYvhhqx4Ds0LRJ8KGV7m4xLthN6BX23YDQnxL5a%2F%2FyWVl1V%2BdIlesOBli7TkgWlPRPEZFDCtbtrLqV6g2rVStCZAp44LkDRcxaphfm6ZTfDtVuBgSEV0bL2R7nb4rrD8L8ExhFSuDiIhh5Zre%2B%2Bg0Vr%2BRhn%2F%2B%2Bywrg4jITngK23X6ZOPtrAQiIrasiIiIYUU%2FrhS9ol1yyR4qLtaxgomIGFbXr2sno7motMYuZWfklLGCiYgYVtevk7fbhfyCSruUnXj0vNZXVJTDDj9SJiJiWHUQ%2Fr7u%2BxJM9jm7b3fCGa2vKigUPZ5CSETEsGqbzFNVL32yN89cW2e1abnZeeXIyau4VPNZ4u8p1jYREcOqTb48VJlkdNOZ4uKzbVruU6uSvn%2Bg4qJsaLG2iYgYVm2Wf75ywca49OrktBKblLf6jRSczC2%2FFFRZoovgTeuIiBhW1yVJZEttnRqz7NmDlusNLBlUWxu30hQkKMDXvCAoERHD6rodSrbsqqgy37dk%2BX513ebjaO0xLHmM6u6HvroyqFS8J%2F5OUfV4kjVMRNQyvNxSMw6n4u3IUKvu3R0nN8R9lG2IGhGA6PG9EBLcGX16%2BFzx2spqM9KyypD4zTl8kXBGhFXFlYXJoJL3BFJwj0m03Fi7REQMK5sxHceb4UPUfEutZdu%2BxLN60Xm2qgB5jEpBghiKVnVYlHQMn7FWiYhajrsBW9rCEgGj6DFCDH4uwqdIAVJEd1qE0MUmXl4hnsvWqeK1wIcq4C4e%2B4ivBrcdZlAREbFlZU9J9bvuZmp3IbYiRgxPhlXElQLvH7zUR1VxQVXQVQwnqnqsNPFkCiIihpUjNboL8TOsDSIi%2B%2BNuQCIiYlgRERExrIiIiGFFRETEsCIiImJYERERw4qIiIhhRUREHR1%2FFNxCqul%2Bt%2B0HDj6Sml6yMO1k6cDi0lr3c8XVytVe7%2B%2Frbvb2dLsQ4Oe%2BT955WN7Q0d7TGBEKlXPKtpKOQ2Et0I283WBY3UB2b4p44NFXd8amZ5d5T5t4M%2B5a2htB3b3Q3d%2Fjqu8pLKo2FBRWBiSYCmNy80%2FNmD7ByyRv6Jhk56utm%2F79FmeYjUT%2B5F5WAnWI7UZ7oHfGSHt0w3PfncdKl%2F9WpD6nC%2FMr2rpu0%2FEnpkzoZXzhd%2BGIGtkNgd084e117ZyXz8vXjbolAHdP66ezquiVfLzk%2Fu4ByuEzhWqmver1%2FntncCthI2%2B8%2FX9anbaX5ZW43biRt988ZnUNW9fu2PLWlozZL68YhYUzg2F0a1t1yffJ969%2FPsrDy6h8HBkGfmUn4naD2w2GlW2a8Bvj0mfHPh2JYYN8bVKmLOe1lVF6g0G3cSQDi4jbDW43GFbX1Yw33e8Wv%2Bd07ALxrcZWC1zjBW%2F%2BjP6KAcrr4pvSVNY2Ebcb3G64dli57FlW8qANVOcAACAASURBVOydzNxy77nT%2Btml%2FCXzBsFo1BmsKrZEDEUwV3Oi9q%2BDbDectt12WliN6QUPV13oUjNKFkWP79nmfc3NkeWOvqWbnOsGWLCGqzlR%2B9cRthvO3G47LayqfBDoqgtdWlZZ8NhI%2B07e5HE9ZM9TdGPlnYe5qhO1bx1hu%2BHM7bbTwkqvYIirLnRFxTUePYO87DqOsAFdLzWqC3VWxHBVJ2rfOsJ2w5nbbecds1Iw0VUXuuKyGsW%2Fi3ur3nO%2BuAanv6vEhbK6Fr2%2BV%2BDlhdpHdJMc%2FRnPfFeMulqzzcstOFuC2joziDqalm43VBXatkJ2tbXWVo3D2dsNZ263nRdWKuZP6Ouax62sFhU6fcuPI2bkViBixh789Bf%2F0hbAFlV8Q%2FliwfUTvd6O%2FoxTY55HetYZm5cb88tVOHw0i1su6nBaut1QxEv%2B9HYGwqfvwW%2F%2FcLR1G2wnbje07bXYbne8sAKSyz3x%2BI2wkD7y%2FFFUVluw5qnhGDaoSyu%2FqGjfkAK5qhN1HLG%2FH47hg7tg66487P7P2TY0cBy%2F3WjYXic7q86cdm1AvYplFgUHwwfjm8MnEN9eF7p%2FJZ7H198WI2qEH%2B6a3KPN1eGMaf%2BuoARbdiQgO%2FcsoieF4xdzxl9%2BLuFAKt7f%2Fm9UVtXgzp%2Fegvmzx4lvhPXf6k7lncffNv0TmdnfYeTw%2Fnjg3mh06uTZ6vFX19Tizc1f4ODX6fDz9cE9v7gDI4b3Q86pQnz48UEsXjQJnXzqy931zyTodAqi7wzHzk8OISjQF4e%2BTkNiUgZG3tIfDy35GdyNbtpniv%2FchFnTo%2FB%2F4nXSvQvu5NaRXIpetJBe%2FN1QTLvvP3hlYwYm3R7o0tsNsZ2eJnqPie12lNhup3WollXiCaRbFcwR27%2FNEaFYMWAA3NvjQvfpvgKtP39673Y37f%2B7eit69fDHnRNuwapXPsCH8Qe1%2F%2B%2F9VzIeeuJvmHzHCPxy7k%2Fx3pZ9WLNup%2FZcUUk5Zsz7A7p164yHRUDIY1TzFr8Mq7X1F3y%2F98F1yD11Tguan9wWhgVL%2FoTcvHPoc3M3HE3JwZPPvKO9znQkE%2F%2Fzh39g%2BJC%2B2uOd8Yew5OG%2FoM5swc%2BnjsJnXxzRPoskj8XFvvoB5ixcjaycszhfVM4tI7mkW8UX3P69vZF0rAQF56tdchrldllun%2BV2Wm6v5Xa7w7WspCOp2DN6MKLMCtZ3ccOD4aF4Hyr26q1I7ZuO3G2AxdUXuG%2FTSrX%2BqOG%2B7W5l%2BcsrSzBkcH3IlldUY%2FvO%2FZg5LQpvbPocjzzwc8z4r1u1524K7CoC6kX89oHp2mtkaDy8ZFr9Chc5CKMnPi5aR2m47dbBLR530pGTyMsvwnt%2Fe0xrsY2OGIiEg8fx2e7DWHLPFKxdtRjRs1Zi3euf4P1t%2F8Jra%2B5Hj5v8Lr%2F%2FiUfuwoK7J2jD%2FfoG4p7frMMLK36hPfZwN%2BL%2F%2FvF0m1p7RI40apgvsk5dREpaGYICnH8If45oreWEoI9FhzB5MoUCzBNfQ1MMokWVdNx5QeX0sLrUwhK9SfI3AzoVs8Tww1Y9BmaFok8EXP9eQiUXarW%2Bv%2B%2F1NQydfS%2Bq4H5BomV1QBuWLZJBA7%2FfpRkyoCcuVtbg7LkLDc%2F1%2FL5prlMwMLiH%2BH9Bq8Iq%2FeQZ5J8pxpg7f3%2FF%2FwcNqC%2B7c2cvrH95Cabd%2FYIWnGNGDbqyAOX7RaN%2F3yCUll7UdllKnl5GmwcV7xVG9hDgV7%2FdKC6tdYnlMgtaebli7coQW98DojUVfeQYjrpCXbnM%2FawaKuRoK5L%2BQXs1SVuzAPj41FdhVbUFvp3d2jxOW9zk73oW3IqKKnTt7K0Nd%2FLxQFl51eXnysWwbP34eHtoXVn5lWc8ysc%2BPq0LB1mODMRd25%2B56mu2f7Qfw8L6YOfHB7FUtLZkgDWluLgcXp7u8PQw2m355E0Yb2yjByNE7uERM3moWInatIenLetfZWV90d6eBi6XzXD5C9nKBeXrdGTJkzAOH8djpXXoK%2BbOPnlyxsgw3OHs6evbs34Dn5Je2u5mfnVV%2FW%2FC5IkO%2F9j%2BL0y5Y6T2eOK44drJFRZL%2FW9ANm%2F5EuEj%2BqNLF2%2FcMX44Pv%2FiCM4VlWnPfZOcjYzMM7g9KrRV45avl620%2BM%2B%2Bvvw%2FeWLFt8dytOEdHx3Qdi3ufH85RkUOxMO%2F3whV%2FX5bUFZWH5hmsxV%2FefNT%2FNfkiMsngBC1htyOyO2J3K7I7Yvczsjtjdzu2PtQxKXtRv%2BbvTgj2kvLqqUyMyH39bwgzyIUSbtNHvNy5kG%2FiWO64cN%2F5mPHp%2FmYPLZ9nYH%2B0BNvaLvTSkorMGHs0MtnzT36m%2BlY8shfcPvkp7Sz8apr6vDOhoe15%2BSuvgVzJ2DCz%2F4bA%2Fv3QFZ2Ada8cA%2B6%2BXdu1bjl2X9vvrYMj694G8%2B8%2BD6MbgbU1NZh7ar7cDztNFa%2BFIcdf39KO%2F704jO%2FxNSYlXjtjV3ayRhagL7%2FJd589wvRoq3F0NDeeP1PD3Btpja1qCwqtonvQQsdfVZybn4lTCkl6NHdA4ODO3Nm3GhhdYlcsESz%2BxXxjeg18XCys6Zj5uSe%2BMP6E%2Fh473d4NLMMoQPax0J3dP%2BftX7%2BmSK4GQ3oHvD978O8vdzx97%2F9FoXnS1FbY0avnv5XvPd3y2bg%2FkWTcaHsIrp366KdMn7Jf%2F75x1a1rg58sVo73dzgpr8i8L498OoV0%2FOvT1%2B84r3LRGjJk0EuVlZfMe0RI4NxaE8s12xqkYbtxyvO%2BPlM7N%2FStKtZLJ0fDO4UuIHDSupUhTXlnnhQnpzhrIOA7kYdXnxctEqeMuE3zx7BR2%2Fcjk7e7adae%2Fbwv%2BpzjUPgR3XfyfOaJzGsfvVD7TdQTZEnZWzd9MTlxzcFte1MShlisiNqC%2B1CsFYME9uR6Y4et9wbI38QHDawM%2B6d05cz40YPq69yUB0Rhn80XNDRZmElL2nSmksu%2FfyOm7B5zSiUltch77vKFrWuKi7W3dAL1pOPzLRb2YsX3nnFaexEbVrP5XZDwT%2FkdsSR2w3ZmpI%2FS1z7zAjcFu6vfeFtqRt9u3HDhlX9nMdeMd8ftWWRXTsZzUWlNYZufi3%2F3cPU8UGtGkdGThm3Fm00dkwYK4FssOnAGEXFnx293ZC7%2FGKm9GzTODrydqPd39ZefJE5JuZ9iC3L7OTtdiG%2FoNKu05149Hz9gqtCXmLBwk0HkWPJ7YbcfnC7wbByCM8KyKtAdrNlmf6%2B7vsSTGftOt27E%2BqveK4qKBS9s9x0EDlct4btB7cbDCv7O5Cn7W%2B26XVKMk9VvfTJ3jxzbZ3VLtOcnVeOnLyKS3NA3k%2FjFLcbRA7n0bD94HaDYeUQKmx8WaYvD1UmGd10prj4bLtM8FOrkhpP%2FUX5hYnbDSKHUxq2H9xuMKzar%2FzzlQs2xqVXJ6eV2LTc1W%2Bk4GRu%2BaUFLkt0EVYddrDGibjd4HaDYdVqSWLZqK1TY5Y9e9BiqwVPLnBbG3%2FrUpAgvtp97SoXiiQibjcYVu3QoWTLrooq831Llu9X120%2Bjrbui5b7mu9%2B6KsrFzgV74m%2FU1Q9nmRNE3G7we3GtRm4aF3b4VS8HRlq1b274%2BSGuI%2ByDVEjAhA9vhdCgjujTw%2BfJt9TWW1GWlYZEr85hy8SzoiFruLKF8gFTl5BXsE9JvFNjLVMxO0GtxsMq%2BtmOo43w4eo%2BZZay7Z9iWf1omvbzZLkvmbRhBdD0aoOi5KO4TNbT2vkT%2B7lDCPiduOGw92ALf2mJBYQRY8RYvBzsfAUKUCK6E6LhejiNd5WIV6TrVPFe4APVcBdPPYRXxFuO2yHBU7e24b3XSLidoMtqw4uqb7pPVO7q3H99QgnwyoWOwXeV3mLj6rigqqgqxhOVPVYaeLJFETcbnC7wbByhEZ3NX7GJVcOtq6IuN24wXA3IBERMayIiIgYVkRExLAiIiJiWBERETGsiIiIYUVERMSwIiKijo4%2FCm5CRKjtbsh2o7P3D5BV0%2F1u2w8cfCQ1vWRh2snSgcWlte7niquvOk5%2FX3ezt6fbhQA%2F933yzq3yhnhcXtrP%2FCZiWLWS6d9vsRKaYe%2BL5u7eFPHAo6%2FujE3PLvOeNvFm3LW0N4K6e6G7v8dV31NYVG0oKKwMSDAVxuTmn5oxfYKXSd4QL8nOV6nuCMsLL5JMDCtq961QW37jVtXndFvX7tiyekPK7AWzgrF6%2BSgY3Vq2x1oGmeyGh%2Fph8dwQQ1x8dtTGuPSUyGHqLFOy5VPOMdeb30QtwWNW5HJkUL21JWP2yytGYeHM4BYH1Q%2FJ98n3r38%2BysPLqHwcGQY2DYgYVkTXT%2B76Ey2h2bFPR2LYIF%2BblCnLeW1llN5g0G0cycAiYlgRXQ95MkX8ntOxC0RryFZB1Tiw5s%2ForxigvC5aWFNZ20QMK2fhPvR2Tp71l5lb7j13Wj%2B7lL9k3iAYjTqDVcWWiKEIZo13aNxeMKycY0wveHB2tm%2BpGSWLosf3bPMxqubIckff0k1upQywYA1rvOPi9oJh5TRVPgjk7Gzf0rLKgsdG2nc2Th7XQ%2FY8RTdW3rmVtd4xcXvBsHIavYIhnJ3tW1FxjUfPIC%2B7jiNsQNf6AQWFDbcYpw6I2wuGlfMomMjZ2b79%2F%2FbOAyyKo43j%2F7uj92oBVFREsSJYsEWDitixJcaQaLArltgS002M%2BWL0Uz81GluixohRo7HEFo0aY0GwgShgQFRURKR37u6bmYMTjCgQODh4f8%2Bzt3u7s7Ozs7Pvf9%2BZ2dknKdkSa3P9Uu3z%2BEk27j7IQFJKbonCO9RWi6EJm3pTrtdQyF5oHdXnpWAlRvVwxIcnbyNLk4ed9cEm3Ln3WCzbWJuiWRMHDB3UCfUdbNRhNmw5hsO%2FX%2F7Hvsu%2B8kM9exuMGL0YymcG7Onb2w3WVqb4cccp1YXSkSJg0xxkZefAd%2FxymJsZ4bvlU8R6zp4D5xH3KAmT%2FLyRlp6FMZP%2F94%2FjdWzXBHOnD8HufeewfdefYp2RoR4a1KsFL09XdOvcvFIvoUKuhFRW8nbvyJg09PI9DV1dKfas6QQLM%2FOXP53lx8%2Fy20qi4fIfHROHuR9vVv9f8MFItGhWHx9%2B8SPCI%2B%2BLdVaWJnB2ssPQgR5o5FhHHXbbzlPYs%2F%2FCP%2BJc9ImvCP%2FWhOWQK%2BSiTJiaGIptJ8%2BE4uyFm%2FDz7Qn%2FueuLTVdBOmoKzE4YpDJ7QeafxKqyCEk1xBw2X6jJg14NjUZ%2Fr3bo1KEpHj1Oxu9%2FXEXvwZ9g5TcThAAUGCkLcyOMfatXkX1trM3E%2FFxgOJYt8oODvbV6W53alrCxMkNqaia%2B%2B%2F6IECqOnBn0c4E30czZHgG7T8P39R5ifez9J4i5%2B0gs5%2BXKRZgNK%2F3FcQuwsjTND5sApUKBOdN9kJ6RjUtXozBt7jr0erUNlix8R2su%2BIzPryIjS471H7uiVVPzUu0rUXlWhppMr0Ndayz86E30HPQxDuz4CE6N6qoKblgMOro7w%2FOVVkh4korjp66hz5AFWPLlGAzu11GEuXM3Hvp6OvCf0K9InHXrqLr4X7wUCXs7K1FW5kzzUXmdj1NwI%2FweLCyMMdt%2FkKps5Ckw0m8JVi2ZgDq1VFWi9exsapTRy7cTIfw2IwkgsdI4MiX85RKcd2uGK5du4oAmj920iT0Tq2ZimRuXA4cvYvq89fjr2H9gnS8QXHwKwjyPNq0aiifkZ%2BHela6urIiQcd6bOQzzF2zFcJ%2FOMNDXe26c7dycYJsviM%2BLtyA9vXq0wTvs6dt76ALs3PMXRgzpUuWv9%2BnAx7h47Qk8XK3g42VX5mKjyTTrMrHhglIgMvp6uuptXLgKrscA7%2FYY2LcDJkxfjfZtm8CurmofW1vzF5Yh7jXPnL8RY970FA86BfDyUbBfbk6emLu1aSQ86poGsw8DeIUIsxcezF6EkwRoD9WmzYo5EhEKCUZIJNji7oKPnJygX1lp4caGG5gjhar%2BHsYlCm%2Bn8JSZlfPUQwuJVq%2B%2FEBzx0mPwKrvGDetg09bjxYYJunSryPHCI2OLDctF7e2RPbBr3zmtuN6HTj0U81GDqmf1FfeyXJrVw8EjQep18fHJ%2FyhDqWmZ6u3NnB3Qx7MtVq49SJbtGbg94HaB2wduJ7i9oFwhz6rSuByG4%2BwB0iNPgtXmupjq5oLtUOKETIEwxwjE7ATkmkpLg3q2uHc%2F4WnarkVj6ap9RcIUtFlxfth%2BAoYG%2BvlPwrrouN75pcf4YNZw%2BE5cBt%2FXuj93%2B9pNh5lX9vQSizarJkOKjc%2BxQS38zDwrbeBaeLKYt29tWW1vTsdnylDYzbv%2FKEO8zcrU6Wlt5uxpPqIaevxorxpt2EYwr%2Fm2MxrIpWjOO1NIgDeUQKgO86iCb5BQkVhVEQ%2BLzXrzd2ikSgxly9MVMjSJckEDdw2%2BtZ6UnA5LCxP1f95hgrdXFMeyRWOfWw34IlxbN0Sn9k2xZuNhGBv%2F8x3HDav8i60GfB6JiSzNliZlOl9Nf9MpMUnllVpb%2FjsHuip%2Fi4qXocYN66r%2Fd%2B%2FWEsu%2FGvvCfXjHHl6Nu3TVXnTp6FJhaavq3%2FCKgkhfDLvhI9ldf455U96Xr%2BMqmXwSq6rnZakK5tXKuBF5h4orzJNa9hLDUh7MmzEUA19fiNf%2BZTuTUqkUPQoLOoWUlvL4ZERp8t3ERFV0M7PksDTTLfMxNZ3uknL%2FwRPR8Wb%2B7OGl3nfG5IHo5j1f3YGnIqBPhBCahgayLUdSUjJw8GgwXn9nCaZO6AfH%2BhXfgN2kcV3083JXd0UvLbzn4JWQaLwzZSUyM3MwYYx2VB852huLeWhEcrUqQ7z359ETV8TrDL4je6B503qljoN7036%2BvfDDthN0UxLkWRFPmTDjW9XTvrGBaOSeP2sYhgzwKBLm%2Bx%2BPi6kwJ%2FZ%2FIXoSFsePO07imxV7kZSaji5e7%2BOvo%2F95brjZ%2FoOx98A%2F38Fx7TKzyH8uauv%2FN1Usc1G1b%2BYHqVQiOmr0ftVVdGcurmdhVcOzky32HI3F7kOx8OqqHSPn8A4ub01cLpYHjvwS3y2bDDdX1Xi6%2FH09PhkZ6qOpsz2mTeyPkcO6Fdmf99Tc%2BUyb4v6AD9VxFGaynze2BPxBNydRbagUV55Xm5RnNUJFxEeftX85hT9zXl7VaUH7BpYobHaOAu0GH0dCUg6Ob%2B0GF6eSV3m1G7S%2F%2FNNdwz5rXx2qAcvbbtQUKivfqBqQ0Er09aRYNKclcvMUmPLpZaSm51GmEEQ1hqoBiSoDHwqpNEMuDexZF1uWtEdyai7uPcgokXeVlp5LGU0QJFYEUXYsTPXyEpKzdWytSv6pob7dSzdiTuTtFMpogtDGh1nKAqKqYGqsmxT7MKNCjxF4VTXosESJVGjwJXGCIEisiGqCtaX%2BqTNBcRV6jGNnVKObKyXgo%2F7GUa4TBIkVQZSKW3cyvzp44l5eTq6iQuKPvpeK2%2FfSCkp%2BFPu9Q7lOECRWBFEq%2FriQEaynKw0KOBBdIfG%2F%2F3Xw0z9KpHNHi3KdIEisCKLUxD7O8N0QEJEVEp5YrvEuXheKv2NSC4Qqik3uCil2U44TBIkVQZSaYKYpObnKYf6fnpeXl2Bxofq5sLcmwRkJcJEGNiUIEiuCKDMXQuS%2FpWXmjZ84%2F6xy5ZYbKGsbFm%2Bjen3ayaJCpcQ29ttHKcM8ymmC0B7oPSuiSnIpDN%2B3c1FIt%2B7%2Be23AvmgdD1cbeHd3gHNjMzSwe%2F5nTDKy8hAelYLAK%2FH4%2Fcx9JlZpRQNwoeLfNpLgnSDmwVEuEwSJldZTeBw0onIIuoGNbi2UsfIc%2Bc5TgXEyNhmWKSLeRiXBGbbkrZRidPB1HKbyQhDaBVUDPgc%2BSCMNcFlFPCwmLBIZ%2BEe2jjDRSWAXJZRNd9nVSX%2FBbmksTLRUyfYB9igBffbfhD2adb5UAUJF5YUgyLMiCNHpgs2GiK8%2FKzCMLXtBwcRBAuNidjFRKpGklMCCLQcqZVgQRJ0pCILEqjp7WJQLVYdCX3%2F%2BhMoLQdQsqBqQIAiCILEiCIIgCBIrgiAIgsSKIAiCIEisCIIgCILEiiAIgiCxIgiCIAgSK4IgCKKmQy8FPwd3FyhryrlW9IusyqAJurvOnZ8RFpH4dvjfyU2eJOfoxz%2FJKvaY1pb6ecaGukk2Vvqn%2BJeD%2BQcZ6XoTmiqvBImV1hH056Zqf44VPfjqsR%2FcJ89csfebiOgU4wGe9eAzqT7q1DJCLWuDYvd5lJCl8%2FBRhs2ZoEfDYmLvDB7UwyiIf5AxuIJHSa8J15vKK0FiRWi9F1meT6xK5WfSn%2F%2B3e8fitaHDfYc2xuL57aGnW7IaZy5kfGrtYoVxI511Ag5Ee2wIiAht10o5NChEfoiuGJVX8rBqJtRmRZQ7XKg27YgcvvSj9nh7SOMSC9Wz8P34%2Fqs%2F9zAw0pPsb9cc9GhNECRWBPHv4VV%2FzBMa%2Fs0H7dCqqWW5xMnjWbXAQ6ajI93QlgSLIEisCOLfwDtTHDh%2B9xtf5g2Vl1AVFqxRgxtJdCD5jnlYfSm3CYLESivtJJuoDruS4b3%2BbsWkGo8c0LBC4p%2F4RlPo6Ul1FErscG%2BJxpTjxL9Akm83CBIrjZLVyQEGdDkrl7DIxNHe3e3L3Eb1Mni8HdrYciujAzmWUI4TZSXfXmRRTpBYaZr4TBPUpstZuYRHpTTu2q5iL4PXK3Z8ZsimrvzLwZTrRFnItxfxlBMkVhqF%2BfIRMgla0OWsXBKeZBvY1zGq0GM0d7JQLUjwKP8T9wRRari94HaDcoLESqNIgHPsx5MuZ%2BXyJCVbYm2uX6p9Hj%2FJxt0HGUhKyS1ReIfaajE0YVNvynWijEbDU9gNQmuoFi8FK6TYzZ6yD%2FdwxIcnb2uuHjo6Jg5zP96s%2Fr%2Fgg5Fo0aw%2BPvziR4RH3hfrrCxN4Oxkh6EDPdDIsY467Ladp7Bn%2F4V%2FxLnoE18R%2Fq0JyyFXyPHd8ikwNTEU206eCcXZCzfh59sT%2FnPXF5uugnRo%2FDrIlZDKSt7PJTImDb18T0NXV4o9azrBwsz85U9X%2BfErlbCS0EvtRBlgdsIgVYlRzG54U26QWGmUy9dx1d0FIamGmMP%2BLtTUcR3qWmPhR2%2Bi56CPcWDHR3BqVFesDwmLQUd3Z3i%2B0goJT1Jx%2FNQ19BmyAEu%2BHIPB%2FTqKMHfuxkNfTwf%2BE%2FoVibNuHVWX74uXImFvZ4Xvvj%2BCOdN8VF7I4xTcCL8HCwtjzPYfJNbl5Skw0m8JVi2ZgDq1VFVk9exstOK6zfj8KjKy5Fj%2FsStaNTUv1b4SlWdlSLcwUVry7UQItxuUGyRWGkemhL9cgvNuzXDl0k0c0MQxdZnYcEEpEBl9PV31Ni5cnTo0E8sDvNtjYN8OmDB9Ndq3bQK7uqp9bG3N1WGex9zpQzBz%2FkaMedMTNlZm6vUG%2Bnrq%2FXJz8sTcrU0jNKhXS2uu1%2BnAx7h47Qk8XK3g42VX5suu6XRfDb2N7btO40liGhzsrDFqxCvqh5Ttu%2F7E0ROXYWigj5HDuuKVLqpm1CvXonE39jErA%2B3F%2F5zcPKz67iCmTegvytBPO0%2Bjg3sT3LkXL8L6DOgovPDDv19i8V1BLgvfsX1TjPDpLMrYteu3sTXgJGIfJKCDmzMmje0jysTLOHTsEizMjRDGHnhO%2FhkCx%2Fq1WRnzgZmZqmp1JUtT1O2HSE7JQMMGtTFhjBdq5z8Abf7pBNxcG%2BPgkSBcv3EHfXq2xdBBnbBxy%2B84fzEczZwdMHeGjzodj%2BKTsX7zUZbWGDg3tsMkvz7sXrGu9HLH7MMANpvF7IUHmX%2Ftotq8FBx4ExEKCUZIJNjCvKyPnJygX5XSx70sl2b1xM1eQDy7oc%2BxhBeeUtMy1du5Aejj2RYr1x6sdgXv0KmHYj5qUH2tSXPs%2FQS8MXYp3Ns0ZmLUDebMyJ8%2Be11s%2B%2B%2BqX4VBf2vkq%2FDu1RYz3t8gPGrh%2BV%2BLwv5Dgep4srNzsZSFz8mTi%2F8%2FMfHzHb%2BM7f8HUtOzkMW2c4964Tc7Rbnp9WobHGZCE307DpevRmGs%2Fyp07eSCmZMHIezmHbz3yZYSpZ%2BL3ztTVzIhScIg9vB0JTQaXy7Zqd6ekJiKbp1bYMwoT7H89sTl6m0%2FsHMbN22VqJLu%2FaqrSFvvwZ8iKTkdg%2Ft3xO8nr2LtxiMibAoTO583FsHayhSz%2FQfDxtoUI95ejLxceaVdO24PuF3g9oHbCW4vyPyTZ1VpXA7DceZweORJsNpcF1PdXLAdSpyQKRDmGIEYdlvKKzN9jvVscY8ZvALCbt5lRmtfkTC8zcrU6Wnt1uxpPswofILxo72qVcG7Fp4s5u1bW2pNmm9FPRRVt9yr4N4IFxKOXK7Auh%2BOYtfW99DSRSW%2B3DtZs%2FEwenZvXaK4p4zri7ffeFUd37C3vsbW72aiXVsnsY5XHysUSoxn3vmsqYPV1ckNHWujQ485WPqlH3R0Xv7sOXVcP0yb2F8sGxkbYNnqp%2BXvs%2FdHIpmJDz9PLyZIO%2Ff8heycXHWNweIFY9C9q8pb%2FOvCTbiwh6mZUwaqzpftx9dxdrD92rk5MW9K1STEvcY9B84j%2BNrfonpcE4xgXvdtZzSQS9E8vzPFG0ogVId5VME3SKhIrKqIh8Vmvfk7OFIlhrLl6QoZmkS5oIF7JY9ywZ9CGzesq%2F7fvVtLLP9q7Av3qe9ggxFDujBR24suHV0qLG2a%2FqZTYlKOmFtb6mtNujt1bIrWLRzh2vVdtGheH690bi4McjrzhrhHzDvGFNC0ib3ogFNSatk%2BbbPjVWjcO2nd0rFoNYhUgvDIWFy68jdWrNmvXs%2Br6rKyc2Ci8%2FL34mWyp4JmxrwkuVz1%2FJaZlYPp89bjSkg02rDjGhroqYXz6b5Pbx8TJnSSQneTSaG4Im%2FdxzHmaXn0nFfk2NlZuRorr1Gq0SliWBIj2V1%2FjnlT3tRGRWJVNb0sVcG8WhE3Qlm4%2F%2BAJzgWGY%2F7s4aXed8bkgejmPR821mYVll%2Fl8cmF0uSbiYlOvpGUw9JMVyvSraerg81rBXRIFgAADTNJREFUZyDuURKCmWCs2XRYLH%2FKPBIJs9xcsKwtTUVYvswNegG5eSV36o2N9EV8%2FOGmlk3Rjie8Gu79d4eKdtB%2FS2Gx%2BfmXM7j%2FkJXRo19DR1cm0v%2FL%2FvMl2vfZ%2F8YmBqL365cf%2B1bp8kpoFzSQbQWTmpopGslHjF4M35E90LxpvVLHYctEys%2B3F37YdqLa5IujvbGYh0Yka02aeS%2FPmxGxwpPp5%2BUu2hN5RwsuIO3dnPBjwEm1N7Lt51PwzK8C5F5TWPhdZGRmi6q8vQcuvPA4vIqRx8erEdU1BsGReBiXKKogv91wCElJ6WI97w168Oi%2F%2F5hyTq5ciLFEqtIAXmbLCm%2Bz28PO8QY752fTTxDkWVUCvErmrfxG6IEjv8R3yyaLHlOcWR9sEpORoT6aOtuLdgLeKF8Y3ibAp8LsD%2FhQHUdhJvt5Y0vAH9Um7zw72WLP0VjsPhQLr67aMVIWF5uJ05cJMeHVZOkZ2diwcqrY9t9Ffhg9aQX2Hw5CenqmaEvinQs4PXu0xur1v8G9%2B2zoymToy4TuZSz%2FehwmzViDtl3fFZ4O72X38w9z4T%2B%2BHx4%2BSoRHr3mwsjBBYko62rk6oX8J4nwRIwZ3RsDu0%2BrjdfUoe5Uzb5d6f%2BZQDGcPaOYmRiLf%2BOsWP22YTUaDKHtNQGUclFe7VGU3nqevpn3Wvryq04L2DSxR2OwcBdoNPo6EpBwc39oNLk4lr%2BJsN2h%2F%2Bae7FNf7XmyCaD8qeAXh2W16%2Bjr%2FqL5TKpWicw1vJzI3Ny7xseITUkQVW%2BFXFzi8jekx22ZrY1aibuslgXt9vDu8uamRujt7ecRX2nPWVHkltMt%2Bk2dFVAr6elIsmtMSfu8HYcqnl7FvXReYGmtHcXSwty71Nt4GVc%2B%2B9C9r2xbTTsk9u8Lx8dFNVq37rdh45r87DO5tX%2FxVFS7AZUmjpuIjajYkVkT5GSeZpFRDLg3sWRdblrRHcmou7j3IKJF3lZaeSxn9HHp0bSkmgiCxIoiXYGGql5eQnK1ja1XyT4v17V6nVMeIvJ1CGU0QNfFhmLKAKC9MjXWTYh9mVOgxAq8%2BFnOJEqmo5Je8CYIgsSK0EGtL%2FVNnguIq9BjHzqhGs1dK8IjN4ijXCYLEiiBKxa07mV8dPHEvLydXUSHxR99Lxe17aQUlN4r93qFcJwgSK4IoFX9cyAjW05UGBRyIrpD43%2F%2B60MuvSvC3Yo9RrhMEiRVBlJrYxxm%2BGwIiskLCy3e0gsXrQvF3TGqBUEWxyZ1%2FdJNynCBIrAii1AQzTcnJVQ7z%2F%2FS8vLwEiwvVz4W9NQnOSICLNDApQZBYEUSZuRAi%2Fy0tM2%2F8xPlnlSu33EBZ27B4G9Xr004WFSoltrHfPkoZ5lFOE0TNgd6zIiqES2H4vp2LQrp1999rA%2FZF63i42sC7uwOcG5uhgZ3Jc%2FfJyMpDeFQKAq%2FE4%2Fcz95lYpRUNwIWKf5tIgneCmAdHuUwQJFY1nsLjkBFlI%2BgGNrq1UMbKc%2BQ7TwXGydhkWKaIeBuVBGfYkrdSitHB13GYrjdB1CyoGvA58EEaaaDMcvKwmLBIZHBli0eY6CSwTA1l012Wu%2Bkv2C2NhYmWKsG%2Fk75HCeiz%2Fybs0arzpQoQKrreBEGeFUGIThdsNkR8vVmBYWzZCwomDhIUNxS3iVKJJKUEFmw5UCnDgiDqTEEQhKbR9CfUCYIgCO2231QNSBAEQVR5SKwIgiAIEiuCIAiCILEiCIIgSKwIgiAIgsSKIAiCIEisCIIgCBIrgiAIgqhgqsUIFvSScfWBhj0iCKLaihUn6M9NdDW1HBpMliCI4qBqQKLKecnkKRMEQWJFEARBkFgRBEEQBIkVQRAEQWKlIXibBPX6IgiC0C4k%2Bfa7xohVVicHGNB1JwiC0B7y7XZWTRKr%2BEwT1KZLTxAEoT3k2%2B34GiNWzIeMkEnQgi49QRCE9sDtNrffNUasJMA59uNJl54gCEKLYHZb2O%2BaIlYKKXYz92pUD0fNt1u9MXYprl2%2FXaKwO%2Ff8hazsnCpZZh7FJ%2BPw75fo5iEIQiMIe83strDfNUWsLl%2FHVTYLSTXEHE0fe9igTqhta%2FHScEqlEjPnb0RKSmaVLDgRt2Lx9fJf6A4iCEIj5NvrkHz7rXEqbWxAmRL%2BcgnOuzXDlUs3cUBTx014kgqJRNVr%2FsjxyzA1MUR4ZCxOnA5Bg%2Fq2mDvNB%2Bbmxti596wIs3bTYZgYG8C7txuaN6330vgPHbuEY39cQW5uHjq2b4oRPp2hr6eLsxdu4qedp5GWnoVePVrjzde6i3QkJ6dj8%2FY%2F4OXZFus3H0X842S8NbIHer%2FqqiogqZlYx9bzNFqYGeOVLs3Rv0877Pz1LBISUvHfVb%2BKcOPHeIlzeRHZObnYtPU4zgXehLmZEcaM6gn3to0Rcy8eu9n5jh%2FN4jBVxcG9NoVCiX5e7tj3WyBsbc1x8VIkLlyMgGvrhpg2sT8M9PUQ9ygJvx68gOE%2BXcRcrlBg3Nu96c4miGoEs9MD2GwWs9selZWGSnspmNnLCIUEI5i93uLugo%2BcnKCvieNy8Xn4KFEtVn5TV%2BL%2BwycY1Lc9Qq7H4ItvfhbbbG3MxNyurhXq2dvA2OjlyVuz8TAWLd0Fz1daoWePNjh0NBi3Yx7hz7NhmDJrLVvXGqNHvYqAX87gP8tUnnRSSjoWr9iDDxZsRds2jdDerQnGz%2FgWsfcTxPYps9fi%2FoMneOdNTyESXAxF%2BqzNoKMrE2njk46O7KXpG%2Be%2FGreiHsB%2FQn%2F06NYKY6asQHRMHBo42CIs%2FC5mf6gaDPjKtWh88PmPaN3CUfzfdygQE6avRnZ2Lgb164BjJ67is68CxLYHcYki%2FSNGf41b0Q%2BEgBIEUT3gdpnbZ26nub3mdruy0lKpo65fDsPxDs3gkSfBanNdTHVzwXYocUKmQJhjBGJ2AvKKTsMkP2%2FMnDJQLHOvghteTo%2BuLcV8UN8OqMW8ipeRl6fAirX78dP6WXBzbSzW%2BfTvKLyThUwApzKBGDJA9VDiYGeDvsMWYDbz4jh6ujrY%2FeN7ao9v78HzuMaE097OGqE37uDzIV3RiWUUn0aNeEWdvuOnrmHEkC4lOs8rIdH4O%2FohNq%2BdAalUgg7uTXD%2BYjh%2BY4I6dXw%2FLFs0Fn2Hf44Va%2FZjxy9%2FYeXi8XCwt1bvP9vfB2PeVPWJcWpYF6PGLcWiT94S%2F%2FUNdLHnx%2FkwY94aQRDaywhAdtsZDeRSNM%2FvTPGGEgjVYR5V8I3KE6pKF6sCD4vNerdtgTZSJYay5ekKGZpEuaCBuwZGuZDKnh6CV43l5pZNH%2BOYt8ar7Aq8EXX8TBj%2Bjo4TVWwFNGlcFzm5eXjAPDoOF6kCoeKYmRpBLlelgwvarA82CRF1c20EP99eaNPSsdTpi7x1X1TZde79XpH19ZlXVSDUa5ZNgvfQBczz6ocuHi5FwhVKHho51hbVmenpqncDeXVgeQsVjbxOEJonSjU6RQy73SOZ9T3HvCnvymqjqnJipfayVBlSpkypCoaNt2txwUlKTYeNlVmRbaYmBkhNe9pRgxt6uVwBY7ZPgcEvDt%2FXuotOIbyK8rdjwXh9zDe4fGaZ2MY7gZQUfqzGDevg6N7Pig2z%2B9ezaNW8AX49GIjJfn1hYWH83HCJyWlCoIyMKq7mlj7CSBBEkQd%2FyoLnw4WHewu8jack8E4Z7do64dv1h9TrLgRHCG%2FGs3trbN%2F1p6gq5GwNOCm8o2dF7bkCsu%2BcqCbk1XZTxvZFekYWsrNyRdoesrjTM7JLlL4uHZvhTmw89h68oF4Xc%2FcRrobeFsu%2F%2FnYBJ8%2BE4pdt7wuvatq8daIKs4Dk1Awx5yK7mp1jn55tIZNR8SEIooZ5VlWRiWP6YMzkFbC0NMHcaUMw3KfzC8Ov%2BHosJs5Yg7Zd34VMRwpDA33s3DwX0ycNYOu%2FRZc%2B78Hc1FgIzg9rZpQoDZu3n8DHX%2F4E58Z2iL4dh0%2FmvS48Hi5WbVo2RMeecyGTSHH4l09Rt47lC8X0%2B2%2BnY%2Fb8Tfj86x1CAHmHiWX%2FGSt6Gn70xTaW1vdgZKiPhR%2B%2FiX757VfvTh0k9t%2F28yls%2FukPZGbliF6R61ZMoQJCEITmHIjqcBK8GrCiPmuflJSOnLw81LIxL%2FE%2Bjx4nC6%2FD2tK0yPr4hBRkMWPPe%2B%2BVhsTENKQxgeM9FHn1W2G458YFpqDLeUl4GJcIKUtfSc9p3LRV6NapuejMwaswS5MXpaHwZ%2B2pGpAgCPKsSkFBu83RE1ew7oejxYb75L3X1J0rijPmvLt5WeCeHZ%2BeR%2B1aqhecl676FecCw4uNY9eWeerlOrUty5QOLop8IgiCILGqonh5uoqpqjLbf3CFxc17IJak%2Bz5BEASJFVFpdO7YjDKBIIhKhbpzEQRBECRWBEEQBEFiRRAEQZBYEQRBEASJFUEQBEGQWBEEQRAkVgRBEARBYkUQBEHUdKrNS8GFx5UjCIIgqhey6nASDx5jAZ%2FsbPEZXdLqAb%2BelAsEQRRA1YAEQRAEQRAEQRD%2Flv8D7QG%2FgPsYKIcAAAAASUVORK5CYII%3D)
+
+```
+bool_expr
+ ::= ( bool_expr ( '<' | '<=' | '>' | '>=' | '==' | '!=' | '&&' | '||' ) | '!' ) bool_expr
+ | ( '(' bool_expr | DEFINED '(' IDENT | IDENT '(' source_name ) ')'
+ | int_const_expr
+```
+
+referenced by:
+
+* bool_expr
+* const_expr
+* constant_def
+* if_stmt
+
+**expr:**
+
+![expr](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAckAAAMRCAYAAACHzU0aAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAIABJREFUeNrs3Ql8FPXdP%2FDP7JkLCEkgFCJBAoEkIIQEnuiDQmnB%2BJSKEKjAQ6Ge4COoD3%2B1YqmKPVBQWxVatIiKtSYc6qPBowhKm3LEDUcTEnIfJEgCue9kd%2Bf%2F%2B20CggckYXezu3zer9dkZsnub2a%2FM%2BSzv5nZGYCIiIi%2Bk%2BIJbyImAqq7v4e0LM9YFz2lmu7V7zhw8MHMnOrF2fm1I6tq24xnqlq6XJPA%2Fkazr7e%2BJijAuC%2BvpHnt54ea0jy1VtzeiZxH5ylvxPTPLW677LE33nlVb4S734i576EX31%2BfU1jnO3PaNbht2VAMGuiDgYFeXW6jorJFd7qiKSjFVJFQXFYy69apPqays02L0jKQ74k14%2FZOxJC8qpzrHVxNn7BV9SnNtpd2Jq3blDF30ZwwrFs1EQa9pkdtyUCVw3URAbh7frguMbkwbnNiTkbsWHWOKd3yMbcwbu9EPaFhCai3yIDckpQ79%2FnVE7F4dliPA%2FKbZDuyvY1Px3n5GJQPYyPBrgsRMSTJfchdrKKnN3f947EYO6q%2FQ%2BYh292wJk6r02k2RzMoiYghSe5AnqSTvOfk%2BkWit%2BeogLwwKBfOGq7ooLwiepS3sPpExJAklybPYs0rrvedP%2FNap8xv6YJRMBg0OquKpJgxCOMaICKGJLmszNzqJfFThtjtGOTlyPlMGjdAniGigwXPcQ0QEUOSXFZ2QV3Y5Nhgp85zxk2D5chbDJOjozCOa4GIGJLkkiqrWr2GDPJx6jwjR%2Fh3TCio0FiRwLVARAxJcklVda1KYD%2BjU%2BcZEnw%2BlP3EMJ1rgYi6HJL%2FMQaX3Pd1ud8TdYfVokKjde53yM%2FNT1URIEZDuRaIPNuV5ta519tCst2CUzER2PZ9jV7u90TO8Oe3C3Dbsv0y6HpM6ehJcjsm8nA9za1JEZgdE4mTZgsK5WNd5x8OGZbzLBbxywi8p9NixaEMlF%2Fwh%2BWSv3cnbe1mbHnrM%2Bw%2FdAJ9%2B%2FhgycIfYuKEkSgtq8S291Jw189%2FjH79fG3P%2Ffveo2gXz%2F%2FJzbHY9akJAf39YDqSj4NfZuO6McPwwLKZ8PYyoOJsLd794ADmz7kR7%2B86hLa2dtx7x83cSu0sv6QB%2F0qrFCGpQlGuqCeqvVpqxu2drlbdzS0ZjhYFL1lUhFx4C4GLjkmqHaEpGy39rgS%2B3O%2FdwdIH%2F4QTuWVYfu9P8KOp1%2BHO%2B19Gbv5XCBkSiOy8U%2FjfxzsuHP3v40X45ZNvYkxUqO3xh598iXvEa5uaW3Hrf03CF%2F%2FMwK9%2F%2B7btd2fEH411f3wPCYufEW2U4WxVPbdQ4vZO5AIul1vneo4W4F3IgPwG3WUatSXw5X7vLj3L4ydKkJl9Egd2r4NGI3siI3HIlIOP%2Fm7Cg%2Ff9FM%2F%2F7g78ZN5v8MKG%2F8N7yYfwx7V3IzRkwPnXP7jsp7hnScc5H6PDQ5Cw6Bk8u2aJ7bHBqMO7bz12%2FlM52cef%2FpqPrPyOP8Km9OqO9fCbY%2Bd%2Fv%2BbBSAT4G1gobu9EXQ3LjtxS8LEZePqbPccuheQ5VuCo6GrGq5f5vdmMQjFTb1cvUnbuKZw5U4cbpv%2Fyon%2Bfn3Cjbezn64U%2F%2F2EZZtz2FO79xQxMmRx1cff9gj18w4cFo7mlDbV1TbbHRr3eLn8wPOFegfaUmVeH%2FYerbNPVtW22sdzlek5zq4V15vZO1GUyt8Sm%2FROzirlibL3cBvidISleuF%2B8sEyMfywa3CzG%2F3up3%2Bt1ePZcT3IeoC0KR6hFg0jxxGniOQvEczN0Ku5PPYEcR7zprv5H6%2BPnhWGhA7H3w99873N2%2Ft8BjIkYatvdJHdRyeMy36WqpgF6gw59xB%2Bar%2Bz4Xi536yB719eV15e04ano89MPr%2F033ny3GKb3p3X2jBxXZ0eZNBrhZgUbxczHiCK8IyqxV2tF5rAcFG8HLNzee7%2B%2B5Pq6sp6%2F%2Bf%2FkwtwS41e89NjS0o47RUfvblVB7Xftav1WSJ5rRO1o5JBeiwgZfmJm%2F3up31%2FYhm0Bc1AgJuWQPGIEVvXT4xGLgoPRkZh3JBN7equwcbGjcLqiBjv%2Bbz%2FmzrrB9m8lpWdRWVmH6HHDsevvadj9%2BVF8vPNJPP1sEu5%2F%2BBW8%2FZeV5%2F8g13V%2BirZYrPjTqx9hxg%2FH2%2F5wOJO96%2BvK68vTiHr%2ByKJiu9iaXqhtx8y8PLSe%2B92X3N7drr7kHuv5Mrm18j%2FG4Nl2C375fWF54Ra%2F%2FVLh14Xff6fON%2FDbCaNtu2a3i08AcY7qoVz2k3Ufb7z%2BpxVYuWoLfvfcdngZ9WhubsPzv78TeQVfYdWTW5H4xsPw9THi6V8twH%2FN%2FQ2e3%2FA%2BHnlgtu31ie%2Bm4O3t%2F0BLaxtGhQ3Bqy%2F%2FT69vMPauryutL0%2F75Cv%2FY6sqFh8%2BgWRu7%2B5fX3KL9XzZ3Or8t%2B8Ny3Mh2SwaKb1E%2BF3u95cl35Dokb4geigbxMMZvVXk%2F4gJx7%2F%2B%2FgzKxSds%2BTWCgQP6nf%2Fdvw%2B8eH7aaNBjzwdPX%2FRaedxm4byb0NDQctHrokYPxbH9f%2BzVjcfe9XWV9XWh51ZdZxvcUWcdX3D2H3BP3d5dpb7k0uu5W7n1zbAUPdBl50NSp8W1l2rkcr%2Fv8ifbZjxX74375QWmjxzHsd4sdvBA%2Fx69zsfbaBtckb3r60rry613D8kLqlsxVtTzVm7vnllfcr313NPcujAs5WPNBf94uRddsS%2BK0AIFf3PHC0wvWTgNN90Q5dLLaO%2F6Omp9yUvEyUvTOVNDY3uvrRdb%2FUQdbfXk9s76klPW85Xm1rnXO%2F8C5yr2ij%2BP17vbCrp%2B4iiEjxjs%2Bgtq7%2Fo6YH359zGYK2tbnVqW3KK6Xlwlon6ijtzeWV9yv%2FXs9JAUHYjjChDOVe4e9XXE%2Burjq68pO93k1LqkHjtrGysq5JUJnPpVAFk%2FWUdunawvud96dnpIejfYurADuMrdo76OWF%2BB%2FY37UkzOvUDT7pRTHZ9GFVSIkbOvDjWgs47E%2BpKbrWenh%2BSBUtv%2BZC%2Bub%2FeoryPWV15J89pde0vNbe1Wp9SksLQeRaUN57Z4%2BX3QEievFq%2FOOhLrS262nnvjpstqR8%2BZ3KS%2Bdl9fnx9qSjPoNabE5EKnFOSxZ9MufDeNsmPp5HWidNaRWF9ys%2FWsYd2pN5SdbVq0OTGnJT272qHzWfdqBvKL688FZIEYYqwa7OQaICKGJLmsNJFdbe1qwvInD1ocFZQyILdd2FtVkCI%2Bin7J73wSEUOSXN6hdMtHDc3me5au2q%2B%2BvDUL9jpGKY9B3r7ii4sDUoW8GeLNqhaPsvJE1FU6loB60%2BFMvB4bYdW8tTN%2FU%2BIHhbq48UGInxKC8LC%2BCB3s16U2mlrMyC6oQ%2BrRM%2Fgs5ZQIyYaLnyADUt7hRMEdJtGDZdWJ6KoLydgb7%2BTadFOmLLw2IUots7RZtu9LLdeKwT73JpXHIBWkQN4TVYMlacfxCbd3IuoOj9jdKu9J11v3ByQ79ShFgClajBeTn4pwqxQrM0MMJ8VabexGMw3iNYUaVbQBvKcCRvHYT3wUvOGwBwUkt3ci9iTpKpTWsSt0tryQcef1YmfAKsJAgW8Xm%2FBTVdSoCuTVvFNVLdaYeJIOETEkv%2F6EzVXq%2FjrPPpXDE6wGt3ei3sSzW4mIiBiSREREDEkiIiKGJBEREUOSiIiIIUlERMSQJCIiYkgSERG5K15xh1yCarpXv%2BPAwQczc6oXZ%2BfXjqyqbTOeqWr53i%2FLB%2FY3mn299TVBAcZ9eSXNa%2BWNnFlFImJIksfZ%2FUbMfQ%2B9%2BP76nMI635nTrsFty4Zi0EAfDAz0%2Bt7XVFS26E5XNAWlmCoSistKZt061cckb%2BScxrt8EBFDkjyi96g%2Bpdn20s6kdZsy5i6aE4Z1qybCoO%2FaEQAZoHK4LiIAd88P1yUmF8ZtTszJiB2rzjGlWz5mdYnIHnhMknqNDMgtSblzn189EYtnh3U5IL9Jvk6%2BfuPTcV4%2BBuXD2EjwPlJExJAk9yV3sYqe39z1j8di7Kj%2BdmlTtrNhTZxWp9NsjmZQEhFDktyRPEknec%2FJ9YtE789eAXlhUC6cNVzRQXlF9ChvYbWJiCFJzmC32zLJs1jziut958%2B81iELunTBKBgMGp1VRVLMGIR5St2IiCFJLur6EHjZq63M3Ool8VOG9PgY5OXIdieNGyDTSQcLnvOUuhERQ5JcVLMfgu3VVnZBXdjk2GCHLu%2BMmwbLkbcYJkdHYZwn1I2IGJLkorQKouzVVmVVq9eQQT4OXd7IEf4dEwoqNFYkeELdiIghSa5KwTR7NVVV16oE9jM6dHFDgs%2BHsJ8YpntC3YiIIUmuSsXCqcPsc3zNalGh0Tr2fJZz7asqAsRoaG%2BUzFYvUTduPEQMSfJ86fXeeNj9OsC2nmSvHBfsrFc6Nx0ihiR5OK2K5WK0csJozHTHxXf2DDvrtLKzbkTEkCRPlnoCOVYF8xQFW2MisHrECBhZlW%2BTdZH1kXWS9ZJ1Y1WI3BcvcE5ddiQTeyaNRpxZwcZ%2Betw%2FIQLvQMVerRWZw3JQvB2w2HN%2B%2B1LP4A9bci%2F6t82%2Fj0FQgOvk8zzRSy0KR6hFg0h5ko4CLFCBDJ2KuLQsBiQRQ5Kuuh6lGE2X3z3UqJgjph%2BwajGyIAKhMXa%2BuszZ6jb8K63yon9rabP2qC3Ru1MdUY8C2NotFm88V7z7A6L3GH%2FkOI5xSyFiSNLV3KvsCIIehUFXAyvh5iG2wR5Er46XhyOibuMxSSIiIoYkERERQ5KIiIghSURExJAkz9rotIrt0nSO1NDYzkITEUOS3I9%2FH4O5srbVofPILapjoYmIIUnup4%2BvvqbsdJND55F67KxtrKioh50vckBEDEkihwnsb9yXYip36Dx2p5yyjVUFFWJUzqoTEUOS3EJeSfPaXXtLzW3tVoe0X1haj6LShnNbeIH4WcKqExFDktzC54ea0gx6jSkxudAh7T%2F2bNrXD1Q0yo4lq05EDElyG2VnmxZtTsxpSc%2Butmu7617NQH5x%2FbmALBBDjFWDnaw4ETEkyW2kiSxra1cTlj950GKvoJQBue3C3qmCFAX4khccJyKGJLmdQ%2BmWjxqazfcsXbVffXlrFnp6jFIeg7x9xRcXB6SKt8XPm1UtHmWliaineBcQ6lWHM%2FF6bIRV89bO%2FE2JHxTq4sYHIX5KCMLD%2BiJ0sN93vqapxYzsgjqkHj2Dz1JOiZBsuPgJMiDlvR0V3GESPVZWmYgYkuS2TFl4bUKUWmZps2zfl1quFYN3jxqSxyAVpIipeFWDJWnH8QmrS0RXgrtbyTV6lCLQFC3Gi8lPRdhVKkCGGE6K0Gu8xMsaxHMKNap4DfCeChjFYz%2Fx0e%2BGwwxIImJPkjxJWseu0dnRURinsSJBTM%2BAVcSkAt%2FveYmfqqJGVeAvplNVLdaYeJIOETEkyZN1no0qhydYDSLqTdzdSkRExJAkIiJiSBIRETEkiYiIGJJEREQMSSIiIoYkERERQ5KIiMhd8WIC5BJU0736HQcOPpiZU704O792ZFVtm%2FFMVYtyudcF9jeafb31NUEBxn15Jc1r5Q2dWU0iYkiSx9j9Rsx9D734%2FvqcwjrfmdOuwW3LhmLQQB8MDPS67GsrKlt0pyuaglJMFQnFZSWzbp3qY5I3dE7j3T%2BIiCFJbt17VJ%2FSbHtpZ9K6TRlzF80Jw7pVE2HQd%2B8IgAxSOVwXEYC754frEpML4zYn5mTEjlXnmNItH7PKRHQleEySeo0MyC1JuXOfXz0Ri2eHdTsgv0m%2BXraz8ek4Lx%2BD8mFsJO5klYmIIUluR%2B5iFT2%2Buesfj8XYUf3t2rZsb8OaOK1Op9kczaAkIoYkuRN5kk7ynpPrF4len70D8sKgXDhruKKD8oroUd7CqhMRQ5IcSbFXQ%2FIs1rziet%2F5M6916AIvXTAKBoNGZ1WRFDMGYe5eNyJiSJKLuj4EXvZqKzO3ekn8lCFXfAzycmT7k8YNkCmlgwXPuXvdiIghSS6q2Q%2FB9moru6AubHJssFOWe8ZNg%2BXIWwyTo6Mwzp3rRkQMSXJRWgVR9mqrsqrVa8ggH6csd%2BQI%2F44JBRUaKxLcuW5ExJAkV6Vgmr2aqqprVQL7Gbv1msZmM05VtHR7XiHB58PYTwzT3bluRMSQJFelYuHUYfY5vma1qNBou3Y%2BS2V1G1paLfh4Xzlm37ff9m9fnel6WJ6bj6oiQIyGOrNktnqJunHjIWJIkudLr%2FfGw86e6Ytv5mLqf%2B9DenatDDo8%2FXIW4ubsRVl5czc7dLaepFOPD3bWK52bDhFDkjycVsVyMVo5YTRmOnO%2BT66IxNIFw%2FHGjiIUnmzEkcwa7PnrTRgS7N2jt%2BGs5e6s08rOuhERQ5I8WeoJ5FgVzFMUbI2JwOoRI2B0xnzlrtV%2FpVWi3azK7zwiu7AeqceqbL1KVyTrIusj6yTrJevGrYfIffEC59RlRzKxZ9JoxJkVbOynx%2F0TIvAOVOzVWpE5LAfF2wGLvecpe5BeIhyfeWQM%2FpJUiN8%2FPAa%2Fej4DU%2BMGYvDA3v8K4jzROy0KR6hFg0h5ko4CLBD5naFTEZeWxYAkYkjSVdejFKPp8juHGhVzxPQDVi1GFkQgNMYBV5dZvTzCNv7oi9MI8DfgxolB%2BEfi1B63J3p5du2DFsDWXrF447ni3R8Qvcf4I8dxjFsKEUOSruZeZUcQ9CgMehJU%2FzV1kG24UqJ3x8vEEVGX8ZgkERERQ5KIiIghSURExJAkIiJiSJJnbXRaxXZpOmdoaGxnwYmIIUnuw7%2BPwVxZ2%2BqUeeUW1bHgRMSQJPfRx1dfU3a6ySnzSj121jZWVNTDARc7ICKGJJFdBfY37ksxlTtlXrtTTtnGqoIKMSpn9YmIIUkuLa%2Bkee2uvaXmtnarQ%2BdTWFqPotKGc1t6gfhZwuoTEUOSXNrnh5rSDHqNKTG50KHzeezZtK8fqGiUHUtWn4gYkuTyys42LdqcmNOSnl3tkPbXvZqB%2FOL6cwFZIIYYqwY7WXkiYkiSy0sTGdbWriYsf%2FKgxd5BKQNy24W9VAUpCvAlLzxORAxJchuH0i0fNTSb71m6ar%2F68tYsXOkxSnkM8vYVX1wckCreFj9vVrV4lBUnou7iXUCoVx3OxOuxEVbNWzvzNyV%2BUKiLGx%2BE%2BCkhCA%2Fri9DBfpd8bVOLGdkFdUg9egafpZwSIdlw8RNkQMp7PCq4wyR6rqw2ETEkye2YsvDahCi1zNJm2b4vtVwrBu8ralAeg1SQIqbiVQ2WpB3HJ6wyEfUEd7eSa%2FQoRZApWowXk5%2BKkKtUgAwxnBRh19iFlzeI5xZqVPFa4D0VMIrHfuIj4A2HGZBExJ4keYK0jl2is6OjME5jRYKYngGriEkFvpd5qZ%2BqokZV4C%2BmU1Ut1ph4kg4RMSTJE3WehSqHJ1gNIupN3N1KRETEkCQiImJIEhERMSSJiIgYkkRERAxJIiIihiQRERFDkoiIyF3xYgLkElTTvfodBw4%2BmJlTvTg7v3ZkVW2b8UxVi3K51wX2N5p9vfU1QQHGfXklzWvlDZ1ZTSJiSJLH2P1GzH0Pvfj%2B%2BpzCOt%2BZ067BbcuGYtBAHwwM9LrsaysqW3SnK5qCUkwVCcVlJbNunepjkjd0TuNdP4iIIUlu3XtUn9Jse2ln0rpNGXMXzQnDulUTYdB37wiADFI5XBcRgLvnh%2BsSkwvjNifmZMSOVeeY0i0fs8pEdCV4TJJ6jQzILUm5c59fPRGLZ4d1OyC%2FSb5etrPx6TgvH4PyYWwk7mSViYghSW5H7mIVPb656x%2BPxdhR%2Fe3atmxvw5o4rU6n2RzNoCQihiS5E3mSTvKek%2BsXiV6fvQPywqBcOGu4ooPyiuhR3sKqExFDkhxJsVdD8izWvOJ63%2Fkzr3XoAi9dMAoGg0ZnVZEUMwZh7l43ImJIkou6PgRe9morM7d6SfyUIVd8DPJyZPuTxg2QKaWDBc%2B5e92IiCFJLqrZD8H2aiu7oC5scmywU5Z7xk2D5chbDJOjozDOnetGRAxJclFaBVH2aquyqtVryCAfpyx35Aj%2FjgkFFRorEty5bkTEkCRXpWCavZqqqmtVAvsZexaw1W04%2BVUTzBa1S88PCT4fxn5imO7OdSMihiS5KhULpw6zz%2FE1qwg4jbb757PIYJy2aB9m3v2vrm%2FgnfNRVQSI0VBnlsxWL1E3bjxEDEnyfOn13ni4Nxfgk32ncaqiBUsShkHXzZBVOnqSTj0%2B2FmvdG46RAxJ8nBaFcvFaOWE0ZjZW8uweVuh%2FEoHfj6rxx1CrbOWtbNOKzvrRkQMSfJkqSeQY1UwT1GwNSYCq0eMgNGZ8z9RUI%2F9hysx60eDMSDQ6LJ1knWR9ZF1kvWSdePWQ%2BS%2BeIFz6rIjmdgzaTTizAo29tPj%2FgkReAcq9mqtyByWg%2BLtgMVR896yrUgeV8SdPxvmUjWZJ3qnReEItWgQKU%2FSUYAFYjEzdCri0rIYkEQMSbrqepRiNF1%2B51CjYo6YfsCqxciCCITGOOjqMvWNZmz7qBTjI%2F0RO%2BbKLmMnenmqPZetALb2isUbzxXv%2FoDoPcYfOY5j3FKIGJJ0NfcqO4KgR2HQ3aBKSj6JxmYz7pp35b1I0bvjZeKIqMt4TJJcmtzFumV7EQL8DZg9YwgLQkQMSaJz%2FvHlGeQWN9jOaDUauLkSEUOS6LzXthVBq1Vs340kImJIEnWSl6DLyq%2FHvFtCcM0PvFkQInI6nrhDzv9kJnqGXbk0XWB%2FA75878oufdrQ2M6CExF7kuQ%2B%2FPsYzJW1rU6ZV25RHQtORAxJch99fPU1ZaebnDKv1GNnbWNFRT0ceLEDImJIEtlFYH%2FjvhRTuVPmtTvllG2sKqgQo3JWn4gYkuTS8kqa1%2B7aW2pua7c6dD6FpfUoKm04t6UXiJ8lrD4RMSTJpX1%2BqCnNoNeYEpMLHTqfx55N%2B%2FqBikbZsWT1iYghSS6v7GzTos2JOS3p2dUOaX%2FdqxnIL64%2FF5AFYoixarCTlScihiS5vDSRYW3tasLyJw9a7B2UMiC3XdhLVZCiAF%2FywuNExJAkt3Eo3fJRQ7P5nqWr9qsvb83ClR6jlMcgb1%2FxxcUBqeJt8fNmVYtHWXEi6i5eTIB61eFMvB4bYdW8tTN%2FU%2BIHhbq48UGInxKC8LC%2BCB3sd8nXNrWYkV1Qh9SjZ%2FBZyikRkg0XP0EGpLzHo4I7TKLnymoTEUOS3I4pC69NiFLLLG2W7ftSy7ViuLJr0MljkApSxFS8qsGStOP4hFUmop7g7lZyjR6lCDJFi%2FFi8lMRcpUKkCGGkyLsGrvw8gbx3EKNKl4LvKcCRvHYT3wEvOEwA5KI2JMkT5DWsUt0dnQUxmmsSBDTM2AVManA9zIv9VNV1KgK%2FMV0qqrFGhNP0iEihiR5os6zUOXwBKtBRL2Ju1uJiIgYkkRERAxJIiIihiQRERFDkoiIiCFJRETEkCQiImJIEhERuSteTIBcgmq6V7%2FjwMEHM3OqF2fn146sqm0znqlqUXraXmB%2Fo9nXW18TFGDcl1fSvFbe6JlVJiKGJLmd3W%2FE3PfQi%2B%2Bvzyms85057RrctmwoBg30wcBArx63WVHZojtd0RSUYqpIKC4rmXXrVB%2BTvNFzGu8GQkQMSXKL3qP6lGbbSzuT1m3KmLtoThjWrZoIg94%2BRwBkwMrhuogA3D0%2FXJeYXBi3OTEnI3asOseUbvmY1SeiruAxSeo1MiC3JOXOfX71RCyeHWa3gPwm2a5sf%2BPTcV4%2BBuXD2EjcyeoTEUOSXJbcxSp6dnPXPx6LsaP6O2Wecj4b1sRpdTrN5mgGJRExJMkVyZN0kvecXL9I9O6cFZAXBuXCWcMVHZRXRI%2FyFq4NImJIkj0o9mpInsWaV1zvO3%2Fmtb3yRpYuGAWDQaOzqkiKGYMwd6kbETEkyUVdHwIve7WVmVu9JH7KEIcdg7wcOd9J4wbI9NLBgufcpW5ExJAkF9Xsh2B7tZVdUBc2OTa4V9%2FPjJsGy5G3GCZHR2GcO9SNiBiS5KK0CqLs1VZlVavXkEE%2Bvfp%2BIkf4d0woqNBYkeAOdSMihiS5KgXT7NVUVV2rEtjP2KtvJyT4fEj7iWG6O9SNiJyPFxOgrlGxcOow%2FOqLIrRcaVNWiwqNtmvns%2Fz7RC2eeikTRaVNGDrYG2sejMK4iH6239U3mnHXYybM%2FOEPsHhOaPc%2BHXbOX1URoDjo%2F4Gol1e9qBs3HiL2JMnzpdd742FnztBqVbHkkS%2BRX9yAlXeOFONG%2FOLRL2Ww2fz57XwcOFKFH0%2Fu%2BWE%2FpaMn6ZDjhp31SuemQ8SQJA%2BnVbFcjFZOGI2ZzppnWXkzSk8320Jw0W1DMe2GgbbHpyqaUVXThk1%2FK8Adc0MxeOAVn0Cqtfeyd9ZpZWfdiIghSZ4s9QRyrArmKQq2xkRg9YgRcPhBRY2mY5eoxaKe71naEk2r4MU382w9yod%2BMVL0Jivx%2FGs5eDWxAGerWnu1TrIusj6yTrJesm7ceojcF49JUpcdycSeSaMRZ1awsZ8e90%2BIwDtQsVdrReawHBRvF3lmz%2FkNCfZG%2BDA%2FfLzvNAYFeeHTf5zG6OF9bOG4ZXsRViwOw67PT2Pl748hYkRfnBI9zw1b85GybSr6%2BumdUpN5IrOLwhFq0SBSnqQjYn2BWLwMnYq4tCwGJBFDkq66HqUYTZffLdSomCOmH7BqMbIgAqExDri6zNt%2FmIR1r%2Bbg4NFK%2FPg%2Fg%2FHLpaPw%2FOYc%2BHhpcd9%2FhyHh%2FgPw76vH53%2B9CX%2F74KQtMPfuP4PbZgzu1nxE70%2FtyfIVwPa6YvHGc8W7PyB6j%2FFHjuMYtxQihiRdzb3KjiDoURh0J5CGhfjiT09Hn39cVNpoC8PH%2F2c0%2BvjqUF3bjn599LZdsAH%2BBttzahrau71MotfHy8cR0bfwmCS5lWdfyUZQfwPu%2Ftkw2%2BOwob746kwLMnLqbL1NaYT4NyIihiRdVbLy6vDu309h5d3h8DJ2nJC6atlo9O9jwA%2F%2Fe5%2FtbNe58UPwnzF%2FpVEDAAAgAElEQVRBLBYR2QV3t5LbkCfnlB%2B6%2BBso8sICR3f9GF9VNMNbBGdQgJGFIiKGJNH5jVir4Jof%2BLAQRGR33N1Kzt%2FoRKhZLWqvLkNDYztXBBExJMn1%2BPcxmCtre%2FdL%2F7lFdVwRRMSQJNfTx1dfU3a6qVeXIfXYWdtYUVEPO18EgYgYkkQ9FtjfuC%2FFVN6ry7A75ZRtrCqoEKNyrhUiYkiSS8graV67a2%2Bpua3d2ivzLyytR1Fpw7n%2FAQXiZwnXChExJMklfH6oKc2g15gSkwt7Zf6PPZv29QMVjbJjybVCRAxJchllZ5sWbU7MaUnPrnbqfNe9moH84vpzAVkghhirBju5RoiIIUkuI01kVVu7mrD8yYMWZwWlDMhtF%2FZeFaQowJe8IDkRMSTJ5RxKt3zU0Gy%2BZ%2Bmq%2FerLW7PgqGOU8hjk7Su%2BuDggVbwtft6savEo1wQRfR9ecYd61eFMvB4bYdW8tTN%2FU%2BIHhbq48UGInxKC8LC%2BCB3s16M2m1rMyC6oQ%2BrRM%2Fgs5ZQIyYaLnyADUt77UcEdJtGj5VogIoYkuSxTFl6bEKWWWdos2%2FellmvF4O2QGcljkApSxFS8qsGStOP4hNUnokvh7lZyjR6lCCxFi%2FFi8lMRZpUKkCGGkyLUGq%2Bg2QbRRqFGFW0C76mAUTz2Ex8NbzjMgCQi9iTJnaR17PqcHR2FcRorEsT0DFhFTCro6Q0i%2FVQVNaoCfzGdqmqxxsSTdIiIIUnurPNsUzk8wWoQUW%2Fi7lYiIiKGJBEREUOSiIiIIUlERMSQJCIiYkgSERExJImIiBiSRERE7ooXEyCXoJru1e84cPDBzJzqxdn5tSOratuMZ6paFHvPJ7C%2F0ezrra8JCjDuyytpXitvAM3qExFDklzW7jdi7nvoxffX5xTW%2Bc6cdg1uWzYUgwb6YGCgl93nVVHZojtd0RSUYqpIKC4rmXXrVB%2BTvAF0Gu8GQkQMSXKp3qP6lGbbSzuT1m3KmLtoThjWrZoIg96xRwBk8MrhuogA3D0%2FXJeYXBi3OTEnI3asOseUbvmYa4WILsRjktRrZEBuScqd%2B%2FzqiVg8O8zhAflNcn5yvhufjvPyMSgfxkbiTq4VImJIUq%2BTu1hFD27u%2BsdjMXZU%2F15dFjn%2FDWvitDqdZnM0g5KIGJLUm%2BRJOsl7Tq5fJHpxvR2QFwblwlnDFR2UV0SP8hauJSJiSFJ32O1MU3kWa15xve%2F8mde61BtcumAUDAaNzqoiKWYMwlytbkTEkCQXdX0I7HaqaWZu9ZL4KUOcfgzycuTyTBo3QKaaDhY852p1IyKGJLmoZj8E26ut7IK6sMmxwS75PmfcNFiOvMUwOToK41ypbkTEkCQXpVUQZa%2B2KqtavYYM8nHJ9xk5wr9jQkGFxooEV6obETEkyVUpmGavpqrqWpXAfkaXfJshwefD208M012pbkTEkCRXpWLh1GH2Ob5mtajQaF3zfJZzy6WqCBCjoVfSlq1eom7ceIgYkuT50uu98bCrLMyJgno8ti4dZhG4l9LYbMaWHUX49J%2Fl3ewA2nqSV3Q8sbNe6dx0iNwXL0tHXaJVsdyi4OCE0Th6%2BASSe2MZ2s1WfPzFaby2vQj7D1dCJ3p9v1kZhe%2F6loUM0TdEOCbtKkVDkxnrHhvbo7fd02UVdZopRitF3eJE3bK5BRExJMmDpZ5ATnQk5mmA7TEReKG2Hevz8tDqjHmfPtuCN3cW4633SlBe2YJBQV54%2BO5wLJ4TCr1O870hKn93803B%2BEVCKKZMGuCUOo0YAWM%2FPR6RAWlVMC8tCzmiXkTEkCRPdyQTeyaNRpxZwUYRBPdPiMA7ULFXa0XmsBwUbwcs9p7nqvUZePPdYlsATv2PAXjml2MQf9MgWy%2FyQv9Kq8TSXx22hejggV54bNkoLLptKIIDHfs1xXmit1kUjlCLBpHyJB2xVAtUIEMnepAyILnVEDEk6SrrUYrRdPkdQo2KOWL6AasWIwsiEBrjgKvLZObV2QIyoJ8BN0wIxKTrAr4VkFKFCEcZkFKseI58rj0CUvQCL3nQswC23xeLJcoV7%2F6A6D3GHzmOY9xSiBiSdDX3KjuCoEdhcLngudDOP11v24UqT775%2FZ9PYP1fchA%2FJRi%2FmDMMN00KOv%2B82TOGIHJkX7yxoxhJu07ig89OYfTwPlgyJxQ%2F%2B0kI%2Bvrpe%2FQ%2BRW%2BQl5UjYkgSuegGKnqNP%2F3RD2xDdmH9%2BRD8cM9XCAv1xb%2BSfghtZ89y1LV9sPaRMVi9fDS2fVSK18VzVz2Xgac3ZOGV307ALVMGsaBExJAkz%2FRdIWixqudD8hxfbx3uSBhmGw4ercJr2wtRXtnKAhIRQ5I834UheDlx4wNsAxFRT%2FBiAkRERAxJcpmNTqvYLk3nihoa27mCiIghSb3Hv4%2FBXFnrmscIc4vquIKIiCFJvaePr76m7HSTSy5b6rGztrGioh4OuDgCETEkiS4psL9xX4qp3CWXbXfKKdtYVVAhRuVcW0QMSSKnyitpXrtrb6m5rd3qUstVWFqPotKGc%2F8zCsTPEq4tIoYkkVN9fqgpzaDXmBKTC11quR57Nu3rByoaZceSa4uIIUnkdGVnmxZtTsxpSc%2BudonlWfdqBvKL688FZIEYYqwa7OSaImJIEjldmsiktnY1YfmTBy29HZQyILdd2KtVkKIAX%2FJC5UTEkKRecyjd8lFDs%2Fmepav2qy9vzYKzj1HKY5C3r%2Fji4oBU8bb4ebOqxaNcQ0TEy9JRrzqciddjI6yat3bmb0r8oFAXNz4I8VNCEB7WF6GD%2Few6r6YWM7IL6pB69Aw%2BSzklQrLh4ifIgJT3hFRwh0n0dLl2iIghSb3OlIXXJkSpZZY2y%2FZ9qeVaMXg7dQHkMUgFKWIqXtVgSdpxfMK1QkQSd7eSa%2FQoRTApWowXk5%2BK0KpUgAwxnBTh1eiA2TWItgs1qpgX8J4KGMVjP%2FGR8YbDDEgiYk%2BSXFFaxy7O2dFRGKexIkFMz4BVxKQCXzvPyk9VUaMq8BfTqaoWa0w8SYeIGJLkDjrPKpXDE6wGEfUm7m4lIiJiSBIRETEkiYiIGJJEREQMSSIiIoYkERERQ5KIiIghSURE5K54MQFyCarpXv2OAwcfzMypXpydXzuyqrbNeKaqRbH3fAL7G82%2B3vqaoADjvryS5rXyBtCsPhExJMll7X4j5r6HXnx%2FfU5hne%2FMadfgtmVDMWigDwYGetl9XhWVLbrTFU1BKaaKhOKyklm3TvUxyRtAp%2FGuH0TEkCSX6j2qT2m2vbQzad2mjLmL5oRh3aqJMOgdewRABq8crosIwN3zw3WJyYVxmxNzMmLHqnNM6ZaPuVaI6EI8Jkm9RgbklqTcuc%2BvnojFs8McHpDfJOcn57vx6TgvH4PyYWwk7uRaISKGJPU6uYtV9ODmrn88FmNH9e%2FVZZHz37AmTqvTaTZHMyiJiCFJvUmepJO85%2BT6RaIX19sBeWFQLpw1XNFBeUX0KG%2FhWiIihiR1h93ONJVnseYV1%2FvOn3mtS73BpQtGwWDQ6KwqkmLGIMzV6kZEDElyUdeHwG6nmmbmVi%2BJnzLE6ccgL0cuz6RxA2Sq6WDBc65WNyJiSJKLavZDsL3ayi6oC5scG%2ByS73PGTYPlyFsMk6OjMM6V6kZEDElyUVoFUfZqq7Kq1WvIIB%2BXfJ%2BRI%2Fw7JhRUaKxIcKW6ERFDklyVgmn2aqqqrlUJ7Gd0ybcZEnw%2BvP3EMN2V6kZEDElyVSoWTh1mn%2BNrVosKjdY1z2c5t1yqigAxGnolbdnqJerGjYeIIUmeL73eGw87e6av7yzCB5%2BdQrvZesnn5RY34NlXsnH6bIudOs62nuQVHU%2FsrFc6Nx0i98XL0lGXaFUstyg4OGE0jh4%2BgWRnzTcjpw5b3y1GcKAXfj57KJYkhGJQ0Lc7tC0tFjy3OQd%2FfD0X8VMG4c65w3DjxKArfts9faGo00wxWinqFifqls0tiIghSR4s9QRyoiMxTwNsj4nAC7XtWJ%2BXh1ZHz%2FeZR8bgptggvCGC8lIhOHZUP%2FwjcSreFD3PbR%2BVInnvVwgf5oc7xPNun3kN%2Bvg6Z1MfMQLGfno8IgPSqmBeWhZyRL2IiCFJnu5IJvZMGo04s4KNIgjunxCBd6Bir9aKzGE5KN4OWOw9T71Og1nTB9sGuUv1jR3FIgRPng%2FBxJf%2BA9f8oONkm4iwPnjm0bF44oFI7BBBKYN11XMZ%2BM2GLDz5YKQtWO1tnuhtFoUj1KJBpDxJRwEWqKIDrBM9SBmQ3GqIGJJ0lfUoxWi6%2FA6hRsUcMf2AVYuRBREIjXHw1WWuDfHF9RMC8O8TNTh4tAqFpU1oaDR%2F63k%2BXlpcHxOI7MIG5BTWo6nFgvzixh7NU%2FQC1Uv9vgC23xeLN54r3v0B0XuMP3Icx7ilEDEk6WruVXYEQY%2FC4HLB801fnWmxHZf86%2FslthNz5DHJR%2B8dZTtGeeHxSXlyz0efn7b1IFNMZ2290PgpwbYe5OTYnh2fFL1BXlaOiCFJ5JpefDMPz%2Fz5BMwW1RZ0v394DG6ZOgi6b3yFpPBkI35yz79wprL1e0OUiIghSR6l4mwrfpEwDL%2BYG4pR1%2Fb53udV17Xbfv%2FsI2O%2FM0SJiBiS5HF%2B9%2F%2B6dlW3CVH%2BeO%2FP17NgRGRXvJgAERERQ5JcZqPTKrZL07mihsZ2riAiYkhS7%2FHvYzBX1ra65LLlFtVxBRERQ5J6Tx9ffU3Z6SaXXLbUY2dtY0VFPRxwcQQiYkgSXVJgf%2BO%2BFFO5Sy7b7pRTtrGqoEKMyrm2iBiSRE6VV9K8dtfeUnNbu9WllquwtB5FpQ3n%2FmcUiJ8lXFtEDEkip%2Fr8UFOaQa8xJSYXutRyPfZs2tcPVMjr2O3m2iJiSBI5XdnZpkWbE3Na0rOrXWJ51r2agfzi%2BnMBWSCGGKsGO7mmiBiSRE6XJjKprV1NWP7kQUtvB6UMyG0X9moVpCjAl7xQORExJKnXHEq3fNTQbL5n6ar96stbs%2BDsY5TyGOTtK764OCBVvC1%2B3qxq8SjXEBHxsnTUqw5n4vXYCKvmrZ35mxI%2FKNTFjQ9C%2FJQQhIf1RehgP7vOq6nFjOyCOqQePYPPUk6JkGy4%2BAkyIOU9IRXcYRI9Xa4dImJIUq8zZeG1CVFqmaXNsn1farlWDN5OXQB5DFJBipiKVzVYknYcn3CtEJHE3a3kGj1KEUyKFuPF5KcitCoVIEMMJ0V4NTpgdg2i7UKNKuYFvKcCRvHYT3xkvOEwA5KI2JMkV5TWsYtzdnQUxmmsSBDTM2AVManA186z8lNV1KgK%2FMV0qqrFGhNP0iEihiS5g86zSuXwBKtBRL2Ju1uJiIgYkkRERAxJIiIihiQRERFDkoiIiCFJRETEkCQiImJIEhERuSteTIBcgmq6V7%2FjwMEHM3OqF2fn146sqm0znqlqUbr6%2BsD%2BRrOvt74mKMC4L6%2Bkea28sTOrSkQMSXJ7u9%2BIue%2BhF99fn1NY5ztz2jW4bdlQDBrog4GBXl1uo6KyRXe6oikoxVSRUFxWMuvWqT4meWPnNN7Ng4gYkuSWvUf1Kc22l3YmrduUMXfRnDCsWzURBn3PjgDIQJXDdREBuHt%2BuC4xuTBuc2JORuxYdY4p3fIxq01EPcFjktRrZEBuScqd%2B%2FzqiVg8O6zHAflNsh3Z3san47x8DMqHsZG4k9UmIoYkuQ25i1X09OaufzwWY0f1d8g8ZLsb1sRpdTrN5mgGJRExJMkdyJN0kvecXL9I9PYcFZAXBuXCWcMVHZRXRI%2FyFlafiBiS5AiKvRqSZ7HmFdf7zp95rVMWfOmCUTAYNDqriqSYMQhz17oREUOSXNT1IfCyV1uZudVL4qcMsdsxyMuR85k0boBMKx0seM5d60ZEDElyUc1%2BCLZXW9kFdWGTY4OduvwzbhosR95imBwdhXHuWDciYkiSi9IqiLJXW5VVrV5DBvk4dfkjR%2Fh3TCio0FiR4I51IyKGJLkqBdPs1VRVXasS2M%2Fo1MUPCT4fyn5imO6OdSMi5%2BPFBKhrVCycOgy%2F%2BqIILVfalNWiQqPt2vksNXXtWPvnE0gxnUVzqxUhg7yxdMFw%2FOSHg7r3abBzfqqKAMVJ272ol1e9qBs3HiL2JMnzpdd742Fnz%2FThZ%2F6NLTuKEPIDHyxJCMWBI5W4a5UJJ79q7mHHztaTdMpxws56pXPTIWJIkofTqlguRisnjMZMZ8635FSTbRwzxh93%2F2wYNBoFVqtq69peydtx9HJ31mllZ92IiCFJniz1BHKsCuYpCrbGRGD1iBFwykHFB5aMgE6r4IUtuZj7Pwch5o9H7x1l6xOe%2FKoJbe1Wl6qTrIusj6yTrJesG7ceIvfFY5LUZUcysWfSaMSZFWzsp8f9EyLwjujQ7dVakTksB8XbAYu95%2Bll0MLPV2c7NmnKqMb8mdfg%2F90VjiE37EK72Yo9b92E60b367WazBO90qJwhFo0iJQn6YgMXyD6uBk6FXFpWQxIIoYkXXU9SjGaLr9rqFExR3b2rFqMLIhAaIydry5zprIVdz1mQlOLBRueisbvNmYhMfkkWtusUFXVtutVnsjTE6K3p9pjGQs69vsWizeeK979AdF7jD9yHMe4pRAxJOlq7lV2BEGPwqCrAZWZX2cLSGn6fw7EjRODMP%2BBg3jv72W2f7v9JyEI8Df0aPlFL4%2BXiyOiy%2BIxSXJZkWF94WXsOMdm0cpU7Dt0BtdHB34ddBk1KC5rYqGIiCFJV58BgUa89kwMBg%2F0wpfp1Xjg6aN4J%2Fkklv88DFMmDUBecQNuuSsFx7JqWSwicgjubiWXNmNyMGbsmo7S082245DBQV5OuzA6ERFDktxCT0%2FQISK6EvxITs7f6LSK7dJ0ztTQ2M7CExFDklyffx%2BDubK21anzzC2qY%2BGJiCFJrq%2BPr76m7LRzz0pNPXbWNlZU1MMBFz0gIoYkkV0E9jfuSzGVO3Weu1NO2caqggoxKudaICKGJLmkvJLmtbv2lpqddd3VwtJ6FJU2nNviC8TPEq4FImJIkkv6%2FFBTmkGvMSUmFzplfo89m%2Fb1AxWNsmPJtUBEDElyWWVnmxZtTsxpSc%2Buduh81r2agfzi%2BnMBWSCGGKsGO7kGiIghSS4rTWRXW7uasPzJgxZHBaUMyG0X9lYVpCjAl7wAORExJMnlHUq3fNTQbL5n6ar96stbs%2Bx2b0h5DPL2FV9cHJAq3hY%2Fb1a1eJSVJ6Ku4hV3qFcdzsTrsRFWzVs78zclflCoixsfhPgpIQgP64vQwX5daqOpxYzsgjqkHj2Dz1JOiZBsuPgJMiDlvR4V3GESPVhWnYgYkuQ2TFl4bUKUWmZps2zfl1quFYN9rkEnj0EqSBFT8aoGS9KO4xNWm4i6g7tbyTV6lCLAFC3Gi8lPRbhVKkCGGE6KkGvsRjMN4jWFGlW0AbynAkbx2E98FLzhMAOSiNiTJHeW1rErdHZ0FMZprEgQ0zNgFTGpwLeLTfipKmpUBf5iOlXVYo2JJ%2BkQEUOSPEnn2adyeILVIKLexN2tREREDEkiIiKGJBEREUOSiIiIIUlERMSQJCIiYkgSERExJImIiNwVLyZALkE13avfceDgg5k51Yuz82tHVtW2Gc9UtSjf9%2FzA%2Fkazr7e%2BJijAuC%2BvpHmtvJEzq0hEDEnyOLvfiLnvoRffX59TWOc7c9o1uG3ZUAwa6IOBgV7f%2B5qKyhbd6YqmoBRTRUJxWcmsW6f6mOSNnNN4lw8iYkiSR%2FQe1ac0217ambRuU8bcRXPCsG7VRBj0XTsCIANUDtdFBODu%2BeG6xOTCuM2JORmxY9U5pnTLx6wuEdkDj0lSr5EBuSUpd%2B7zqydi8eywLgfkN8nXyddvfDrOy8egfBgbiTtZXSJiSJLbkrtYRc9v7vrHYzF2VH%2B7tCnb2bAmTqvTaTZHMyiJiCFJ7kiepJO85%2BT6RaL3Z6%2BAvDAoF84aruigvCJ6lLew2kTEkCRnUOzVkDyLNa%2B43nf%2BzGsdsqBLF4yCwaDRWVUkxYxBmKfUjYgYkuSirg%2BBl73aysytXhI%2FZUiPj0Fejmx30rgBMp10sOA5T6kbETEkyUU1%2ByHYXm1lF9SFTY4NdujyzrhpsBx5i2FydBTGeULdiIghSS5KqyDKXm1VVrV6DRnk49DljRzh3zGhoEJjRYIn1I2IGJLkqhRMs1dTVXWtSmA%2FY9efX9uGk181wWJRu%2FyakODzIewnhumeUDciYkiSq1KxcOow%2Bxxfs4qw02i7fj7LM3%2FOxoRb9%2BD02Zaub9id7asqAsRoaG%2BUzFYvUTduPEQMSfJ86fXeeNj9OsC2nmSvHBfsrFc6Nx0ihiR5OK2K5WK0csJozHTHxXf2DDvrtLKzbkTEkCRPlnoCOVYF8xQFW2MisHrECBhZlW%2BTdZH1kXWS9ZJ1Y1WI3BcvcE5ddiQTeyaNRpxZwcZ%2Betw%2FIQLvQMVerRWZw3JQvB2wXG01mSd6qUXhCLVoEClP0lGABSqQoVMRl5bFgCRiSNJV16MUo%2Bnyu4caFXPE9ANWLUYWRCA0xoWvLiN6d6oj2i2Ard1i8cZzxbs%2FIHqP8UeO4xi3FCKGJF3NvcqOIOhRGDgqsC5F9Op4eTgi6jYekyQiImJIEhERMSSJiIgYkkRERI7EE3fI%2BZ%2FMtEq3Lk23bOFwzJo%2BGAP6d%2F2rmQ2N7Sw0ETEkyf349zGYK2tbdQMCunYp2OFDfW1Dd%2BQW1bHQRHTlH%2BpZAnK2Pr76mrLTTQ6dR%2Bqxs7axoqIeV%2BFFDoiIIUluKrC%2FcV%2BKqdyh89idcso2VhVUiFE5q05EDElyC3klzWt37S01t7VbHdJ%2BYWk9ikobzm3hBeJnCatORAxJcgufH2pKM%2Bg1psTkQoe0%2F9izaV8%2FUNEoO5asOhExJMltlJ1tWrQ5MaclPbvaru2uezUD%2BcX15wKyQAwxVg12suJExJAkt5EmsqytXU1Y%2FuRBi72CUgbktgt7pwpSFOBLXnCciBiS5HYOpVs%2Bamg237N01X715a1Z6OkxSnkM8vYVX1wckCreFj9vVrV4lJUmop7i9ySpVx3OxOuxEVbNWzvzNyV%2BUKiLGx%2BE%2BCkhCA%2Fri9DBft%2F5mqYWM7IL6pB69Aw%2BSzklQrLh4ifIgJT3dlRwh0n0WFllImJIktsyZeG1CVFqmaXNsn1farlWDN49akgeg1SQIqbiVQ2WpB3HJ6wuEV0J7m4l1%2BhRikBTtBgvJj8VYVepABliOClCr%2FESL2sQzynUqOI1wHsqYBSP%2FcRHvxsOMyCJiD1J8iRpHbtGZ0dHYZzGigQxPQNWEZMKvu%2BadH6qihpVgb%2BYTlW1WGPiSTpExJAkT9Z5NqocnmA1iKg3cXcrERERQ5KIiIghSURExJAkIiJiSBIRETEkiYiIGJJEREQMSSIiInfFiwmQS1BN9%2Bp3HDj4YGZO9eLs%2FNqRVbVtxjNVLUpXXx%2FY32j29dbXBAUY9%2BWVNK%2BVN3ZmVYmIIUlub%2FcbMfc99OL763MK63xnTrsGty0bikEDfTAw0KvLbVRUtuhOVzQFpZgqEorLSmbdOtXHJG%2FsnMa7gBARQ5LcsveoPqXZ9tLOpHWbMuYumhOGdasmwqDv2REAGahyuC4iAHfPD9clJhfGbU7MyYgdq84xpVs%2BZrWJqCd4TJJ6jQzILUm5c59fPRGLZ4f1OCC%2FSbYj29v4dJyXj0H5MDYSd7LaRMSQJLchd7GKnt7c9Y%2FHYuyo%2Fg6Zh2x3w5o4rU6n2RzNoCQihiS5A3mSTvKek%2BsXid6eowLywqBcOGu4ooPyiuhR3sLqExFDkuyea2JQ7NWYPIs1r7jed%2F7Ma52y8EsXjILBoNFZVSTFjEGYk2undNaPiBiS5KFarg%2BBl70ay8ytXhI%2FZYjdjkFejpzPpHEDZFrpYMFzzixcZ91auAkRMSTJc51p9kOwvRrLLqgLmxwb7NQ3MOOmwXLkLYbJ0VEY56z5dtbtDDchIoYkeSgVyNEqiLJXe5VVrV5DBvk49T1EjvDvmFBQobEiwVnzlXWT9eNWRMSQJA%2BlAAfEj2n2aq%2BqrlUJ7Gd06nsICT4fyn5imO7E4k2z1Y%2BIGJLkmawa7BTdyYVTh9nnuKTVokKj7d55QKrojq1YcxQ%2FW3EQldVt3d%2FQO%2Bcn2gkQo6HOqJutXqJutvoREUOSPNOR4zgmRun13ni4t5bh9Z1FSEw%2BiS8OncHDa%2F99Jb1i2ZN0ygHRznqld9aPiBiS5Km0KpaL0coJozHT2fMuK2%2FGbzdk4caJQfjl0lFI%2FvwrJO0qvaK34%2Bhl7qzTys66ERFDkjxZ6gnkWBXMUxRsjYnA6hEj4LSDirLn2NZuxXOPXYcHfzESE6L88fhzGSg93exydZJ1kfWRdZL1knXj1kPEkKSrwJFM7BE9ozgVmNJPj6IJEXhB9pgmhmP4PAf1znZ8UobP%2FlWBlXeJmQz1hU6rYMOaaFtoPvD0Uduxyt4k37d8%2F7IOsh6yLrI%2Bsk6yXtxqiNwb7wJC3e5RitF0%2BV1DjYo5YvoBqxYjCyIQGmPHq%2FKcM3p4H7y%2F6QZMvO7ry9eNDPXD39%2B8EVU1bWhutcDHq%2Fv5LHp7donXgo6r6RSLN54r3v0B0XuM5zFIIoYkXe29yo4g6FEYdCegxoT3%2Fc5%2Fjwjrc0XLn5Zl%2F0AnIs%2FD3a1EREQMSSIiIoYkERERQ5KIiIghSZ610WkV26XpnKmhsZ2FJyKGJLk%2B%2Fz4Gc2Vtq1PnmVtUx8ITEUOSXF8fX31N2ekmp84z9dhZ21hRUS9GFq4FImJIkksK7G%2Fcl2Iqd%2Bo8d6ecso1VBRViVM61QEQMSXJJeSXNa3ftLTXLS8s5Q2FpPYpKG85t8QXiZwnXAhExJMklfX6oKc2g15gSkwudMr%2FHnk37%2BoGKRtmx5FogIoYkuayys02LNifmtKRnVzt0PutezUB%2Bcf25gCwQQwxvgkxEDElyaWkiu9ra1YTlTx60OCooZUBuu7C3qiBFAb7kBciJiCFJLu9Qugf0J4QAACAASURBVOWjhmbzPUtX7Vdf3poFex2jlMcgb1%2FxxcUBqeJt8fNmVYtHWXki6ireBYR61eFMvB4bYdW8tTN%2FU%2BIHhbq48UGInxKC8LC%2BCB3s16U2mlrMyC6oQ%2BrRM%2Fgs5ZQIyYaLnyADUsE0RcEdJtGDZdWJiCFJbsOUhdcmRKllljbL9n2p5VoxeNulYXkMUkGKmIpXNViSdhyfsNpE1B3c3Uqu0aMUAaZoMV5MfirCrVIBMsRwUoRcYzeaaRCvKdSoog3gPRUwisd%2B4qPgDYcZkETEniS5s7SOXaGzo6MwTmNFgpieAauISQW%2BXWzCT1VRoyrwF9OpqhZrTDxJh4gYkuRJOs8%2BlcMTrAYR9SbubiUiImJIEhERMSSJiIgYkkRERAxJIiIihiQRERFDkoiIiCFJRETkrngxAeoR1XSvfseBgw9m5lQvzs6vHVlV22Y8U9WifPN5gf2NZl9vfU1QgHFfXknzWnnDZUcvW0wEVK6hnknLgsIqEDEk6QrsfiPmvodefH99TmGd78xp1%2BC2ZUMxaKAPBgZ6feu5FZUtutMVTUEppoqE4rKSWbdO9THJGy6nOfhuHKZ%2FbuGK6qbYG%2B9kEYgYktTj3qP6lGbbSzuT1m3KmLtoThjWrZoIg%2F7Se%2BxlcMrhuogA3D0%2FXJeYXBi3OTEnI3asOseUbvmYVXUt53rh7FESdeAxSeoyGZBbknLnPr96IhbPDrtsQH6TfL583can47x8DMqHsZFg14WIGJLk%2FuQuVtEDnLv%2B8ViMHdX%2FitqSr9%2BwJk6r02k2RzMoiYghSe5MnqSTvOfk%2BkWiF3ilAXlhUC6cNVzRQXlF9ChvYZWJiCFJTss1MdjtmJI8izWvuN53%2Fsxr7bqQSxeMgsGg0VlVJMWMQRhXG%2FWA0rm9EzEkqctarg%2BBl70ay8ytXhI%2FZUi3j0Fejmxv0rgB8q%2BcDhY8x9VG3dW5nbewEsSQpO440%2ByHYHs1ll1QFzY5NtghCzrjpsFy5C2GydFRGMdVR93RuZ2fYSWIIUldpgI5WgVR9mqvsqrVa8ggH4csa%2BQI%2F44JBRUaKxK49qg75HYut3dWghiS1GUKcED8mGav9qrqWpXAfkaHLGtI8Pnw9RPDdK496ubGPs22vRM5CC8m4IGsGuwUvbJPpg7Dr74ouvLjNVaLCo3WMd8tP9euqiJAcfL2WFhcjkd%2B%2Feb5x2sen4%2Bo0UPxq9%2F8Fdm5p%2FDMUz%2FHiOE%2FsP0uv%2FA0nnv5ffz5hWVYcNfzaG%2B3fGebdy%2F%2BMeJ%2FPOGS862vb8YLf%2FoA%2F%2FhXBhobW%2FGDQf0RN3EUlt1xM%2Fr188XipX9EU3Ob7bk%2Fm%2F2ftuGJ3%2F0Nmdml32pr%2FNhhWP3Iz2A6kodn%2FvDut37%2Fi4U%2FxMz4iR65nYvt26texUKxvcfzfz0xJKnLjhzHsZgIpNd742Hx8Ldu0vuVPUlvZ84z5AeB%2BO3q%2F8aPbv01kpNWnw%2FE9MxiEV4tWPfHd%2FHqS%2Ffb%2Fq1BPD58rONKeg%2Fe91OoVqttesWjf8HiBT%2FExOgRtsfXhl7%2B2O3PRQgG9PfDC7%2B%2Fyzb%2B9%2FFiJO74hwjtCoy%2F7lqsffLnWLzsRcxPuBHxP4q2veb2hMmoq2s634bZbMXDv34d0dd1nHFcXdOAopJyvLzunovmNWxosMdu553bd7rc3vm%2FnhiS1C1aFcstCg5OGI2jh08g2V0W25kz0xt0GDI4wDYte3NGg%2F7875bdEY%2Bnnk3EsYwijBsz7KLXxcWGn5%2F2MhoQER6C6yeN7tI8q6sb8OXhXKR8uvZ8oF4zJAg%2FmRFjCz5pyOBAGPQ6BAb0Qd%2B%2BHbujZQ%2F3Qr%2F%2B7d%2FE6wbglw8lXLQsXV0Odye265litFJs53H8306OxGOSHir1BHKsCuYpCraKXuXqESNgZFW6Tu72vO%2FOW7D2hR12bdff3xfBA%2F2x4dWPUFB0%2BuJPrLqu%2FXdMejcFuz8%2Fildf%2FJ%2BLXtPS2oYDYsVfOHx1utqj1ovcjuX2LLdruX3L7ZxbK7EnST1yJBN7RMcizqxgYz897p8QgXegYq%2FWisxhOSjeDlhYpe931%2BIfY8tfP0PKgUz06WOfs3sV8df99T89gF%2F%2F7m3cGP84%2FHy9MG7stVg8f2qXjh0eOVaAp9clYcebj9p21V7cS23E8xs%2BuOjf3P2Y5DxAWxSOUIsGkZ0n6SxQgQyd6EGmZTEgiSFJduhRitF0%2BR1EjYo5YvoBqxYjCyIQGgPXu9ODK90L0tvLgP%2F9n1ux9g878fsnfm63duXu2w%2Fe%2BZXtGOPx7JP45%2F5MrHjkL6JXqL3kST8VZ2px9wMbsW7NEkSMuuZbv5e7jHdsfdSj1kNBx9V0isWGmiu21gOi9xjPY5DEkCT79yo7%2FrD06I9Ld%2F5gph6rQrtZRdTIvvDvq%2B%2F2vOxxiyZ7%2FoFfkHAjNm35BB%2Fvtv%2B9ouXxxusnjrINWSIsj%2Fy74HtDsq3djLtWbMDtcybjJzfHOnx74a2yiDrwmCTZ1c%2F%2F35e4bdl%2B%2FPtErWd8itRr8ciDs%2FHa1s%2Fs0l5u%2Fld45NdvoKik4vy%2F5eSdsu1GnThh5Pe%2B7vE1byEooA8eXnEbNzIi9iSJHC87t8z2dQzpp%2FN%2Fh1f%2BcB8mjP%2F2ddZn%2Fdck%2FOkvH6O2vvGK5xkQ4Ieq6gZMm%2Flr9OvnA4NBh%2FqGFvzvfT%2FFj6d2XJXvR7c%2BgYLC03jq9%2B%2Bgsqoe9yyZjv%2FblYqm5lZcE3nXRe0NHzYI%2F%2Fzk97Zp%2Bb3PIaMvvvPYU4%2FNxz2%2FmMGVTdRDvbJLRe4O4%2B4c9yHXl%2BmDnzqs%2FdhbPzw%2Fba%2FdraZ%2FbnHpmprbLfiqouPM0yE%2FCIRG0%2Fv%2FHWJvvNOu64HIE3KDPUkiO3rl9U%2Bx%2B%2FPvP%2FT7%2Bp9WoI%2Bft203rvx%2BJBG5NoYkXZa8dJyjLk3X0NjuUbVaesfNtoGIPOTvH0tAl%2BPfx2CurG11SNu5RXUsMBExJMl99fHV15SdbnJI26nHztrGiop68OIGRMSQJHcT2N%2B4L8VU7pC2d6ecso1VBfI7EeWsNhExJMmt5JU0r921t9Tc1m61a7uFpfUoKm04tyUWiJ8lrDYRMSTJrXx%2BqCnNoNeYEpML7druY89ecBUbFfJLiLtZbSJiSJLbKTvbtGhzYk5LerZ97iqx7tUM5BfXnwvIAjHEyJtFs9JExJAkt5MmMq2tXU1Y%2FuRBy5UGpQzIbRf2ShWkKMCXvHA1ETEkyW0dSrd81NBsvmfpqv3qy1uz0N1jlPIY5O0rvrg4IFW8LX7erGrxKCtMRK6GFxOgbjmciddjI6yat3bmb0r8oFAXNz4I8VNCEB7WF6GDL76%2FYVOLGdkFdUg9egafpZwSIdlwcWMyIOU9AhXcYRI9VVaXiBiS5PZMWXhtQpRaZmmzbN%2BXWq4Vg3e3GpDHIBWkiKl4VYMlacfxib2X8cLrkBIR9RR3t1LPepQi2BQtxovJT0XoVSpAhhhOivD7rltlNIjfFWpU8VzgPRUwisd%2B4iPaDYcdEJDyIsi8QDcRsSdJvSqtYxfp7OgojNNYkSCmZ8AqwkmB7zee6qeqqFEV%2BIvpVFWLNSaepENEDEm6GnSelSqHJ1wqxNmbJKIrxN2tREREDEkiIiKGJBEREUOSiIiIIUlERMSQJCIiYkgSERExJImIiNwVLybQRarpXv2OAwcfzMypXpydXzuyqrbNeKaq5Xu%2FrB7Y32j29dbXBAUY9%2BWVNK%2BVNy529DLGREB19zrzAgBE%2FPvGkHQzu9%2BIue%2BhF99fn1NY5ztz2jW4bdlQDBrog4GBXt%2F7morKFt3piqagFFNFQnFZyaxbp%2FqY5I2L0xx8twvTP7e4bZ15UXIi%2Fn1zNdremOngAfj%2F7d0JXBTVAwfw3y63gNyeqKSI4C144K14m7dRXnmWpqLmVWpqZdrhUZpaaYplpqZp5ZFpavrXIhWvVBAwBO8TQUCQa%2F%2FvDbBBagLCHvD7fj7LXrMzszNv32%2FezPDmnet38K7Bb11p3lHXdLy7aelXoVM7tXE1nzvZG74NXFDWxQrWpf57%2B0K%2BL4drVM8ZL3V7Tp2hgeuZ0HsjyzirTly7pblQVMt15PCeRlsYV675SfkOxlI%2BiIy69WiE9Zs%2B6gUek%2FwPmz7d8l3gdxEvLJrZCIN7V4O5WcEWl%2Fyc%2FPzyOb6WpcxV2xvWBJtMRMT6zQgwJP9jF8SqjeEvLJjREHVqOBTKOOV4lr3ra2Jqql7VgEFJRKzfGJJGuRsieKTZjn2XFwwSW0eFVYByFqQBPauqTKFaIba4unBpExHrN4bk4xjsWYzyLK8L0fHW%2Fbo9VyTjH9W%2FBszN1aYZGnznUxvV%2BLMlItZvhpkXegvJpq6wNNRCFBJxb0jn1hULvI%2F%2BaeR4G9dzkWvdFOlYyJ8tEbF%2BM8y80FtIJtmgrKEWorDI%2B9VaNCza2evYqoK8sxK3Fg1qoR5%2FukTE%2Bs3w8kJvIWmiQi1DLUR3Yx5aVixXqkinUdPdPnsnwi11Bvryp0tErN8MLy%2F0d0xSBT9DLUQx9x%2BqnOws8vWZOzEPcfn6A8TeT83T8K5ltYXURtw68KdLRIZUv2k0UOo0eUtJycjXNAq9ftNjXugvJDUY0MbNMI9LZqRroDbJ%2B3HiiOgE%2BPTch7YD%2F6cUqDwt%2BKzxi4LoKO4q86dLRIZUv6nEIJ%2BsiYB3j32YOO90%2FoKlEOs3JSdEXpS8kATOxFthSnEodBPmnMaD5HQsnFYXdWrY5XMDSdnSKsufLhEZmgVv1kVdTzts%2BvkKfv39ZgEagM9ev2XlxJkSF5ImGgSIu0nenuhmzIXof0fv4NhfMfCt74heHSsUeHHoer5TUtPwReAvGDxqMQKmrMSxExHK61eu3sXHy35CXFyidtg9%2B09h5%2B5g5bG8Dzp6HktX7MTAVz7GR4u3Iik5RXnv1p04ZZyxsYn46tv9WLlmN2sZIiNmIlqE70%2BurTz%2BeFWEzuu3rHyYlJUXJSskRT0bnqGCv2jSr%2FXxwkx3d1gYYyHadfCGcj%2Bgh3HtMR014TOcj7iKgJHPo12buhg%2Bdiki%2Fr4O14pOCLtwDRNnZHaU%2Fte5KLz59teoXauK8nz7L8fwqvjsg6SH6NG1MQ4cOotZc79V3rstQnL%2B4h%2FQd%2FCHYhxXcScmnrUMkZFrIhoAVStb4%2Fi5e7hxJ1kn05R5IHNB5oPMCZkX%2Bvr%2Ber0KyMkQ7GvsCd80FZbbmWGstxc2QIP9JhkIcQtH9GYg3dAL0F9hccp9o7oORlPoz52%2FhJCwywj6dT7UannsoDqOBIfj5z3BmDC6OxbNG4bn%2Fd9TWpQ%2F7DiCxR%2B8giquLtrPT3itO14dknks3tPDFX0HfYiP3h2iPDe3MMXWb6bBzs6atQtRMdGojgMiLyXibNh9lHMu%2FFNJ%2FEVrM8oDVdLVqClP0hG1Un8NcNZUA9%2FjofoLSL2HZHaLUtx1kP9Lo9agj3g8PsME1SO9UMUHhn9twXuxmbsanRyerSGsy2tBhkVcw%2B3b99Gsw5u5Xu%2FXt6Vyb2Ntic8%2FeQ0de72DkUM7onWL3Gdfq3KslapuZZXdrXH3M09YsjAzK5SALA7XxiQqLpwdM%2Bu3mLiUIvk9R0J5P1pULRGi1g8SrcfOJ8%2FhtCF8d4O5nmTWAjmdjy2MsUXVBM9PBW1jk7kIk5LT4VDarMDTLIyLDed1vm1tLOFWpQz2b3%2FvicNs%2BSkItb0qK7tX5S5ZRwebxw4XE5sAM3NT2IpgvV6I64AXXyZ6VGNPeMg9b%2BLHUVv82Au0560gG6APHmSO2trKtMT9ng2%2Bg3O54o%2BFI%2FLEeew4EYpJcalwE0v7YLoKfzaoiXb6nj%2B3ipmtprPhcUaz0n0b1sCNW7H4%2Fqc%2FtK9dunIHJ09HKo937jmOX387hS3rpsGvVV2MnbICGRn%2F%2FK7uZ7Ua09Mz8NnKn9GxbX0lKImo6Mj6TtZ7sv6T9aCsD2W9KOvHoj40lV2%2FVa1UqsQtd6Or2S5cwENxN9fbE6dEwm%2BWxzT1eVDXr6kLfthzFVt2XUXHFsbxnxy2tlZY89k4TJoeiHkLN8PSwgxJSSlY9P5wXIi8julvr8XGr6bAupQF5rzVH11feA%2BLlv2IqeN7K5%2FfuPUwvt38PyQ%2FTEGNahWxcukY1mBERdyCTNdgs0aDwTIYdTnt6KsPEHz2HiqUsYRntdIMSWMhC4qPFz4WW1bLxNOO%2BpqP3h0rYt7y89i%2B%2Fzpev3AfXu7GUYia%2BHjg9z0f4qZoUapUKpRx%2Bef%2FO%2F8KWqJ9bGFuhn3b5uT6rDxOOcC%2FFRISknN9rpZnZZz%2BYzFrNKJCllXPfazrgJQWfBmm9L7z2oBquc5HKCmM%2BnqStklKD%2FN19NlBuIW5Gu9PqY3UtAyMefsk4hPTjGoZli1jnyvo8qqUlUWBPkdE%2BZNVv9XJqu90Su4lkx0J1KxeGsP93Urk8jfqA0kHopDsUxPrszrQLbQzoWSXSvnpmq57u%2FJYu7AR4uJTceX6gzy1JhMSU41ymQ8Z4AcnB1vWXES6asnI%2Bk2F9bK%2B02X9JluP8lSET2fXRzNvJ6VBkFfGWr8Vu5DMXJPYL9bj64U5Sntb87S7cQ9NXRzz%2Fv9AXVqXy9c0IqLuG%2BXibtqoBmstIp1WcWiq0qDQjmPktX6Tu1b7dqpYoGkYa%2F322I0KY%2F8CYoPonFiXHoU5Tltrs9irNx4U6XwfPX0nsyBqILulSWdVQESPDSsoJ%2B2cY%2F3GkCwQqwTIXnddCnOcTg4WBw8H3yzS%2Bf718LXMrUQVbom7m6wKiOgJXLLqOdZvDMn8C7qi7Kcv1H6SLlxK%2BmDn%2FitpKakZRTLPF6%2FEI%2BpKQvYakP%2BceIn1ABE9gWVWPcf6jSFZIBoUcvd1vx15cNzcTB28ccfFIpnhaR8dzzn38nIbv7IeIKInUGXVc6zfGJKG4%2BqdB4NWbQxPPhN2r1DHO3%2FlWfwdHZ9dgCLFzSdDjS1c4kTE%2Bo0haTSOi3WdkqrpG%2FD2n%2BmFVZBkAdqUc%2BtNhcNiE%2FGYoXTkS0Ss31i%2FMSTz7MiZ9J8TktJeHTX9D83StaEo6D58uY%2F%2BpXEHchcgDeRFGDtpTPAGlzQRsX4zTOyV%2BilOhGBNQ68M9Tdb%2Fv5i47aLpr71ndG5tSs8qpVGlQqPvzLGg%2BQ0hEXex9FTt7H38DVRiBJyDyALkLyiiQrDgsUWHZcyEbF%2BY0gareBQrPaupbmanpK%2B%2BeDRmybiZlWgEcl99CocFo86a9QYcvwcfinseW3YcjhXGBEVy%2FpNH7i7Na9bXGKFq0xQXzzcLQrDXRVwVtwui0KR%2BB8fSxDDXFRrxGeAHzSAhXhuIzZNmp0oggIkr9nG6zASUXGs39iSNALHM3cd9JYdDmf1F9sRGaIYqWD9hI%2FYaDSI1ahgLx4f1Zjg3WCepENErN8YksVZ1tla8jbbIAs7W5NEVEzrN13j7lYiIiKGJBEREUOSiIiIIUlERMSQJCIiYkgSERExJImIiBiSRERExoqdCTyGj1fhXeDU2BV1xwSa4JFm3wf9OSEk%2FN7gsL%2FjqsfEpVjcjkl%2B4jSdHCzSrK3MYp0dLQ7KK6zLC8iyfJGhl3NiSBY7wYcCS%2FwyKOrO0n%2F9ymf060t%2BXBB%2B8b51N79K6PVaZZQrUwplnCyf%2BJlbd5NNb9x64Hw4%2BFbf6KuXevZoUypYXkD2uJFdbYDlq%2BSUc2JIUgloVRfmlrZG845606dbvpv%2FxdkXBvWphvnTG8HcLG97%2FmWAyltdL0e80s%2FDdOOOi76rNoafbVhH0yf4TPourjEylHJOxQOPSZLOyYAM%2FC7ihUUzG2Fw72p5Dsh%2Fk5%2BTn18%2Bx9eylLlqe8OaYJOAiBiSZLzkLlbR8nthwYyGqFPDoVDGKcez7F1fE1NT9aoGDEoiYkiSMZIn6ezYd3nBINH6K6yAzBmUA3pWVZlCtUK0KLtwaRMRQzJH%2FStuPJZg4ORZrBei4637dXuuSMY%2Fqn8NmJurTTM0%2BM6nNqpxiVMxoMqq34gh%2BUySm7rCkqvTsIVE3BvSuXXFAh%2BDfBo53sb1XGStYop0LOQSJ2OXVa8lc0kwJJ%2FV7SQblOXqNGxhkfertWhYtKupY6sK8s5K3FrIK6xzqZMxy6rXbnNJMCSfiQYIN1GhFlenYbsb89CyYrlSRTqNmu72mQ9UuKXOQF8udTJmsl6T9RuXBEPymaiAIPHHj6vTsMXcf6hysrPI12fuxDzE5esPEHs%2FNU%2FDu5bVhrCNuHXgUicjr9z8lPqN9KZYdCaQocYW0Wr4pY0b3joQpdv99zH3EvDx8p%2Fw%2B5%2BhSEpKgWsFJ%2Fg2roHRI7rAupQF%2FIfMhybrsPuQ%2Fm3RvUsjvDHra0RG33xkXE3F5yYH9MShP0Kw5Isdj7w%2FekRntGtdV3kcdPQ8Plv1CyL%2BvgZLSzO0aVkHE0d3h52dtfL%2BkePhWLDkx0fG8e6MfqjlWVk%2F6yldA7VJ3s%2BviohOQPtB%2F4OZmRo%2FfN4U9qXtnr7VlzV%2BscwdVcWgfP9X%2Bdq6LUgpR2%2B%2F%2BZJ2%2BPT0DARMXYnBoqzZly6FWfM2wL9XM7zUp4V2mJCwy5gtXu%2FdvQkG%2BrfGrTtxGDNphfb90rZWaNLQA0MH%2BsHC3Ez7%2Bo5fjuGr9b%2FhytU7sLa2RPfOjfDaiE6wtDBX3t%2F281Fl3NMm5q8Bf%2F3GPYx740vt8yqVXNC7WxO0aFpT%2B9rjfjNWlub4ZuXrCL9wDTPmrHtkvBNe64aWzWoa7boX9ZllvAYDRP3WmVHFkHwmJ8%2FhtI8XzsRbYYp4OldX09WImviloQtQvVoFLF0wUlQupXD6zEWs23QQPbvGiNfL45P3R4ig%2FAjjRnUTQVZb%2Bdygfq2RmPhPlj9MScPEaavRsqlXVuvpPm7eisX8OYNzTa%2Fac%2BWV%2B1%2F2nsB4UanMnPoi5s0ehPvxD%2FDJ8m3oNfAD7Ng0SwnnmJgEXL56G4s%2FGJFrHJUqOBvNep0w5zQeJKfjy1n1UaeGXb4%2Bq8psSVoZc7l%2BWvl6vlNDtOo6A21b1Ear5plHGwLX7cO16zHwFSF35HgEzoZGI%2BrSTRGIvjA3y%2Fy5f%2FblLpw7fwkNG2SeAJycnKpsdG1YPVlskJjg9p37%2BGjxVnEfp5Qx6cuvf8VSseH23qwB8K5XTSmf783fhKBjYcrn1GoVrt2IQWjYlXx%2Fz6Tkh8r0N301VfnOJ05HYvCoJVi7YoI2KP86FwU%2FsYGY%2FRuRTExMlPuEhCRlucjhc6ruXsGo67Ws%2BuyMrN8YVQzJZ2aiQUC6Cn96e%2BLUifPYoYtpXrl2V9ly%2Fnb1JJRxzqzEK7s6K63FtLQM5blrRSeYmprC2ak0bG0y6%2By6tdxyjWfi9NWoU6uKEqTZZNA1bez52IpzzoffYcZkf6W1kG3F4jHo1OdtrPvuAEYN66Td0n7cOIzB%2F47ewbG%2FRGVf3xG9Oha4sjMx5jL9tPJlaqrG9El9lVbU%2Fh3v4e7deCz%2BfBu2rH0TKlVmi7qsiz08RFhs2noYg15qIzac7uD02Si0a1X3kek1aeShbTnKYa5dv5dZWYsQWrBkK1YsGYO2LetkbmxVdMa6lRPRrOOb2LP%2FJDq3937m7%2BvbqIYIPrUSjDIoD%2F5%2BLldrUm50Pqk8m4hlYaxl%2FXFEPSYrg0miXvNlTOlXselMQGyIhmeo4C%2FqhrWiVTnT3R0WRT3NsmXs4eBgg0%2FFFnb05Vu5tz5M87ZoV3%2BzV6kQli8cpWyNZ0t8kLl1nfN263YcLkbfxCVR0cndUf%2BeXo8ujUXFcjbHFnpKrs9fiLxuNOtz18Ebyv2AHpVL7I8zL%2BVrwAut4Ohog%2BUrf8bb76%2FHyyIIPT1ccw0bMPJ5pfUog3XFmt0YObSjEir%2FduRYuFJO5G5VuctfDicdO3EB5hZmaNOidq7hbW2t0L5NPRw4fLbQW9C3bseKDQKXXK9H%2FH09V3k%2BKlrK2dLFd8v5nty4MEay3pL1l6zHZH0m6zXGFFuSheZkCPaJjUnfNBWW25lhrLcXNkCD%2FSYZCHELR%2FRm8VsqzOnJ3VeBy8aJymkD1qzbp1Qa3vWqYtjAdujQtv5TP%2F%2FHkfNY%2FNk2%2FLRhhvLZnGQlsWjZtlyvyWOS8liQpaiwso89%2FrtSvXX7vva5bFnkHEfr5rVEa%2FV5o1iXf4XFKfeN6jqU2B9nXsqXbDF%2B%2BM5gdH9xnmg12uHTBa8%2BMp56td1QqZKLGMde7D94BrPeeBHBpy48MtySz7dDpVaLME1Xyt9u0UKsX%2Fc5ZberbJFmt05zKlfWQTkuXhg%2BEb8FtZiGbMWWKmUJ%2F97Ncr3%2F857gXMGYfUxSSklNzVXW69aqgtk5jtUaKn%2FRCI7yQJV0NWpmnaTTXwOcNRUtyOOhDEiGZBG1KMVdB%2Fk%2FcmoN%2BojH4zNMUD3SC1V8iqBXnsY%2B1bFry2zExiYqx38OBYVgRMAyrF81Kdeuon%2BTu71GT%2FwCSz56FVXdyj3y%2FnNVyuL7tW888vrZ0EuiQkhTbtnHmLLFJyTDxvqfPhXkrt7HjaMgdH0NxHuxKcq9k4OFUc23PspXzRqV0NzXUzlWmH0Szb8FvNoVA15ZpOymz3kyTk7rAydr37t7Lx5tu85UTuCRZSohMemxn5G7Yq2tC68fjzsx8cpJSnu3zXnku0wY3R29uz1%2B76OVlUWhlHVdl5fIzN50okXFFCFqpyDReuzMY5AMSd20KjML2mld%2FVDs7a2VSiv7eMqJvyKfGJJyN%2BjwMUsxangn%2BLWqk6%2FpyONLcgv6cFDoI5899Mc5paVRFArjEkL5Wa42NqZZyyodDqXNimy%2B%2F2NLfmxR7eoqivJlYWH2n2cOy7M8Rw7thJf7tcnT9JwcbFG5sguiom%2BJVms95WSgyKgbuTbo5G5RGWiyZVsYJo7poRyTlMfjB49ajG0b3lK%2Bty4V9qWyGnvCQ%2B7ZEiOtLVZ6ke7ZoqLBDs6fwakzF5WTJmSrMJs8a%2FDc%2Bcto1MD9yZXB9NVK2I15Jf%2F9cMvW46tDO2Lme98qxyezBa7biyPB4Rg2Gzky0wAAIABJREFUqF2xWLZuFTMrx7PhcUU6HVlRHQtHpDzZ60QoJsWlwk1UaAflSWANaqKdMZavJ5G7WW3y0Op7mJKKH3ceQUjoZTRr4omKFZzQ6%2FkmmDBttfLvIlJaajrmLtgsWpjJ6NOjaaF%2B7%2BmTXlDO6H1l3DKkpqQZbRmW5UeWI1meZLmS5UuWM1neGJBsSZYI5crYK%2F8z1rLLDGXLW24FJyU9xIxJfbVn2jVr%2Fyau3ozB1Jlf4fbE3ujftxW27zqmvCcropzkWa9y15p0JiQaFT1zX%2FVpwXtDMcC%2FFSaN7YmMDA069noHTo62SHyQrJw9%2B%2B2qScpZh8WBX1MX%2FLDnKrbsuoqOLXTX4%2BCFC3go7ubKs6TFFuRmeYxbXydP5KV8FaaqdUcp93I6tb0qY9WyscrGnFL25g7FrLnr0bzDNKXMxd5PRA33itgYOCVX8O49cPqRcht6dBlKl857T0vyBLalC15F7wEfYPLMNfh0fuZx1oApK5VbNnm2%2BPng5QZZfmULMl2DzaKxPVhXZ9tT0dDLlTPk7iZDvgK4nL%2FgQ4F5Hl5u7d64Has81mVIyS1%2BecarbF3Kk3YKW8OWwwt1N5SyXLd1z%2BN3y0DDnvtwNzYF%2B75pCS%2F30nmf7x7bC2W%2B5VmG4q6VGEfHkli%2BHkeedR1zLx5WVuZwdiyN4qCwy3nWOt4j7v4nxjcXZNS5wZZkITAzN9VL5SVPsiguLcdHv5sa70%2BpjeHTgjHm7ZPYtrI5bK11W1xtk7Aw3gpj5Ulg%2BjyZQl%2Fl63Hk8UJ5y4%2F%2BIxYhNfXxexdlhwb57aHH0Ckd62egjig%2FPVg7Gj%2BGJOmMPLEkP13TdW9XHmsXNkJcfCquXH%2BQp9ZkQmJqoc2v7OLQpybWZ3WUzjMOC0j2yFOiyrksLyqs13UXmcSQJCNnb2uedjfuoamLY97%2FZaBL63L5mkZE1P3CnWkN9muA17n2KO9FBk1VGizmkigmGz1cBKQrttZmsVdvPCjSaRw9nXkmqKik4lEIZxCKhu850e714NqjvJLlRZYbLgmGJFG%2BODlYHDwcfLNIp%2FHr4czeXzQqyH7cnnliVgnKOFy49igfXLLKDTEkifLuwqWkD3buv5KWkppRJOO%2FeCUeUVcSskt2pPh76VnHGXRFOa5kybVH%2BWCZVW6IIUmUd78deXDc3EwdvHHHxSIZ%2F7SPjv%2FzRINE2bAshNHK3nFUXHuUD6qsckMMSaL8uXrnwaBVG8OTz4TdK9Txzl95Fn9Hx2fHWqS4%2BciLcXOJExFDkozGcZFlKamavgFv%2F5leWEEpA3JTztapCofFpvwxdhRNRAxJMjpHzqT%2FnJCU9uqo6X9olq4NRUGPUcpjkC%2BNO5A7IDX4VvztpDHBG1zSRPSs%2BH%2BSpBcnQrCmoVeG%2Bpstf3%2BxcdtFU9%2F6zujc2hUe1UqjSgWbx37mQXIawiLv4%2Bip29h7%2BJoIyYTcA8iAlFfyUGFYsGixcikTEUOyiOTsz5GKRnAoVnvX0lxNT0nffPDoTRNxsyrQiOQxSBUOi0edNWoMOX4Ov7B8EVFh4O7Wx5Cd6BpyB%2BzFqkUpAk1lgvri4W4RdnfFQj8rbpfF0k%2F8j48liGEuqjXiM8APGsBCPLcRm3zNThhBQLJ8EbElSZT30MjcNdpbdgyd1U9qR2SIEFHhSVfctdFoEKtRQV765KjGBO8G8yQdImJI6n6Ln0tBd7LORpW32SxfRGQIuLuViIiIIUlERMSQJCIiYkgSERExJImIiBiSREREDEkiIiKGJBERkbFiZwJEOubjVXIuyMsOE4ghSUT5FnwosNh%2FR3biTsUBd7cSUZG2mktSy5kYkkRERAxJIiIihiQRERExJIkKSB5T41malBeqrPJCDEmiEiO5qSssuRjoabLKSTKXBEOSqCS5nWSDslwM9DRZ5eQ2lwRDkqjE0ADhJirU4pKgp5HlRJYXLgmGJFGJoQKCxB8%2FLgnKQ2HxU8oLFRvscYfoKTLU2KLOwC9t3PDWgSjdHW%2B6GH0TU2d9rX3%2B7ox%2BqOVZGW%2B9tw5hEdeU1xwdbODhXgF9uvuiqls57bDfbj6IH7YfeWSc788epAz%2F8sjFSM9Ix4rFY2BrY6W8d%2BDwWfxx5DyGD2qHgKlfPnG%2BsueDchPlwzJegwGivHTm0mBIEpUYJ8%2FhtI8XzsRbYYp4OldX03Ut74S5MweiXY9Z2PHdTLhXLa%2B8fiYkGk18PODXqg7uxsRj38G%2F0Kn3u1g4byh6dm2iDHPp8m1YmJsiYGTXXOMsX85BuT92IgIVKzhixZrdmDKul%2FLanTv3ERp2Bfb21pgc0EN5LS0tA%2F2GL8SyhSNRroy98lqlCs4sFI%2BRVT7OyPLCpcGQJCpRTDQISFfhT29PnDpxHjt0MU0zEXIyyLLDzcLcTPueDMymjT2Vx906N0L3Lo0xcvxyNGpQHRXKZ37GxcVOO8zjTB3fG69PX42hA%2F3g7Fha%2B7qlhbn2c6kpacq9d72qqFKpDAvCE4hy0U3cTRLlxJdLo3jhMUmiPDh6HuEZKvirVFgrWpUz3d1hYUjzJ1uVXp6VsHN3sPa127fjECRmPOctPiFJ%2B76nhys6%2BTXA0i92cgUXkCwHsjzIciHLhywnXCpsSRKVSCdDsE80sHzTVFhuZ4ax3l7YAA32m2QgxC0c0ZuBdH3On1slF1y5dlf7POT8ZSxati3XMPKYpK27lfb55HG90KHnbLw6pCNXcB74AyZRHqiSrkbNrJN0%2BmuAs6aiBXk8lAHJkCRii1JWhB0a1EI9tQZ9xOPxGSaoHumFKj567pUnNi4R1Z4rr33eumVtLP5gxH9%2BprKrM%2Fx7Nxdh%2BiOaN%2FEqsnkrLlcCiczsTSdarOgIsbaDROuxM49BMiSJ6N%2BtysyKsUCVY1EExrXrMQg6Gobpk1%2FI92cnjO6Olp2nw9mpdJEtL158mYwVj0kSGbH4%2BCTs2X8K%2FkPmY1C%2FNqhZo1K%2Bx%2BEiwnH4oPb46tv9XKBEbEkSGYewiKt4edRi5XH3fvOw4pPR8K5fTXk%2BaUagcitlZYEaHhUxbtTz6Ne3Za7Pb%2F7hd%2BWW0%2FaNb2nHkdPo4Z2xduNvXOhE%2F6KXXSBydxN3v1BJJct%2F8KHAYv89G7Ycrn3M3zsZa25wdysRERFDkoiIiCFJRETEkCQiImJIEhERMSSJiIgYkkRERAxJIiIihiQRERFDkoiIiCFJRERUorGDcyI9yNmvKRGxJUlEWWQnzezwm4ghSUREZNS4u5VIjy1KLgUitiSJiIgYkkRERAxJIiIihiQRERFDkoiIiBiSREREDEkiIiKGJBERUVEoFp0J%2BHhBw1VpWPiP8kTEkDQgwYcCuTYNBDvvJqLigrtbqcha92zhExFDkoiIiCFJRETEkCQiIiI9hyTPfiQiIoPOC72FZFNXWHK9ExGRIeeF3kIyyQZlueqJiMiQ80JvIWmiQi2ueiIiMuS80N8xSRX8uOqJiMiQ80J%2FPe5oMKCNG946EIVkXU3yYvRNTJ31tfb5uzP6oZZnZbz13jqERVzDh%2B%2B8DPeq5ZX3%2Fr54AwuX%2FojPP34N%2FUcsQmpq%2BmPH%2Bcrg9ujc3vs%2FpyvH3651Pfi1qpPr9R93HsG67w5mrghTNebMGIAZc9Y9cTwfvz8cW7cF4fCfoY%2B8t%2BrTsTAzN8WQ15ZoX6tY3hHPd2qIjn71Hxn%2Bo8VbcezEBaxYMhpODrba1zd8fwi378Zh%2FKhu%2FGESkd6JnLCMF3lR8kISOBNvhSnifq6uJuha3glzZw5Eux6zsOO7mdpAPBMSjcTEZMwXwbFShI2UIJ6fOP238njC6O7QZGQoj8e98SUG92%2BLRg3clefPVXn6rnI5%2Frq13B55vV2ruoiPT8KKNbuxMXAK7OxKYXJAD%2BW9mNhEjBy%2FHGtXvI5SVubKa85Otoj4%2BxoqVnBEvz4tco3LupQFHiQ9RNDR81i1NAB2pUvhr3NRCJiyAgvnDkOPro21w8rvtnrtr6jk6oyfRFAPH9Re%2B96lK7dx9dpd%2FjKJyCBk5cQZcStXokLSRIOAdBX%2B9PbEqRPnsUMX05QtLRkwUvlyDrAwN9O%2B99qwznjno404fTYK9WrnDjTfhh7ax5YW5vDycEXTxp7PPD%2B2tlZwcrSFmZkJXCs6Ka9lj%2FfmrVjlvrF3dWW4nCpVdH789EVISj4NqqGMsx2aNfHEhcjr%2BO3QmVwhuWvPcdSt%2FRxe6NkU32w8kCskiYgMhcgHuUtrksgLX5EXYfqYB70dkxQNnvAMFfxVKqz18cJMd3dY6HNl2NlZY%2FTwLvjg4%2B8NvuBcvnpHaTHmvKWmpD122Os37qGyq0uu177fFoS%2BPZri%2BY4NERp2RQlSIiJDIfNA5oLMB5kTMi%2F0NS96vQrIyRDsEw0i3zQVltuZYay3FzZAg%2F0mGQhxC0f0ZiBdl%2FMzYnB7BK7bi8NBIaL1VspgC9CRY%2BG4ei0m12vymKQq699tVwTuVna%2FRojwi7mXIFqK7XKF5vGTF5ThZQu1fdt62CJC883X%2B%2FCXSUR64Q%2BYRHmgSroaNeVJOqIq668BzpqKFuTxUP0FpN5DMrtFKe46NKiFemoNZE09PsME1SO9UMVHx70sWFmaY%2BKYHvjgky14f%2FbLBlugXujVDFPG9Xrk9bi4RO1jedzxl19P4McNM5RWcrat24OUY5G%2F7D2hPC8tglK%2B9saE3iJkC39x80ogRPQ0kVDqiWhRA0WIWj9ItB47nzyH04YwbwZzPcmsBVKghVKYFXH%2Fvi3xReAv2PXrcaMtcKOGd1KOSZYtY4%2FhY5cqJynJY7DZISl3v%2F4htk604Xr%2FAf4MDkfTRjUKfV548WUiMmamXAT%2FWiBmJpgqWlVTZ34FR0cbo%2F4uo4Z1Us6GHTxqMX5YPx1Rl27h2o172LXlbZib%2FbPqzUxNseWnP4okJImIGJJGIiziKl4WgSF17zcPKz4ZDe%2F61R4ZrmfXxvjsy12Ii08stGlPmhGo3LI19%2FVCjy6NsGDJj4gV02necRp%2B3%2FNhnsb1yfJtyi1XS%2FzQJ7Awf3R1fvj2YPQbsQijJ36B56qUQdcOPrkCUurdvQmGiRbnvNmDlOfyGKW85XT1fCB%2FLURU4uhlV5jcPVqYu%2BHk%2BIIPsRI3FA1bDtc%2B5u5WIjLE3GBLUkdkRwC%2F%2FvbkQ6lrPhsHWxsrLigiIiPEkHxG8rifvBERUfGj5iIgIiJiSBIRETEkiYiIGJJEREQMSSIiIoYkERERQ5KIiIghSURExJAkIiIqXopNjzs5%2BwslIiJiSzKL7PSWHWkTERFDkoiISEeKVQfnbE0SERFbkkRERAxJIiIihiQRERFDkoiIiCFJRETEkCQiImJIEhERMSSJiIiomHQm4OMFTUlZYewwgYiIIZlvwYcCi%2F3KYifuRES6xd2tRthqLkktZyIihiQRERFDkoiIiCFJRETEkHwGPEuTiIgMOi%2F0FpJNXWHJ9U5ERIacF3oLySQblOWqJyIiQ84LvYWkiQq1uOqJiMiQ80J%2FxyRV8OOqJyIiQ84L%2FfW4o8GANm5460AUknU1yYvRNzF11tfa5%2B%2FO6IdanpXx1nvrEBZxTXnN0cEGHu4V0Ke7L6q6ldMO%2B%2B3mg%2Fhh%2B5FHxvn%2B7EHK8C%2BPXIz0jHSsWDwGtjZWynsHDp%2FFH0fOY%2FigdgiY%2BuUT5yt7PoiIKDeRE5bxIi9KXkgCZ%2BKtMEXcz9XVBF3LO2HuzIFo12MWdnw3E%2B5Vy2fOSEg0mvh4wK9VHdyNice%2Bg3%2BhU%2B93sXDeUPTs2kQZ5tLl27AwN0XAyK65xlm%2BnINyf%2BxEBCpWcMSKNbsxZVwv5bU7d%2B4jNOwK7O2tMTmgh%2FJaWloG%2Bg1fiGULR6JcGXvltUoVnPlLICJ6jKycOCNu5UpUSJpoEJCuwp%2Fenjh14jx26GKaZiLkZJBlh5uFuZn2PRmYTRt7Ko%2B7dW6E7l0aY%2BT45WjUoDoqlM%2F8jIuLnXaYx5k6vjden74aQwf6wdmxtPZ1Swtz7edSU9KUe%2B96VVGlUhn%2BAoiInkDkQzdxN0nkha%2FIizB9zIPejkkePY%2FwDBX8VSqs9fHCTHd3WBjSypGtSi%2FPSti5O1j72u3bcQgSM57zFp%2BQpH3f08MVnfwaYOkXO1m6iYgKSOaBzAWZDzInZF7oa170ehWQkyHYJxpYvmkqLLczw1hvL2yABvtNMhDiFo7ozUC6PufPrZILrly7q30ecv4yFi3blmsYeUzS1t1K%2B3zyuF7o0HM2Xh3SkSWdiCgP%2FAGTKA9USVejpjxJRwX01wBnTUUL8nio%2FgJS7yGZ3aIUdx0a1EI9tQZ9xOPxGSaoHumFKj567pUnNi4R1Z4rr33eumVtLP5gxH9%2BprKrM%2Fx7Nxdh%2BiOaN%2FEqsnnjlUCIqLiIhFKfRYsKP0LU%2BkGi9dj55DmcNoR5M5jrSWYtkAItlKIIjGvXYxB0NAzTJ7%2BQ789OGN0dLTtPh7NT6SJbXrz4MhFR0WMH5%2F8SH5%2BEPftPwX%2FIfAzq1wY1a1TK9zhcRDgOH9QeX327nwuUiMiImZakLxsWcRUvj1qsPO7ebx5WfDIa3vWrKc8nzQhUbqWsLFDDoyLGjXoe%2Ffq2zPX5zT%2F8rtxy2r7xLe04cho9vDPWbvyNJYyIyIjpZZed3D1amLsL5fiCDwUW%2B5XVsOVw7WPubiWikqSwcyOvuLuViIiIIUlERMSQJCIiYkgSERExJImIiBiSREREDEkiIiKGJBEREUOSiIiIIUlERMSQJCIiKtGKTQfnOfs1JSIiYksyi%2Bz0lh1%2BExERQ5KIiEhHitX1JNmaJCIitiSJiIgYkkRERAxJIiIihiQRERFDkoiIiCFJRETEkCQiImJIEhERUTHpTMDHCxquSsPCjh2IiCFpQIIPBXJtGgh2Nk9ExQV3t1KRte7ZwicihiQRERFDkoiIiCFJREREeg5Jnv1IREQGnRd6C8mmrrDkeiciIkPOC72FZJINynLVExGRIeeF3kLSRIVaXPVERGTIeaG%2FY5Iq%2BHHVExGRIeeF%2Fnrc0WBAGze8dSAKybqcbMy9BHy8%2FCf8%2FmcokpJS4FrBCb6Na2D0iC7Yui0IkdE38fabL2mHT0%2FPQMDUlRjcvy3sS5fCrHkb4N%2BrGV7q00I7TEjYZcwWr%2Ffu3gQD%2FVvj1p04jJm0Qvt%2BaVsrNGnogaED%2FWBhbqZ9fccvx%2FDV%2Bt9w5eodWFtbonvnRnhtRCdYWpgr72%2F7%2Bagy7mkT%2B%2BbrO16%2FcQ%2Fj3vhS%2B7xKJRf07tYELZrW1L72xqyvle%2Bak5WlOb5Z%2BTrCL1zDjDnrHhnvhNe6oWWzmvzBEpHOiJywjBd5UfJCEjgTb4Up4n6uznJZo8FLQxegerUKWLpgpAivUjh95iLWbTqInl1j8HynhmjVdQbatqiNVs0zW%2FeB6%2Fbh2vUY%2BIqQO3I8AmdDoxF16aYIRF%2BYm2Uuvs%2B%2B3IVz5y%2BhYYNqyvPk5FQEHT2PDasnw8zMBLfv3MdHi7eK%2BzjMnPqiMsyXX%2F%2BKpV%2FswHuzBsC7XjXcvBWL9%2BZvQtCxMOVzarUK127EIDTsSr6%2FZ1LyQ2X6m76aqnznE6cjMXjUEqxdMUEblH%2Bdi4Jf67po2dTrn10aJibKfUJCkrJc5PA5VXevwF8sEelUVk6cEbdyJSokTTQISFfhT29PnDpxHjt0Mc0r1%2B4qLbNvV09CGWc75bXKrs7o3qUR0tIyYGqqxvRJfZVW1P4d7%2BHu3Xgs%2Fnwbtqx9EypV5hnIZV3s4SHCYtPWwxj0UhtcFq3A02ej0K5V3Uem16SRh7blKIe5dv1e5koXIbRgyVasWDIGbVvWUV6rVNEZ61ZORLOOb2LP%2FpPo3N77mb%2Bvb6MaIvjUSjDKoDz4%2B7lcrcnq1cqjaWPPx68fsSye9B4RkS6IfOgm7iaJvPAVeRGmj3nQ2zFJ0dAJz1DBX2TPWh8vzHR3h0VRT7NsGXs4ONjgU9GCi758K%2FfWgmnmohjwQis4Otpg%2Bcqf8fb76%2FGyCEJPD9dcwwaMfF5pPcpgXbFmN0YO7aiEyr8dORautOjkbtVDf4Qow0nHTlyAuYUZ2ogWa062tlZo36YeDhw%2BW%2Bgt6Fu3Y8UGgUuu1yP%2Bvq7MX%2FbtqGgpZ0sX3y3ne3LjgohIF2QeyFyQ%2BSBzQuaFvuZFr1cBORmCfaKx4pumwnI7M4z19sIGaLDfJAMhbuGI3izq6sKcntw9GrhsnAi%2FDVizbp8SSt71qmLYwHbo0La%2BMoxsMX74zmB0f3GeaDXa4dMFrz4ynnq13VCpkosYx17sP3gGs954EcGnLjwy3JLPt0OlVoswTVdCardoIdav%2B5yy21W2SLNbpzmVK%2BsgwutaoXzfTz7bBrWYhmzFliplCf%2FezXK9%2F%2FOe4FzBmH1MUkpJTcWiZdu079WtVQWzcxyrJSIqLP6ASZQHqqSrUVOepCNqxv4a4KypaEEeD9VfQOo9JLNblOKuQ4NaqKfWoI94PD7DBNUjvVDFpwh6WWjsUx27tsxGbGyicnzxUFAIRgQsw%2FpVk7S7ImvWqITmvp7KscLsk2j%2BLeDVrhjwyiLMmOyf62ScnNYHTta%2Bd%2FdePNp2namcwGNjbYmExKTHfkbuipUn8RSWOzHxyklKe7fNeeS7TBjdHb27%2BT72c1ZWFvh%2B7RvPPH1eCYSIniYSSj0RLSr8CFHrB4nWY%2BeT53DaEObNYK4nmbVACrRQClIR29tbK6GYfbzuxF%2BRuY7XWViYQW3y5IyWZ3mOHNoJL%2Fdrk6fpOTnYonJlF0RF3xKt1nrKyUCRUTdQ1e2fY9Fyt6gMNNmyLQwTx%2FRQjklal7LA4FGLsW3DW8r31iVefJmIjFmJ6uD81JmLykk58mSbbPKs1HPnL6NRA%2Fd8j0%2FuZrXJQ6vvYUoqftx5BCGhl9GsiScqVnBCr%2BebYMK01cq%2Fi0hpqemYu2CzaGEmo0%2BPpoX6vadPekE5o%2FeVccuQmpLGUk9EZGwtSV0oV8Ze%2BZ%2FEll1mKC072cpKSnqIGZP6FsmZnFXrjlLu5XRqe1XGqmVjlTNjpQVzh2LW3PVo3mEanBxtEXs%2FETXcK2Jj4JRcwbv3wGlU9Byea7yhR5ehdOlSed8SUquwdMGr6D3gA0yeuQafzs88zhowZaVyy2ZrY4Xzwcv5qyAiyqKXXWFy92hh7oaT4ws%2BFJjn4WVr6sbtWOWx%2FNcLfUp88BAx9%2BJhZWUOZ8fSxaJQNWz5T6hzdysRGWJusCX5H8zMTfUejtnk8UJ5y4%2F%2BIxYhNfXxJ%2F7KDg3y20MPERExJIsN2SMPEREVPTUXAREREUOSiIiIIUlERMSQJCIiYkgSERExJImIiBiSREREDEkiIiKGJBERUfFSbHrcydlfKBEREVuSWWSnt%2BxIm4iIGJJEREQ6Uqw6OGdrkoiI2JIkIiJiSBIRETEkiYiIGJJEREQMSSIiIoYkERERQ5KIiIghSURERMWkMwEfL2i4KnWLHTcQEUPSiAQfCuTa1BF2Jk9EJQV3t1KBW%2B9swRMRQ5KIiIghSURERAxJIiIiAw5JeSyLZ0cSEVFeqLJyo8SEZHJTV1hyvRMR0dNk5UVySQrJ20k2KMtVT0RET5OVF7dLTEiKNnO4iQq1uOqJiOhpZF7I3CgxIakCgsQfP656IiLKQ2j4KblRUkIyQ40tojk5oI0bj0sSEdGTKTkh8kLJjZISkifP4bS4OxNvhSksAkRE9CRZOXEmKzd0Tm99t5poEJCuwp%2Fenjh14jx26Gq6n67YgcEvtYW9vbXyfN%2FBv2BlaY5mTTwR8fd1BJ%2B8gEoVnbBu00FkZGgwbtTzqFOzinbYX%2FaewN2YeLg4lUbvHk3h29BDee%2F3P0PxMCUVZVzscfDwWXh6uOJsSDT6%2B7dCGWc7ZZi0tAwsW7kTwwb6wc7O%2BqnzunN3MH7aeQSpael4vmNDvNCrGVJT0vDFmt3wa10HtTwrK8OFhF3G4T9C8MqQjvjrXBQuXb6N9IwMbN91DA72Nnh9THfxnZyVYZet%2FBkv9m6OP46eR%2BTFGxg%2BqL12WRARGRKRD93E3SSRF776mge9dSYg6ujwDBX8VSqs9fHCTHd3WOgkJD%2Ffgdj7idrnew%2Bcxu9HQpXHFyKvY%2FqcbxC4bh%2F8WtWFswjCIa8tQXp6hvL%2B9Zv3lGAaNrAd3KuWx%2BCRnyDq0i3lvcMiJN98e624fY07IkTjE5JEYEXjm40HtNPave%2BEEnx5CciVIgg%2FW70LL%2Fdri6ED2imPv9t6GGbmprCxtsSIsctw%2F%2F4DxMcn4ZWA5ahcyQVqtQqnz1zEhDdX4X%2B%2Fn0Pn9t5ISkrBwFc%2B1n6HZV%2FuRJ9BH2Lvb6cRG5eItIx0%2FhKJyKDIPJC5IPNB5oTMC33Ni16vAnIyBPsae8I3TYXldmYY6%2B2FDdBgv0kGQtzCEb0Z0HkNXqtGJQQuH6c87tPNV4Tcb7h6PQaVXZ0x6MXWSElNU8K0ds3KqFDeEafPXoRb5TLK8A3qPIcVS8ZApcrsJ8HJwRYTpq3ChNe6w9RUjTXf7sfwl9s%2FdR5koC3%2BYgd2bZmNKq4uymsT7nfDhu8P4aU%2BLTBsUDulxTvprUCoxbR6d2%2BiBGK2dm3q4pMPRmi%2FQ53mE5Tw9K5fTXlt%2FpwhSsuZiMgQ%2BAMmUR6okq5GzayTdPprgLOmogV5PFR%2FAan3kMxuUYq7Dg1qoZ5agz7i8fgME1SP9EIVHz30yqM2%2BadxbWpmglJWFkgVwZjdupO7K2uJgCxXxh5xoiWXnv5PJxAuLnbagJRaNPVSWn2yBSlbnucjriiB9jS3bschTrTyXhqyINfrHu4VtI8XzB2KVl1moFxZB3yxeMyTV7D4DpUqOOPGrdh%2F5jNr929h4JVAiOhZRWb2phMtas8IUesHidZjZ30dgzS4kNS2KjMXSIEWSn4qahliaWn5b6DeuHkP8z7%2BHv%2Fb9b62dffSsIVPndaQAX74av1%2BVK9WAf37toSlhflTpyWDVX521%2Fez4eBg89hh5DFQK0sLZXfv8VOogaAKAAACNklEQVQX0Mi7%2BhPHdy8u4YnjeVa8%2BDIRFWclroNzecLNsRMXlMcXo2%2FixKm%2F8%2FQ5efIMNBpYmpspz8MiroqAuvnUz73Yq7myq%2FP7H3%2FHkP55%2B9dQW1srNG1cAx8t2aqc7CPJY4%2B%2FHTqjPJbB%2BMasr%2FHlp2Mwd%2BZAvDbxC9yJua%2F9fEJisnLSkfT9T3%2BI2dagYb1qLO1ERMbaktSV8aO7Ydq732DJ59thLVpsDnZ5O7NTnh068MU2aNFpOhwdbVC2jH2eWoUy8Lp08EHig2S4VnTK83wuWzASAVNXom7zCbC3LYV79xPx2rBO8G1UA6%2BMW47J43spZ9DK2%2BGgEIwWQbkxMPM%2FakLPX0FjvylKUJqbmWLl4jHKCT9ERJQ%2FxWJXmdzdGnwoMM%2FDx8YmIj4xSftvEflx604cNCJ8ZEjmhTwJp0WnaVg0b3iBTpa5dy8BCSJg8zqvX6%2Ffj0MiNFeIYLx2IwauFZxyHSctDA1bDtc%2B5u5WImJLspiR%2FxdY0P8NLJPPk17k%2F1WWKmWRKyB%2F%2Fe0UVqzZ88TPzH7zRdSt5aY8lscSC3I80cREXaCNACIiKuEhqUvOzqW1%2F46RrUPb%2BsqtKDT39VJOEiIiIoakwWvi46HT6cl%2FNZE3IiJ6dmouAiIiIoYkERERQ5KIiIghSURExJAkIiJiSBIRETEkiYiIGJJERERGqth0JpCzP1EiIqLCYFIcvsT1O3hX3iq44B2uUt0vey4FIiquuLuViIiIiIiI8uf%2FC8mYNyvnK0oAAAAASUVORK5CYII%3D)
+
+```
+expr ::= expr ( ( '+' | '-' | '*' | '/' | '%' | '<<' | '>>' | '&' | '|' | '^' ) expr | '.' INT_SIZE )
+ | ( '(' expr | SIZEOF '(' ( SYMBOL_REF | IDENT ) ) ')'
+ | INT_LITERAL
+ | IDENT
+ | SYMBOL_REF
+ | unary_expr
+```
+
+referenced by:
+
+* expr
+* int_const_expr
+* unary_expr
+
+**unary_expr:**
+
+![unary_expr](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMUAAABRCAYAAABiz2KlAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAADnhJREFUeNrtXQl0FEUa%2FnrOXAjkZCFLgEAgAYQcYOQhIEpAiRwGnsBjyYoKcVFRhFXUXU4PTpVLYVlEXdaQyCUgCoKyRkLCJIAJCbkJJAEmFwkh58z0VnVm8pIISQg9kznqe69f9Ux1%2FTX19%2F%2F1X%2F90HQADA0MTcNbaMF41T%2F5t7NmFKemlc9KyyvqVlNUqC0uq29xel65KjaO9%2FJars%2FJ05tWqD3%2BOq0ywNB0E%2BoK39PuYkGp6G5VZIyFO7A58%2BfVPD65Lzyl3DB37Z0yJ6Ilu7g5wd7Frswx1cbXshrrSNUalDsvNvzp50hgHVX5R5eyEZGRZki5Uv%2B6y2PsY9NjcDqlXalXegV8u8XMujtq8O3XJ%2BDGeitVvBiDY3w0ebvZwdLg%2F%2FtPrablhQ1zxXGhviY6HZ1Jq6Tx3Vy6xQM1nWoI%2Burth%2Bby5ky32fu744pDQBnpcL8IKU9UrsSZSRG3at3fX3oxpG94bhjlTvaGQi9M8KofK27oy2M5BwR0O8sNcMFgtrIYUtMu0MzJ92rp3gjC4f1ej1EHlblkRLJXJJDv9GTEYKcw9qD5y8tq62eRpbixCNCbGrMl9OBm47cRjPMVMiJHCLEH%2FZcrMve04I7S3SeqbP7M%2FFAqJjMQZewMHwZuZESOF2SElozR8wugeosUQbYkxhg9xo%2F8VyqDFemZGjBRmh7Tscu%2BRQR4mrTNkVHea2JNjpP9ADGGmxEhhViguqbHr0c3BpHX69e1Sf8JBLdEhjJkSI4VZoaS8hnPprDRpnZ4eDSR0Isc4ZkpWRopHBqHFvkdr%2BR0NnZaHRGra0QCG%2BngeziTpyUyp4%2FGgdmooL5CiTouCQF9E3Utoa%2FmWis%2F2ZGNKxBlq2O0GV%2B8pPJhJdjzaa6fDfTE10A%2FXNFrk0M8y%2FY2l5Jiu1ZJMXxyQSfFqXDJuNrrxLeZbKrKuVuC3hGJCCh4c90CexuKHy9TWabDr659wJu4yHurkgPBZj2NYQD%2Fk5Rcj6kAMXvjLk%2Bjc2VG49vipC6gj108cH4SjP6rg3NUJqvNZOHsuDQ8P6oXXIkJhb6eAuqgM%2B7%2BLxYxnH8PBo3Gora3DvOfHG60N92unlAxaDptIR8Oz8dDJJjEFX08SKjTvboxrLZ%2FBcjF%2F4TZczsjHK%2FMm4okxD2Pugs3IyLoOzx4uSMsswBvv1A8s%2FP3SFby17EsMGuglfD78wzm8RMpWVtVg0tPD8cuvyfjH6j1CXiEhxdpPDiBszkdERj6KSm6bpC2t2anBM2iB%2FaCEaAZZK0IFxrWWb0meY9t%2FspCaVX9zVEmlQrpw1cWG%2FBUL%2FeDcRWFThLh0%2BSpS0q4h9sRaSCTUY%2FZDnCod3x9XYeHLz2DD%2B89j4vRV2LjlEA4cicMnH74IL0%2B3hvILI57BS%2BH1%2FzUM8PFE2OyPsGZFuPBZoZRh%2F9dvN3gZU%2BIPdsrhmAZY2dwztIkUDQEscIG4kgl8K%2FkaDXJIpfaWYAApmeU4k1ginJeW1Qop7UIZUFWjbZdcS567kJZRgMLCcowY91aT72eEPSakTo52%2BOzjCIRMWY55fw3B6JEDm3ZbGvU8%2B%2FTyQFV1LcrKK4XPSrlcFEI8iH6pnZKfOFHDYxpJda0Jkt2jb3aGFMwn6ZNE4E6SvtFSvlyGNQZPMZ30r6%2F4wEsrgR%2B5cCy5Zia5NlnGY0H8ZaQb46bej8K2LPdvOF%2F84e%2F4cn8uVAfH6p%2BQ7YfYk2GGD4CPhsNWInQQadw3pIWnpDqk9EpHbjSgFVMvnZzs0MvLHacOr7rnNfsOxWKQb0%2Bhu0S7WDSOuBtKblVArpChEyHSdRH10Rb9Nm9vYzsl6XY7OXZV12EueZC%2FyHMou1vX6Q%2BkMAjh64XEyaXwpcZOKnujpfzGMoQblo5sckqPI337YmlnOZaQgOasvx%2Bmn0%2FBSdaDbxlET08QFx9N9L2xrA6hmZmoMeSdM0J9wUH9cUN9C98eOoNpk0cI313NK0JxcTn8h%2FTB0eMJOPHzBRzbtwwr1%2BzFgsXbsedfixoeJOV6r6DV6rBtx%2FcIeXyoQIyOQit2uojEGGvqtHjrXuRo%2FMujWzL2NuTfFfobujpggNDViiZPwGBjeQxrAPUQlBA8jzmJl3HEFHV26mSPL7a9ikVLd%2BH99dGwU8pRVVWLDR%2FMRWb2dSxd9hUidy%2BGo4MSK9%2BdiaenrcKGLQex5LWpQvnI%2FTHYE%2F0%2FVNfUor93D%2BzY%2FLeOVGGrdqr%2F7p7kMJCiigjJa8HYW8tvFfQGE4%2BzkXiMLeRjiDkY4PqlDwuHOUGvn42mIoQBjwT64LfjH%2BEm8Rj072l3t84Neb%2FHftpwrlTIcfK7lU3K0jhj1vRRqKioblJu4ICeuHjmE1M2477stDk5iIeJaCCFTIreLQlpLb%2FNT6QqrL9tjwV0AN35S7jI%2FEKzbhMdWKjDYKKnSR31Gzzcu7SrnIO9Ujg6Eu2108bkoJ8ljb5srdAD45crqCYdvv%2BKPYCODrmgQz1MiYo7daLLFPRC9CPoyUIQPmssRo0YaBa%2F5UHt1FDe9AMCeZwi5vuomCK7dFJoistqTNqMjCvlRlAN0QvRjyV5t0eH9YdP3%2B5W5bFNTgryQL9E%2Bm4%2BogaKjvJb%2BTcqTdqO%2BItF9f908KBvArViyKR6ofphHUkbI4V9heCi3MSU6dJVeTpGZdoX6idiCuqf7hzUJBGrcje9fhhsiRSxeUJ%2F2U5MmXQFv6On8jS1dTqTtCEn7zau5FUYNEjfx1wVSbSdXj8MtkSK%2Bq6zuG9%2F6ZKWCrlEFXkkxyQNeHtNQuPW3KGOQyTRnF4%2FDDZGCqOALmm5MzK9Oimt1Kj1rN2RjKzc2wZCZJMjUCfBPmZKjBRmB7rGa20dH%2FbKsrNaYxGDEiKqsTfiEEMe7efYOxdGCrNFXJL2%2B4oqzUvzl57hN3%2BVCrFiDBpDPPfqL00JwYNOGhjPS%2FF3ZkbWBatbdTwxBV8E%2BeokX%2B%2FL%2BjzyuxxZ8FBXTBjtCR%2Fvh%2BDV3alNMiqrNXTZHMRfKMRPMQWEFBXNo6I9wghgDs%2BrLGwVcgYbJAWFKhX%2FDhjI52trtdGn429KySHOXA8aQ5AuE%2BgcEwnCEy7hB3PXRUctZ8%2B6T%2BboMYjBclIMJac%2FEmMuJn3%2FZHJcI0Z95z7EVJAyORKeyAAO8IBSWKhAhhGJFkAIOgehIzY9YZ7CzINvkkylA%2B30461CoCNGwqGtU8GceB63eA50lFw8iR9WqFhQzUhhDdD%2FO0SPf9riTWbegnWfGBgYKRgYGCkYGBgpGBgYKRgYGCkYGBgpGBgYKRgYLANW%2B%2FKObiNMd01NSS%2Bdk5ZV1q%2BkrFZZWFJ9z5dYLl2VGkd7%2BS1XZ%2BVpOpOPTlxi5sFIYTWgG82%2F%2FunBdek55Y6hY%2F%2BMKRE90c3dAe4u954Fqy6ult1QV7rGqNRhuflXJ08a46CiE5cS2ChYm0OHbDbS3Q3LrxdhhejegV8u8XMujtq8O3XJ%2BDGeitVvBiDY3w0ebvZwdGiZ%2FzSfXjdsiCueC%2B0t0fHwTEotnefuyiUWqPlMS9YLgw3HFFGb9u3dtTdj2ob3hmHOVO9276tNy9HyW1cG2zkouMNBfmDjrxkpLLPLtDMyfdq6d4IwuH9XUWRSOVtWBEtlMslOf0YMRgpLC6qPnLy2bjZ5uotFiMbEmDW5DycDt514jKeYyTBSGM2OIeIyN%2FRfpszc244zQnsb5cfOn9kfCoVERuKMvYGD4G0knbDlbWycFNWPeoq3IFpKRmn4hNE92h1DtCXGGD7EjVqtDFqsN0Yden2whdBsmBSFVU7i7ayall3uPTLIuBu1howSFhGmc71HCkvmiwy9PgqZSdooKUgfIV3KQbT124tLaux6dHMw6m%2F269vF0MlRi72VAAXVB9ULM0kbJQXphsTSJWLEkldSXsO5dDbuhiGeHg2ko%2BvkjDOCUsYKemGwTVIIy0zymDWmlzhxBd2whW7cYlRF6eXzPJxJ0lNM2YIeiD7Y8ps2TAr9QgJJt%2B2x2NIUxtV7ClEDGL0ektjym7YdaEPK4xWSLAoYgFAL1Jtow2P07V%2Bk1weDLZOCbhus4zCd4%2FBVoC%2Fe69sXSltSPG0vbTdtP9UD20bZfNCho2TpRvN0X20Nh62d5VgQ4Itv6J5vUh1SeqUjN1qkbbMMOB1fiI93ZTT5bucHgXB1Nj4fpxPvcsUHXloJ%2FPRB9UweSJbxCE5IZYRgpGjmMUgyTljFj8ez5Pw1nRT9sn3hFSjy5i5FpbX4LaG4yXfVte1bmZw85e%2Fr7XN2%2FdvqXNKgDNKqWOIdJrAYgpGiLcH3RWMaaNj4HsIhBtiqeyymYGBgpGBgYKRgYGBgpGBgsFpS0CEYdKiHMVFxp45ZCyOF5aBLJ4WmuKzGqHVkXCln1sJIYTno5Ci%2FlX%2Bj0qh1xF8sElKOB91EW8tMh5HCrOHSVXk6RnXTqHWciCkQUp6DmiQ3mekwUpg16Ip%2BR0%2FlacTaN7s56D7aVwzbBkvoy2lcZabDSGHWoEtcKuQSVWTjzd9FxNtrGq2gyQu7q55gpsNIYfagS1zujEyvTkorFVXu2h3JyMq9bSBENjkC2WQg64bUWhpyXY3SP7ly54%2F%2Fmj8jaLCrxMPVXhRCRDX2PhwOc0BRYgo2MdNhpLAMb6HmM1y66q4dO5U3qbJGy%2Fn7uUDajmmqNIaIeDcWMeduNu427SGkCCEam0kJyEzHemGVIz2DfPECx3Gfy%2BUSWfBQV0wY7Qkf74fg1d3prtdXVmvoMjmIv1CIn2IKCCkqml5QT4ixHIcXVCk4xsyGkcIiETAQE6BDNFfvDdvXl6IxBIcYkk7gpQhPvIQfmMmw7pPlxhiFyOzeDVHEoL3J4Uae8tmEIDXEyOkcEsU9ilWQa%2FIlPOJ5Dkk84CXhUEhKzCCEOMfMhXkKq4Ewq69%2BAbMQQpAepNWeLXiHPJKfT86O03%2BZ2Ow4BgYGm8f%2FAY9whRXOA8A8AAAAAElFTkSuQmCC)
+
+```
+unary_expr
+ ::= ( '+' | '-' ) expr
+```
+
+referenced by:
+
+* expr
+
+##
+![rr-2.0](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAIGNIUk0AAHomAACAhAAA%2BgAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAEZ0FNQQAAsY58%2B1GTAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A%2FwD%2FoL2nkwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAltJREFUeNp1k21IU2EUx393u0aslxlDrDTLZJUaUmREYBIIlpqQ5YciikAoKiIJihgk6JcWRBlpnwr6EOWHiOiN3j6ZMOd068WXZW8SpEY22LI1N7fb8%2BzmcroO3Av33P%2FvnPOccx6FGaa5KfD%2F5LjjNbVaDDMKRCIEghN0bi6iYUU17ul6JQF2kyaEV5%2B7qFMNKCXrwDT3n9A%2FDu1uNKPKk8oydiqFhBMBJGy%2FwaeBIbJbTsGCeaS0WAxONsehH5cayVKsTBjkj8gkLRLu%2BwgXb%2BnCVHDTNejwwGQUS08XbdJvlGd%2B6uD6kV0ovgA8aIdRH5SuF5mUZPjhS6guhXPHwNXH6jY794wn9tA0OsbGgpU6JOHpQTQtGT5bBwZRdziC8s3HItXZy26DyGRrBfN8qN%2BrZ5VBJCyfRx06XFsGZ1p03YFK8LynXBXlpY%2BHYG0eDH6BkTE9iwRlVmk7tui%2B7gFYmgFpKrwT2jQjCw1TcxQl4fNDXvbfsWr%2Fn4R3CIrz9W81HCWwfAmWjHTIz4W3H%2BB%2Bu162zCxNViIbum87bN0gjiP8bq%2BYhlgwNRTCuSqHSnmunMWzGxZfFkXvibSpJuZmwc3HeIwX6vE6%2BzlkXYaSqtsSTjUdwWixKEeNzbcZOVjFptY7WF84k%2BHEvs8IMiwaHQzSub8BW1y2rYIauZ7issyCp0z65L%2BqEvj6Hb9BoyK%2BifLVeIWo4y6XM00UuvpZI5ck05IcICq639ULv37jyLZQfPg8%2FqTbmLiVPRS9GcT2eZjyOSrm%2BNZN4hcjfmU2Ya85zbPp%2Bj%2Fv7PhdECerqgAAAABJRU5ErkJggg%3D%3D) generated by [RR - Railroad Diagram Generator][RR]
+
+[RR]: http://bottlecaps.de/rr/ui
diff --git a/docs/usage/installation.rst b/docs/usage/installation.rst
index 002de326..7c215ccd 100644
--- a/docs/usage/installation.rst
+++ b/docs/usage/installation.rst
@@ -7,7 +7,7 @@ Requirements
------------
- Make sure to have `Python 3.8+ `_ installed (old version 2.x is not supported).
-- Create and activate a virtual environment (``venv``, ``pipenv``, etc.)
+- It is recommended to create and activate a virtual environment (``venv``, ``pipenv``, etc.) to avoid conflict with other packages
- Upgrade PyPI to the latest version
- Install SPSDK
@@ -96,7 +96,7 @@ For *SPSDK* to access connected devices using USB, it is necessary to configure
-------------
-macOS @ Intel
+macOS
-------------
To install *SPSDK* under *macOS* follow:
@@ -111,72 +111,6 @@ To install *SPSDK* under *macOS* follow:
*SPSDK* help for command-line applications should be displayed.
-----------
-macOS @ M1
-----------
-
-It's recommended to use the ``pyenv`` package for Python installation. To install *SPSDK* follow those steps:
-
-1. Install ``homebrew``. *Homebrew* is a package manager for macOS located `here `_
-
-.. code-block:: bash
-
- $ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
-
-2. Install *pyenv*
-
-.. code-block:: bash
-
- $ brew update
- $ brew install pyenv
-
-3. Enable ``pyenv``, execute the following lines to set environment variables, assuming you are using ``zsh``
-
-.. code-block:: bash
-
- $ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zprofile
- $ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zprofile
-
-4. Install *Python*
-
-.. code-block:: bash
-
- $ pyenv install 3.9.5
-
-5. Make ``pyenv`` Python global and rehash
-
-.. code-block:: bash
-
- $ pyenv global 3.9.5
- $ pyenv rehash
-
-Now you can use ``pip`` for package installation.
-
-6. Install *rust compiler*. To build some *SPSDK* dependencies a *rust compiler* is needed, to install it a *rustup script* could be used: https://rustup.rs.
-
-.. code-block:: bash
-
- $ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
-
-7. Install *Python* build dependencies
-
-.. code-block:: bash
-
- $ brew install openssl readline sqlite3 xz zlib
-
-8. Export compiler flags for ``openssl``
-
-.. code-block:: bash
-
- $ export LDFLAGS="-L/opt/homebrew/opt/openssl@1.1/lib"
- $ export CPPFLAGS="-I/opt/homebrew/opt/openssl@1.1/include"
-
-9. Install *SPSDK*
-
-.. code-block:: bash
-
- $ pip install spsdk
-
------
GitHub
------
@@ -229,12 +163,43 @@ Also you will need `swig compiler `_ which is a requirement
.. note::
- In **Mac OS** you need to install gcc, swig (http://www.swig.org), and pcsc-lite (https://pcsclite.apdu.fr/).
+ On **Mac OS** you need to install gcc, swig (http://www.swig.org), and pcsc-lite (https://pcsclite.apdu.fr/).
(**brew install swig pcsc-lite**)
- In **Linux** you need to install pcscd and libpcsclite-dev. (**sudo apt install pcdcs libpcsclite-dev**)
+ On **Linux** you need to install pcscd and libpcsclite-dev. (**sudo apt install pcdcs libpcsclite-dev**)
+
+.. code:: bash
+
+ $ pip install spsdk[tp]
+
+
+In case you are installing from local repository.
+
+.. code:: bash
+
+ $ pip install ".[tp]"
+
+This command will install SPSDK with Trust Provisioning support.
+
+
+-------------------
+DK6 Tools
+-------------------
+
+The command below install extra dependencies required for DK6 to work.
.. code:: bash
- $ pip install 'spsdk[tp]'
+ $ pip install spsdk[dk6]
-This command will install SPSDK with Trust Provisioning support
+
+In case you are installing from local repository.
+
+.. code:: bash
+
+ $ pip install ".[dk6]"
+
+
+.. note::
+ For Pyftdi backend Linux, macOS libusb 1.x is needed.
+ Install it with apt-get install libusb-1.0 or brew install libusb on macOS
+ On Windows install D2XX drivers https://ftdichip.com/drivers/d2xx-drivers/
diff --git a/spsdk/data/cpu_data/exec_hab_audit_rt1020.c b/examples/data/hab_audit/exec_hab_audit_rt1020.c
similarity index 100%
rename from spsdk/data/cpu_data/exec_hab_audit_rt1020.c
rename to examples/data/hab_audit/exec_hab_audit_rt1020.c
diff --git a/spsdk/data/cpu_data/exec_hab_audit_rt1050.c b/examples/data/hab_audit/exec_hab_audit_rt1050.c
similarity index 100%
rename from spsdk/data/cpu_data/exec_hab_audit_rt1050.c
rename to examples/data/hab_audit/exec_hab_audit_rt1050.c
diff --git a/spsdk/data/cpu_data/exec_hab_audit_rt1060.c b/examples/data/hab_audit/exec_hab_audit_rt1060.c
similarity index 100%
rename from spsdk/data/cpu_data/exec_hab_audit_rt1060.c
rename to examples/data/hab_audit/exec_hab_audit_rt1060.c
diff --git a/spsdk/data/cpu_data/rt1020_exec_hab_audit.bin b/examples/data/hab_audit/rt1020_exec_hab_audit.bin
similarity index 100%
rename from spsdk/data/cpu_data/rt1020_exec_hab_audit.bin
rename to examples/data/hab_audit/rt1020_exec_hab_audit.bin
diff --git a/spsdk/data/cpu_data/rt1050_exec_hab_audit.bin b/examples/data/hab_audit/rt1050_exec_hab_audit.bin
similarity index 100%
rename from spsdk/data/cpu_data/rt1050_exec_hab_audit.bin
rename to examples/data/hab_audit/rt1050_exec_hab_audit.bin
diff --git a/spsdk/data/cpu_data/rt1060_exec_hab_audit.bin b/examples/data/hab_audit/rt1060_exec_hab_audit.bin
similarity index 100%
rename from spsdk/data/cpu_data/rt1060_exec_hab_audit.bin
rename to examples/data/hab_audit/rt1060_exec_hab_audit.bin
diff --git a/examples/jupyter_examples/dk6/dk6prog_intro.ipynb b/examples/jupyter_examples/dk6/dk6prog_intro.ipynb
new file mode 100644
index 00000000..3b8373b2
--- /dev/null
+++ b/examples/jupyter_examples/dk6/dk6prog_intro.ipynb
@@ -0,0 +1,237 @@
+{
+ "cells": [
+ {
+ "attachments": {
+ "image.png": {
+ "image/png": "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"
+ }
+ },
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# DK6 Programming tool\n",
+ "\n",
+ "DK6 Programming tool also known as DK6Prog is an alternative tool to \"JN51xx Production Flash Programmer\" (https://www.nxp.com/docs/en/user-guide/JN-UG-3099.pdf). DK6Prog is part of the SPSDK and written in Python. DK6 is a name that was given to development kit for K32W, JN51xx and QN90xx devices. (https://www.nxp.com/products/wireless/multiprotocol-mcus/advanced-development-kit-for-k32w061-and-jn5189-88:IOTZTB-DK006)\n",
+ "\n",
+ "DK6 development kit is utilizing FTDI chip for sending ISP sequence in GPIO bitbang mode.\n",
+ "\n",
+ "> **_NOTE:_** Before running this Notebook, please make sure to install DK6 support in SPSDK: *pip install -e \".[dk6]\"*\n",
+ "\n",
+ "## Backends\n",
+ "User might select between four backends that will be used for communication. \n",
+ "\n",
+ "- PYFTDI is a pure Python implementation of libFTDI. (https://eblot.github.io/pyftdi/index.html). Default selection for Linux and MacOS\n",
+ "- PYLIBFTDI is a Ctypes wrapper for libFTDI (https://pypi.org/project/pylibftdi/), which is an open source implementation of FTDI D2xx driver.\n",
+ "- FTD2XX is a Ctypes wrapper for official FTDI D2XX library. Default selecltion for Windows\n",
+ "- PYSERIAL is meant for pure UART communication, bitbang mode is not supported.\n",
+ "\n",
+ "## DK6 Board overview\n",
+ "![image.png](attachment:image.png)\n",
+ "\n",
+ "Backends are selected with *-d* or *--device* option.\n",
+ "\n",
+ "## CLI operations\n",
+ "\n",
+ "1. Connect the USB cable to *FTDI USB* slot.\n",
+ "2. Connect JP7 and JP4 to UART0 - FTDI\n",
+ "3. Issue *dk6prog listdev* optionally with the *-b* option to select the backend\n",
+ "4. Get the DEVICE ID\n",
+ "5. Issue any command specifying DEVICE ID with *-d* parameter\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "env: JUPYTER_SPSDK=1\n",
+ "Created `%!` as an alias for `%execute`.\n",
+ "dk6prog listdev \n",
+ "\n",
+ "!!! THIS IS AN EXPERIMENTAL UTILITY! USE WITH CAUTION !!!\n",
+ "\n",
+ "List of available devices:\n",
+ "DEVICE ID: 0, VID: 0x0, PID: 0x0, Serial number: b'DN03TBTK', Description: b'DK6 Carrier Board', Address: 67330069, Backend: Backend.FTD2xx\n"
+ ]
+ }
+ ],
+ "source": [
+ "%run ../init_notebook.ipynb\n",
+ "\n",
+ "DEVICE_ID = 0\n",
+ "NO_VERBOSE = \"\"\n",
+ "VERBOSE = \"-v\"\n",
+ "DEBUG = \"-vv\"\n",
+ "VERBOSITY = NO_VERBOSE\n",
+ "\n",
+ "# Get the device ID\n",
+ "%! dk6prog $VERBOSITY listdev\n",
+ "\n"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## ISP Protocol\n",
+ "\n",
+ "- ISP sequence is controlled by FTDI CBUS pins in bitbang mode (or\n",
+ "manually with ISP button)\n",
+ "- Memory must be open in desired access mode before reading/writing\n",
+ "- Default 115200 baud rate 8N1, no ABR (support up to 1 MBd)\n",
+ "- ISP authentication (Signed unlock key n=288), Authenticated\n",
+ "commands not implemented (SHA-256 + signature)\n",
+ "- Encrypted transfer AES-CTR – not implemented\n",
+ "\n",
+ "## Memory operations\n",
+ "What's supported:\n",
+ "\n",
+ "- Read – read to file, stdout\n",
+ "- Write – write to file, stdout\n",
+ "- Erase – erase and check if memory is erased\n",
+ "- Info – info about chip, memories, etc.\n",
+ "- Command chaining – multiple commands might be chained\n",
+ "\n",
+ "At first, let's print the memory map of the device using the *info* command and see what's available.\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "dk6prog -d 0 info \n",
+ "\n",
+ "!!! THIS IS AN EXPERIMENTAL UTILITY! USE WITH CAUTION !!!\n",
+ "\n",
+ "Chip ID: 0x88888888\n",
+ "ROM Version: 0x0\n",
+ "MAC Address: 9A:13:1F:03:00:8D:15:00\n",
+ "\n",
+ "Detected DEVICE: 0\n",
+ "\n",
+ " Memory Memory ID Base Address Length Sector Size Memory Type Access \n",
+ "------------------------------------------------------------------------------------\n",
+ " FLASH 0 0x0 0x9de00 0x200 FLASH ALL \n",
+ " PSECT 1 0x0 0x1e0 0x10 FLASH ALL \n",
+ " pFLASH 2 0x0 0x1e0 0x10 FLASH ALL \n",
+ " Config 3 0x9fc00 0x200 0x200 FLASH ALL \n",
+ " EFUSE 4 0x0 0x80 0x2 EFUSE (OTP) WRITE \n",
+ " ROM 5 0x3000000 0x20000 0x1 ROM WRITE \n",
+ " RAM0 6 0x4000000 0x16000 0x1 RAM WRITE \n",
+ " RAM1 7 0x4020000 0x10000 0x1 RAM WRITE \n"
+ ]
+ }
+ ],
+ "source": [
+ "%! dk6prog -d $DEVICE_ID $VERBOSITY info"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "dk6prog -d 0 read 0x96000 8 FLASH \n",
+ "\n",
+ "!!! THIS IS AN EXPERIMENTAL UTILITY! USE WITH CAUTION !!!\n",
+ "\n",
+ "Reading memory\n",
+ "Read 8/8 bytes from 0x96000:0x96008 Memory ID: FLASH\n",
+ "de ad de ad de ad de ad\n",
+ "dk6prog -d 0 read -o data.bin 0x96000 8 FLASH \n",
+ "\n",
+ "!!! THIS IS AN EXPERIMENTAL UTILITY! USE WITH CAUTION !!!\n",
+ "\n",
+ "Reading memory\n",
+ "Read 8/8 bytes from 0x96000:0x96008 Memory ID: FLASH\n",
+ "Writing data to data.bin\n",
+ "dk6prog -d 0 erase 0x96000 8 FLASH \n",
+ "\n",
+ "!!! THIS IS AN EXPERIMENTAL UTILITY! USE WITH CAUTION !!!\n",
+ "\n",
+ "Erasing memory\n",
+ "dk6prog -d 0 write 0x96000 [[123456789abcdef0]] 8 FLASH \n",
+ "\n",
+ "!!! THIS IS AN EXPERIMENTAL UTILITY! USE WITH CAUTION !!!\n",
+ "\n",
+ "Writing memory\n",
+ "Writen 8 bytes to memory ID FLASH at address 0x96000\n",
+ "dk6prog -d 0 read 0x96000 8 FLASH \n",
+ "\n",
+ "!!! THIS IS AN EXPERIMENTAL UTILITY! USE WITH CAUTION !!!\n",
+ "\n",
+ "Reading memory\n",
+ "Read 8/8 bytes from 0x96000:0x96008 Memory ID: FLASH\n",
+ "12 34 56 78 9a bc de f0\n",
+ "dk6prog -d 0 erase 0x96000 8 FLASH \n",
+ "\n",
+ "!!! THIS IS AN EXPERIMENTAL UTILITY! USE WITH CAUTION !!!\n",
+ "\n",
+ "Erasing memory\n"
+ ]
+ }
+ ],
+ "source": [
+ "# read 8 bytes from flash at addr 0x96000\n",
+ "%! dk6prog $VERBOSITY -d $DEVICE_ID read 0x96000 8 FLASH \n",
+ "# read data to file\n",
+ "%! dk6prog $VERBOSITY -d $DEVICE_ID read -o data.bin 0x96000 8 FLASH \n",
+ "# erase 8 bytes from flash\n",
+ "%! dk6prog $VERBOSITY -d $DEVICE_ID erase 0x96000 8 FLASH \n",
+ "# writes data to flash, read it and erase them\n",
+ "%! dk6prog $VERBOSITY -d $DEVICE_ID write 0x96000 [[123456789abcdef0]] 8 FLASH \n",
+ "%! dk6prog $VERBOSITY -d $DEVICE_ID read 0x96000 8 FLASH\n",
+ "%! dk6prog $VERBOSITY -d $DEVICE_ID erase 0x96000 8 FLASH"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "venv",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.0"
+ },
+ "orig_nbformat": 4,
+ "vscode": {
+ "interpreter": {
+ "hash": "7e49b31b08ee6a6d8509263078c11b076a18c33ce0e89644813165ae065c47df"
+ }
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/examples/jupyter_examples/kw45xx_k32w1xx/hello_world_UART0.bin b/examples/jupyter_examples/kw45xx_k32w1xx/hello_world_UART0.bin
new file mode 100644
index 00000000..d8954cea
Binary files /dev/null and b/examples/jupyter_examples/kw45xx_k32w1xx/hello_world_UART0.bin differ
diff --git a/examples/jupyter_examples/kw45xx_k32w1xx/kw45xx_k32w1xx_load_NBU_image.ipynb b/examples/jupyter_examples/kw45xx_k32w1xx/kw45xx_k32w1xx_load_NBU_image.ipynb
index 0a7935fa..8336206b 100644
--- a/examples/jupyter_examples/kw45xx_k32w1xx/kw45xx_k32w1xx_load_NBU_image.ipynb
+++ b/examples/jupyter_examples/kw45xx_k32w1xx/kw45xx_k32w1xx_load_NBU_image.ipynb
@@ -11,6 +11,7 @@
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -34,6 +35,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
+ "env: JUPYTER_SPSDK=1\n",
"Created `%!` as an alias for `%execute`.\n"
]
}
@@ -60,10 +62,15 @@
"output_type": "stream",
"text": [
"nxpcrypto key generate -k secp384r1 workspace/ec_pk_secp384r1_cert0.pem --force \n",
+ "The key pair has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_pk_secp384r1_cert0.pub, C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_pk_secp384r1_cert0.pem\n",
"nxpcrypto key generate -k secp384r1 workspace/ec_pk_secp384r1_cert1.pem --force \n",
+ "The key pair has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_pk_secp384r1_cert1.pub, C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_pk_secp384r1_cert1.pem\n",
"nxpcrypto key generate -k secp384r1 workspace/ec_pk_secp384r1_cert2.pem --force \n",
+ "The key pair has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_pk_secp384r1_cert2.pub, C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_pk_secp384r1_cert2.pem\n",
"nxpcrypto key generate -k secp384r1 workspace/ec_pk_secp384r1_cert3.pem --force \n",
- "nxpcrypto key generate -k secp384r1 workspace/ec_pk_secp384r1_sign_cert.pem --force \n"
+ "The key pair has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_pk_secp384r1_cert3.pub, C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_pk_secp384r1_cert3.pem\n",
+ "nxpcrypto key generate -k secp384r1 workspace/ec_pk_secp384r1_sign_cert.pem --force \n",
+ "The key pair has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_pk_secp384r1_sign_cert.pub, C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_pk_secp384r1_sign_cert.pem\n"
]
}
],
@@ -124,6 +131,7 @@
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -143,15 +151,15 @@
"output_type": "stream",
"text": [
"nxpcrypto cert get-template workspace/cert0_template.yml --force \n",
- "The configuration template file has been created: c:\\repos\\spsdk_master\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\cert0_template.yml\n",
+ "The configuration template file has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\cert0_template.yml\n",
"nxpcrypto cert get-template workspace/cert1_template.yml --force \n",
- "The configuration template file has been created: c:\\repos\\spsdk_master\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\cert1_template.yml\n",
+ "The configuration template file has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\cert1_template.yml\n",
"nxpcrypto cert get-template workspace/cert2_template.yml --force \n",
- "The configuration template file has been created: c:\\repos\\spsdk_master\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\cert2_template.yml\n",
+ "The configuration template file has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\cert2_template.yml\n",
"nxpcrypto cert get-template workspace/cert3_template.yml --force \n",
- "The configuration template file has been created: c:\\repos\\spsdk_master\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\cert3_template.yml\n",
+ "The configuration template file has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\cert3_template.yml\n",
"nxpcrypto cert get-template workspace/sign_cert_template.yml --force \n",
- "The configuration template file has been created: c:\\repos\\spsdk_master\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\sign_cert_template.yml\n"
+ "The configuration template file has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\sign_cert_template.yml\n"
]
}
],
@@ -178,6 +186,7 @@
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -344,15 +353,15 @@
" 'STREET_ADDRESS': '1.maje 1009'},\n",
" 'subject_public_key': 'workspace/ec_pk_secp384r1_sign_cert.pub'}\n",
"nxpcrypto cert generate -c workspace/cert0_template.yml -o workspace/ec_secp384r1_cert0.pem --force \n",
- "The certificate file has been created: c:\\repos\\spsdk_master\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_secp384r1_cert0.pem\n",
+ "The certificate file has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_secp384r1_cert0.pem\n",
"nxpcrypto cert generate -c workspace/cert1_template.yml -o workspace/ec_secp384r1_cert1.pem --force \n",
- "The certificate file has been created: c:\\repos\\spsdk_master\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_secp384r1_cert1.pem\n",
+ "The certificate file has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_secp384r1_cert1.pem\n",
"nxpcrypto cert generate -c workspace/cert2_template.yml -o workspace/ec_secp384r1_cert2.pem --force \n",
- "The certificate file has been created: c:\\repos\\spsdk_master\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_secp384r1_cert2.pem\n",
+ "The certificate file has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_secp384r1_cert2.pem\n",
"nxpcrypto cert generate -c workspace/cert3_template.yml -o workspace/ec_secp384r1_cert3.pem --force \n",
- "The certificate file has been created: c:\\repos\\spsdk_master\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_secp384r1_cert3.pem\n",
+ "The certificate file has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_secp384r1_cert3.pem\n",
"nxpcrypto cert generate -c workspace/sign_cert_template.yml -o workspace/ec_secp384r1_sign_cert.pem --force \n",
- "The certificate file has been created: c:\\repos\\spsdk_master\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_secp384r1_sign_cert.pem\n"
+ "The certificate file has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_secp384r1_sign_cert.pem\n"
]
}
],
@@ -463,6 +472,7 @@
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -478,7 +488,7 @@
"metadata": {},
"outputs": [],
"source": [
- "import os, binascii\n",
+ "import binascii\n",
"\n",
"SB3KDK_KEY_PATH = WORKSPACE + \"sb3kdk.txt\"\n",
"with open(SB3KDK_KEY_PATH, \"wb\") as f:\n",
@@ -488,6 +498,7 @@
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -507,109 +518,99 @@
"output_type": "stream",
"text": [
"nxpimage sb31 get-template -f kw45xx -o workspace/sb31_config.yml \n",
- "Creating workspace/sb31_config.yml template file.\n",
+ "Creating C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\sb31_config.yml template file.\n",
"# =========== Secure Binary v3.1 Configuration template for kw45xx. ===========\n",
"# ----------------------------------------------------------------------------------------------------\n",
"# == Basic Settings == \n",
"# ----------------------------------------------------------------------------------------------------\n",
- "firmwareVersion: 0 # [Optional], Firmware version., Version of application image firmware.\n",
- "family: kw45xx # [Required], MCU family, MCU family name., Possible options:['lpc55s3x', 'kw45xx', 'k32w1xx']\n",
- "containerOutputFile: my_new.sb3 # [Required], SB3 filename, Generated SB3 container filename.\n",
+ "firmwareVersion: 0 # [Optional], Firmware version; Version of application image firmware.\n",
+ "family: kw45xx # [Required], MCU family name; Possible options:['k32w1xx', 'kw45xx', 'lpc55s3x', 'mcxn9xx']\n",
+ "containerOutputFile: my_new.sb3 # [Required], SB3 filename; Generated SB3 container filename.\n",
+ "# ----------------------------------------------------------------------------------------------------\n",
+ "# == Root Keys Settings == \n",
+ "# ----------------------------------------------------------------------------------------------------\n",
+ "rootCertificate0File: my_certificate0.pub # [Conditionally required], Root Certificate File 0; Root certificate file index 0.\n",
+ "rootCertificate1File: my_certificate1.pub # [Optional], Root Certificate File 1; Root certificate file index 1.\n",
+ "rootCertificate2File: my_certificate2.pub # [Optional], Root Certificate File 2; Root certificate file index 2.\n",
+ "rootCertificate3File: my_certificate3.pub # [Optional], Root Certificate File 3; Root certificate file index 3.\n",
+ "mainRootCertId: 0 # [Conditionally required], Main Certificate Index; Index of certificate that is used as a main. If not defined, the certificate matching private key will be selected.\n",
"# ----------------------------------------------------------------------------------------------------\n",
"# == Certificate V3.1 Settings == \n",
"# ----------------------------------------------------------------------------------------------------\n",
- "useIsk: false # [Required], Use ISK for signature certification, Enable ISK type of signature certification\n",
- "signingCertificatePrivateKeyFile: isk_prv_key.pem # [Conditionally required], ISK Certificate private key, ISK Certificate private key used to sign certificate\n",
- "mainRootCertPrivateKeyFile: main_cert_prv_key.pem # [Conditionally required], Main root Certification Private Key, Path to Main root Certification Private Key\n",
- "rootCertificateEllipticCurve: secp256r1 # [Optional], Type of elliptic curve of root key, Elliptic curve type used for root key., Possible options:['secp256r1', 'secp384r1']\n",
- "iskCertificateEllipticCurve: secp256r1 # [Optional], Type of elliptic curve of ISK key, Elliptic curve type used for ISK key., Possible options:['secp256r1', 'secp384r1']\n",
- "signingCertificateFile: sign_cert.pem # [Conditionally required], Signing Certificate, Path to Signing Certificate\n",
- "signingCertificateConstraint: 0 # [Optional], Signing certificate constrain, Signing certificate constrain number\n",
- "signCertData: sign_cert.bin # [Optional], Signing Certificate data, Path to Signing Certificate data\n",
+ "rootCertificateEllipticCurve: secp256r1 # [Conditionally required], Type of elliptic curve of root key; Elliptic curve type used for root key; Possible options:['secp256r1', 'secp384r1']\n",
+ "iskCertificateEllipticCurve: secp256r1 # [Conditionally required], Type of elliptic curve of ISK key; Elliptic curve type used for ISK key; Possible options:['secp256r1', 'secp384r1']\n",
"# ----------------------------------------------------------------------------------------------------\n",
- "# == Certificate Settings == \n",
+ "# == ISK Certificate Settings == \n",
"# ----------------------------------------------------------------------------------------------------\n",
- "rootCertificate0File: my_certificate0.pub # [Required], Root Certificate File 0, Root certificate file index 0.\n",
- "rootCertificate1File: my_certificate1.pub # [Optional], Root Certificate File 1, Root certificate file index 1.\n",
- "rootCertificate2File: my_certificate2.pub # [Optional], Root Certificate File 2, Root certificate file index 2.\n",
- "rootCertificate3File: my_certificate3.pub # [Optional], Root Certificate File 3, Root certificate file index 3.\n",
- "mainRootCertId: 0 # [Conditionally required], Main Certificate Index, Index of certificate that is used as a main.\n",
+ "binaryCertificateBlock: my_isk_cert.bin # [Conditionally required], Binary Certificate; Optionally the certificate could be defined as a pre-generated binary block. In case that is defined, all other configuration for certification block must be deleted ('useIsk', 'mainRootCertPrivateKeyFile', 'signingCertificateFile', 'signingCertificateConstraint', 'signCertData') In case that ISK is defined, certicate block must be deleted\n",
+ "useIsk: false # [Conditionally required], Use ISK for signature certification; Enable ISK type of signature certification. Don't use when 'binaryCertificateBlock' is defined\n",
+ "mainRootCertPrivateKeyFile: main_cert_prv_key.pem # [Conditionally required], Main root Certification Private Key; Path to Main root Certification Private Key. Don't use when 'binaryCertificateBlock' is defined\n",
+ "signingCertificateFile: sign_cert.pem # [Conditionally required], Signing Certificate; Path to Signing Certificate. Don't use when 'binaryCertificateBlock' is defined\n",
+ "signingCertificateConstraint: 0 # [Optional], Signing certificate constrain number. Don't use when 'binaryCertificateBlock' is defined\n",
+ "signCertData: sign_cert.bin # [Optional], Signing Certificate data; Path to Signing Certificate data. Don't use when 'binaryCertificateBlock' is defined\n",
+ "signingCertificatePrivateKeyFile: isk_prv_key.pem # [Optional], ISK Certificate private key used to sign certificate. It can be replaced by signProvider key.\n",
+ "iskSignProvider: type=file;file_path=my_isk_prv_key.pem # [Optional], ISK Signature Provider; Signature provider configuration in format 'type=;=;=\".\n",
"# ----------------------------------------------------------------------------------------------------\n",
"# == Secure Binary v3.1 Settings == \n",
"# ----------------------------------------------------------------------------------------------------\n",
- "containerKeyBlobEncryptionKey: my_pck.txt # [Optional], Part Common Key, Path to PCK/NPK key in plain hex string format.\n",
- "isNxpContainer: false # [Optional], Enable NXP Container format, Internal usage only, used for generating SB files with NXP content e.g. provisioning firmware, sentinel firmware...\n",
- "kdkAccessRights: 0 # [Optional], KDK access rights, Accepted values are 0, 1, 2 and 3. Value used as key properties for key derivation process, more details can be found in CSSv2 manual., Possible options:[0, 1, 2, 3]\n",
- "containerConfigurationWord: 0 # [Optional], Container configuration word, Flag value in SB3.1 manifest, not used by silicons with LPC55S3x ROM. Value can be kept 0, or it can be removed from the configuration file.\n",
- "description: This is description of generated SB file. # [Optional], Description, Description up to 16 characters, longer will be truncated. Stored in SB3.1 manifest.\n",
+ "containerKeyBlobEncryptionKey: my_pck.txt # [Optional], Part Common Key; Path to PCK/NPK key in plain hex string format.\n",
+ "isNxpContainer: false # [Optional], Enable NXP Container format; Internal usage only, used for generating SB files with NXP content e.g. provisioning firmware, sentinel firmware...\n",
+ "kdkAccessRights: 0 # [Optional], KDK access rights; Accepted values are 0, 1, 2 and 3. Value used as key properties for key derivation process, more details can be found in CSSv2 manual; Possible options:[0, 1, 2, 3]\n",
+ "containerConfigurationWord: 0 # [Optional], Container configuration word; Flag value in SB3.1 manifest, not used by silicons with LPC55S3x ROM. Value can be kept 0, or it can be removed from the configuration file.\n",
+ "description: This is description of generated SB file. # [Optional], Description up to 16 characters, longer will be truncated. Stored in SB3.1 manifest.\n",
"# ----------------------------------------------------------------------------------------------------\n",
"# == Secure Binary v3.1 Commands Settings == \n",
"# ----------------------------------------------------------------------------------------------------\n",
- "commands: # [Required], SB3.1 Commands, Secure Binary v3.1 commands block, list of all possible options - Modify it according to your application\n",
+ "commands: # [Required], SB3.1 Commands; Secure Binary v3.1 commands block, list of all possible options - Modify it according to your application\n",
" # ----------------------------------------------------------------------------------------------------\n",
- " # == List of possible 13 options. Option types[object,object,object,object,object,object,object,object,object,object,object,object,object] == \n",
+ " # == List of possible 10 options. Option types[object,object,object,object,object,object,object,object,object,object] == \n",
" # ----------------------------------------------------------------------------------------------------\n",
" - # [Example of possible configuration #0] \n",
- " erase: # [Required], Erase, Performs a flash erase of the given address range. The erase will be rounded up to the sector size.\n",
- " address: 0 # [Required], Address, Address of memory block to be erased.\n",
- " size: 4096 # [Required], Size, Size of memory block to be erased.\n",
- " memoryId: 0 # [Optional], Memory ID, ID of memory block to be erased.\n",
+ " erase: # [Required], Erase; Performs a flash erase of the given address range. The erase will be rounded up to the sector size.\n",
+ " address: 0 # [Required], Address of memory block to be erased.\n",
+ " size: 4096 # [Required], Size of memory block to be erased.\n",
+ " memoryId: 0 # [Optional], Memory ID; ID of memory block to be erased.\n",
" - # [Example of possible configuration #1] \n",
- " load: # [Required], Load, If set, then the data to write immediately follows the range header. The length field contains the actual data length\n",
- " address: 0 # [Required], Address, Address of memory block to be loaded.\n",
- " memoryId: 0 # [Optional], Memory ID, ID of memory block to be loaded.\n",
- " file: my_binary.bin # [Optional], Binary file., Binary file to be loaded.\n",
- " values: 0x1234, 0x5678, 0, 12345678 # [Optional], Binary values., Binary values delimited by comma to be loaded.\n",
- " authentication: cmac # [Optional], Authentication, Type of Image authentication [None, cmac, hashlocking]. If authentication is not used, just omit this option.\n",
+ " load: # [Required], Load; If set, then the data to write immediately follows the range header. The length field contains the actual data length\n",
+ " address: 0 # [Required], Address of memory block to be loaded.\n",
+ " memoryId: 0 # [Optional], Memory ID; ID of memory block to be loaded.\n",
+ " file: my_binary.bin # [Optional], Binary file to be loaded.\n",
+ " values: 0x1234, 0x5678, 0, 12345678 # [Optional], Binary values delimited by comma to be loaded.\n",
+ " authentication: cmac # [Optional], Authentication; If authentication is not used, just omit this option or set 'none'; Possible options:['none', 'cmac', 'hashlocking']\n",
" - # [Example of possible configuration #2] \n",
- " execute: # [Required], Execute, Address is the jump-to address. No further processing of SB after jump, ROM do not expect to return.\n",
- " address: 0 # [Required], Address, Jump-to address to start execute code.\n",
+ " execute: # [Required], Execute; Address is the jump-to address. No further processing of SB after jump, ROM do not expect to return.\n",
+ " address: 0 # [Required], Address; Jump-to address to start execute code.\n",
" - # [Example of possible configuration #3] \n",
- " call: # [Required], Call, Address is address to jump. However, the state machine should expect a return to the next statement to continue processing the SB file\n",
- " address: 0 # [Required], Address, Jump-to address to start execute code.\n",
+ " programFuses: # [Required], Program Fuses; Address is OTP index of fuses to be programmed (Check the reference manual for more information). Values is a comma separated list of 32bit values.\n",
+ " address: 0 # [Required], Address; OTP Index of fuses to be programmed. Depends on the chip ROM.\n",
+ " values: 0x1234, 0x5678, 0, 12345678 # [Required], Binary values; 32bit binary values delimited by comma to be programmed.\n",
" - # [Example of possible configuration #4] \n",
- " programFuses: # [Required], Program Fuses, Address is OTP index of fuses to be programmed (Check the reference manual for more information). Values is a comma separated list of 32bit values.\n",
- " address: 0 # [Required], Address, OTP Index of fuses to be programmed. Depends on the chip ROM.\n",
- " values: 0x1234, 0x5678, 0, 12345678 # [Required], Binary values, 32bit binary values delimited by comma to be programmed.\n",
+ " programIFR: # [Required], Program IFR; The startAddress will be the address into the IFR region, length will be in number of bytes to write to IFR region. The data to write to IFR region at the given address will immediately follow the header\n",
+ " address: 0 # [Required], Address of IFR region to be programmed.\n",
+ " file: my_binary.bin # [Required], Binary file to be programmed.\n",
" - # [Example of possible configuration #5] \n",
- " programIFR: # [Required], Program IFR, The startAddress will be the address into the IFR region, length will be in number of bytes to write to IFR region. The data to write to IFR region at the given address will immediately follow the header\n",
- " address: 0 # [Required], Address, Address of IFR region to be programmed.\n",
- " file: my_binary.bin # [Required], Binary file, Binary file to be programmed.\n",
+ " loadCMAC: # [Required], Load CMAC; If set, then the data to write immediately follows the range header. The length field contains the actual data length. ROM is calculating cmac from loaded data and storing on address known by ROM decided based on startAddress.\n",
+ " address: 0 # [Required], Address of memory block to be CMAC loaded.\n",
+ " memoryId: 0 # [Optional], Memory ID; ID of memory block to be CMAC loaded.\n",
+ " file: my_cmac_binary.bin # [Required], Binary file to be loaded.\n",
" - # [Example of possible configuration #6] \n",
- " loadCMAC: # [Required], Load CMAC, If set, then the data to write immediately follows the range header. The length field contains the actual data length. ROM is calculating cmac from loaded data and storing on address known by ROM decided based on startAddress.\n",
- " address: 0 # [Required], Address, Address of memory block to be CMAC loaded.\n",
- " memoryId: 0 # [Optional], Memory ID, ID of memory block to be CMAC loaded.\n",
- " file: my_cmac_binary.bin # [Required], Binary file, Binary file to be loaded.\n",
+ " loadHashLocking: # [Required], Load with HASH locking; If set, then the data to write immediately follows the range header. The length field contains the actual data length. ROM is calculating hash of the data and storing the value in the last 64 bytes of the loaded data, which are reserved for it.\n",
+ " address: 0 # [Required], Address of memory block to be loaded.\n",
+ " memoryId: 0 # [Optional], Memory ID; ID of memory block to be loaded.\n",
+ " file: my_hashlocking_binary.bin # [Required], Binary file to be loaded.\n",
" - # [Example of possible configuration #7] \n",
- " copy: # [Required], Copy, Used for copying data from one place to another. 32 bytes fixed size.\n",
- " addressFrom: 0 # [Required], Address From, Address of memory block to be copied.\n",
- " memoryIdFrom: 0 # [Optional], Memory ID From, ID of memory block to be copied.\n",
- " size: 4096 # [Required], Size, Size of memory block to be copied.\n",
- " addressTo: 536870912 # [Required], Address To, Address of memory where block to be copied.\n",
- " memoryIdTo: 0 # [Optional], Memory ID To, ID of memory block where to be copied.\n",
+ " configureMemory: # [Required], Configure memory.\n",
+ " configAddress: 0 # [Required], Address; Configuration address.\n",
+ " memoryId: 0 # [Optional], Memory ID; ID of memory block to be configured.\n",
" - # [Example of possible configuration #8] \n",
- " loadHashLocking: # [Required], Load with HASH locking, If set, then the data to write immediately follows the range header. The length field contains the actual data length. ROM is calculating hash of the data and storing the value in the last 64 bytes of the loaded data, which are reserved for it.\n",
- " address: 0 # [Required], Address, Address of memory block to be loaded.\n",
- " memoryId: 0 # [Optional], Memory ID, ID of memory block to be loaded.\n",
- " file: my_hashlocking_binary.bin # [Required], Binary file, Binary file to be loaded.\n",
+ " fillMemory: # [Required], Fill memory; Used for filling of the memory range by same repeated int32 pattern.\n",
+ " address: 0 # [Required], Address of memory block to be filled.\n",
+ " size: 4096 # [Required], Size of memory block to be filled.\n",
+ " pattern: 2779096485 # [Required], Pattern which will be used to fill memory.\n",
" - # [Example of possible configuration #9] \n",
- " loadKeyBlob: # [Required], Load Key Blob, Wrapped key blob immediately follows the range key blob header. The length field contains the actual data length.\n",
- " offset: 0 # [Required], Offset, Offset of the key blob.\n",
- " wrappingKeyId: 0 # [Required], Wrapping key ID, Wrapping ID of key blob., Possible options:['NXP_CUST_KEK_INT_SK', 'NXP_CUST_KEK_EXT_SK']\n",
- " file: my_keyblob.bin # [Required], Binary file, Binary file to be loaded.\n",
- " - # [Example of possible configuration #10] \n",
- " configureMemory: # [Required], Configure memory, Configure memory.\n",
- " configAddress: 0 # [Required], Address, Configuration address.\n",
- " memoryId: 0 # [Optional], Memory ID, ID of memory block to be configured.\n",
- " - # [Example of possible configuration #11] \n",
- " fillMemory: # [Required], Fill memory, Used for filling of the memory range by same repeated int32 pattern.\n",
- " address: 0 # [Required], Address, Address of memory block to be filled.\n",
- " size: 4096 # [Required], Size, Size of memory block to be filled.\n",
- " pattern: 2779096485 # [Required], Pattern, Pattern which will be used to fill memory.\n",
- " - # [Example of possible configuration #12] \n",
- " checkFwVersion: # [Required], Check firmware version, Used to execute check of provided counter value with value stored in specified monotonous counter in device. If values are not same, SB file is rejected.\n",
- " value: 1 # [Required], Value - Firmware version, Firmware version to be compared.\n",
- " counterId: secure # [Required], Counter ID, ID of FW counter to be checked., Possible options:['none', 'nonsecure', 'secure', 'radio', 'snt', 'bootloader']\n",
+ " checkFwVersion: # [Required], Check firmware version; Used to execute check of provided counter value with value stored in specified monotonous counter in device. If values are not same, SB file is rejected.\n",
+ " value: 1 # [Required], Value - Firmware version; Firmware version to be compared.\n",
+ " counterId: secure # [Required], Counter ID; ID of FW counter to be checked; Possible options:['none', 'nonsecure', 'secure', 'radio', 'snt', 'bootloader']\n",
"\n"
]
}
@@ -645,6 +646,7 @@
" 'family': 'kw45xx',\n",
" 'firmwareVersion': 0,\n",
" 'isNxpContainer': False,\n",
+ " 'iskSignProvider': 'type=file;file_path=my_isk_prv_key.pem',\n",
" 'kdkAccessRights': 3,\n",
" 'mainRootCertId': 0,\n",
" 'mainRootCertPrivateKeyFile': 'workspace/ec_pk_secp384r1_cert0.pem',\n",
@@ -680,12 +682,28 @@
" sb31['mainRootCertId'] = 0\n",
" sb31['mainRootCertPrivateKeyFile'] = ROTK0_PRIVATE_KEY_PATH\n",
" sb31['rootCertificateEllipticCurve'] = \"secp384r1\"\n",
- " sb31['useIsk'] = False\n",
+ " del sb31['binaryCertificateBlock']\n",
+ " # Choose between two scenarios:\n",
+ "\n",
+ " # # scenario 1\n",
+ " # # if you want to use ISK:\n",
+ " # sb31['useIsk'] = True\n",
+ " # sb31['signingCertificateFile'] = ISK_CERT_PATH\n",
+ " # sb31['signingCertificatePrivateKeyFile'] = ISK_PRIVATE_KEY_PATH\n",
+ " # sb31['signingCertificateConstraint'] = 0\n",
+ " # sb31['iskCertificateEllipticCurve'] = \"secp384r1\"\n",
+ " # # [optional, can contain user data\n",
+ " # del sb31['signCertData']\n",
+ "\n",
+ " # scenario 2\n",
+ " #if you do not use ISK:\n",
" del sb31['signingCertificatePrivateKeyFile']\n",
" del sb31['signingCertificateFile']\n",
" del sb31['signCertData']\n",
- " del sb31['commands']\n",
" del sb31['iskCertificateEllipticCurve']\n",
+ "\n",
+ " # This is common for both scenarios:\n",
+ " del sb31['commands']\n",
" sb31['commands'] = [\n",
" {\n",
" \"erase\": {\n",
@@ -709,6 +727,7 @@
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -727,15 +746,9 @@
"output_type": "stream",
"text": [
"nxpimage -v sb31 export workspace/sb31_config.yml \n",
- "Success. (Secure binary 3.1: c:/repos/spsdk_master/examples/jupyter_examples/kw45xx_k32w1xx/workspace/sb3.sb3 created.)\n"
- ]
- },
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "INFO:spsdk.sbfile.sb31.images:SB3KDK: b1075a0177d1e531cded22ee2ab21f6a2683be98b2034f0ceb86f95925bbd1b4\n",
- "INFO:spsdk.utils.crypto.cert_blocks:RoTKTH: 3d1d02dbd118a9448bcf536d4198f24184762d63ce9be0da9320dd0b0e3af5daa2d903f60bbdb17a10b58eb20b4d320a\n"
+ "\u001b[37m\u001b[1mINFO:spsdk.sbfile.sb31.images:SB3KDK: 74cd7710ba864fc92244e6b2bef5f998b2bc3f505c82ad339152dbb8bbaec040\u001b[39m\u001b[0m\n",
+ "\u001b[37m\u001b[1mINFO:spsdk.utils.crypto.cert_blocks:RoTKTH: 9af7e81ec9957cea6b4b4f8ede279e417d2a91f07cafdca7679764594933ac338292a8683e30a15644dd1fad84bbfc3a\u001b[39m\u001b[0m\n",
+ "Success. (Secure binary 3.1: c:/spsdk/examples/jupyter_examples/kw45xx_k32w1xx/workspace/sb3.sb3 created.)\n"
]
}
],
@@ -783,7 +796,7 @@
"\n",
"-------- Connected NXP UART Devices --------\n",
"\n",
- "Port: COM9\n",
+ "Port: COM6\n",
"Type: mboot device\n",
"\n",
"-------- Connected NXP SIO Devices --------\n",
@@ -805,7 +818,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "blhost -p com9 get-property current-version \n",
+ "blhost -p com6 get-property current-version \n",
"Response status = 0 (0x0) Success.\n",
"Response word 1 = 1258488064 (0x4b030100)\n",
"Current Version = K3.1.0\n"
@@ -814,12 +827,13 @@
],
"source": [
"# choose com port\n",
- "UART_CONNECTION = \"-p com9\"\n",
+ "UART_CONNECTION = \"-p com6\"\n",
"\n",
"%! blhost $UART_CONNECTION get-property current-version"
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -840,15 +854,15 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "blhost -p com9 set-property 0x16 1 \n",
+ "blhost -p com6 set-property 0x16 1 \n",
"Response status = 0 (0x0) Success.\n",
- "blhost -p com9 fuse-program 0x20 [[b1075a0177d1e531cded22ee2ab21f6a2683be98b2034f0ceb86f95925bbd1b4]] \n",
+ "blhost -p com6 fuse-program 0x20 [[74cd7710ba864fc92244e6b2bef5f998b2bc3f505c82ad339152dbb8bbaec040]] \n",
"Response status = 0 (0x0) Success.\n",
"Response word 1 = 32 (0x20)\n",
- "blhost -p com9 fuse-program 0x1F [[3d1d02dbd118a9448bcf536d4198f24184762d63ce9be0da9320dd0b0e3af5daa2d903f60bbdb17a10b58eb20b4d320a]] \n",
+ "blhost -p com6 fuse-program 0x1F [[9af7e81ec9957cea6b4b4f8ede279e417d2a91f07cafdca7679764594933ac338292a8683e30a15644dd1fad84bbfc3a]] \n",
"Response status = 0 (0x0) Success.\n",
"Response word 1 = 48 (0x30)\n",
- "blhost -p com9 set-property 0x16 0 \n",
+ "blhost -p com6 set-property 0x16 0 \n",
"Response status = 0 (0x0) Success.\n"
]
}
@@ -858,15 +872,16 @@
"%! blhost $UART_CONNECTION set-property 0x16 1\n",
"# program SB3KDK (CUST_PROD_OEMFW_ENC_SK)\n",
"# put value SB3KDK generated by nxpimage\n",
- "%! blhost $UART_CONNECTION fuse-program 0x20 [[b1075a0177d1e531cded22ee2ab21f6a2683be98b2034f0ceb86f95925bbd1b4]]\n",
+ "%! blhost $UART_CONNECTION fuse-program 0x20 [[74cd7710ba864fc92244e6b2bef5f998b2bc3f505c82ad339152dbb8bbaec040]]\n",
"# program RoTKTH (CUST_PROD_OEMFW_AUTH_PUK)\n",
"# put value RoTKTH generated by nxpimage\n",
- "%! blhost $UART_CONNECTION fuse-program 0x1F [[3d1d02dbd118a9448bcf536d4198f24184762d63ce9be0da9320dd0b0e3af5daa2d903f60bbdb17a10b58eb20b4d320a]]\n",
+ "%! blhost $UART_CONNECTION fuse-program 0x1F [[9af7e81ec9957cea6b4b4f8ede279e417d2a91f07cafdca7679764594933ac338292a8683e30a15644dd1fad84bbfc3a]]\n",
"# Set voltage to normal value\n",
"%! blhost $UART_CONNECTION set-property 0x16 0"
]
},
{
+ "attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
@@ -884,7 +899,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "blhost -p com9 receive-sb-file workspace/sb3.sb3 \n",
+ "blhost -p com6 receive-sb-file workspace/sb3.sb3 \n",
"Sending SB file\n",
"Response status = 0 (0x0) Success.\n"
]
@@ -915,7 +930,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.9.0"
+ "version": "3.10.8"
},
"vscode": {
"interpreter": {
diff --git a/examples/jupyter_examples/kw45xx_k32w1xx/kw45xx_k32w1xx_secure_boot.ipynb b/examples/jupyter_examples/kw45xx_k32w1xx/kw45xx_k32w1xx_secure_boot.ipynb
new file mode 100644
index 00000000..b9e0601f
--- /dev/null
+++ b/examples/jupyter_examples/kw45xx_k32w1xx/kw45xx_k32w1xx_secure_boot.ipynb
@@ -0,0 +1,816 @@
+{
+ "cells": [
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# KW45xx and K32W1xx Secure Boot\n",
+ "\n",
+ "This notebook describes how to how to set up a basic secure boot on KW45xx/K32W1xx devices using the SPSDK command line utilities."
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Keys preparation\n",
+ "\n",
+ "First we need to generate RoTKs (Root of Trust Keys) and optionally ISK (Image Signing Certificate). We will use *nxpcrypto* app for this purpose. \n",
+ "Script by default generates 4 RoTKs and 1 ISK key (full set of possible keys). Feel free to modify it according your needs.\n",
+ "RoTK 0 generation is mandatory.\n",
+ "\n",
+ "See the script's comments and modify the script according to the application security requirements. \n",
+ "Key generation is done only once on the beginning. Based on generated keys, RoTKTH value is calculated and loaded in the device fuses so that's why keys cannot be changed anymore for the device.\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "env: JUPYTER_SPSDK=1\n",
+ "Created `%!` as an alias for `%execute`.\n"
+ ]
+ }
+ ],
+ "source": [
+ "%run ../init_notebook.ipynb\n",
+ "\n",
+ "import os\n",
+ "import pprint\n",
+ "\n",
+ "pp = pprint.PrettyPrinter(indent=4)\n",
+ "\n",
+ "WORKSPACE = \"workspace/\" # change this to path to your workspace\n",
+ "VERBOSITY = \"\" # verbosity of commands, might be -v or -vv for debug or blank for no additional info"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "nxpcrypto key generate -k secp384r1 workspace/ec_pk_secp384r1_cert0.pem --force \n",
+ "The key pair has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_pk_secp384r1_cert0.pub, C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_pk_secp384r1_cert0.pem\n",
+ "nxpcrypto key generate -k secp384r1 workspace/ec_pk_secp384r1_cert1.pem --force \n",
+ "The key pair has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_pk_secp384r1_cert1.pub, C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_pk_secp384r1_cert1.pem\n",
+ "nxpcrypto key generate -k secp384r1 workspace/ec_pk_secp384r1_cert2.pem --force \n",
+ "The key pair has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_pk_secp384r1_cert2.pub, C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_pk_secp384r1_cert2.pem\n",
+ "nxpcrypto key generate -k secp384r1 workspace/ec_pk_secp384r1_cert3.pem --force \n",
+ "The key pair has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_pk_secp384r1_cert3.pub, C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_pk_secp384r1_cert3.pem\n",
+ "nxpcrypto key generate -k secp384r1 workspace/ec_pk_secp384r1_sign_cert.pem --force \n",
+ "The key pair has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_pk_secp384r1_sign_cert.pub, C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_pk_secp384r1_sign_cert.pem\n"
+ ]
+ }
+ ],
+ "source": [
+ "# generate private key based on secp384r1 curve - ROTK0\n",
+ "ROTK0_PRIVATE_KEY_PATH = WORKSPACE + \"ec_pk_secp384r1_cert0.pem\"\n",
+ "ROTK0_PUBLIC_KEY_PATH = WORKSPACE + \"ec_pk_secp384r1_cert0.pub\"\n",
+ "\n",
+ "%! nxpcrypto $VERBOSITY key generate -k secp384r1 $ROTK0_PRIVATE_KEY_PATH --force\n",
+ "\n",
+ "# verify that keys were generated\n",
+ "assert os.path.exists(ROTK0_PRIVATE_KEY_PATH)\n",
+ "assert os.path.exists(ROTK0_PUBLIC_KEY_PATH)\n",
+ "\n",
+ "\n",
+ "# generate private key based on secp384r1 curve - ROTK1\n",
+ "ROTK1_PRIVATE_KEY_PATH = WORKSPACE + \"ec_pk_secp384r1_cert1.pem\"\n",
+ "ROTK1_PUBLIC_KEY_PATH = WORKSPACE + \"ec_pk_secp384r1_cert1.pub\"\n",
+ "\n",
+ "%! nxpcrypto $VERBOSITY key generate -k secp384r1 $ROTK1_PRIVATE_KEY_PATH --force\n",
+ "\n",
+ "# verify that keys were generated\n",
+ "assert os.path.exists(ROTK1_PRIVATE_KEY_PATH)\n",
+ "assert os.path.exists(ROTK1_PUBLIC_KEY_PATH)\n",
+ "\n",
+ "\n",
+ "# generate private key based on secp384r1 curve - ROTK2\n",
+ "ROTK2_PRIVATE_KEY_PATH = WORKSPACE + \"ec_pk_secp384r1_cert2.pem\"\n",
+ "ROTK2_PUBLIC_KEY_PATH = WORKSPACE + \"ec_pk_secp384r1_cert2.pub\"\n",
+ "\n",
+ "%! nxpcrypto $VERBOSITY key generate -k secp384r1 $ROTK2_PRIVATE_KEY_PATH --force\n",
+ "\n",
+ "# verify that keys were generated\n",
+ "assert os.path.exists(ROTK2_PRIVATE_KEY_PATH)\n",
+ "assert os.path.exists(ROTK2_PUBLIC_KEY_PATH)\n",
+ "\n",
+ "\n",
+ "# generate private key based on secp384r1 curve - ROTK3\n",
+ "ROTK3_PRIVATE_KEY_PATH = WORKSPACE + \"ec_pk_secp384r1_cert3.pem\"\n",
+ "ROTK3_PUBLIC_KEY_PATH = WORKSPACE + \"ec_pk_secp384r1_cert3.pub\"\n",
+ "\n",
+ "%! nxpcrypto $VERBOSITY key generate -k secp384r1 $ROTK3_PRIVATE_KEY_PATH --force\n",
+ "\n",
+ "# verify that keys were generated\n",
+ "assert os.path.exists(ROTK3_PRIVATE_KEY_PATH)\n",
+ "assert os.path.exists(ROTK3_PUBLIC_KEY_PATH)\n",
+ "\n",
+ "\n",
+ "# generate private key based on secp384r1 curve - ISK\n",
+ "ISK_PRIVATE_KEY_PATH = WORKSPACE + \"ec_pk_secp384r1_sign_cert.pem\"\n",
+ "ISK_PUBLIC_KEY_PATH = WORKSPACE + \"ec_pk_secp384r1_sign_cert.pub\"\n",
+ "\n",
+ "%! nxpcrypto $VERBOSITY key generate -k secp384r1 $ISK_PRIVATE_KEY_PATH --force\n",
+ "\n",
+ "# verify that keys were generated\n",
+ "assert os.path.exists(ISK_PRIVATE_KEY_PATH)\n",
+ "assert os.path.exists(ISK_PUBLIC_KEY_PATH)"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Certificates preparation\n",
+ "\n",
+ "Generate self-signed x509 certificate(s) containing public key for private key generated in previous step (ROTKX). \n",
+ "Application *nxpcrypto* will be used. First step is to get a template."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "nxpcrypto cert get-template workspace/cert0_template.yml --force \n",
+ "The configuration template file has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\cert0_template.yml\n",
+ "nxpcrypto cert get-template workspace/cert1_template.yml --force \n",
+ "The configuration template file has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\cert1_template.yml\n",
+ "nxpcrypto cert get-template workspace/cert2_template.yml --force \n",
+ "The configuration template file has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\cert2_template.yml\n",
+ "nxpcrypto cert get-template workspace/cert3_template.yml --force \n",
+ "The configuration template file has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\cert3_template.yml\n",
+ "nxpcrypto cert get-template workspace/sign_cert_template.yml --force \n",
+ "The configuration template file has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\sign_cert_template.yml\n"
+ ]
+ }
+ ],
+ "source": [
+ "# obtain a template for root cert ROTK0\n",
+ "ROOT0_CERT_CONFIG_PATH = WORKSPACE + \"cert0_template.yml\"\n",
+ "%! nxpcrypto $VERBOSITY cert get-template $ROOT0_CERT_CONFIG_PATH --force\n",
+ "\n",
+ "# obtain a template for root cert ROTK1\n",
+ "ROOT1_CERT_CONFIG_PATH = WORKSPACE + \"cert1_template.yml\"\n",
+ "%! nxpcrypto $VERBOSITY cert get-template $ROOT1_CERT_CONFIG_PATH --force\n",
+ "\n",
+ "# obtain a template for root cert ROTK2\n",
+ "ROOT2_CERT_CONFIG_PATH = WORKSPACE + \"cert2_template.yml\"\n",
+ "%! nxpcrypto $VERBOSITY cert get-template $ROOT2_CERT_CONFIG_PATH --force\n",
+ "\n",
+ "# obtain a template for root cert ROTK3\n",
+ "ROOT3_CERT_CONFIG_PATH = WORKSPACE + \"cert3_template.yml\"\n",
+ "%! nxpcrypto $VERBOSITY cert get-template $ROOT3_CERT_CONFIG_PATH --force\n",
+ "\n",
+ "# obtain a template for root cert ISK\n",
+ "ISK_CERT_CONFIG_PATH = WORKSPACE + \"sign_cert_template.yml\"\n",
+ "%! nxpcrypto $VERBOSITY cert get-template $ISK_CERT_CONFIG_PATH --force"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Configuration template for certificates should look like this:\n",
+ "```yaml\n",
+ "# This is template for configuration file used for generating certificates\n",
+ "\n",
+ "# ==============================================\n",
+ "# Issuer identification fields\n",
+ "# ==============================================\n",
+ "# All available option can be found within class NameOID in\n",
+ "# cryptography/src/cryptography/x509/oid.py at https://github.com/pyca/cryptography\n",
+ "\n",
+ "issuer:\n",
+ " COMMON_NAME: NXP\n",
+ " COUNTRY_NAME: CZ\n",
+ " LOCALITY_NAME: Roznov pod Radhostem\n",
+ " STATE_OR_PROVINCE_NAME: Morava\n",
+ " STREET_ADDRESS: 1.maje 1009\n",
+ " ORGANIZATION_NAME: SPSDK Team\n",
+ "\n",
+ "# ==============================================\n",
+ "# Subject identification fields\n",
+ "# ==============================================\n",
+ "# All available option can be found within class NameOID in\n",
+ "# cryptography/src/cryptography/x509/oid.py at https://github.com/pyca/cryptography\n",
+ "subject:\n",
+ " COMMON_NAME: NXP - SPSDK\n",
+ " COUNTRY_NAME: CZ\n",
+ " LOCALITY_NAME: Roznov pod Radhostem\n",
+ " STATE_OR_PROVINCE_NAME: Morava\n",
+ " STREET_ADDRESS: 1.maje 1009\n",
+ " ORGANIZATION_NAME: SPSDK Team\n",
+ " POSTAL_CODE: 756 61\n",
+ "\n",
+ "# ==============================================\n",
+ "# The certificate settings\n",
+ "# ==============================================\n",
+ "\n",
+ "# Path, where issuer private key is stored\n",
+ "issuer_private_key: issuer_key.pem\n",
+ "# Path, where subject public key is stored\n",
+ "subject_public_key: subject_key.pub\n",
+ "# Serial number of certificate\n",
+ "serial_number: 12346578\n",
+ "# Validity duration in days\n",
+ "duration: 3650\n",
+ "\n",
+ "# ==============================================\n",
+ "# Certificate basic extensions\n",
+ "# ==============================================\n",
+ "extensions:\n",
+ " BASIC_CONSTRAINTS:\n",
+ " # Delegate certificate as a signing authority to create an intermediate certificates.\n",
+ " ca: false # Valid values true|false\n",
+ " # Integer length of the path of certificate signature from a given certificate, back to the root certificate\n",
+ " path_length: 0\n",
+ "```\n",
+ "Certificates are in x.509 format and should be DER encoded."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Root Certificate config:\n",
+ "{ 'duration': 3650,\n",
+ " 'extensions': {'BASIC_CONSTRAINTS': {'ca': False, 'path_length': 0}},\n",
+ " 'issuer': { 'COMMON_NAME': 'NXP',\n",
+ " 'COUNTRY_NAME': 'CZ',\n",
+ " 'LOCALITY_NAME': 'Roznov pod Radhostem',\n",
+ " 'ORGANIZATION_NAME': 'SPSDK Team',\n",
+ " 'STATE_OR_PROVINCE_NAME': 'Morava',\n",
+ " 'STREET_ADDRESS': '1.maje 1009'},\n",
+ " 'issuer_private_key': 'workspace/ec_pk_secp384r1_cert0.pem',\n",
+ " 'serial_number': 12346578,\n",
+ " 'subject': { 'COMMON_NAME': 'NXP - SPSDK',\n",
+ " 'COUNTRY_NAME': 'CZ',\n",
+ " 'LOCALITY_NAME': 'Roznov pod Radhostem',\n",
+ " 'ORGANIZATION_NAME': 'SPSDK Team',\n",
+ " 'POSTAL_CODE': '756 61',\n",
+ " 'STATE_OR_PROVINCE_NAME': 'Morava',\n",
+ " 'STREET_ADDRESS': '1.maje 1009'},\n",
+ " 'subject_public_key': 'workspace/ec_pk_secp384r1_cert0.pub'}\n",
+ "Root Certificate config:\n",
+ "{ 'duration': 3650,\n",
+ " 'extensions': {'BASIC_CONSTRAINTS': {'ca': False, 'path_length': 0}},\n",
+ " 'issuer': { 'COMMON_NAME': 'NXP',\n",
+ " 'COUNTRY_NAME': 'CZ',\n",
+ " 'LOCALITY_NAME': 'Roznov pod Radhostem',\n",
+ " 'ORGANIZATION_NAME': 'SPSDK Team',\n",
+ " 'STATE_OR_PROVINCE_NAME': 'Morava',\n",
+ " 'STREET_ADDRESS': '1.maje 1009'},\n",
+ " 'issuer_private_key': 'workspace/ec_pk_secp384r1_cert1.pem',\n",
+ " 'serial_number': 12346578,\n",
+ " 'subject': { 'COMMON_NAME': 'NXP - SPSDK',\n",
+ " 'COUNTRY_NAME': 'CZ',\n",
+ " 'LOCALITY_NAME': 'Roznov pod Radhostem',\n",
+ " 'ORGANIZATION_NAME': 'SPSDK Team',\n",
+ " 'POSTAL_CODE': '756 61',\n",
+ " 'STATE_OR_PROVINCE_NAME': 'Morava',\n",
+ " 'STREET_ADDRESS': '1.maje 1009'},\n",
+ " 'subject_public_key': 'workspace/ec_pk_secp384r1_cert1.pub'}\n",
+ "Root Certificate config:\n",
+ "{ 'duration': 3650,\n",
+ " 'extensions': {'BASIC_CONSTRAINTS': {'ca': False, 'path_length': 0}},\n",
+ " 'issuer': { 'COMMON_NAME': 'NXP',\n",
+ " 'COUNTRY_NAME': 'CZ',\n",
+ " 'LOCALITY_NAME': 'Roznov pod Radhostem',\n",
+ " 'ORGANIZATION_NAME': 'SPSDK Team',\n",
+ " 'STATE_OR_PROVINCE_NAME': 'Morava',\n",
+ " 'STREET_ADDRESS': '1.maje 1009'},\n",
+ " 'issuer_private_key': 'workspace/ec_pk_secp384r1_cert2.pem',\n",
+ " 'serial_number': 12346578,\n",
+ " 'subject': { 'COMMON_NAME': 'NXP - SPSDK',\n",
+ " 'COUNTRY_NAME': 'CZ',\n",
+ " 'LOCALITY_NAME': 'Roznov pod Radhostem',\n",
+ " 'ORGANIZATION_NAME': 'SPSDK Team',\n",
+ " 'POSTAL_CODE': '756 61',\n",
+ " 'STATE_OR_PROVINCE_NAME': 'Morava',\n",
+ " 'STREET_ADDRESS': '1.maje 1009'},\n",
+ " 'subject_public_key': 'workspace/ec_pk_secp384r1_cert2.pub'}\n",
+ "Root Certificate config:\n",
+ "{ 'duration': 3650,\n",
+ " 'extensions': {'BASIC_CONSTRAINTS': {'ca': False, 'path_length': 0}},\n",
+ " 'issuer': { 'COMMON_NAME': 'NXP',\n",
+ " 'COUNTRY_NAME': 'CZ',\n",
+ " 'LOCALITY_NAME': 'Roznov pod Radhostem',\n",
+ " 'ORGANIZATION_NAME': 'SPSDK Team',\n",
+ " 'STATE_OR_PROVINCE_NAME': 'Morava',\n",
+ " 'STREET_ADDRESS': '1.maje 1009'},\n",
+ " 'issuer_private_key': 'workspace/ec_pk_secp384r1_cert3.pem',\n",
+ " 'serial_number': 12346578,\n",
+ " 'subject': { 'COMMON_NAME': 'NXP - SPSDK',\n",
+ " 'COUNTRY_NAME': 'CZ',\n",
+ " 'LOCALITY_NAME': 'Roznov pod Radhostem',\n",
+ " 'ORGANIZATION_NAME': 'SPSDK Team',\n",
+ " 'POSTAL_CODE': '756 61',\n",
+ " 'STATE_OR_PROVINCE_NAME': 'Morava',\n",
+ " 'STREET_ADDRESS': '1.maje 1009'},\n",
+ " 'subject_public_key': 'workspace/ec_pk_secp384r1_cert3.pub'}\n",
+ "Root Certificate config:\n",
+ "{ 'duration': 3650,\n",
+ " 'extensions': {'BASIC_CONSTRAINTS': {'ca': False, 'path_length': 0}},\n",
+ " 'issuer': { 'COMMON_NAME': 'NXP',\n",
+ " 'COUNTRY_NAME': 'CZ',\n",
+ " 'LOCALITY_NAME': 'Roznov pod Radhostem',\n",
+ " 'ORGANIZATION_NAME': 'SPSDK Team',\n",
+ " 'STATE_OR_PROVINCE_NAME': 'Morava',\n",
+ " 'STREET_ADDRESS': '1.maje 1009'},\n",
+ " 'issuer_private_key': 'workspace/ec_pk_secp384r1_sign_cert.pem',\n",
+ " 'serial_number': 12346578,\n",
+ " 'subject': { 'COMMON_NAME': 'NXP - SPSDK',\n",
+ " 'COUNTRY_NAME': 'CZ',\n",
+ " 'LOCALITY_NAME': 'Roznov pod Radhostem',\n",
+ " 'ORGANIZATION_NAME': 'SPSDK Team',\n",
+ " 'POSTAL_CODE': '756 61',\n",
+ " 'STATE_OR_PROVINCE_NAME': 'Morava',\n",
+ " 'STREET_ADDRESS': '1.maje 1009'},\n",
+ " 'subject_public_key': 'workspace/ec_pk_secp384r1_sign_cert.pub'}\n",
+ "nxpcrypto cert generate -c workspace/cert0_template.yml -o workspace/ec_secp384r1_cert0.pem --force \n",
+ "The certificate file has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_secp384r1_cert0.pem\n",
+ "nxpcrypto cert generate -c workspace/cert1_template.yml -o workspace/ec_secp384r1_cert1.pem --force \n",
+ "The certificate file has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_secp384r1_cert1.pem\n",
+ "nxpcrypto cert generate -c workspace/cert2_template.yml -o workspace/ec_secp384r1_cert2.pem --force \n",
+ "The certificate file has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_secp384r1_cert2.pem\n",
+ "nxpcrypto cert generate -c workspace/cert3_template.yml -o workspace/ec_secp384r1_cert3.pem --force \n",
+ "The certificate file has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_secp384r1_cert3.pem\n",
+ "nxpcrypto cert generate -c workspace/sign_cert_template.yml -o workspace/ec_secp384r1_sign_cert.pem --force \n",
+ "The certificate file has been created: C:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\ec_secp384r1_sign_cert.pem\n"
+ ]
+ }
+ ],
+ "source": [
+ "ROOT_0_CERT_PATH = WORKSPACE + \"ec_secp384r1_cert0.pem\"\n",
+ "ROOT_1_CERT_PATH = WORKSPACE + \"ec_secp384r1_cert1.pem\"\n",
+ "ROOT_2_CERT_PATH = WORKSPACE + \"ec_secp384r1_cert2.pem\"\n",
+ "ROOT_3_CERT_PATH = WORKSPACE + \"ec_secp384r1_cert3.pem\"\n",
+ "ISK_CERT_PATH = WORKSPACE + \"ec_secp384r1_sign_cert.pem\"\n",
+ "\n",
+ "# Fill the configuration file accordingly\n",
+ "import yaml\n",
+ "\n",
+ "assert os.path.exists(ROOT0_CERT_CONFIG_PATH)\n",
+ "assert os.path.exists(ROOT1_CERT_CONFIG_PATH)\n",
+ "assert os.path.exists(ROOT2_CERT_CONFIG_PATH)\n",
+ "assert os.path.exists(ROOT3_CERT_CONFIG_PATH)\n",
+ "\n",
+ "# Create configuration for root certificate 0 \n",
+ "with open(ROOT0_CERT_CONFIG_PATH) as cert_config:\n",
+ " # load yaml configuration to dictionary\n",
+ " cert = yaml.safe_load(cert_config)\n",
+ " # change path to private and public keys\n",
+ " cert['issuer_private_key'] = ROTK0_PRIVATE_KEY_PATH\n",
+ " cert['subject_public_key'] = ROTK0_PUBLIC_KEY_PATH\n",
+ "\n",
+ "with open(ROOT0_CERT_CONFIG_PATH, \"w+\") as cert_config:\n",
+ " print(\"Root Certificate config:\")\n",
+ " pp.pprint(cert)\n",
+ " # dump the dictionary back to YAML\n",
+ " yaml.dump(cert, cert_config)\n",
+ "\n",
+ "# Create configuration for root certificate 1\n",
+ "with open(ROOT1_CERT_CONFIG_PATH) as cert_config:\n",
+ " # load yaml configuration to dictionary\n",
+ " cert = yaml.safe_load(cert_config)\n",
+ " # change path to private and public keys\n",
+ " cert['issuer_private_key'] = ROTK1_PRIVATE_KEY_PATH\n",
+ " cert['subject_public_key'] = ROTK1_PUBLIC_KEY_PATH\n",
+ "\n",
+ "with open(ROOT1_CERT_CONFIG_PATH, \"w+\") as cert_config:\n",
+ " print(\"Root Certificate config:\")\n",
+ " pp.pprint(cert)\n",
+ " # dump the dictionary back to YAML\n",
+ " yaml.dump(cert, cert_config)\n",
+ "\n",
+ "# Create configuration for root certificate 2\n",
+ "with open(ROOT2_CERT_CONFIG_PATH) as cert_config:\n",
+ " # load yaml configuration to dictionary\n",
+ " cert = yaml.safe_load(cert_config)\n",
+ " # change path to private and public keys\n",
+ " cert['issuer_private_key'] = ROTK2_PRIVATE_KEY_PATH\n",
+ " cert['subject_public_key'] = ROTK2_PUBLIC_KEY_PATH\n",
+ "\n",
+ "with open(ROOT2_CERT_CONFIG_PATH, \"w+\") as cert_config:\n",
+ " print(\"Root Certificate config:\")\n",
+ " pp.pprint(cert)\n",
+ " # dump the dictionary back to YAML\n",
+ " yaml.dump(cert, cert_config)\n",
+ "\n",
+ "# Create configuration for root certificate 3\n",
+ "with open(ROOT3_CERT_CONFIG_PATH) as cert_config:\n",
+ " # load yaml configuration to dictionary\n",
+ " cert = yaml.safe_load(cert_config)\n",
+ " # change path to private and public keys\n",
+ " cert['issuer_private_key'] = ROTK3_PRIVATE_KEY_PATH\n",
+ " cert['subject_public_key'] = ROTK3_PUBLIC_KEY_PATH\n",
+ "\n",
+ "with open(ROOT3_CERT_CONFIG_PATH, \"w+\") as cert_config:\n",
+ " print(\"Root Certificate config:\")\n",
+ " pp.pprint(cert)\n",
+ " # dump the dictionary back to YAML\n",
+ " yaml.dump(cert, cert_config)\n",
+ "\n",
+ "# Create configuration for ISK certificate \n",
+ "with open(ISK_CERT_CONFIG_PATH) as cert_config:\n",
+ " # load yaml configuration to dictionary\n",
+ " cert = yaml.safe_load(cert_config)\n",
+ " # change path to private and public keys\n",
+ " cert['issuer_private_key'] = ISK_PRIVATE_KEY_PATH\n",
+ " cert['subject_public_key'] = ISK_PUBLIC_KEY_PATH\n",
+ "\n",
+ "with open(ISK_CERT_CONFIG_PATH, \"w+\") as cert_config:\n",
+ " print(\"Root Certificate config:\")\n",
+ " pp.pprint(cert)\n",
+ " # dump the dictionary back to YAML\n",
+ " yaml.dump(cert, cert_config)\n",
+ "\n",
+ "\n",
+ "# Generate root certificates 0\n",
+ "%! nxpcrypto $VERBOSITY cert generate -c $ROOT0_CERT_CONFIG_PATH -o $ROOT_0_CERT_PATH --force\n",
+ "# Generate root certificates 1\n",
+ "%! nxpcrypto $VERBOSITY cert generate -c $ROOT1_CERT_CONFIG_PATH -o $ROOT_1_CERT_PATH --force\n",
+ "# Generate root certificates 2\n",
+ "%! nxpcrypto $VERBOSITY cert generate -c $ROOT2_CERT_CONFIG_PATH -o $ROOT_2_CERT_PATH --force\n",
+ "# Generate root certificates 3\n",
+ "%! nxpcrypto $VERBOSITY cert generate -c $ROOT3_CERT_CONFIG_PATH -o $ROOT_3_CERT_PATH --force\n",
+ "\n",
+ "# Generate ISK certificate\n",
+ "%! nxpcrypto $VERBOSITY cert generate -c $ISK_CERT_CONFIG_PATH -o $ISK_CERT_PATH --force\n",
+ "\n",
+ "# verify that certificates were generated\n",
+ "assert os.path.exists(ROOT_0_CERT_PATH)\n",
+ "assert os.path.exists(ROOT_1_CERT_PATH)\n",
+ "assert os.path.exists(ROOT_2_CERT_PATH)\n",
+ "assert os.path.exists(ROOT_3_CERT_PATH)\n",
+ "assert os.path.exists(ISK_CERT_PATH)"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Prepare MBI configuration file\n",
+ "\n",
+ "In order to generate MBI file, npximage tool is used. The nxpimage tool generates the MBI file according to the configuration file.\n",
+ "Let's create a template for MBI. Modify examples according your needs. "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "nxpimage mbi get-templates -f kw45xx -o workspace/MBI \n",
+ "Creating c:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\MBI\\kw45xx_int_xip_plain.yaml template file.\n",
+ "Creating c:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\MBI\\kw45xx_int_xip_crc.yaml template file.\n",
+ "Creating c:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\MBI\\kw45xx_int_xip_signed.yaml template file.\n",
+ "Creating c:\\spsdk\\examples\\jupyter_examples\\kw45xx_k32w1xx\\workspace\\MBI\\kw45xx_int_xip_nxp_signed.yaml template file.\n"
+ ]
+ }
+ ],
+ "source": [
+ "MBI_PATH = WORKSPACE + \"MBI\"\n",
+ "%! nxpimage $VERBOSITY mbi get-templates -f kw45xx -o $MBI_PATH\n",
+ "# For K32W1XX device:\n",
+ "# %! nxpimage $VERBOSITY sb31 get-template -f k32w1xx -o $MBI_PATH"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "MBI:\n",
+ "{ 'family': 'kw45xx',\n",
+ " 'firmwareVersion': 0,\n",
+ " 'inputImageFile': 'hello_world_UART0.bin',\n",
+ " 'mainRootCertId': 0,\n",
+ " 'mainRootCertPrivateKeyFile': 'workspace/ec_pk_secp384r1_cert0.pem',\n",
+ " 'manifestDigestHashAlgorithm': 'sha256',\n",
+ " 'masterBootOutputFile': 'my_mbi.bin',\n",
+ " 'noSignature': False,\n",
+ " 'outputImageAuthenticationType': 'Signed',\n",
+ " 'outputImageExecutionAddress': 0,\n",
+ " 'outputImageExecutionTarget': 'Internal flash (XIP)',\n",
+ " 'rootCertificate0File': 'workspace/ec_secp384r1_cert0.pem',\n",
+ " 'rootCertificate1File': 'workspace/ec_secp384r1_cert1.pem',\n",
+ " 'rootCertificate2File': 'workspace/ec_secp384r1_cert2.pem',\n",
+ " 'rootCertificate3File': 'workspace/ec_secp384r1_cert3.pem',\n",
+ " 'rootCertificateEllipticCurve': 'secp384r1',\n",
+ " 'signingCertificateConstraint': 0,\n",
+ " 'useIsk': False}\n"
+ ]
+ }
+ ],
+ "source": [
+ "MBI_TEMPLATE = MBI_PATH + \"/\" + \"kw45xx_int_xip_signed.yaml\"\n",
+ "MBI_OUTPUT_FILE = MBI_PATH + \"/\" + \"my_mbi.bin\"\n",
+ "INPUT_IMAGE_FILE = \"hello_world_UART0.bin\"\n",
+ "import yaml\n",
+ "assert os.path.exists(MBI_TEMPLATE)\n",
+ "\n",
+ "# Create configuration for MBI\n",
+ "with open(MBI_TEMPLATE) as mbi_config:\n",
+ " # load yaml configuration to dictionary\n",
+ " mbi = yaml.safe_load(mbi_config)\n",
+ " # change paths\n",
+ " mbi['rootCertificate0File'] = ROOT_0_CERT_PATH\n",
+ " mbi['rootCertificate1File'] = ROOT_1_CERT_PATH\n",
+ " mbi['rootCertificate2File'] = ROOT_2_CERT_PATH\n",
+ " mbi['rootCertificate3File'] = ROOT_3_CERT_PATH\n",
+ " mbi['mainRootCertId'] = 0\n",
+ " mbi['mainRootCertPrivateKeyFile'] = ROTK0_PRIVATE_KEY_PATH\n",
+ " mbi['rootCertificateEllipticCurve'] = \"secp384r1\"\n",
+ " mbi['inputImageFile'] = INPUT_IMAGE_FILE\n",
+ " del mbi['enableTrustZone']\n",
+ " del mbi['trustZonePresetFile']\n",
+ " del mbi['binaryCertificateBlock']\n",
+ " # Choose between two scenarios:\n",
+ "\n",
+ " # # scenario 1\n",
+ " # # if you want to use ISK:\n",
+ " # mbi['useIsk'] = True\n",
+ " # mbi['signingCertificateFile'] = ISK_CERT_PATH\n",
+ " # mbi['signingCertificatePrivateKeyFile'] = ISK_PRIVATE_KEY_PATH\n",
+ " # mbi['signingCertificateConstraint'] = 0\n",
+ " # mbi['iskCertificateEllipticCurve'] = \"secp384r1\"\n",
+ " # # [optional, can contain user data\n",
+ " # del mbi['signCertData']\n",
+ "\n",
+ " # scenario 2\n",
+ " #if you do not use ISK:\n",
+ " mbi['useIsk'] = False\n",
+ " del mbi['signingCertificatePrivateKeyFile']\n",
+ " del mbi['signingCertificateFile']\n",
+ " del mbi['signCertData']\n",
+ " del mbi['iskSignProvider']\n",
+ " del mbi['signProvider']\n",
+ "\n",
+ " # This is common for both scenarios:\n",
+ "\n",
+ "with open(MBI_TEMPLATE, \"w+\") as mbi_config:\n",
+ " print(\"MBI:\")\n",
+ " pp.pprint(mbi)\n",
+ " # dump the dictionary back to YAML\n",
+ " yaml.dump(mbi, mbi_config)"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### MBI generation\n",
+ "\n",
+ "We have created certificates and keys required for the creation of MBI file. Let's create a MBI."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "nxpimage -v mbi export workspace/MBI/kw45xx_int_xip_signed.yaml \n",
+ "\u001b[37m\u001b[1mINFO:spsdk.utils.crypto.cert_blocks:RoTKTH: 9fa47edbeb32ce004d913cc5a0db98efb504edc3701221587efd4c3062c71d3a7ade6a77502ca600f9517454521153c2\u001b[39m\u001b[0m\n",
+ "Success. (Master Boot Image: c:/spsdk/examples/jupyter_examples/kw45xx_k32w1xx/workspace/MBI/my_mbi.bin created.)\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Verbosity needs to be at least info (-v) in order to get SB3KDK and RoTKTH values\n",
+ "# %! nxpimage $VERBOSITY mbi export $MBI_TEMPLATE\n",
+ "%! nxpimage $VERBOSITY mbi export $MBI_TEMPLATE\n",
+ "assert os.path.exists(MBI_OUTPUT_FILE)"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Device preparation\n",
+ "\n",
+ "Now it's time to prepare the device. In this example we will use KW45xx-EVK/K32W1xx board.\n",
+ "\n",
+ "First step is to enter ISP mode, this could be achieved by:\n",
+ "\n",
+ "1 ) Put JP25 to (1-2)\n",
+ "\n",
+ "2 ) Reset the board with SW4 pressed\n",
+ "\n",
+ "![KW45xx-EVK](img/KW45xx-EVK.png \"KW45xx-EVK\")\n",
+ "\n",
+ "![K32W1xx-EVK](img/K32W1xx-EVK.png \"K32W1xx-EVK\")\n",
+ "\n",
+ "\n",
+ "Use app *nxpdevscan* to check if the device is connected to the PC in ISP mode.\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "nxpdevscan \n",
+ "-------- Connected NXP USB Devices --------\n",
+ "\n",
+ "-------- Connected NXP UART Devices --------\n",
+ "\n",
+ "Port: COM6\n",
+ "Type: mboot device\n",
+ "\n",
+ "-------- Connected NXP SIO Devices --------\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "# check if the device is connected and detected by PC\n",
+ "%! nxpdevscan"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "blhost -p com6 get-property current-version \n",
+ "Response status = 0 (0x0) Success.\n",
+ "Response word 1 = 1258488064 (0x4b030100)\n",
+ "Current Version = K3.1.0\n"
+ ]
+ }
+ ],
+ "source": [
+ "# choose com port\n",
+ "UART_CONNECTION = \"-p com6\"\n",
+ "\n",
+ "%! blhost $UART_CONNECTION get-property current-version"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Program device fuses with keys/RoTKTH generated in previous steps\n",
+ "To program fuses blhost tool is used. Device needs to be in ISP mode, where it can communicate with blhost and process blhost commands.\n",
+ "To serve the purpose of this document, ISP communication only over UART peripheral is considered for scripts. \n",
+ "Also, accurate COMx port must be used.\n",
+ "-\tWARNING!!! This step is destructive operation (burning fuses), be sure that you set value of RoTKH correctly in script as printed in output from nxpimage"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "blhost -p com6 set-property 0x16 1 \n",
+ "Response status = 0 (0x0) Success.\n",
+ "blhost -p com6 fuse-program 0x1F [[9fa47edbeb32ce004d913cc5a0db98efb504edc3701221587efd4c3062c71d3a7ade6a77502ca600f9517454521153c2]] \n",
+ "Response status = 0 (0x0) Success.\n",
+ "Response word 1 = 48 (0x30)\n",
+ "blhost -p com6 set-property 0x16 0 \n",
+ "Response status = 0 (0x0) Success.\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Increase voltage for fuse burning\n",
+ "%! blhost $UART_CONNECTION set-property 0x16 1\n",
+ "# program RoTKTH (CUST_PROD_OEMFW_AUTH_PUK)\n",
+ "# put value RoTKTH generated by nxpimage\n",
+ "%! blhost $UART_CONNECTION fuse-program 0x1F [[9fa47edbeb32ce004d913cc5a0db98efb504edc3701221587efd4c3062c71d3a7ade6a77502ca600f9517454521153c2]]\n",
+ "# Set voltage to normal value\n",
+ "%! blhost $UART_CONNECTION set-property 0x16 0"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Send MBI file to device\n",
+ "\n",
+ "Last step is to uploads MBI file with NBU image to device."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "blhost -p com6 write-memory 0x0 workspace/MBI/my_mbi.bin \n",
+ "Writing memory\n",
+ "Response status = 0 (0x0) Success.\n",
+ "Response word 1 = 2904 (0xb58)\n"
+ ]
+ }
+ ],
+ "source": [
+ "# uploads MBI\n",
+ "%! blhost $UART_CONNECTION write-memory 0x0 $MBI_OUTPUT_FILE"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "blhost -p com6 reset \n",
+ "Response status = 0 (0x0) Success.\n"
+ ]
+ }
+ ],
+ "source": [
+ "%! blhost $UART_CONNECTION reset"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.8"
+ },
+ "vscode": {
+ "interpreter": {
+ "hash": "4ab21a5ebbf811bd5fc1902f6d9a7de0ca45b807ca8a4f69822a44f79381cc89"
+ }
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/examples/signature_provider/dat/dck.pub b/examples/jupyter_examples/rt5xx_signature_provider/data_dat/dck.pub
similarity index 100%
rename from examples/signature_provider/dat/dck.pub
rename to examples/jupyter_examples/rt5xx_signature_provider/data_dat/dck.pub
diff --git a/examples/jupyter_examples/rt5xx_signature_provider/data_dat/dck_rsa_2048.yml b/examples/jupyter_examples/rt5xx_signature_provider/data_dat/dck_rsa_2048.yml
new file mode 100644
index 00000000..1b0c453f
--- /dev/null
+++ b/examples/jupyter_examples/rt5xx_signature_provider/data_dat/dck_rsa_2048.yml
@@ -0,0 +1,16 @@
+# Copyright 2023 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+socc: 0x0001
+uuid: "E004090E6BDD2155BBCE9E0665805BE3"
+cc_socu: 0x03FF
+cc_vu: 0x5678
+cc_beacon: 0
+rot_meta:
+ - ./p0_cert0_2048.pub
+ - ./p1_cert0_2048.pub
+rot_id: 0
+dck: ./dck.pub
+rotk: k1_cert0_2048.pem
+
+
diff --git a/examples/signature_provider/dat/p0_cert0_2048.pub b/examples/jupyter_examples/rt5xx_signature_provider/data_dat/p0_cert0_2048.pub
similarity index 100%
rename from examples/signature_provider/dat/p0_cert0_2048.pub
rename to examples/jupyter_examples/rt5xx_signature_provider/data_dat/p0_cert0_2048.pub
diff --git a/examples/signature_provider/dat/p1_cert0_2048.pub b/examples/jupyter_examples/rt5xx_signature_provider/data_dat/p1_cert0_2048.pub
similarity index 100%
rename from examples/signature_provider/dat/p1_cert0_2048.pub
rename to examples/jupyter_examples/rt5xx_signature_provider/data_dat/p1_cert0_2048.pub
diff --git a/examples/signature_provider/mbimg/my_application.bin b/examples/jupyter_examples/rt5xx_signature_provider/data_mbimg/my_application.bin
similarity index 100%
rename from examples/signature_provider/mbimg/my_application.bin
rename to examples/jupyter_examples/rt5xx_signature_provider/data_mbimg/my_application.bin
diff --git a/examples/signature_provider/mbimg/root_k0_signed_cert0_noca.der.cert b/examples/jupyter_examples/rt5xx_signature_provider/data_mbimg/root_k0_signed_cert0_noca.der.cert
similarity index 100%
rename from examples/signature_provider/mbimg/root_k0_signed_cert0_noca.der.cert
rename to examples/jupyter_examples/rt5xx_signature_provider/data_mbimg/root_k0_signed_cert0_noca.der.cert
diff --git a/examples/signature_provider/hsm/hsm_k0_cert0_2048.pem b/examples/jupyter_examples/rt5xx_signature_provider/hsm/hsm_k0_cert0_2048.pem
similarity index 100%
rename from examples/signature_provider/hsm/hsm_k0_cert0_2048.pem
rename to examples/jupyter_examples/rt5xx_signature_provider/hsm/hsm_k0_cert0_2048.pem
diff --git a/examples/signature_provider/hsm/hsm_k1_cert0_2048.pem b/examples/jupyter_examples/rt5xx_signature_provider/hsm/hsm_k1_cert0_2048.pem
similarity index 100%
rename from examples/signature_provider/hsm/hsm_k1_cert0_2048.pem
rename to examples/jupyter_examples/rt5xx_signature_provider/hsm/hsm_k1_cert0_2048.pem
diff --git a/examples/signature_provider/hsm/sahsm.py b/examples/jupyter_examples/rt5xx_signature_provider/hsm/sahsm.py
similarity index 84%
rename from examples/signature_provider/hsm/sahsm.py
rename to examples/jupyter_examples/rt5xx_signature_provider/hsm/sahsm.py
index 604248d7..5e718d23 100644
--- a/examples/signature_provider/hsm/sahsm.py
+++ b/examples/jupyter_examples/rt5xx_signature_provider/hsm/sahsm.py
@@ -8,6 +8,8 @@
"""Module represent a customer-specific HSM system."""
import base64
import os
+from http import HTTPStatus
+from typing import Optional
from flask import Flask, Response, jsonify, request
@@ -25,6 +27,8 @@ def signer(num: int) -> Response:
:return: Signature wrapped in json, encoded in base64
"""
private_key = load_private_key(num)
+ if not private_key:
+ return Response(response=f"Key with index {num} not found", status=HTTPStatus.BAD_REQUEST)
data_to_sign = base64.b64decode(request.args["data"])
signature = sign_data(private_key, data_to_sign)
@@ -40,6 +44,8 @@ def verifier(num: int) -> Response:
:return: Verification status(true/false) wrapped in json
"""
private_key = load_private_key(num)
+ if not private_key:
+ return Response(response=f"Key with index {num} not found", status=HTTPStatus.BAD_REQUEST)
public_key = private_key.public_key()
public_key_bytes = base64.b64decode(request.args["public_key"])
@@ -63,12 +69,14 @@ def sign_data(private_key: crypto.RSAPrivateKey, data: bytes) -> bytes:
)
-def load_private_key(num: int) -> crypto.RSAPrivateKey:
+def load_private_key(num: int) -> Optional[crypto.RSAPrivateKey]:
"""Create an instance of RSAPrivateKey by its index.
:param num: Index of the key to use (rot_id)
"""
private_key_file = os.path.join(THIS_DIR, f"hsm_k{num}_cert0_2048.pem")
+ if not os.path.isfile(private_key_file):
+ return None
private_key = crypto.load_private_key(private_key_file)
# in this example we assume RSA keys
assert isinstance(private_key, crypto.RSAPrivateKey)
diff --git a/examples/signature_provider/hsm/sasp.py b/examples/jupyter_examples/rt5xx_signature_provider/plugins/sasp.py
similarity index 79%
rename from examples/signature_provider/hsm/sasp.py
rename to examples/jupyter_examples/rt5xx_signature_provider/plugins/sasp.py
index e75f4ec5..668e5527 100644
--- a/examples/signature_provider/hsm/sasp.py
+++ b/examples/jupyter_examples/rt5xx_signature_provider/plugins/sasp.py
@@ -9,7 +9,7 @@
import base64
-import requests # type: ignore
+import requests
from spsdk.crypto.signature_provider import SignatureProvider
@@ -37,6 +37,7 @@ def sign(self, data: bytes) -> bytes:
endpoint = f"{self.url}/signer/{self.key_number}"
params = {"data": base64.b64encode(data)}
response = requests.get(endpoint, params=params)
+ self.check_response(response)
signature = response.json()["signature"]
data = base64.b64decode(signature)
return data.zfill(256)
@@ -50,6 +51,7 @@ def verify_public_key(self, public_key: bytes) -> bool:
endpoint = f"{self.url}/verifier/{self.key_number}"
params = {"public_key": base64.b64encode(public_key)}
response = requests.get(endpoint, params=params)
+ self.check_response(response)
is_matching = response.json()["is_matching"]
return is_matching
@@ -57,3 +59,14 @@ def verify_public_key(self, public_key: bytes) -> bool:
def signature_length(self) -> int:
"""Return length of the signature."""
return 256
+
+ @staticmethod
+ def check_response(response: requests.Response) -> None:
+ """Raise if response is not 2xx."""
+ try:
+ response.raise_for_status()
+ except requests.HTTPError as e:
+ if response.text:
+ raise requests.HTTPError(f"{str(e)}; Error Message: {response.text}")
+ else:
+ raise e
diff --git a/examples/jupyter_examples/rt5xx_signature_provider/rt5xx_dat.ipynb b/examples/jupyter_examples/rt5xx_signature_provider/rt5xx_dat.ipynb
new file mode 100644
index 00000000..900d77b9
--- /dev/null
+++ b/examples/jupyter_examples/rt5xx_signature_provider/rt5xx_dat.ipynb
@@ -0,0 +1,193 @@
+{
+ "cells": [
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Debug Credentials with Signature Provider\n",
+ "\n",
+ "This notebook describes how to use a custom remote signing service for debug certificate generation"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "env: JUPYTER_SPSDK=1\n",
+ "Created `%!` as an alias for `%execute`.\n"
+ ]
+ }
+ ],
+ "source": [
+ "%run ../init_notebook.ipynb\n",
+ "\n",
+ "import pprint\n",
+ "import os\n",
+ "\n",
+ "pp = pprint.PrettyPrinter(indent=4)\n",
+ "\n",
+ "plugins_dir = 'plugins/'\n",
+ "\n",
+ "SASP_PLUGIN = os.path.join(plugins_dir, 'sasp.py')\n",
+ "WORKSPACE = \"workspace/dat/\" # change this to path to your workspace\n",
+ "DATA_DIR = \"data_dat/\" # change this to path to your workspace\n",
+ "VERBOSITY = \"-v\" # verbosity of commands, might be -v or -vv for debug or blank for no additional info"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Signature Provider Plugin\n",
+ "\n",
+ "First, we need to setup the Signature Provider plugin and start the custom HSM. In order to do that, open this [notebook](signature_provider.ipynb) and follow the instructions there. Once you are done, come back and continue here."
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Config File Setup\n",
+ "\n",
+ "The nxpdebugmbox configuration file must be updated in order to integrate the custom Signature Provider.\n",
+ "\n",
+ "The signature provider configuration must meet following rules:\n",
+ " - Configuration key\n",
+ " - key names `sign_provider` or `signProvider` are allowed\n",
+ "\n",
+ " - Configuration value\n",
+ " - format `\"type=;=;=;...\"`\n",
+ " - the `sp_type` has to match the sp_type class attribute defined in the custom signature provider(`plugins/sasp.py`)\n",
+ " - the remaining key-value pairs are passed to the `__init__` method of the concrete Signature Provider\n",
+ " - e.g.: `\"type=file;file_path=private_key.pem\"` will instantiate `spsdk.crypto.PlainFileSP(file_path='private_key.pem')`\n",
+ "\n",
+ "New configuration field `rot_id` has been introduced:\n",
+ " - due to the nature of creating Debug Credential file we need to know in advance which of the private keys will be used to perform the actual signing\n",
+ " - `rot_id` is a 0-based index representing the private key that will be used with respect to `rot_meta`\n",
+ " - e.g.: if we want to use a private key that corresponds to the public key `p1_cert0_2048.pub`, `rot_id` has to be set to `1`\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\"All files are ready in folder 'workspace/dat/'\"\n"
+ ]
+ }
+ ],
+ "source": [
+ "import yaml\n",
+ "import os\n",
+ "import shutil\n",
+ "from spsdk.utils.misc import load_configuration\n",
+ "# choose family for the MCU\n",
+ "FAMILY = \"rt5xx\"\n",
+ "CONFIG_PATH = os.path.join(WORKSPACE, 'dck_rsa_2048.yml')\n",
+ "\n",
+ "os.makedirs(WORKSPACE, exist_ok=True)\n",
+ "shutil.copyfile(os.path.join(DATA_DIR, 'dck_rsa_2048.yml'), CONFIG_PATH)\n",
+ "\n",
+ "config = load_configuration(CONFIG_PATH)\n",
+ "del config['rotk']\n",
+ "config['sign_provider'] = \"type=sasp;key_number=0\"\n",
+ "\n",
+ "with open(CONFIG_PATH, 'w') as file:\n",
+ " yaml.dump(config, file, default_flow_style=False)\n",
+ "\n",
+ "files_needed = ['p0_cert0_2048.pub', 'p1_cert0_2048.pub', 'dck.pub']\n",
+ "for file in files_needed:\n",
+ " shutil.copyfile(os.path.join(DATA_DIR, file), os.path.join(WORKSPACE, file))\n",
+ "\n",
+ "pp.pprint(f\"All files are ready in folder '{WORKSPACE}'\")\n"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Execution\n",
+ "\n",
+ "At this point, we have everything we need to run create debug certificate signed by remote HSM."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "workspace/dat/dck_rsa_2048.yml\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "nxpdebugmbox gendc --config workspace/dat/dck_rsa_2048.yml --plugin plugins/sasp.py workspace/dat/dc_out.cert \n",
+ "RoT Key Hash: 5905022784a39901b0dc0860c9455cd1b83c5336a2e973825759961554664c89\n",
+ "Creating Debug credential file succeeded\n"
+ ]
+ }
+ ],
+ "source": [
+ "CONFIG_PATH = os.path.join(WORKSPACE, 'dck_rsa_2048.yml')\n",
+ "OUTPUT_PATH = os.path.join(WORKSPACE, 'dc_out.cert')\n",
+ "print(CONFIG_PATH)\n",
+ "\n",
+ "%! nxpdebugmbox gendc --config $CONFIG_PATH --plugin $SASP_PLUGIN $OUTPUT_PATH\n",
+ " \n",
+ "# check if the signed image exists\n",
+ "assert os.path.exists(OUTPUT_PATH)"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### HSM teardown\n",
+ "\n",
+ "Last step is to stop custom HSM. In order to do that, open again the [notebook](sahsm.ipynb) and stop the running jupyter notebook code cell."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "venv",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ },
+ "orig_nbformat": 4
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/examples/jupyter_examples/rt5xx_signature_provider/rt5xx_mbimg.ipynb b/examples/jupyter_examples/rt5xx_signature_provider/rt5xx_mbimg.ipynb
new file mode 100644
index 00000000..ffaacc1a
--- /dev/null
+++ b/examples/jupyter_examples/rt5xx_signature_provider/rt5xx_mbimg.ipynb
@@ -0,0 +1,209 @@
+{
+ "cells": [
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Masterboot image with Signature Provider\n",
+ "\n",
+ "This notebook describes how to use a custom remote signing service for signing the masterboot image.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "env: JUPYTER_SPSDK=1\n",
+ "Created `%!` as an alias for `%execute`.\n"
+ ]
+ }
+ ],
+ "source": [
+ "%run ../init_notebook.ipynb\n",
+ "\n",
+ "import pprint\n",
+ "import os\n",
+ "\n",
+ "pp = pprint.PrettyPrinter(indent=4)\n",
+ "\n",
+ "plugins_dir = 'plugins/'\n",
+ "\n",
+ "SASP_PLUGIN = os.path.join(plugins_dir, 'sasp.py')\n",
+ "WORKSPACE = \"workspace/mbimg/\" # change this to path to your workspace\n",
+ "DATA_DIR = \"data_mbimg/\" # change this to path to your workspace\n",
+ "VERBOSITY = \"-v\" # verbosity of commands, might be -v or -vv for debug or blank for no additional info"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Signature Provider Plugin\n",
+ "\n",
+ "First, we need to setup the Signature Provider plugin and start the custom HSM. In order to do that, open this [notebook](signature_provider.ipynb) and follow the instructions there. Once you are done, come back and continue here."
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Config File Setup\n",
+ "\n",
+ "The masterboot image configuration file must be updated in order to integrate the custom Signature Provider.\n",
+ "\n",
+ "The signature provider configuration must meet following rules:\n",
+ " - Configuration key\n",
+ " - key names `sign_provider` or `signProvider` are allowed\n",
+ "\n",
+ " - Configuration value\n",
+ " - format `\"type=;=;=;...\"`\n",
+ " - the `sp_type` has to match the sp_type class attribute defined in the custom signature provider(`plugins/sasp.py`)\n",
+ " - the remaining key-value pairs are passed to the `__init__` method of the concrete Signature Provider\n",
+ " - e.g.: `\"type=file;file_path=private_key.pem\"` will instantiate `spsdk.crypto.PlainFileSP(file_path='private_key.pem')`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "nxpimage -v mbi get-templates -f rt5xx -o workspace/mbimg/ \n",
+ "Creating c:\\spsdk\\examples\\jupyter_examples\\rt5xx_signature_provider\\workspace\\mbimg\\rt5xx_ext_xip_plain.yaml template file.\n",
+ "Creating c:\\spsdk\\examples\\jupyter_examples\\rt5xx_signature_provider\\workspace\\mbimg\\rt5xx_ext_xip_crc.yaml template file.\n",
+ "Creating c:\\spsdk\\examples\\jupyter_examples\\rt5xx_signature_provider\\workspace\\mbimg\\rt5xx_ext_xip_signed.yaml template file.\n",
+ "Creating c:\\spsdk\\examples\\jupyter_examples\\rt5xx_signature_provider\\workspace\\mbimg\\rt5xx_ram_plain.yaml template file.\n",
+ "Creating c:\\spsdk\\examples\\jupyter_examples\\rt5xx_signature_provider\\workspace\\mbimg\\rt5xx_ram_crc.yaml template file.\n",
+ "Creating c:\\spsdk\\examples\\jupyter_examples\\rt5xx_signature_provider\\workspace\\mbimg\\rt5xx_ram_signed.yaml template file.\n",
+ "Creating c:\\spsdk\\examples\\jupyter_examples\\rt5xx_signature_provider\\workspace\\mbimg\\rt5xx_ram_encrypted.yaml template file.\n",
+ "\"All files are ready in folder 'workspace/mbimg/'\"\n"
+ ]
+ }
+ ],
+ "source": [
+ "import yaml\n",
+ "import os\n",
+ "import shutil\n",
+ "from spsdk.utils.misc import load_configuration\n",
+ "# choose family for the MCU\n",
+ "FAMILY = \"rt5xx\"\n",
+ "\n",
+ "%! nxpimage $VERBOSITY mbi get-templates -f $FAMILY -o $WORKSPACE\n",
+ "\n",
+ "CONFIG_PATH = os.path.join(WORKSPACE, \"rt5xx_ext_xip_signed.yaml\")\n",
+ "# just for verification that the template was generated\n",
+ "assert os.path.exists(CONFIG_PATH)\n",
+ "\n",
+ "# we can remove all optional setting as we don't need them for thsi example\n",
+ "filtered_config = []\n",
+ "with open(CONFIG_PATH, 'r') as file:\n",
+ " for line in file:\n",
+ " if '[Optional]' not in line:\n",
+ " filtered_config.append(line)\n",
+ "\n",
+ "with open(CONFIG_PATH, 'w') as file:\n",
+ " for line in filtered_config:\n",
+ " file.write(f\"{line}\")\n",
+ "\n",
+ "# update the config so it uses our custom Signature Provider\n",
+ "config = load_configuration(CONFIG_PATH)\n",
+ "\n",
+ "# either the 'mainCertPrivateKeyFile' or 'signProvider' setting can be used\n",
+ "del config['mainCertPrivateKeyFile']\n",
+ "config['signProvider'] = 'type=sasp;key_number=0'\n",
+ "config['rootCertificate0File'] = 'root_k0_signed_cert0_noca.der.cert'\n",
+ "with open(CONFIG_PATH, 'w') as file:\n",
+ " yaml.dump(config, file, default_flow_style=False)\n",
+ "\n",
+ "# copy additional files needed for masterboot image creation\n",
+ "files_needed = ['my_application.bin', 'root_k0_signed_cert0_noca.der.cert']\n",
+ "for file in files_needed:\n",
+ " shutil.copyfile(os.path.join(DATA_DIR, file), os.path.join(WORKSPACE, file))\n",
+ "\n",
+ "pp.pprint(f\"All files are ready in folder '{WORKSPACE}'\")"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Execution\n",
+ "\n",
+ "At this point, we have everything we need to run nxpimage application using remote HSM for image signing."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "nxpimage -v mbi export --plugin plugins/sasp.py workspace/mbimg/rt5xx_ext_xip_signed.yaml \n",
+ "\u001b[37m\u001b[1mINFO:spsdk.image.mbi_mixin:RKTH: db31d46c717711a8231cbc38b1de8a6e8657e1f733e04c2ee4b62fcea59149fa\u001b[39m\u001b[0m\n",
+ "Success. (Master Boot Image: c:/spsdk/examples/jupyter_examples/rt5xx_signature_provider/workspace/mbimg/my_mbi.bin created.)\n"
+ ]
+ }
+ ],
+ "source": [
+ "%! nxpimage $VERBOSITY mbi export --plugin $SASP_PLUGIN $CONFIG_PATH\n",
+ "\n",
+ "# check if the signed image exists\n",
+ "output_file = os.path.join(WORKSPACE, config['masterBootOutputFile'])\n",
+ "assert os.path.exists(output_file)"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### HSM teardown\n",
+ "\n",
+ "Last step is to stop custom HSM. In order to do that, open again the [notebook](sahsm.ipynb) and stop the running jupyter notebook code cell."
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "venv",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ },
+ "orig_nbformat": 4
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/examples/jupyter_examples/rt5xx_signature_provider/sahsm.ipynb b/examples/jupyter_examples/rt5xx_signature_provider/sahsm.ipynb
new file mode 100644
index 00000000..8720af1a
--- /dev/null
+++ b/examples/jupyter_examples/rt5xx_signature_provider/sahsm.ipynb
@@ -0,0 +1,87 @@
+{
+ "cells": [
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### HSM setup\n",
+ "\n",
+ "HSM provide the required secure environment that is needed to generate and protect the cryptographic keys used to protect and authenticate sensitive data.\n",
+ "\n",
+ "We will use a simple Flask REST API service representing the remote HSM machine.\n",
+ "\n",
+ "Looking into `hsm` directory, we can see following files:\n",
+ "- `hsm/sahsm.py` is an example of a remote signing service.\n",
+ "- `hsm/hsm_k0_cert0_2048.pem` test private key used for signing the data.\n",
+ "- `hsm/hsm_k1_cert0_2048.pem` test private key used for signing the data.\n",
+ "\n",
+ "IN order to start the HSM service, run following code:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Collecting flask\n",
+ " Using cached Flask-2.3.2-py3-none-any.whl (96 kB)\n",
+ "Collecting requests\n",
+ " Using cached requests-2.31.0-py3-none-any.whl (62 kB)\n",
+ "Requirement already satisfied: Werkzeug>=2.3.3 in c:\\users\\nxf93270\\repos\\spsdk_1\\venv\\lib\\site-packages (from flask) (2.3.4)\n",
+ "Requirement already satisfied: Jinja2>=3.1.2 in c:\\users\\nxf93270\\repos\\spsdk_1\\venv\\lib\\site-packages (from flask) (3.1.2)\n",
+ "Requirement already satisfied: itsdangerous>=2.1.2 in c:\\users\\nxf93270\\repos\\spsdk_1\\venv\\lib\\site-packages (from flask) (2.1.2)\n",
+ "Requirement already satisfied: click>=8.1.3 in c:\\users\\nxf93270\\repos\\spsdk_1\\venv\\lib\\site-packages (from flask) (8.1.3)\n",
+ "Requirement already satisfied: blinker>=1.6.2 in c:\\users\\nxf93270\\repos\\spsdk_1\\venv\\lib\\site-packages (from flask) (1.6.2)\n",
+ "Requirement already satisfied: charset-normalizer<4,>=2 in c:\\users\\nxf93270\\repos\\spsdk_1\\venv\\lib\\site-packages (from requests) (3.1.0)\n",
+ "Requirement already satisfied: idna<4,>=2.5 in c:\\users\\nxf93270\\repos\\spsdk_1\\venv\\lib\\site-packages (from requests) (3.4)\n",
+ "Requirement already satisfied: urllib3<3,>=1.21.1 in c:\\users\\nxf93270\\repos\\spsdk_1\\venv\\lib\\site-packages (from requests) (2.0.2)\n",
+ "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\nxf93270\\repos\\spsdk_1\\venv\\lib\\site-packages (from requests) (2023.5.7)\n",
+ "Requirement already satisfied: colorama in c:\\users\\nxf93270\\repos\\spsdk_1\\venv\\lib\\site-packages (from click>=8.1.3->flask) (0.4.6)\n",
+ "Requirement already satisfied: MarkupSafe>=2.0 in c:\\users\\nxf93270\\repos\\spsdk_1\\venv\\lib\\site-packages (from Jinja2>=3.1.2->flask) (2.1.3)\n",
+ "Installing collected packages: requests, flask\n",
+ "Successfully installed flask-2.3.2 requests-2.31.0\n",
+ " * Serving Flask app 'hsm.sahsm'\n",
+ " * Debug mode: off\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Install a the required dependencies into the current Jupyter kernel\n",
+ "import sys\n",
+ "!{sys.executable} -m pip install flask requests\n",
+ "\n",
+ "# Start remote signing service\n",
+ "from hsm.sahsm import APP\n",
+ "APP.run()\n",
+ "# This will keep running\n"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "venv",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ },
+ "orig_nbformat": 4
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/examples/jupyter_examples/rt5xx_signature_provider/signature_provider.ipynb b/examples/jupyter_examples/rt5xx_signature_provider/signature_provider.ipynb
new file mode 100644
index 00000000..e1831a11
--- /dev/null
+++ b/examples/jupyter_examples/rt5xx_signature_provider/signature_provider.ipynb
@@ -0,0 +1,244 @@
+{
+ "cells": [
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Signature Provider Plugin\n",
+ "\n",
+ "This notebook describes how to setup a Signature Provider plugin\n",
+ "\n",
+ "When signing the data with SPSDK, there are two options:\n",
+ "- Using the local private key (not recommended)\n",
+ "- Using the remote signing service(HSM)\n",
+ "\n",
+ "Let's look at the second option and setup Signature Provider \n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "env: JUPYTER_SPSDK=1\n",
+ "Created `%!` as an alias for `%execute`.\n"
+ ]
+ }
+ ],
+ "source": [
+ "%run ../init_notebook.ipynb\n",
+ "\n",
+ "import pprint\n",
+ "\n",
+ "pp = pprint.PrettyPrinter(indent=4)\n",
+ "\n",
+ "PLUGINS_DIR = \"plugins/\" # change this to path to your workspace\n",
+ "VERBOSITY = \"-v\" # verbosity of commands, might be -v or -vv for debug or blank for no additional info"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### HSM setup\n",
+ "\n",
+ "First, we need to start the custom HSM. In order to do that, open this [notebook](sahsm.ipynb) and follow the instructions there. Once you are done, come back and continue here."
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Now the HSM should be up and running. In order to test the functionality of HSM from previous step, run a simple test:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{'signature': 'QWjBWnbG7QtninaD6R9dQZqGiMZZskdVLCV1peXZEp43SJx3PATOoXTIQhvLhOZ5Q0f1683dtGAkEzb1aHKY05fIw2iPAGNHsL7IAe5nH0t3dOaCvemlodzAbb8GDpdahUHBURpnJOsgqYccZZOR6E3GSuIwD8qKBlZ7sGomtwzrBGuNHU5AG8U0J+8hLhExpEttd953mtnyMnC5aq3W30SbwU+7lZDAc2jIJn1PltVUetdHOVyGSPi4yAGZIlnzgYD8vpse2xlPP+3Ifdfuu3ckkNSZ0xzmK8adehKGTqD5hlpnP9iWPd7lio+82SovjmQ552RwwtRGbFmqC2qEkg=='}\n"
+ ]
+ }
+ ],
+ "source": [
+ "import requests\n",
+ "response = requests.get(\"http://127.0.0.1:5000/signer/0?data=b'ABC'\")\n",
+ "print(response.json())"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Signature Provider plugin\n",
+ "\n",
+ "Plugins extend the existing SPSDK functionality with additional features. \n",
+ "\n",
+ "In order to use remote signing, a Signature Provider plugin used for communication with HSM must be implemented.\n",
+ "\n",
+ "Explore the file `plugins\\sasp.py`. It will be used later on."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "#!/usr/bin/env python\n",
+ "# -*- coding: UTF-8 -*-\n",
+ "#\n",
+ "# Copyright 2020-2023 NXP\n",
+ "#\n",
+ "# SPDX-License-Identifier: BSD-3-Clause\n",
+ "\n",
+ "\"\"\"Customer-specific Signature Provider.\"\"\"\n",
+ "\n",
+ "import base64\n",
+ "\n",
+ "import requests\n",
+ "\n",
+ "from spsdk.crypto.signature_provider import SignatureProvider\n",
+ "\n",
+ "\n",
+ "class SuperAwesomeSP(SignatureProvider):\n",
+ " \"\"\"Signature Provider based on a remote signing service.\"\"\"\n",
+ "\n",
+ " # identifier of this signature provider; used in yaml configuration file\n",
+ " sp_type = \"sasp\"\n",
+ "\n",
+ " def __init__(self, key_number: int) -> None:\n",
+ " \"\"\"Initialize the Super Awesome SignatureProvider.\n",
+ "\n",
+ " :param key_number: index of the key to use (rot_id from yaml config)\n",
+ " \"\"\"\n",
+ " self.url = f\"http://127.0.0.1:5000\"\n",
+ " self.key_number = key_number\n",
+ "\n",
+ " def sign(self, data: bytes) -> bytes:\n",
+ " \"\"\"Perform the signing.\n",
+ "\n",
+ " :param data: Data to sign\n",
+ " :return: Signature\n",
+ " \"\"\"\n",
+ " endpoint = f\"{self.url}/signer/{self.key_number}\"\n",
+ " params = {\"data\": base64.b64encode(data)}\n",
+ " response = requests.get(endpoint, params=params)\n",
+ " self.check_response(response)\n",
+ " signature = response.json()[\"signature\"]\n",
+ " data = base64.b64decode(signature)\n",
+ " return data.zfill(256)\n",
+ "\n",
+ " def verify_public_key(self, public_key: bytes) -> bool:\n",
+ " \"\"\"Verify if given public key matches private key.\n",
+ "\n",
+ " :param data: Public key to verify\n",
+ " :return: True if public_key is matching private_key, False otherwise\n",
+ " \"\"\"\n",
+ " endpoint = f\"{self.url}/verifier/{self.key_number}\"\n",
+ " params = {\"public_key\": base64.b64encode(public_key)}\n",
+ " response = requests.get(endpoint, params=params)\n",
+ " self.check_response(response)\n",
+ " is_matching = response.json()[\"is_matching\"]\n",
+ " return is_matching\n",
+ "\n",
+ " @property\n",
+ " def signature_length(self) -> int:\n",
+ " \"\"\"Return length of the signature.\"\"\"\n",
+ " return 256\n",
+ "\n",
+ " @staticmethod\n",
+ " def check_response(response: requests.Response) -> None:\n",
+ " \"\"\"Raise if response is not 2xx.\"\"\"\n",
+ " try:\n",
+ " response.raise_for_status()\n",
+ " except requests.HTTPError as e:\n",
+ " if response.text:\n",
+ " raise requests.HTTPError(f\"{str(e)}; Error Message: {response.text}\")\n",
+ " else:\n",
+ " raise e\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "import os\n",
+ "\n",
+ "plugins_dir = 'plugins/'\n",
+ "# The content of plugin will be printed here\n",
+ "SASP_PLUGIN = os.path.join(plugins_dir, 'sasp.py')\n",
+ "with open(SASP_PLUGIN, 'r') as f:\n",
+ " print(f.read())\n"
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The only plugin requirement is that it contains a class derived from `spsdk.crypto.SignatureProvider` base class.\n",
+ "\n",
+ "- The derived class has to implement:\n",
+ " - `sp_type: str`: class attribute that identifies the concrete implementation of SignatureProvider\n",
+ " - `sign(bytes) -> bytes`: method which performs the actual signing\n",
+ " - `signature_length -> str`: property which returns a length of a signature\n",
+ "- The derived class can also optionally implement:\n",
+ " - `info() -> str`: method which returns information about the signature provider (for debugging purposes). The default implementation returns a class name as a string\n",
+ " - `verify_public_key(bytes) -> bool`: method which verifies if a given public key matches a private key. If not implemented, the `SPSDKUnsupportedOperation` exceptipon is raised.\n",
+ "\n",
+ "> Omitting the implementation of optional methods such as `info()` or `verify(bytes)` does not break the functionality of application."
+ ]
+ },
+ {
+ "attachments": {},
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Signature Formats\n",
+ "\n",
+ "The signature must meet following formats:\n",
+ "\n",
+ "- RSA: Standard format\n",
+ "- ECC: Extracted public numbers r+s stored in big endian"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "venv",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.6"
+ },
+ "orig_nbformat": 4
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/examples/plugins/README.md b/examples/plugins/README.md
new file mode 100644
index 00000000..16dfe1b1
--- /dev/null
+++ b/examples/plugins/README.md
@@ -0,0 +1,43 @@
+# Plugins
+
+SPSDK allows user to install additional plugins and integrate them with SPSDK functionality. They allow uset ot extend the normal SPSDK funtionality with additional features.
+
+## Supported plugin types
+
+The table bellow shows the list of support plugin types with associated package entrypoints, cokiecutter templates and base class they are derived from.
+
+| Plugin | Entrypoint | Template name | Base class |
+|:-------------------|:---------------|:---------------------------------|----------------------------------|
+| Signature Provider | spsdk.sp | cookiecutter-spsdk-sp-plugin.zip | spsdk.crypto.SignatureProvider |
+
+## Plugin implementation
+
+There are basically two ways how a plugin can be implemented.
+
+- A Python package installed in the environment (preffered)
+- A single Python module with the plugin implementation in it
+
+The actual implementation depends on actual plugin type.
+In general every plugin must be derived from the plugin base class and implement it's methods.
+
+### Plugin as a Python package
+All the plugins installed in the Python environment will be discovered automatically.
+The only requirement for package is to add specific entrypoint metadata into the package.
+
+You can find the list of plugin entrypoints based on the plugin type in the table above.
+
+In order to make the implementation of the plugins easier, a cookiecutter template can be used.
+You can find all the cookiecutter templates in the `/templates` folder.
+
+The instructions for generating plugin package from cookiecutter template:
+- Unzip plugin template: `plugins/.zip`
+- Install cookiecutter: `pip install cookiecutter`
+- Create plugin: `cookiecutter `
+- Follow the instructions in the command prompt
+- A new plugin package is cretaed
+
+### Plugin as a single Python module
+In some situations the installation into the Python environment is not possible.
+For such scenarios a plugin as a single Python module can be implemented.
+In this case the plugin is not loaded automatically.
+The plugin will be loaded if the `--plugin ` option is used in SPSDK application command.
diff --git a/examples/plugins/templates/cookiecutter-spsdk-sp-plugin.zip b/examples/plugins/templates/cookiecutter-spsdk-sp-plugin.zip
new file mode 100644
index 00000000..dea96617
Binary files /dev/null and b/examples/plugins/templates/cookiecutter-spsdk-sp-plugin.zip differ
diff --git a/examples/sbfile.py b/examples/sbfile.py
index 2f51141a..854dcdfb 100644
--- a/examples/sbfile.py
+++ b/examples/sbfile.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#
-# Copyright 2021-2022 NXP
+# Copyright 2021-2023 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
@@ -15,6 +15,7 @@
from binascii import unhexlify
from spsdk import SPSDKError
+from spsdk.crypto.signature_provider import get_signature_provider
from spsdk.sbfile.sb2.commands import CmdErase, CmdLoad, CmdReset
from spsdk.sbfile.sb2.images import BootImageV20, BootImageV21, BootSectionV2, SBV2xAdvancedParams
from spsdk.utils.crypto import CertBlockV2, Certificate, KeyBlob, Otfad
@@ -106,8 +107,8 @@ def gen_boot_section_otfad() -> BootSectionV2:
KEK_VALUE = unhexlify("AC701E99BD3492E419B756EADC0985B3D3D0BC0FDB6B057AA88252204C2DA732")
DEK_VALUE = b"\xA0" * 32 # it is recommended to use random value
MAC_VALUE = b"\x0B" * 32 # it is recommended to use random value
-with open(f"{DATA_DIR}/selfsign_privatekey_rsa2048.pem", "rb") as key_file:
- PRIVATE_KEY_PEM_DATA = key_file.read()
+
+PRIVATE_KEY_FILE = f"{DATA_DIR}/selfsign_privatekey_rsa2048.pem"
def gen_boot_image_20_base() -> bytes:
@@ -140,7 +141,8 @@ def gen_boot_image_20() -> bytes:
# add certificate block
boot_image.cert_block = gen_cert_block()
- boot_image.private_key_pem_data = PRIVATE_KEY_PEM_DATA
+ signature_provider = get_signature_provider(local_file_key=PRIVATE_KEY_FILE)
+ boot_image.signature_provider = signature_provider
# add boot sections
boot_image.add_boot_section(boot_section)
# print image info
@@ -167,7 +169,8 @@ def gen_boot_image_21() -> bytes:
# add certificate block
boot_image.cert_block = gen_cert_block()
- boot_image.private_key_pem_data = PRIVATE_KEY_PEM_DATA
+ signature_provider = get_signature_provider(local_file_key=PRIVATE_KEY_FILE)
+ boot_image.signature_provider = signature_provider
# print image info
print(boot_image.info())
diff --git a/examples/signature_provider/.gitignore b/examples/signature_provider/.gitignore
deleted file mode 100644
index f59ec20a..00000000
--- a/examples/signature_provider/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*
\ No newline at end of file
diff --git a/examples/signature_provider/README.md b/examples/signature_provider/README.md
deleted file mode 100644
index c27d67fb..00000000
--- a/examples/signature_provider/README.md
+++ /dev/null
@@ -1,92 +0,0 @@
-# Signature Provider Integration
-
-This example demonstrates how to use a custom remote signing service for signing data such as Debug Credential file or Masterboot image.
-
-## 1. Content
-This chapter describes the content of this directory
-
-### 1.1 Signature Provider
-Content of the `hsm` directory represents the remote side of things
-
-`hsm/sahsm.py` represents a remote signing service
-
-`hsm/sasp.py` is the custom Signature Provider, an interface to the signing service.
-It contains a class derived from `spsdk.crypto.SignatureProvider`
-
-- the derived class has to implement:
- - `sp_type: str`: class attribute that identifies the concrete implementation of SignatureProvider
- - `sign(bytes) -> bytes`: method which performs the actual signing
- - `signature_length -> str`: property which returns a length of a signature
-- the derived class can also optionally implement:
- - `info() -> str`: method which returns information about the signature provider (for debugging purposes). The default implementation returns a class name as a string
- - `verify_public_key(bytes) -> bool`: method which verifies if a given public key matches a private key. If not implemented, the `SPSDKUnsupportedOperation` exceptipon is raised.
-
-> Omitting the implementation of optional methods such as `info()` or `verify(bytes)` does not break the functionality of application.
-
-### 1.2 Debug Credentials
-Content of the `dat` directory holds the files required for running the example for Debug Credentials application
-
- `dat/dck_rsa_2048.yml`
-- configuration file for `nxpdebugmbox gendc` command
-- new configuration field `sign_provider`/`signProvider`(both accepted) has been introduced
-- new configuration field `rot_id`:
- - due to the nature of creating Debug Credential file we need to know in advance which of the private keys will be used to perform the actual signing
- - `rot_id` is a 0-based index representing the private key that will be used with respect to `rot_meta`
- - e.g.: if we want to use a private key that corresponds to the public key `p1_cert0_2048.pub`, `rot_id` has to be set to `1`
-
-### 1.3 Masterboot Image
-Content of the `mbimg` directory holds the files required for running the example for Masterboot Image application
-
- `mbimg/mbimg_rsa_2048.yml`
- - configuration file for `nxpimage mbi export` command
- - new configuration field `sign_provider`/`signProvider`(both accepted) has been introduced
- - the `sign_provider`/`signProvider` and `mainCertPrivateKeyFile` configuration fields are mutually exclusive as they have the same purpose
-
-
-## 2. How to run this example
-### 2.1 Remote signature service
-
-- install two additional dependencies:
- - `pip install flask requests`
-- run the custom HSM (a flask application) in a separate shell:
- - `python hsm\sahsm.py`
-
-### 2.2 Debug Cedentials
-The steps required for signing generated debug certificate with remote signing service:
-
- - Check the configuration file
- - `dat/dck_rsa_2048.yml` config file is preconfigured to use `sasp` signature provider
- - see the [next chapter](#3-signature-provider-config-values) for better understanding of the configuration values
- > For comparison, you may try to use signing a local file, to do so, comment out line 115 in `dat/dck_rsa_2048.yml` file and uncomment line 114 or 118 (the have the same effect)
- - Generate signed debug certificate
- - `nxpdebugmbox gendc --config dat/dck_rsa_2048.yml --plugin hsm/sasp.py my.dc`
-
- > Use `--plugin` parameter in order to integrate custom signature provider
-
- > Use `--force` flag if you run the example multiple times
-
-
-### 2.2 Masterboot image
-The steps required for signing generated masteboot image with remote signing service:
-
- - Check the configuration file
- - `mbimg/mbimg_rsa_2048.yml` config file is preconfigured to use `sasp` signature provider
- - see the [next chapter](#3-signature-provider-config-values) for better understanding of the configuration values
- > For comparison, you may try to use signing a local file, to do so, comment out line 34 in `mbimg/mbimg_rsa_2048.yml` file and uncomment line 32 or 33 (the have the same effect)
- - Generate signed masterboot image
- - `nxpimage mbi export --plugin hsm/sasp.py mbimg/mbimg_rsa_2048.yml`
-
- > Use `--plugin` parameter in order to integrate custom signature provider
-
-
-## 3 Signature provider config values
-The signature provider configuration must meet following rules:
- - Configuration key
- - key names `sign_provider` or `signProvider` are allowed
-
- - Configuration value
- - format `"type=;=;=;..."`
- - the `sp_type` has to match the sp_type class attribute defined in the custom signature provider(`hsm/sasp.py`)
- - the remaining key-value pairs are passed to the `__init__` method of the concrete Signature Provider
- - e.g.: `"type=file;file_path=private_key.pem"` will instantiate `spsdk.crypto.PlainFileSP(file_path='private_key.pem')`
-
diff --git a/examples/signature_provider/dat/dck_rsa_2048.yml b/examples/signature_provider/dat/dck_rsa_2048.yml
deleted file mode 100644
index 0456d842..00000000
--- a/examples/signature_provider/dat/dck_rsa_2048.yml
+++ /dev/null
@@ -1,119 +0,0 @@
-# DC Block structure
-# ============================================
-# ============================================
-# ============================================
-# === Version ===
-# ============================================
-# === Soc Class ===
-# ============================================
-# === UUID ===
-# ============================================
-# === RoT Meta SHA256 of following: ===
-# === RoT Key0 SHA256 ===
-# === RoT Key1 SHA256 ===
-# === RoT Key2 SHA256 ===
-# === RoT Key3 SHA256 ===
-# ============================================
-# === Debugger Key DCK (Pub): ===
-# === Mod: 2048 Exp: 32 ===
-# ============================================
-# === CC SOCU ===
-# ============================================
-# === CC VU ===
-# ============================================
-# === CB ===
-# ============================================
-# === RoT Key (pub) ===
-# === Mod: 2048 Exp: 32 ===
-# ============================================
-# ============================================
-# === Signature of all block ===
-# === SHA256 of whole block => RSA(RoTK) ===
-# ============================================
-# ============================================
-# ============================================
-
-# ============ SoC Class ============
-# A unique identifier for a set of SoCs that require no SoC-specific differentiation in
-# their debug authentication. The main usage is to allow a different set of debug
-# domains and options to be negotiated between the device configuration and
-# credentials. A class can contain just a single revision of a single SoC model, if the
-# granularity of debug control warrants it.
-# Examples list of possible settings:
-# 0x0001: LPC550x, LPC55s0x, LPC551x, LPC55s1x, LPC552x, LPC55s2x, LPC55s3x, LPC55s6x
-
-socc: 0x0001
-
-# ============ Device UUID ============
-# 128-bit IETF RFC4122 compliant non-sequential Universally Unique Identifier (UUID)
-uuid: "E004090E6BDD2155BBCE9E0665805BE3"
-
-# ============ SoC Usage ============
-# A CC (constraint) value that is a bit mask, and whose bits are used in an
-# SoCC-specific manner. These bits are typically used for controlling which debug
-# domains are accessed via the authentication protocol, but device-specific debug
-# options can be managed in this way also.
-cc_socu: 0x03FF
-
-# ============ Vendor Usage ============
-# A CC (constraint) value that is opaque to the debug authentication protocol itself but
-# which can be leveraged by vendors in product-specific ways.
-cc_vu: 0x5678
-
-# ============ Credential Beacon & Authentication beacon ============
-# A value that is passed through the authentication protocol, which is not interpreted
-# by the protocol but is instead made visible to the application being debugged. A
-# credential beacon is associated with a DC and is therefore vendor/RoT-signed. An
-# authentication beacon is provided and signed by the debugger during the
-# authentication process.
-cc_beacon: 0
-
-# ============ RoT meta-data ============
-# The RoT meta-data required by the device to corroborate; the ROTID sent in the
-# DAC, the field in this DC, and any additional RoT state that is not stored within the
-# device. This allows different RoT identification, management and revocation
-# solutions to be handled.
-rot_meta:
- - ./p0_cert0_2048.pub
- - ./p1_cert0_2048.pub
-
-# ============ RoT Identifier ============
-# RoTID allows the debugger to infer which RoT public key(s) are acceptable to the
-# device. If the debugger cannot or does not provide such a credential, the
-# authentication process will fail.
-rot_id: 0
-
-# ============ Debug Credential Key ============
-# Copyright 2023 NXP
-#
-# SPDX-License-Identifier: BSD-3-Clause
-
-# A user-owned key pair. The public part of the key is associated with a DC, the
-# private part is held by the user and used to produce signatures during
-# authentication.
-dck: ./dck.pub
-
-# ==================================================================================================
-# Signature configuration area
-# ==================================================================================================
-# There are two ways how sign the final DC data blob.
-#
-# 1. In case that you have available private pair for rot_meta with index rot_id just use first simple style
-# to use it by rotk key. As a second way to do same is use sign_provider option with 'type=file'.
-#
-# 2. For case that Debug Credential files are generated in untrusted environment (without access to RoT private keys),
-# there is option to use plugin (example how to create own plugin is in: ./SPSDK/examples/dat/hsm/). The plugin
-# has simple interface that allows handle DC data blob into plugin with index of RoT meta public key to get back signed
-# DC image.
-#
-# Those options are exclusive, so only one option could be used to sign the DC.
-
-# ============ Signature Provider ============
-# To use signing provider examples
-#
-# sign_provider: 'type=file;file_path=./../hsm/hsm_k0_cert0_2048.pem'
-sign_provider: "type=sasp;key_number=0"
-# ============ RoT signature private key ============
-# Private key for for the RoT meta chosen by rot_id to sign the image.
-# rotk: rotk0.pem
-
diff --git a/examples/signature_provider/mbimg/mbimg_rsa_2048.yml b/examples/signature_provider/mbimg/mbimg_rsa_2048.yml
deleted file mode 100644
index 65af5292..00000000
--- a/examples/signature_provider/mbimg/mbimg_rsa_2048.yml
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright 2023 NXP
-#
-# SPDX-License-Identifier: BSD-3-Clause
-
-family: rt5xx
-outputImageExecutionTarget: External flash (XIP)
-outputImageAuthenticationType: Signed
-masterBootOutputFile: my_mbi.bin
-inputImageFile: my_application.bin
-outputImageExecutionAddress: 0
-enableHwUserModeKeys: false
-enableTrustZone: false
-trustZonePresetFile: ""
-mainRootCertId: 0
-
-# ----------------------------------------------------------------------------------------------------
-# Signature configuration area
-# ----------------------------------------------------------------------------------------------------
-# There are two ways how sign the final masterboot image.
-#
-# 1. In case that you have available private key, specify in mainCertPrivateKeyFile key
-# As a second way to do same is use signProvider option with 'type=file'.
-#
-# 2. For case that Masterboot image is generated in untrusted environment (without access to RoT private keys),
-# there is option to use plugin (example how to create own plugin is in: SPSDK/examples/signature_providerdat/hsm/). The plugin
-# has simple interface that allows handle masterboot image binary into plugin with index of RoT private key to get back signed
-# masterboot image.
-#
-# Those options are exclusive, so only one option could be used to sign the masterboot image.
-
-
-#mainCertPrivateKeyFile: .\..\hsm\hsm_k0_cert0_2048.pem
-#signProvider: type=file;file_path=.\..\hsm\hsm_k0_cert0_2048.pem
-signProvider: type=sasp;key_number=0 # Signature Provider, A signature provider definition. It can be either path to local private key or signature provider string. Caution This is a replacement for mainCertPrivateKeyFile.
-rootCertificate0File: root_k0_signed_cert0_noca.der.cert # Root Certificate File 0, Root certificate file index 0.
-
diff --git a/examples/signature_provider/plugins/cookiecutter-spsdk-sp-plugin.zip b/examples/signature_provider/plugins/cookiecutter-spsdk-sp-plugin.zip
new file mode 100644
index 00000000..dea96617
Binary files /dev/null and b/examples/signature_provider/plugins/cookiecutter-spsdk-sp-plugin.zip differ
diff --git a/release_notes.txt b/release_notes.txt
index 2c205861..7ba3a000 100644
--- a/release_notes.txt
+++ b/release_notes.txt
@@ -7,23 +7,36 @@ configure the device, prepare, download and upload data, including security oper
delivered in the form of a python library and command-line applications.
-Version: 1.10.1
+Version: 1.11.0
================
-Date: 26-May-2023
+Date: 7-July-2023
+
+ANNOUNCEMENT:
+
+Next version of spsdk (2.0) will introduce breaking changes:
+- elftosb will be replaced by nxpimage
+- nxpcertgen and nxpkeygen will be replaced by nxpcrypto
+- select appropriate family will be done using: -f/--family parameter
+- move towards options for all parameters with an exception to BLHost
+- removal of crypto backends
+- extend dedicated spsdk.crypto module - serve as the de-facto backend of SPSDK
+- module level imports via init files
New features
- nxpimage:
- - support encrypted image hab
- - support for RT11xx and RT10xx
- - improve OTFAD/IEE names generation
-- add API to retrieve info about fuses
+ - enable signature providers for AHAB image and signed messages
+ - add support for rt104x in bootable-image
+- tphost/tpconfig:
+ - add possibility to check TP_RESPONSE only with NXP_PROD raw binary key
+- add support for mcxn9xx
+- add API for FuseLockedStatus
+- possibility to declare private keys with passphrase in signature provider config
+- add checking of written data length in usb interface
+- add support for dk6 tools
Bugfixes
- nxpimage:
- - fix XMCD load_from_config
- - fix IEE template
-- fix circular dependency in signature provider import
-- fix issue with loading keys as INT
-- not enable logging when spsdk is used as a library
+ - fix offset on NAND memory in AHAB image
+- fix plugin error for signature Provider for sb21
Supported devices
=================
@@ -50,6 +63,17 @@ Python 3.8+ interpreter, old version 2.x is not supported
Revision History
================
+1.10.1
+- nxpimage:
+ - support encrypted image hab
+ - support for RT11xx and RT10xx
+ - improve OTFAD/IEE names generation
+ - fix XMCD load_from_config
+ - fix IEE template
+- add API to retrieve info about fuses
+- fix circular dependency in signature provider import
+- fix issue with loading keys as INT
+- not enable logging when spsdk is used as a library
1.10.0
- blhost:
- add new command: ele_message
diff --git a/requirements-develop.txt b/requirements-develop.txt
index f7f38316..28538cfa 100644
--- a/requirements-develop.txt
+++ b/requirements-develop.txt
@@ -1,33 +1,33 @@
# tox has to be installed first
-tox<4.5
+tox<4.7
-r requirements.txt
# testing
pytest<7.4
-pytest-cov<4.1
-pytest-xdist<3.3
+pytest-cov<4.2
+pytest-xdist<3.4
voluptuous<0.14
# metrics
radon<6.1
-mypy>=0.800,<1.3
-types-requests>=2.26,<2.29
-types-setuptools<67.7
+mypy>=0.800,<1.4
+types-requests>=2.26,<2.32
+types-setuptools<67.9
types-pyyaml<6.1
# codestyle
-pylint>=2.6.0,<2.18
+pylint>=2.13.0,<2.18
pydocstyle[toml]<6.4
black<23.4
# cli executables
-pyinstaller<5.11
-pyinstaller-hooks-contrib<2023.3
+pyinstaller<5.13
+pyinstaller-hooks-contrib<2023.4
# developement/CI tools
bump2version<1.1
-pre-commit<3.3
+pre-commit<3.4
openpyxl<3.2
cachier<2.2
jira<3.6
inquirerpy<0.4
# examples
-flask<2.3
-requests<2.29
-ipython<8.13
+flask<2.4
+requests<2.32
+ipython<8.15
notebook<6.6
diff --git a/requirements.txt b/requirements.txt
index 11331d6b..c5b213a5 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -8,19 +8,19 @@ click>=7.1,<8.2
colorama>=0.4.6,<0.5
commentjson>=0.9,<0.10
crcmod<1.8
-cryptography>=3.4.4,<40.1
+cryptography>=3.4.4,<41.1
deepmerge<1.2
-fastjsonschema>=2.15.1,<2.17
+fastjsonschema>=2.15.1,<2.18
hexdump<3.4
jinja2>=3.0,<3.2
libusbsio>=2.1.11,<2.2
oscrypto<1.4
-pycryptodome>=3.9.3,<3.18
-pylink-square>=0.8.2,<0.15
+pycryptodome>=3.9.3,<3.19
+pylink-square>=1.0,<1.2
pyocd-pemicro>=1.1.5,<1.2
-pyocd>=0.33.0,<0.35
+pyocd>=0.35.1,<0.36
pypemicro>=0.1.11,<0.2
pyserial>=3.1,<3.6
ruamel.yaml>=0.17,<0.18
sly<0.6
-typing-extensions<4.6
+typing-extensions<4.7
diff --git a/setup.py b/setup.py
index 48bb9782..b03cf08e 100644
--- a/setup.py
+++ b/setup.py
@@ -5,6 +5,7 @@
#
# SPDX-License-Identifier: BSD-3-Clause
+import itertools
import os
from setuptools import find_packages, setup # type: ignore
@@ -22,6 +23,14 @@
with open(os.path.join(base_dir, "spsdk", "__version__.py")) as f:
exec(f.read(), version_info)
+extras_require = {
+ "tp": ["pyscard==2.0.2"],
+ "examples": ["flask", "requests", "ipython", "notebook"],
+ "dk6": ["pyftdi", "pylibftdi", "ftd2xx"],
+}
+# specify all option that contains all extras
+extras_require["all"] = list(itertools.chain.from_iterable(extras_require.values()))
+
setup(
name="spsdk",
version=version_info["__version__"],
@@ -58,7 +67,9 @@
"Topic :: System :: Hardware",
"Topic :: Utilities",
],
- packages=find_packages(exclude=["tests.*", "tests", "examples.*", "examples", "tools", "tools.*"]),
+ packages=find_packages(
+ exclude=["tests.*", "tests", "examples.*", "examples", "tools", "tools.*"]
+ ),
entry_points={
"console_scripts": [
"elftosb=spsdk.apps.elftosb:safe_main",
@@ -78,9 +89,8 @@
"ifr=spsdk.apps.ifr:safe_main",
"tpconfig=spsdk.apps.tpconfig:safe_main",
"tphost=spsdk.apps.tphost:safe_main",
+ "dk6prog=spsdk.apps.dk6prog:safe_main",
],
},
- extras_require={
- "tp": ["pyscard==2.0.2"],
- },
+ extras_require=extras_require,
)
diff --git a/spsdk/__init__.py b/spsdk/__init__.py
index 3cc00115..587df4d7 100644
--- a/spsdk/__init__.py
+++ b/spsdk/__init__.py
@@ -53,6 +53,6 @@
config_data = load_configuration(logging_config_file)
logging.config.dictConfig(config_data)
print(f"Logging config loaded from {logging_config_file}")
-except SPSDKError:
+except Exception:
# no logging config file found
pass
diff --git a/spsdk/__version__.py b/spsdk/__version__.py
index 602c8045..02ebcdd4 100644
--- a/spsdk/__version__.py
+++ b/spsdk/__version__.py
@@ -10,4 +10,4 @@
Having the version in a separate file makes it easier to share it with setup.py
"""
-__version__ = "1.10.1"
+__version__ = "1.11.0"
diff --git a/spsdk/apps/blhost.py b/spsdk/apps/blhost.py
index b3b47aca..23fd4ed4 100644
--- a/spsdk/apps/blhost.py
+++ b/spsdk/apps/blhost.py
@@ -50,7 +50,7 @@
@click.group(name="blhost", no_args_is_help=True, cls=CommandsTreeGroup)
-@isp_interfaces(uart=True, usb=True, lpcusbsio=True, buspal=True)
+@isp_interfaces(uart=True, usb=True, sdio=True, lpcusbsio=True, buspal=True)
@spsdk_apps_common_options
@click.option(
"-s",
@@ -63,6 +63,7 @@ def main(
ctx: click.Context,
port: str,
usb: str,
+ sdio: str,
buspal: str,
lpcusbsio: str,
use_json: bool,
@@ -91,6 +92,7 @@ def main(
module="mboot",
port=port,
usb=usb,
+ sdio=sdio,
timeout=timeout,
buspal=buspal,
lpcusbsio=lpcusbsio,
diff --git a/spsdk/apps/dk6prog.py b/spsdk/apps/dk6prog.py
new file mode 100644
index 00000000..2e6870b2
--- /dev/null
+++ b/spsdk/apps/dk6prog.py
@@ -0,0 +1,484 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+#
+# Copyright 2022-2023 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+"""DK6 Prog CLI interface."""
+import logging
+import os
+import sys
+from typing import Dict, List
+
+import click
+import colorama
+import hexdump
+import prettytable
+
+from spsdk import SPSDKError
+from spsdk.apps.blhost_helper import progress_bar
+from spsdk.apps.utils import spsdk_logger
+from spsdk.apps.utils.common_cli_options import spsdk_apps_common_options
+from spsdk.apps.utils.utils import (
+ INT,
+ WARNING_MSG,
+ catch_spsdk_error,
+ parse_file_and_size,
+ parse_hex_data,
+)
+from spsdk.dk6.commands import MemoryAccessValues, MemoryId, MemoryType
+from spsdk.dk6.dk6device import DK6Device, DK6Memory
+from spsdk.dk6.driver import Backend, DriverInterface
+from spsdk.utils.misc import value_to_int
+
+MEMORY_IDS = {
+ "flash": 0,
+ "psect": 1,
+ "pflash": 2,
+ "config": 3,
+ "efuse": 4,
+ "rom": 5,
+ "ram0": 6,
+ "ram1": 7,
+}
+
+logger = logging.getLogger(__name__)
+
+
+def print_memory_table(memories: Dict[int, DK6Memory]) -> str:
+ """Prints the List of Interfaces to nice colored table."""
+ if len(memories) == 0:
+ return (
+ colorama.Fore.RED
+ + "Nothing to print - empty interface list!"
+ + colorama.Style.RESET_ALL
+ )
+
+ header = [
+ "Memory",
+ "Memory ID",
+ "Base Address",
+ "Length",
+ "Sector Size",
+ "Memory Type",
+ "Access",
+ ]
+
+ table = prettytable.PrettyTable(header)
+ table.align = "l"
+ table.header = True
+ table.border = True
+ table.hrules = prettytable.HEADER
+ table.vrules = prettytable.NONE
+ for memory_id, memory in memories.items():
+ fields = [
+ colorama.Fore.YELLOW + str(MemoryId.get(memory_id)),
+ colorama.Fore.MAGENTA + str(memory.mem_id),
+ colorama.Fore.GREEN + hex(memory.base_address),
+ colorama.Fore.RED + hex(memory.length),
+ colorama.Fore.MAGENTA + hex(memory.sector_size),
+ colorama.Fore.CYAN + str(MemoryType.get(memory.mem_type)),
+ colorama.Fore.BLUE + str(MemoryAccessValues.get(memory.access)),
+ ]
+
+ table.add_row(fields)
+
+ return table.get_string() + colorama.Style.RESET_ALL
+
+
+def parse_memory_id(memory_id: str) -> MemoryId:
+ """Convert the memory id as name or stringified number into integer.
+
+ :param memory_id: Name or number of the property tag
+ :return: memory id integer tag
+ """
+ try:
+ value = value_to_int(memory_id)
+ return MemoryId.from_int(value) if value in MEMORY_IDS.values() else MemoryId.FLASH
+ except SPSDKError:
+ return MemoryId.from_int(MEMORY_IDS.get(memory_id.lower(), 0))
+
+
+def _split_string(string: str, length: int) -> List:
+ """Split the string into chunks of same length."""
+ return [string[i : i + length] for i in range(0, len(string), length)]
+
+
+def format_raw_data(data: bytes, use_hexdump: bool = False, line_length: int = 16) -> str:
+ """Format bytes data into human-readable form.
+
+ :param data: Data to format
+ :param use_hexdump: Use hexdump with addresses and ASCII, defaults to False
+ :param line_length: bytes per line, defaults to 32
+ :return: formatted string (multilined if necessary)
+ """
+ if use_hexdump:
+ return hexdump.hexdump(data, result="return")
+ data_string = data.hex()
+ parts = [_split_string(line, 2) for line in _split_string(data_string, line_length * 2)]
+ result = "\n".join(" ".join(line) for line in parts)
+ return result
+
+
+def get_dk6(ctx: click.Context) -> DK6Device:
+ """Get initialized DK6 Device from click context.
+
+ :param ctx: click Context
+ :raises SPSDKError: if the device ID is not specified
+ :return: DK6Device
+ """
+ dk6: DK6Device = ctx.obj["dk6"]
+ if dk6 is None:
+ raise SPSDKError("You have to specify DEVICE ID")
+ dk6.init()
+
+ return dk6
+
+
+def get_default_backend() -> Backend:
+ """Return default backend based on the operating system.
+
+ :return: Backend
+ """
+ try:
+ backend = {
+ "win32": Backend.FTD2xx,
+ "linux": Backend.PYFTDI,
+ "darwin": Backend.PYFTDI,
+ }[sys.platform]
+ except KeyError:
+ logger.warning(
+ f"Platform {sys.platform} is not supported. Only Windows, Linux or Mac are supported."
+ )
+ backend = Backend.PYFTDI
+ return backend
+
+
+@click.group(name="dk6prog", chain=True, no_args_is_help=True)
+@spsdk_apps_common_options
+@click.option(
+ "-d",
+ "--device-id",
+ help="DK6 Serial device ID, obtained by list command",
+)
+@click.option(
+ "-r",
+ "--baudrate",
+ default=115200,
+ help="Serial port baudrate. Default baud rate is 115200.",
+)
+@click.option(
+ "-b",
+ "--backend",
+ "backend",
+ type=click.Choice(Backend.__members__), # type: ignore
+ callback=lambda c, p, v: getattr(Backend, v) if v else None,
+ help="PYFTDI backend, pure Python implementation of libFTDI.\n"
+ + "PYLIBFTDI backend. Ctypes wrapper for libFTDI.\n"
+ + "FTD2XX backend. Ctypes wrapper for D2XX.\n"
+ + "PYSERIAL backend for simple UART",
+)
+@click.option(
+ "-n",
+ "--no-isp",
+ "no_isp",
+ is_flag=True,
+ default=False,
+ help="Do not send ISP sequence",
+)
+@click.pass_context
+def main(
+ ctx: click.Context,
+ device_id: str,
+ backend: Backend,
+ baudrate: int,
+ log_level: int,
+ no_isp: bool,
+) -> int:
+ """Tool for reading and programming flash memory of DK6 target devices.
+
+ !!! THIS IS AN EXPERIMENTAL UTILITY! USE WITH CAUTION !!!
+ """
+ spsdk_logger.install(level=log_level)
+ click.echo(WARNING_MSG)
+ backend = backend or get_default_backend()
+ interface = DriverInterface(backend)
+ if device_id is not None:
+ if not no_isp:
+ interface.go_to_isp(device_id)
+ interface.init_serial(device_id, baudrate)
+ dk6 = DK6Device(interface.get_serial())
+ dk6.init()
+ else:
+ dk6 = None
+
+ ctx.obj = {"backend": backend, "interface": interface, "dk6": dk6, "device_id": device_id}
+ return 0
+
+
+@main.command()
+@click.pass_context
+def listdev(ctx: click.Context) -> None:
+ """Prints the information about the connected devices.
+
+ DEVICE_ID identifier is a parameter used for identification of device in other commands.
+ """
+ interface: DriverInterface = ctx.obj["interface"]
+ click.echo("List of available devices:")
+ for device in interface.list_devices():
+ click.echo(device)
+
+
+@main.command()
+@click.pass_context
+def isp(ctx: click.Context) -> None:
+ """Issues ISP sequence as defined in Driver interface."""
+ interface: DriverInterface = ctx.obj["interface"]
+ device_id: str = ctx.obj["device_id"]
+ interface.go_to_isp(device_id)
+
+
+@main.command()
+@click.argument("address", type=INT(), required=True)
+@click.argument("length", type=INT(), required=True)
+@click.argument("memory_id", type=str, default="0", required=False)
+@click.option(
+ "-o",
+ "--out-file",
+ metavar="FILE",
+ type=click.File("wb"),
+ required=False,
+ help="Save output to file",
+)
+@click.option("-h", "--use-hexdump", is_flag=True, default=False, help="Use hexdump format")
+@click.option(
+ "-r",
+ "--relative",
+ is_flag=True,
+ default=False,
+ help="Use address relative to memory base address",
+)
+@click.pass_context
+def read(
+ ctx: click.Context,
+ address: int,
+ length: int,
+ memory_id: str,
+ out_file: click.File,
+ use_hexdump: bool,
+ relative: bool,
+) -> None:
+ """Reads the memory and writes it to the file or stdout.
+
+ Returns the contents of memory at the given , for a specified .
+
+ \b
+ ADDRESS - starting address
+ BYTE_COUNT - number of bytes to read
+ FILE - store result into this file, if not specified use stdout.
+ If needed specify MEMORY_ID argument, use '-' instead name of file
+ to print to stdout.
+ MEMORY_ID - id of memory to read from (default: 0)
+
+ \b
+ Available Memory IDs:
+ 0 or 'PFLASH'
+ 1 or 'pSECT'
+ 2 or 'pFlash'
+ 3 or 'Config'
+ 4 or 'EFUSE'
+ 5 or 'ROM'
+ 6 or 'RAM0'
+ 7 or 'RAM1'
+
+ """
+ dk6 = get_dk6(ctx)
+
+ memory = parse_memory_id(memory_id)
+
+ with progress_bar(label="Reading memory") as progress_callback:
+ data = dk6.read_memory(
+ memory,
+ address,
+ length,
+ progress_callback=progress_callback,
+ relative=relative,
+ )
+
+ click.echo(
+ f"Read {len(data)}/{length} bytes from {hex(address)}:{hex(address+len(data))} Memory ID: {memory_id}"
+ )
+ if len(data) > 0:
+ if out_file and out_file.name != "":
+ click.echo(f"Writing data to {out_file.name}")
+ out_file.write(data) # type: ignore
+ else:
+ click.echo(format_raw_data(data, use_hexdump=use_hexdump))
+
+
+@main.command()
+@click.argument("address", type=INT(), required=True)
+@click.argument("data_source", metavar="FILE[,BYTE_COUNT] | {{HEX-DATA}}", type=str, required=True)
+@click.argument("length", type=INT(), required=False)
+@click.argument("memory_id", type=str, default="0", required=False)
+@click.option(
+ "-r",
+ "--relative",
+ is_flag=True,
+ default=False,
+ help="Use address relative to memory base address",
+)
+@click.pass_context
+def write(
+ ctx: click.Context,
+ address: int,
+ data_source: str,
+ length: int,
+ memory_id: str,
+ relative: bool,
+) -> None:
+ """Write the memory.
+
+ Writes the data to memory.
+
+ \b
+ ADDRESS - starting address
+ FILE - write the content of this file
+ LENGTH - if specified, load only first LENGTH number of bytes from file
+ HEX-DATA - string of hex values: {{112233}}, {{11 22 33}}
+ MEMORY_ID - id of memory to read from (default: 0)
+
+ \b
+ Available Memory IDs:
+ 0 or 'PFLASH'
+ 1 or 'pSECT'
+ 2 or 'pFlash'
+ 3 or 'Config'
+ 4 or 'EFUSE'
+ 5 or 'ROM'
+ 6 or 'RAM0'
+ 7 or 'RAM1'
+
+ """
+ try:
+ data = parse_hex_data(data_source)
+ except SPSDKError:
+ file_path, length = parse_file_and_size(data_source)
+ with open(file_path, "rb") as f:
+ data = f.read(length)
+
+ if length == -1:
+ length = os.stat(file_path).st_size
+
+ dk6 = get_dk6(ctx)
+
+ memory = parse_memory_id(memory_id)
+
+ with progress_bar(label="Writing memory") as progress_callback:
+ dk6.write_memory(
+ memory,
+ address,
+ length,
+ data,
+ progress_callback=progress_callback,
+ relative=relative,
+ )
+
+ click.echo(f"Writen {length} bytes to memory ID {memory_id} at address {hex(address)}")
+
+ dk6.reset()
+
+
+@main.command()
+@click.argument("address", type=INT(), required=True)
+@click.argument("length", type=INT(), required=True)
+@click.argument("memory_id", type=str, default="0", required=False)
+@click.option(
+ "-r",
+ "--relative",
+ is_flag=True,
+ default=False,
+ help="Use address relative to memory base address",
+)
+@click.option(
+ "-v",
+ "--verify",
+ is_flag=True,
+ default=False,
+ help="Verify that the data were erase using blank check command",
+)
+@click.pass_context
+def erase(
+ ctx: click.Context,
+ address: int,
+ length: int,
+ memory_id: str,
+ relative: bool,
+ verify: bool,
+) -> None:
+ """Erase the memory.
+
+ Erase the content of memory at the given , for a specified .
+
+ \b
+ ADDRESS - starting address
+ LENGTH - count of bytes to be erased
+ MEMORY_ID - id of memory to erase (default: 0)
+
+ \b
+ Available Memory IDs:
+ 0 or 'PFLASH'
+ 1 or 'pSECT'
+ 2 or 'pFlash'
+ 3 or 'Config'
+ 4 or 'EFUSE'
+ 5 or 'ROM'
+ 6 or 'RAM0'
+ 7 or 'RAM1'
+
+ """
+ dk6 = get_dk6(ctx)
+
+ memory = parse_memory_id(memory_id)
+
+ with progress_bar(label="Erasing memory") as progress_callback:
+ dk6.erase_memory(
+ memory,
+ address,
+ length,
+ relative=relative,
+ verify=verify,
+ progress_callback=progress_callback,
+ )
+
+
+@main.command()
+@click.pass_context
+def info(ctx: click.Context) -> None:
+ """Prints the information about the connected device.
+
+ :param ctx: click Context
+ :raises SPSDKError: When the DEVICE ID is not specified
+ """
+ dk6: DK6Device = ctx.obj["dk6"]
+ if dk6 is None:
+ raise SPSDKError("You have to specify DEVICE ID")
+
+ if dk6.chip_id:
+ click.echo(
+ f"Chip ID: {hex(dk6.chip_id.chip_id)}\nROM Version: {hex(dk6.chip_id.chip_version)}"
+ )
+
+ click.echo(f"MAC Address: {dk6.get_mac_str()}\n")
+ click.echo(f"Detected DEVICE: {dk6.dev_type}\n")
+ click.echo(print_memory_table(dk6.memories))
+
+
+@catch_spsdk_error
+def safe_main() -> None:
+ """Calls the main function."""
+ sys.exit(main()) # pylint: disable=no-value-for-parameter
+
+
+if __name__ == "__main__":
+ safe_main()
diff --git a/spsdk/apps/elftosb.py b/spsdk/apps/elftosb.py
index 925d3ca0..d7230bdd 100644
--- a/spsdk/apps/elftosb.py
+++ b/spsdk/apps/elftosb.py
@@ -15,12 +15,14 @@
from spsdk import __version__ as spsdk_version
from spsdk.apps.utils.utils import SPSDKAppError, catch_spsdk_error
+from spsdk.crypto.signature_provider import get_signature_provider
from spsdk.exceptions import SPSDKError
from spsdk.image import TrustZone, get_mbi_class
from spsdk.image.mbimg import mbi_generate_config_templates, mbi_get_supported_families
from spsdk.sbfile.sb2.images import generate_SB21
from spsdk.sbfile.sb31.images import SB3_SCH_FILE, SecureBinary31
from spsdk.utils.misc import load_configuration, write_file
+from spsdk.utils.plugins import load_plugin_from_source
from spsdk.utils.schema_validator import ValidationSchemas, check_config
SUPPORTED_FAMILIES = mbi_get_supported_families()
@@ -92,6 +94,7 @@ def generate_secure_binary_21(
signing_certificate_file_paths: List[str],
root_key_certificate_paths: List[str],
hoh_out_path: str,
+ plugin: str,
external_files: List[str],
) -> None:
"""Generate SecureBinary image from BD command file.
@@ -108,17 +111,25 @@ def generate_secure_binary_21(
passed in signing_certificate_file_paths.
:param hoh_out_path: output path to hash of hashes of root keys. If set to
None, 'hash.bin' is created under working directory.
+ :param plugin: External python file containing a custom SignatureProvider implementation.
:param external_files: external files referenced from BD file.
:raises SPSDKAppError: If incorrect bf file is provided
"""
+ if plugin:
+ load_plugin_from_source(plugin)
if output_file_path is None:
raise SPSDKAppError("Error: no output file was specified")
+ signature_provider = (
+ get_signature_provider(local_file_key=private_key_file_path)
+ if os.path.isfile(private_key_file_path)
+ else get_signature_provider(sp_cfg=private_key_file_path)
+ )
try:
sb2_data = generate_SB21(
bd_file_path=str(bd_file_path),
key_file_path=str(key_file_path),
- private_key_file_path=str(private_key_file_path),
+ signature_provider=signature_provider,
signing_certificate_file_paths=[str(x) for x in signing_certificate_file_paths],
root_key_certificate_paths=[str(x) for x in root_key_certificate_paths],
hoh_out_path=str(hoh_out_path),
@@ -228,6 +239,12 @@ def generate_secure_binary_31(container_conf: str) -> None:
help="Path to output hash of hashes of root keys. If argument is not \
provided, then by default the tool creates hash.bin in the working directory.",
)
+@click.option(
+ "--plugin",
+ type=click.Path(exists=True, dir_okay=False),
+ required=False,
+ help="External python file containing a custom SignatureProvider implementation.",
+)
@click.version_option(spsdk_version, "--version")
@click.help_option("--help")
@click.argument("external", type=click.Path(), nargs=-1)
@@ -244,12 +261,14 @@ def main(
tzm_conf: str,
config_template: str,
hash_of_hashes: str,
+ plugin: str,
external: List[str],
) -> None:
"""Tool for generating TrustZone, MasterBootImage and SecureBinary images.
!!! The ELFTOSB tool is deprecated, use new NXPIMAGE tool from SPSDK for new projects !!!
"""
+ click.secho("Deprecated tool! Use npximage instead", fg="yellow")
if command:
if output is None:
raise SPSDKAppError("Error: no output file was specified")
@@ -261,6 +280,7 @@ def main(
signing_certificate_file_paths=cert,
root_key_certificate_paths=root_key_cert,
hoh_out_path=hash_of_hashes,
+ plugin=plugin,
external_files=external,
)
diff --git a/spsdk/apps/elftosb_utils/sb_31_helper.py b/spsdk/apps/elftosb_utils/sb_31_helper.py
index 4b9d9d53..eb410945 100644
--- a/spsdk/apps/elftosb_utils/sb_31_helper.py
+++ b/spsdk/apps/elftosb_utils/sb_31_helper.py
@@ -33,12 +33,14 @@ def __init__(self, data: dict, search_paths: Optional[List[str]] = None) -> None
check_config(data, val_schemas, search_paths=search_paths)
self.config_data = data
+ self.signature_provider_cfg = data.get("signProvider")
+
self.private_key = data.get("mainCertPrivateKeyFile") or data.get(
"mainRootCertPrivateKeyFile"
)
- if not self.private_key:
+ if not self.signature_provider_cfg and not self.private_key:
raise SPSDKError(
- "Private key not specified (mainCertPrivateKeyFile or mainRootCertPrivateKeyFile)"
+ "One of 'mainCertPrivateKeyFile', 'mainRootCertPrivateKeyFile', 'signProvider' must be specified."
)
self.public_keys = find_root_certificates(data)
data_main_cert_index = get_main_cert_index(data, search_paths=search_paths)
diff --git a/spsdk/apps/ifr.py b/spsdk/apps/ifr.py
index d06e5bdc..c7575294 100644
--- a/spsdk/apps/ifr.py
+++ b/spsdk/apps/ifr.py
@@ -115,7 +115,7 @@ def get_template(device: str, revision: str, output: str, full: bool) -> None:
ifr_obj = ROMCFG(device=device, revision=revision)
data = ifr_obj.get_yaml_config(not full)
yaml_data = ConfigTemplate.convert_cm_to_yaml(data)
- _store_output(yaml_data, output, msg=f"IFR configuration template has been created.")
+ _store_output(yaml_data, output, msg="IFR configuration template has been created.")
@main.command(name="parse-binary", no_args_is_help=True)
@@ -184,7 +184,7 @@ def generate_binary(output: str, user_config_file: str, device: str) -> None:
ifr_obj.set_config(ifr_config, raw=False)
data = ifr_obj.export()
- _store_output(data, output, "wb", msg=f"Success. (IFR binary has been generated)")
+ _store_output(data, output, "wb", msg="Success. (IFR binary has been generated)")
@main.command(name="write", no_args_is_help=True)
diff --git a/spsdk/apps/nxpcertgen.py b/spsdk/apps/nxpcertgen.py
index ef279b99..a1f56ab7 100644
--- a/spsdk/apps/nxpcertgen.py
+++ b/spsdk/apps/nxpcertgen.py
@@ -60,7 +60,11 @@ def __init__(self, config_data: dict) -> None:
@click.group(name="nxpcertgen", no_args_is_help=True, cls=CommandsTreeGroupAliasedGetCfgTemplate) # type: ignore
@spsdk_apps_common_options
def main(log_level: int) -> None:
- """Utility for certificate generation."""
+ """Utility for certificate generation.
+
+ !!! The NXPCERTGEN tool is deprecated, use new NXPCRYPTO tool from SPSDK for new projects !!!
+ """
+ click.secho("Deprecated tool! Use npxcrypto instead", fg="yellow")
spsdk_logger.install(level=log_level, logger=logger)
diff --git a/spsdk/apps/nxpcrypto.py b/spsdk/apps/nxpcrypto.py
index 06996ca6..08d6f931 100644
--- a/spsdk/apps/nxpcrypto.py
+++ b/spsdk/apps/nxpcrypto.py
@@ -9,7 +9,6 @@
import copy
import hashlib
-import logging
import os
import sys
from typing import Dict, Union
diff --git a/spsdk/apps/nxpdebugmbox.py b/spsdk/apps/nxpdebugmbox.py
index eb8aabcb..7c80bdbd 100644
--- a/spsdk/apps/nxpdebugmbox.py
+++ b/spsdk/apps/nxpdebugmbox.py
@@ -26,6 +26,7 @@
from spsdk.apps.utils.common_cli_options import (
CommandsTreeGroupAliasedGetCfgTemplate,
spsdk_apps_common_options,
+ spsdk_plugin_option,
)
from spsdk.apps.utils.utils import (
INT,
@@ -42,14 +43,8 @@
from spsdk.debuggers.utils import PROBES, open_debug_probe, test_ahb_access
from spsdk.exceptions import SPSDKValueError
from spsdk.utils.images import BinaryImage
-from spsdk.utils.misc import (
- find_file,
- import_source,
- load_binary,
- load_configuration,
- load_text,
- write_file,
-)
+from spsdk.utils.misc import find_file, load_binary, load_configuration, load_text, write_file
+from spsdk.utils.plugins import load_plugin_from_source
logger = logging.getLogger(__name__)
NXPDEBUGMBOX_DATA_FOLDER: str = os.path.join(SPSDK_DATA_FOLDER, "nxpdebugmbox")
@@ -97,8 +92,8 @@ def is_rsa(self) -> bool:
is_rsa = protocol_version[0] == "1"
return is_rsa
- def __post_init__(self) -> None:
- """Post init validation.
+ def validate(self) -> None:
+ """Validate protocol value.
:raises SPSDKValueError: In case that protocol is using unsupported key type.
"""
@@ -172,8 +167,7 @@ def _open_debugmbox(
"--protocol",
"protocol",
metavar="VERSION",
- default="1.0",
- help=f"Set the protocol version. Default is 1.0 (RSA). "
+ help=f"Set the protocol version. Currently this option is used for gendc and auth sub commands"
f'Available options are: {", ".join(DatProtocol.VERSIONS)}',
type=click.Choice(DatProtocol.VERSIONS),
)
@@ -187,7 +181,7 @@ def _open_debugmbox(
@click.option(
"-n",
"--no-reset",
- "reset",
+ "no_reset",
is_flag=True,
default=True,
help=(
@@ -218,7 +212,7 @@ def main(
timing: float,
serial_no: str,
debug_probe_option: List[str],
- reset: bool,
+ no_reset: bool,
operation_timeout: int,
) -> int:
"""Tool for working with Debug Mailbox."""
@@ -234,7 +228,7 @@ def main(
ctx.obj = {
"debug_mailbox_params": DebugMailboxParams(
- reset=reset, more_delay=timing, operation_timeout=operation_timeout
+ reset=no_reset, more_delay=timing, operation_timeout=operation_timeout
),
"debug_probe_params": DebugProbeParams(
interface=interface, serial_no=serial_no, debug_probe_user_params=probe_user_params
@@ -255,9 +249,22 @@ def main(
is_flag=True,
help="When used, exit debug mailbox command is not executed after debug authentication.",
)
+@click.option(
+ "-x",
+ "--nxp-keys",
+ type=bool,
+ is_flag=True,
+ default=False,
+ help="Use the ROM NXP keys to authenticate.",
+)
@click.pass_obj
-def auth_command(pass_obj: dict, beacon: int, certificate: str, key: str, no_exit: bool) -> None:
- """Perform the Debug Authentication."""
+def auth_command(
+ pass_obj: dict, beacon: int, certificate: str, key: str, no_exit: bool, nxp_keys: bool
+) -> None:
+ """Perform the Debug Authentication.
+
+ The -p protocol option must be defined in main application.
+ """
auth(
pass_obj["debug_probe_params"],
pass_obj["debug_mailbox_params"],
@@ -266,6 +273,7 @@ def auth_command(pass_obj: dict, beacon: int, certificate: str, key: str, no_exi
certificate,
key,
no_exit,
+ nxp_keys,
)
@@ -277,6 +285,7 @@ def auth(
certificate: str,
key: str,
no_exit: bool,
+ nxp_keys: bool,
) -> None:
"""Perform the Debug Authentication.
@@ -287,16 +296,25 @@ def auth(
:param certificate: Path to Debug Credentials.
:param key: Path to DCK private key.
:param no_exit: When true, exit debug mailbox command is not executed after debug authentication.
+ :param nxp_keys: When true, Use the ROM NXP keys to authenticate.
:raises SPSDKAppError: Raised if any error occurred.
"""
+ protocol.validate()
try:
logger.info("Starting Debug Authentication")
with _open_debugmbox(debug_probe_params, debug_mailbox_params) as mail_box:
debug_cred_data = load_binary(certificate)
debug_cred = DebugCredential.parse(debug_cred_data)
- dac_rsp_len = 30 if debug_cred.HASH_LENGTH == 48 and debug_cred.socc == 4 else 26
- dac_data = dm_commands.DebugAuthenticationStart(dm=mail_box, resplen=dac_rsp_len).run()
+ dac_rsp_len = 30 if debug_cred.HASH_LENGTH == 48 and debug_cred.socc in [4, 6] else 26
+ if nxp_keys:
+ dac_data = dm_commands.NxpDebugAuthenticationStart(
+ dm=mail_box, resplen=dac_rsp_len
+ ).run()
+ else:
+ dac_data = dm_commands.DebugAuthenticationStart(
+ dm=mail_box, resplen=dac_rsp_len
+ ).run()
# convert List[int] to bytes
dac_data_bytes = struct.pack(f"<{len(dac_data)}I", *dac_data)
dac = DebugAuthenticationChallenge.parse(dac_data_bytes)
@@ -313,9 +331,14 @@ def auth(
dar_data = dar.export()
# convert bytes to List[int]
dar_data_words = list(struct.unpack(f"<{len(dar_data) // 4}I", dar_data))
- dar_response = dm_commands.DebugAuthenticationResponse(
- dm=mail_box, paramlen=len(dar_data_words)
- ).run(dar_data_words)
+ if nxp_keys:
+ dar_response = dm_commands.NxpDebugAuthenticationResponse(
+ dm=mail_box, paramlen=len(dar_data_words)
+ ).run(dar_data_words)
+ else:
+ dar_response = dm_commands.DebugAuthenticationResponse(
+ dm=mail_box, paramlen=len(dar_data_words)
+ ).run(dar_data_words)
logger.debug(f"DAR response: {dar_response}")
if not no_exit:
exit_response = dm_commands.ExitDebugMailbox(dm=mail_box).run()
@@ -423,11 +446,11 @@ def start(debug_probe_params: DebugProbeParams, debug_mailbox_params: DebugMailb
@click.pass_obj
def exit_command(pass_obj: dict) -> None: # pylint: disable=redefined-builtin
"""Exit DebugMailBox."""
- exit(pass_obj["debug_probe_params"], pass_obj["debug_mailbox_params"])
+ exit_debug_mbox(pass_obj["debug_probe_params"], pass_obj["debug_mailbox_params"])
click.echo("Exit Debug Mailbox succeeded")
-def exit(
+def exit_debug_mbox(
debug_probe_params: DebugProbeParams, debug_mailbox_params: DebugMailboxParams
) -> None: # pylint: disable=redefined-builtin
"""Exit DebugMailBox.
@@ -532,7 +555,7 @@ def ispmode(
raise SPSDKAppError(f"Entering into ISP mode failed: {e}") from e
-@main.command(name="blankauth", no_args_is_help=True)
+@main.command(name="token_auth", no_args_is_help=True)
@click.option(
"-f", "--file", type=click.Path(), required=True, help="Path to token file (string hex format)."
)
@@ -543,19 +566,19 @@ def ispmode(
help="When used, exit debug mailbox command is not executed after debug authentication.",
)
@click.pass_obj
-def blankauth_command(pass_obj: dict, file: str, no_exit: bool) -> None:
- """Debug Authentication for Blank Device."""
- blankauth(pass_obj["debug_probe_params"], pass_obj["debug_mailbox_params"], file, no_exit)
- click.echo("Debug authentication for blank device succeeded")
+def token_auth_command(pass_obj: dict, file: str, no_exit: bool) -> None:
+ """Debug Authentication using token."""
+ token_auth(pass_obj["debug_probe_params"], pass_obj["debug_mailbox_params"], file, no_exit)
+ click.echo("Debug authentication using token succeeded")
-def blankauth(
+def token_auth(
debug_probe_params: DebugProbeParams,
debug_mailbox_params: DebugMailboxParams,
token_file: str,
no_exit: bool,
) -> None:
- """Debug Authentication for Blank Device.
+ """Debug Authentication using token.
:param debug_probe_params: DebugProbeParams object holding information about parameters for debug probe.
:param debug_mailbox_params: DebugMailboxParams object holding information about parameters for debugmailbox.
@@ -591,13 +614,15 @@ def blankauth(
if not ahb_access_granted:
raise SPSDKAppError("Access to AHB is not granted.")
- logger.info(f"Debug Authentication ends {res_str}{colorama.Fore.RESET}.")
+ logger.info(
+ f"Debug Authentication using token ends {res_str}{colorama.Fore.RESET}."
+ )
else:
logger.info(
- "Debug Authentication ends without exit and without test of AHB access."
+ "Debug Authentication using token ends without exit and without test of AHB access."
)
except Exception as e:
- raise SPSDKAppError(f"Debug authentication for blank device failed: {e}") from e
+ raise SPSDKAppError(f"Debug authentication using token failed: {e}") from e
@main.command(name="get-crp")
@@ -837,7 +862,7 @@ def get_uuid_command(pass_obj: dict) -> None:
if uuid:
click.echo(f"The device UUID is: {uuid.hex()}")
else:
- click.echo(f"The device UUID is not possible to retrieve from target.")
+ click.echo("The device UUID is not possible to retrieve from target.")
def get_uuid(
@@ -884,7 +909,7 @@ def get_uuid(
raise SPSDKAppError(f"Getting UUID from target failed: {e}") from e
if dac.uuid == bytes(16):
- logger.warning(f"The valid UUID is not included in DAC.")
+ logger.warning("The valid UUID is not included in DAC.")
logger.info(f"DAC info:\n {dac.info()}")
return None
@@ -915,12 +940,7 @@ def get_uuid(
default=False,
help="Force overwriting of an existing file. Create destination folder, if doesn't exist already.",
)
-@click.option(
- "--plugin",
- type=click.Path(exists=True, dir_okay=False),
- required=False,
- help="External python file containing a custom SignatureProvider implementation.",
-)
+@spsdk_plugin_option
@click.argument("dc_file_path", metavar="PATH", type=click.Path(file_okay=True))
@click.pass_obj
def gendc_command(
@@ -933,6 +953,8 @@ def gendc_command(
) -> None:
"""Generate debug certificate (DC).
+ The -p protocol option must be defined in main application.
+
\b
PATH - path to dc file
"""
@@ -965,9 +987,10 @@ def gendc(
:param force: Force overwriting of an existing file.
:raises SPSDKAppError: Raised if any error occurred.
"""
+ protocol.validate()
try:
if plugin:
- import_source(plugin)
+ load_plugin_from_source(plugin)
check_file_exists(dc_file_path, force)
logger.info("Loading configuration from yml file...")
yaml_content = load_configuration(config)
@@ -980,8 +1003,13 @@ def gendc(
yaml_content["rot_meta"] = [
find_file(x, search_paths=[elf2sb_config_dir]) for x in rot_info.public_keys
]
- assert rot_info.private_key
- yaml_content["rotk"] = find_file(rot_info.private_key, search_paths=[elf2sb_config_dir])
+ assert rot_info.private_key or rot_info.signature_provider_cfg
+ if rot_info.private_key:
+ yaml_content["rotk"] = find_file(
+ rot_info.private_key, search_paths=[elf2sb_config_dir]
+ )
+ if rot_info.signature_provider_cfg:
+ yaml_content["sign_provider"] = rot_info.signature_provider_cfg
yaml_content["rot_id"] = rot_info.public_key_index
# enforcing rot_id presence in yaml config...
diff --git a/spsdk/apps/nxpdevhsm.py b/spsdk/apps/nxpdevhsm.py
index d32f9128..7147bbeb 100644
--- a/spsdk/apps/nxpdevhsm.py
+++ b/spsdk/apps/nxpdevhsm.py
@@ -54,14 +54,7 @@
class DeviceHsm:
"""Class to handle device HSM provisioning procedure."""
- DEVBUFF_BASE = 0x20008000
DEVBUFF_SIZE = 0x100
-
- DEVBUFF_BASE0 = DEVBUFF_BASE
- DEVBUFF_BASE1 = DEVBUFF_BASE0 + DEVBUFF_SIZE
- DEVBUFF_BASE2 = DEVBUFF_BASE1 + DEVBUFF_SIZE
- DEVBUFF_BASE3 = DEVBUFF_BASE2 + DEVBUFF_SIZE
-
DEVBUFF_GEN_MASTER_SHARE_INPUT_SIZE = 16
DEVBUFF_GEN_MASTER_ENC_SHARE_OUTPUT_SIZE = 48
DEVBUFF_GEN_MASTER_ENC_MASTER_SHARE_OUTPUT_SIZE = 64
@@ -138,6 +131,14 @@ def __init__(
self.wrapped_cust_mk_sk = bytes()
self.final_sb = bytes()
self.family = family
+ self.devbuff_base = value_to_int(
+ self.database.get_device_value("devbuff_base_address", self.family)
+ )
+
+ def get_devbuff_base_address(self, index: int) -> int:
+ """Get devbuff base address."""
+ assert index < 4 and index >= 0
+ return self.devbuff_base + index * self.DEVBUFF_SIZE
def update_keyblob_offset(self) -> int:
"""Update keyblob offset based on family."""
@@ -364,19 +365,19 @@ def oem_generate_master_share(self, oem_share_input: bytes) -> Tuple[bytes, byte
:raises SPSDKError: In case of any vulnerability.
:return: Tuple with OEM generate master share outputs.
"""
- if not self.mboot.write_memory(self.DEVBUFF_BASE0, oem_share_input):
+ if not self.mboot.write_memory(self.devbuff_base, oem_share_input):
raise SPSDKError(
f"Cannot write OEM SHARE INPUT into device. Error: {self.mboot.status_string}"
)
oem_gen_master_share_res = self.mboot.tp_oem_gen_master_share(
- self.DEVBUFF_BASE0,
+ self.devbuff_base,
self.DEVBUFF_GEN_MASTER_SHARE_INPUT_SIZE,
- self.DEVBUFF_BASE1,
+ self.get_devbuff_base_address(1),
self.DEVBUFF_SIZE,
- self.DEVBUFF_BASE2,
+ self.get_devbuff_base_address(2),
self.DEVBUFF_SIZE,
- self.DEVBUFF_BASE3,
+ self.get_devbuff_base_address(3),
self.DEVBUFF_SIZE,
)
@@ -394,7 +395,7 @@ def oem_generate_master_share(self, oem_share_input: bytes) -> Tuple[bytes, byte
raise SPSDKError("OEM generate master share command has invalid results.")
oem_enc_share = self.mboot.read_memory(
- self.DEVBUFF_BASE1,
+ self.get_devbuff_base_address(1),
self.DEVBUFF_GEN_MASTER_ENC_SHARE_OUTPUT_SIZE,
)
if not oem_enc_share:
@@ -404,7 +405,7 @@ def oem_generate_master_share(self, oem_share_input: bytes) -> Tuple[bytes, byte
self.store_temp_res("ENC_OEM_SHARE.bin", oem_enc_share)
oem_enc_master_share = self.mboot.read_memory(
- self.DEVBUFF_BASE2,
+ self.get_devbuff_base_address(2),
self.DEVBUFF_GEN_MASTER_ENC_MASTER_SHARE_OUTPUT_SIZE,
)
if not oem_enc_master_share:
@@ -414,7 +415,7 @@ def oem_generate_master_share(self, oem_share_input: bytes) -> Tuple[bytes, byte
self.store_temp_res("ENC_OEM_MASTER_SHARE.bin", oem_enc_master_share)
oem_cert = self.mboot.read_memory(
- self.DEVBUFF_BASE3,
+ self.get_devbuff_base_address(3),
self.DEVBUFF_GEN_MASTER_CUST_CERT_PUK_OUTPUT_SIZE,
)
if not oem_cert:
@@ -438,9 +439,9 @@ def generate_key(
hsm_gen_key_res = self.mboot.tp_hsm_gen_key(
key_type,
0,
- self.DEVBUFF_BASE0,
+ self.devbuff_base,
self.DEVBUFF_SIZE,
- self.DEVBUFF_BASE1,
+ self.get_devbuff_base_address(1),
self.DEVBUFF_SIZE,
)
@@ -454,7 +455,7 @@ def generate_key(
raise SPSDKError("OEM generate master share command has invalid results.")
prk = self.mboot.read_memory(
- self.DEVBUFF_BASE0,
+ self.devbuff_base,
self.DEVBUFF_HSM_GENKEY_KEYBLOB_SIZE,
)
if not prk:
@@ -463,7 +464,7 @@ def generate_key(
)
puk = self.mboot.read_memory(
- self.DEVBUFF_BASE1,
+ self.get_devbuff_base_address(1),
self.DEVBUFF_HSM_GENKEY_KEYBLOB_PUK_SIZE,
)
if not puk:
@@ -483,7 +484,7 @@ def wrap_key(self, cust_mk_sk: bytes) -> bytes:
:raises SPSDKError: In case of any vulnerability.
:return: Wrapped CUST_MK_SK by RFC3396.
"""
- if not self.mboot.write_memory(self.DEVBUFF_BASE0, cust_mk_sk):
+ if not self.mboot.write_memory(self.devbuff_base, cust_mk_sk):
raise SPSDKError(
f"Cannot write CUST_MK_SK into device. Error: {self.mboot.status_string}"
)
@@ -491,9 +492,9 @@ def wrap_key(self, cust_mk_sk: bytes) -> bytes:
hsm_store_key_res = self.mboot.tp_hsm_store_key(
TrustProvKeyType.CKDFK,
0x01,
- self.DEVBUFF_BASE0,
+ self.devbuff_base,
self.DEVBUFF_CUST_MK_SK_KEY_SIZE,
- self.DEVBUFF_BASE1,
+ self.get_devbuff_base_address(1),
self.DEVBUFF_SIZE,
)
@@ -504,7 +505,7 @@ def wrap_key(self, cust_mk_sk: bytes) -> bytes:
raise SPSDKError("HSM Store Key command has invalid results.")
wrapped_cust_mk_sk = self.mboot.read_memory(
- self.DEVBUFF_BASE1,
+ self.get_devbuff_base_address(1),
self.DEVBUFF_WRAPPED_CUST_MK_SK_KEY_SIZE,
)
@@ -525,20 +526,20 @@ def sign_data_blob(self, data_to_sign: bytes, key: bytes) -> bytes:
:raises SPSDKError: In case of any vulnerability.
:return: Data blob signature (64 bytes).
"""
- if not self.mboot.write_memory(self.DEVBUFF_BASE0, key):
+ if not self.mboot.write_memory(self.devbuff_base, key):
raise SPSDKError(
f"Cannot write signing key into device. Error: {self.mboot.status_string}"
)
- if not self.mboot.write_memory(self.DEVBUFF_BASE1, data_to_sign):
+ if not self.mboot.write_memory(self.get_devbuff_base_address(1), data_to_sign):
raise SPSDKError(
f"Cannot write Data to sign into device. Error: {self.mboot.status_string}"
)
hsm_gen_key_res = self.mboot.tp_hsm_enc_sign(
- self.DEVBUFF_BASE0,
+ self.devbuff_base,
len(key),
- self.DEVBUFF_BASE1,
+ self.get_devbuff_base_address(1),
len(data_to_sign),
- self.DEVBUFF_BASE2,
+ self.get_devbuff_base_address(2),
self.DEVBUFF_SB3_SIGNATURE_SIZE,
)
@@ -549,7 +550,7 @@ def sign_data_blob(self, data_to_sign: bytes, key: bytes) -> bytes:
)
signature = self.mboot.read_memory(
- self.DEVBUFF_BASE2,
+ self.get_devbuff_base_address(2),
self.DEVBUFF_SB3_SIGNATURE_SIZE,
)
if not signature:
@@ -608,12 +609,12 @@ def encrypt_data_blocks(
:raises SPSDKError: In case of any vulnerability.
:return: List of encrypted command blocks on device.
"""
- if not self.mboot.write_memory(self.DEVBUFF_BASE0, cust_fw_enc_key):
+ if not self.mboot.write_memory(self.devbuff_base, cust_fw_enc_key):
raise SPSDKError(
f"Cannot write customer fw encryption key into device. Error: {self.mboot.status_string}"
)
self.store_temp_res("SB3_header.bin", sb3_header, "to_encrypt")
- if not self.mboot.write_memory(self.DEVBUFF_BASE1, sb3_header):
+ if not self.mboot.write_memory(self.get_devbuff_base_address(1), sb3_header):
raise SPSDKError(
f"Cannot write SB3 header into device. Error: {self.mboot.status_string}"
)
@@ -621,7 +622,7 @@ def encrypt_data_blocks(
encrypted_blocks = []
for data_cmd_block_ix, data_cmd_block in enumerate(data_cmd_blocks, start=1):
self.store_temp_res(f"SB3_block_{data_cmd_block_ix}.bin", data_cmd_block, "to_encrypt")
- if not self.mboot.write_memory(self.DEVBUFF_BASE2, data_cmd_block):
+ if not self.mboot.write_memory(self.get_devbuff_base_address(2), data_cmd_block):
raise SPSDKError(
f"Cannot write SB3 data block{data_cmd_block_ix} into device. "
f"Error: {self.mboot.status_string}"
@@ -630,13 +631,13 @@ def encrypt_data_blocks(
self.family, CmdLoadKeyBlob.KeyTypes.NXP_CUST_KEK_INT_SK
)
if not self.mboot.tp_hsm_enc_blk(
- self.DEVBUFF_BASE0,
+ self.devbuff_base,
len(cust_fw_enc_key),
key_id,
- self.DEVBUFF_BASE1,
+ self.get_devbuff_base_address(1),
len(sb3_header),
data_cmd_block_ix,
- self.DEVBUFF_BASE2,
+ self.get_devbuff_base_address(2),
self.DEVBUFF_DATA_BLOCK_SIZE,
):
raise SPSDKError(
@@ -645,7 +646,7 @@ def encrypt_data_blocks(
)
encrypted_block = self.mboot.read_memory(
- self.DEVBUFF_BASE2,
+ self.get_devbuff_base_address(2),
self.DEVBUFF_DATA_BLOCK_SIZE,
)
if not encrypted_block:
@@ -707,7 +708,7 @@ def main(log_level: int) -> int:
@main.command(no_args_is_help=True)
-@isp_interfaces(uart=True, usb=True, lpcusbsio=True, buspal=True, json_option=False)
+@isp_interfaces(uart=True, usb=True, sdio=True, lpcusbsio=True, buspal=True, json_option=False)
@click.option(
"-k",
"--key",
@@ -768,6 +769,7 @@ def main(log_level: int) -> int:
def generate(
port: str,
usb: str,
+ sdio: str,
buspal: str,
lpcusbsio: str,
oem_share_input: str,
diff --git a/spsdk/apps/nxpdevscan.py b/spsdk/apps/nxpdevscan.py
index b22ff965..921b8c73 100644
--- a/spsdk/apps/nxpdevscan.py
+++ b/spsdk/apps/nxpdevscan.py
@@ -7,7 +7,6 @@
"""NXP USB Device Scanner."""
-import logging
import sys
from typing import IO
@@ -46,6 +45,13 @@
flag_value="usb",
help="Search only for USB devices",
)
+@optgroup.option(
+ "-sd",
+ "--sdio",
+ "scope",
+ flag_value="sdio",
+ help="Search only for SDIO devices",
+)
@optgroup.option(
"-p",
"--port",
@@ -66,6 +72,14 @@ def main(extend_vids: str, out: IO[str], scope: str, log_level: int) -> None:
spsdk_logger.install(level=log_level)
additional_vids = [int(vid, 16) for vid in extend_vids]
+ if scope in ["all", "sdio"]:
+ nxp_sdio_devices = nxpdevscan.search_nxp_sdio_devices()
+ if out.name == "":
+ click.echo(8 * "-" + " Connected NXP SDIO Devices " + 8 * "-" + "\n", out)
+ for sdio_dev in nxp_sdio_devices:
+ click.echo(sdio_dev.info(), out)
+ click.echo("", out)
+
if scope in ["all", "usb"]:
nxp_usb_devices = nxpdevscan.search_nxp_usb_devices(additional_vids)
if out.name == "":
diff --git a/spsdk/apps/nxpimage.py b/spsdk/apps/nxpimage.py
index 416537e7..f8bc5232 100644
--- a/spsdk/apps/nxpimage.py
+++ b/spsdk/apps/nxpimage.py
@@ -6,6 +6,7 @@
# SPDX-License-Identifier: BSD-3-Clause
"""NXP MCU Image tool."""
+import datetime
import logging
import os
import sys
@@ -15,7 +16,11 @@
import click
from spsdk.apps.utils import spsdk_logger
-from spsdk.apps.utils.common_cli_options import CommandsTreeGroup, spsdk_apps_common_options
+from spsdk.apps.utils.common_cli_options import (
+ CommandsTreeGroup,
+ spsdk_apps_common_options,
+ spsdk_plugin_option,
+)
from spsdk.apps.utils.utils import (
INT,
SPSDKAppError,
@@ -24,6 +29,7 @@
get_key,
store_key,
)
+from spsdk.crypto.signature_provider import get_signature_provider
from spsdk.exceptions import SPSDKError
from spsdk.image import TrustZone, get_mbi_class
from spsdk.image.ahab.ahab_container import AHABImage
@@ -34,7 +40,11 @@
from spsdk.image.hab.config_parser import ImageConfig
from spsdk.image.hab.hab_container import HabContainer
from spsdk.image.keystore import KeyStore
-from spsdk.image.mbimg import mbi_generate_config_templates, mbi_get_supported_families
+from spsdk.image.mbimg import (
+ MasterBootImage,
+ mbi_generate_config_templates,
+ mbi_get_supported_families,
+)
from spsdk.image.xmcd.xmcd import XMCD
from spsdk.sbfile.sb2 import sly_bd_parser as bd_parser
from spsdk.sbfile.sb2.commands import CmdLoad
@@ -48,14 +58,19 @@
align,
align_block,
get_abs_path,
- import_source,
load_binary,
load_configuration,
load_text,
value_to_int,
write_file,
)
-from spsdk.utils.schema_validator import ConfigTemplate, ValidationSchemas, check_config
+from spsdk.utils.plugins import load_plugin_from_source
+from spsdk.utils.schema_validator import (
+ CommentedConfig,
+ ConfigTemplate,
+ ValidationSchemas,
+ check_config,
+)
logger = logging.getLogger(__name__)
@@ -77,12 +92,8 @@ def mbi_group() -> None:
@mbi_group.command(name="export", no_args_is_help=True)
-@click.option(
- "--plugin",
- required=False,
- help="External python file/package containing a custom SignatureProvider implementation.",
-)
@click.argument("config", type=click.Path(exists=True, readable=True))
+@spsdk_plugin_option
def mbi_export_command(
config: str,
plugin: str,
@@ -104,7 +115,7 @@ def mbi_export(config: str, plugin: Optional[str] = None) -> None:
"""
config_data = load_configuration(config)
if plugin:
- import_source(plugin)
+ load_plugin_from_source(plugin)
config_dir = os.path.dirname(config)
mbi_cls = get_mbi_class(config_data)
check_config(config_data, mbi_cls.get_validation_schemas(), search_paths=[config_dir])
@@ -118,6 +129,54 @@ def mbi_export(config: str, plugin: Optional[str] = None) -> None:
click.echo(f"Success. (Master Boot Image: {mbi_output_file_path} created.)")
+@mbi_group.command(name="parse", no_args_is_help=True)
+@click.option(
+ "-f",
+ "--chip-family",
+ default="lpc55s3x",
+ type=click.Choice(mbi_get_supported_families(), case_sensitive=False),
+ required=True,
+ help="Select the chip family.",
+)
+@click.option(
+ "-b",
+ "--binary",
+ type=click.Path(exists=True, readable=True, resolve_path=True),
+ required=True,
+ help="Path to binary MBI image to parse.",
+)
+@click.option(
+ "-k",
+ "--dek",
+ type=str,
+ required=False,
+ help=(
+ "Data encryption key, if it's specified, the parse method tries decrypt all encrypted images. "
+ "It could be specified as binary/HEX text file path or directly HEX string"
+ ),
+)
+@click.argument("parsed-data", type=click.Path(resolve_path=True))
+def mbi_parse_command(chip_family: str, binary: str, dek: str, parsed_data: str) -> None:
+ """Parse MBI Image into YAML configuration and binary images."""
+ mbi_parse(chip_family, binary, dek, parsed_data)
+
+
+def mbi_parse(chip_family: str, binary: str, dek: str, parsed_data: str) -> None:
+ """Parse AHAB Image into YAML configuration and binary images."""
+ if not os.path.exists(parsed_data):
+ os.makedirs(parsed_data, exist_ok=True)
+
+ mbi = MasterBootImage.parse(family=chip_family, data=load_binary(binary), dek=dek)
+
+ if not mbi:
+ click.echo(f"Failed. (MBI: {binary} parsing failed.)")
+ return
+
+ mbi.create_config(output_folder=parsed_data)
+
+ click.echo(f"Success. (MBI: {binary} has been parsed and stored into {parsed_data} )")
+
+
@mbi_group.command(name="get-templates", no_args_is_help=True)
@click.option(
"-f",
@@ -172,7 +231,12 @@ def sb21_group() -> None:
@click.option(
"-k", "--key", type=click.Path(exists=True), help="Add a key file and enable encryption."
)
-@click.option("-s", "--pkey", type=click.Path(exists=True), help="Path to private key for signing.")
+@click.option(
+ "-s",
+ "--pkey",
+ type=str,
+ help="Path to private key or signature provider configuration used for signing.",
+)
@click.option(
"-S",
"--cert",
@@ -198,6 +262,12 @@ def sb21_group() -> None:
help="Path to output hash of hashes of root keys. If argument is not \
provided, then by default the tool creates hash.bin in the working directory.",
)
+@click.option(
+ "--plugin",
+ type=click.Path(exists=True, dir_okay=False),
+ required=False,
+ help="External python file containing a custom SignatureProvider implementation.",
+)
@click.argument("external", type=click.Path(), nargs=-1)
def sb21_export_command(
command: str,
@@ -207,13 +277,14 @@ def sb21_export_command(
cert: List[str],
root_key_cert: List[str],
hash_of_hashes: str,
+ plugin: str,
external: List[str],
) -> None:
"""Generate Secure Binary v2.1 Image from configuration.
EXTERNAL is a space separated list of external binary files defined in BD file
"""
- sb21_export(command, output, key, pkey, cert, root_key_cert, hash_of_hashes, external)
+ sb21_export(command, output, key, pkey, cert, root_key_cert, hash_of_hashes, plugin, external)
def sb21_export(
@@ -224,16 +295,25 @@ def sb21_export(
cert: List[str],
root_key_cert: List[str],
hash_of_hashes: str,
+ plugin: str,
external: List[str],
) -> None:
"""Generate Secure Binary v2.1 Image from configuration."""
+ if plugin:
+ load_plugin_from_source(plugin)
if output is None:
raise SPSDKAppError("Error: no output file was specified")
+ signature_provider = (
+ get_signature_provider(local_file_key=pkey)
+ if os.path.isfile(pkey)
+ else get_signature_provider(sp_cfg=pkey)
+ )
+
try:
sb2_data = generate_SB21(
bd_file_path=command,
key_file_path=key,
- private_key_file_path=pkey,
+ signature_provider=signature_provider,
signing_certificate_file_paths=cert,
root_key_certificate_paths=root_key_cert,
hoh_out_path=hash_of_hashes,
@@ -285,7 +365,7 @@ def sb21_parse(binary: str, key: str, parsed_data: str) -> None:
logger.debug(f"Dumping certificate {file_name}")
write_file(certificate.dump(), file_name, mode="wb")
- for section_idx, boot_sections in enumerate(parsed_sb._boot_sections):
+ for section_idx, boot_sections in enumerate(parsed_sb.boot_sections):
for command_idx, command in enumerate(boot_sections._commands):
if isinstance(command, CmdLoad):
file_name = os.path.abspath(
@@ -726,7 +806,15 @@ def ahab_parse(chip_family: str, image_type: str, binary: str, dek: str, parsed_
config = ahab_image.create_config(parsed_data)
write_file(
- ConfigTemplate.convert_cm_to_yaml(config),
+ CommentedConfig(
+ main_title=(
+ f"AHAB recreated configuration from :"
+ f"{datetime.datetime.now().strftime('%d/%m/%Y %H:%M:%S')}."
+ ),
+ schemas=AHABImage.get_validation_schemas(),
+ values=config,
+ export_template=False,
+ ).export_to_yaml(),
os.path.join(parsed_data, "parsed_config.yaml"),
)
click.echo(f"Success. (AHAB: {binary} has been parsed and stored into {parsed_data}.)")
@@ -1008,7 +1096,7 @@ def otfad_export(alignment: int, config: str, index: Optional[int] = None) -> No
write_file(blhost_script, blhost_script_filename)
click.echo(f"Created OTFAD BLHOST load fuses script:\n{blhost_script_filename}")
- click.echo(f"Success. OTFAD files have been created")
+ click.echo("Success. OTFAD files have been created")
@otfad_group.command(name="get-kek", no_args_is_help=False)
@@ -1160,7 +1248,7 @@ def iee_export(config: str) -> None:
"Output folder contains:\n"
" - Binary file that contains whole image data including "
f"IEE key blobs data {iee_all}.\n"
- f"\IEE memory map:\n{binary_image.draw(no_color=True)}"
+ f"IEE memory map:\n{binary_image.draw(no_color=True)}"
)
for image in binary_image.sub_images:
@@ -1179,7 +1267,7 @@ def iee_export(config: str) -> None:
write_file(memory_map, readme_file)
logger.info(f"Created IEE readme file:\n{readme_file}")
else:
- logger.info(f"Skipping generation of IEE readme file")
+ logger.info("Skipping generation of IEE readme file")
if iee.database.get_device_value("has_kek_fuses", iee.family) and config_data.get(
"generate_fuses_script"
@@ -1191,7 +1279,7 @@ def iee_export(config: str) -> None:
else:
logger.info("Skipping generation of IEE BLHOST load fuses script")
- click.echo(f"Success. IEE files have been created")
+ click.echo("Success. IEE files have been created")
@iee_group.command(name="get-template", no_args_is_help=True)
@@ -1939,6 +2027,7 @@ def binary_get_template(overwrite: bool, output: str) -> None:
@click.option(
"-i",
"--input",
+ "input_file",
type=click.Path(file_okay=True, dir_okay=False, resolve_path=True),
required=True,
help="Binary file name to be aligned.",
@@ -1946,6 +2035,7 @@ def binary_get_template(overwrite: bool, output: str) -> None:
@click.option(
"-o",
"--output",
+ "output_file",
type=click.Path(resolve_path=True),
help="Aligned file name. If not specified, input file will be updated.",
)
@@ -1963,33 +2053,34 @@ def binary_get_template(overwrite: bool, output: str) -> None:
default="zeros",
help="Pattern of used padding ('zeros', 'ones', 'rand', 'inc' or any number value).",
)
-def binary_align_command(input: str, output: str, alignment: int, pattern: str) -> None:
+def binary_align_command(input_file: str, output_file: str, alignment: int, pattern: str) -> None:
"""Align binary file to provided alignment and padded with specified pattern."""
- binary_align(input, output, alignment, pattern)
+ binary_align(input_file, output_file, alignment, pattern)
def binary_align(
- input: str, output: Optional[str] = None, alignment: int = 1, pattern: str = "zeros"
+ input_file: str, output_file: Optional[str] = None, alignment: int = 1, pattern: str = "zeros"
) -> None:
"""Align binary file to provided alignment and padded with specified pattern.
- :param input: Input file name.
- :param output: Output file name. If not specified, input file will be updated.
+ :param input_file: Input file name.
+ :param output_file: Output file name. If not specified, input file will be updated.
:param alignment: Size of alignment block.
:param pattern: Padding pattern.
:raises SPSDKError: Invalid input arguments.
"""
- if not input or not os.path.isfile(input):
+ if not input_file or not os.path.isfile(input_file):
raise SPSDKError("Binary file alignment: Invalid input file")
if alignment <= 0:
raise SPSDKError("Binary file alignment: Alignment value must be 1 or greater.")
- if not output:
- output = input
- binary = align_block(data=load_binary(input), alignment=alignment, padding=pattern)
- write_file(binary, output, mode="wb")
+ if not output_file:
+ output_file = input_file
+ binary = align_block(data=load_binary(input_file), alignment=alignment, padding=pattern)
+ write_file(binary, output_file, mode="wb")
click.echo(
- f"The {input} file has been aligned to {len(binary)} ({hex(len(binary))}) bytes and stored into {output}"
+ f"The {input_file} file has been aligned to {len(binary)} ({hex(len(binary))}) bytes \
+ and stored into {output_file}"
)
@@ -1997,6 +2088,7 @@ def binary_align(
@click.option(
"-i",
"--input",
+ "input_file",
type=click.Path(file_okay=True, dir_okay=False, resolve_path=True),
required=True,
help="Binary file name to be padded.",
@@ -2021,34 +2113,35 @@ def binary_align(
default="zeros",
help="Pattern of used padding ('zeros', 'ones', 'rand', 'inc' or any number value).",
)
-def binary_pad_command(input: str, output: str, size: int, pattern: str) -> None:
+def binary_pad_command(input_file: str, output: str, size: int, pattern: str) -> None:
"""Pad binary file to provided final size with specified pattern."""
- binary_pad(input, output, size, pattern)
+ binary_pad(input_file, output, size, pattern)
def binary_pad(
- input: str, output: Optional[str] = None, size: int = 1, pattern: str = "zeros"
+ input_file: str, output: Optional[str] = None, size: int = 1, pattern: str = "zeros"
) -> None:
"""Pad binary file to provided final size with specified pattern.
- :param input: Input file name.
+ :param input_file: Input file name.
:param output: Output file name. If not specified, input file will be updated.
:param size: Final size of file.
:param pattern: Padding pattern.
:raises SPSDKError: Invalid input arguments.
"""
- if not input or not os.path.isfile(input):
+ if not input_file or not os.path.isfile(input_file):
raise SPSDKError("Binary file alignment: Invalid input file")
if not output:
- output = input
- binary = load_binary(input)
+ output = input_file
+ binary = load_binary(input_file)
if len(binary) < size:
binary = align_block(data=binary, alignment=size, padding=pattern)
write_file(binary, output, mode="wb")
click.echo(
- f"The {input} file has been padded to {len(binary)} ({hex(len(binary))}) byte size and stored into {output}"
+ f"The {input_file} file has been padded to {len(binary)} ({hex(len(binary))}) byte size\
+ and stored into {output}"
)
@@ -2153,6 +2246,7 @@ def convert_bin2hex(input_file: str, reverse: bool, output: str) -> None:
@click.option(
"-t",
"--type",
+ "output_type",
type=click.Choice(["uint8_t", "uint16_t", "uint32_t", "uint64_t"]),
default="uint8_t",
help="The output C array type.",
@@ -2195,7 +2289,7 @@ def convert_bin2hex(input_file: str, reverse: bool, output: str) -> None:
def convert_bin2carr(
input_file: str,
name: str,
- type: str,
+ output_type: str,
endian: str,
padding: str,
count_per_line: int,
@@ -2208,7 +2302,7 @@ def convert_bin2carr(
converted to 16/32 or 64 bit unsigned types with specified endianness.
"""
raw_binary = load_binary(input_file)
- width = {"uint8_t": 1, "uint16_t": 2, "uint32_t": 4, "uint64_t": 8}[type]
+ width = {"uint8_t": 1, "uint16_t": 2, "uint32_t": 4, "uint64_t": 8}[output_type]
if len(raw_binary) != align(len(raw_binary), width) and padding is None:
raise SPSDKAppError("Unaligned binary image, if still to be used, define '-p' padding.")
@@ -2220,7 +2314,7 @@ def convert_bin2carr(
count = rest_bytes // width
name = name or os.path.splitext(os.path.basename(input_file))[0]
index = 0
- ret = f"const {type} {name}[{count}] = {{\n"
+ ret = f"const {output_type} {name}[{count}] = {{\n"
while rest_bytes:
line_cnt = min(count_per_line, rest_bytes // width)
comment = f"// 0x{index:09_X}"
diff --git a/spsdk/apps/nxpkeygen.py b/spsdk/apps/nxpkeygen.py
index 3f0293c0..b2a4dfb8 100644
--- a/spsdk/apps/nxpkeygen.py
+++ b/spsdk/apps/nxpkeygen.py
@@ -83,6 +83,8 @@ def get_list_of_supported_keys() -> List[str]:
def main(log_level: int, key_type: str, path: str, password: str, force: bool) -> int:
"""NXP Key Generator Tool.
+ !!! The NXPKEYGEN tool is deprecated, use new NXPCRYPTO tool from SPSDK for new projects !!!
+
\b
PATH - output file path, where the key pairs (private and public key) will be stored.
Each key will be stored in separate file (.pub and .pem).
diff --git a/spsdk/apps/pfr.py b/spsdk/apps/pfr.py
index efdf5976..9142bf07 100644
--- a/spsdk/apps/pfr.py
+++ b/spsdk/apps/pfr.py
@@ -293,7 +293,7 @@ def generate_binary(
if not pfr_config.revision:
pfr_config.revision = pfr_obj.revision
data = pfr_obj.export(add_seal=add_seal, keys=keys)
- _store_output(data, output, "wb", msg=f"Success. (PFR binary has been generated)")
+ _store_output(data, output, "wb", msg="Success. (PFR binary has been generated)")
@main.command(name="info", no_args_is_help=True)
@@ -321,7 +321,7 @@ def info(device: str, revision: str, area: str, output: str, open_result: bool)
regs_exclude=["SHA256_DIGEST"],
fields_exclude=["FIELD"],
)
- _store_output(html_output, output, msg=f"Success. (PFR info HTML page has been generated)")
+ _store_output(html_output, output, msg="Success. (PFR info HTML page has been generated)")
if open_result: # pragma: no cover # can't test opening the html document
click.launch(f"{output}")
diff --git a/spsdk/apps/sdphost.py b/spsdk/apps/sdphost.py
index f3cfb34b..37cab256 100644
--- a/spsdk/apps/sdphost.py
+++ b/spsdk/apps/sdphost.py
@@ -9,7 +9,6 @@
import inspect
import json
-import logging
import sys
from typing import Optional
diff --git a/spsdk/apps/sdpshost.py b/spsdk/apps/sdpshost.py
index b972e905..5abdc160 100644
--- a/spsdk/apps/sdpshost.py
+++ b/spsdk/apps/sdpshost.py
@@ -7,7 +7,6 @@
"""Console script for SDPS module aka SDPSHost."""
-import logging
import sys
import click
@@ -18,14 +17,10 @@
isp_interfaces,
spsdk_apps_common_options,
)
-from spsdk.apps.utils.utils import catch_spsdk_error, get_interface
+from spsdk.apps.utils.utils import WARNING_MSG, catch_spsdk_error, get_interface
from spsdk.sdp import SDPS
from spsdk.sdp.sdps import ROM_INFO
-WARNING_MSG = """
-!!! THIS IS AN EXPERIMENTAL UTILITY! USE WITH CAUTION !!!
-"""
-
@click.group(name="sdpshost", no_args_is_help=True, cls=CommandsTreeGroup)
@isp_interfaces(uart=True, usb=True, is_sdp=True, json_option=False)
@@ -57,7 +52,6 @@ def write_file(ctx: click.Context, bin_file: click.File) -> None:
\b
FILE - binary file to write
"""
- click.echo(WARNING_MSG)
data = bin_file.read() # type: ignore
with SDPS(ctx.obj["interface"], device_name=ctx.obj["name"]) as sdps:
sdps.write_file(data)
diff --git a/spsdk/apps/spsdk_apps.py b/spsdk/apps/spsdk_apps.py
index e15c356c..4f8f3180 100644
--- a/spsdk/apps/spsdk_apps.py
+++ b/spsdk/apps/spsdk_apps.py
@@ -20,6 +20,7 @@
from spsdk.apps.utils.common_cli_options import CommandsTreeGroup
from .blhost import main as blhost_main
+from .dk6prog import main as dk6prog_main
from .elftosb import main as elftosb_main
from .ifr import main as ifr_main
from .nxpcertgen import main as nxpcertgen_main
@@ -64,6 +65,8 @@ def main() -> int:
main.add_command(sdphost_main, name="sdphost")
main.add_command(sdpshost_main, name="sdpshost")
main.add_command(shadowregs_main, name="shadowregs")
+main.add_command(dk6prog_main, name="dk6prog")
+
if TP:
main.add_command(tpconfig_main, name="tpconfig")
main.add_command(tphost_main, name="tphost")
diff --git a/spsdk/apps/tpconfig.py b/spsdk/apps/tpconfig.py
index 50590048..1016d971 100644
--- a/spsdk/apps/tpconfig.py
+++ b/spsdk/apps/tpconfig.py
@@ -6,7 +6,6 @@
# SPDX-License-Identifier: BSD-3-Clause
"""Console script for Trust provisioning config application."""
-import logging
import os
import sys
from typing import List
diff --git a/spsdk/apps/tphost.py b/spsdk/apps/tphost.py
index 4846b6da..612166f9 100644
--- a/spsdk/apps/tphost.py
+++ b/spsdk/apps/tphost.py
@@ -33,10 +33,12 @@
)
from spsdk.apps.utils.utils import SPSDKAppError
from spsdk.crypto import Encoding, ec
-from spsdk.crypto.loaders import extract_public_key, load_certificate
+from spsdk.crypto.loaders import extract_public_key, load_certificate_from_data
+from spsdk.exceptions import SPSDKError
from spsdk.tp import TP_DATA_FOLDER, TpDevInterface, TpTargetInterface, TrustProvisioningHost
from spsdk.tp.data_container import Container
from spsdk.tp.data_container.payload_types import PayloadType
+from spsdk.tp.exceptions import SPSDKTpError
from spsdk.tp.utils import (
get_supported_devices,
reconstruct_cryptography_key,
@@ -489,9 +491,9 @@ def get_tp_response(
@click.option(
"-r",
"--root-cert",
- help="NXP Glob Root Certificate authority certificate.", # type: ignore # not sure what is mypy on about
+ help="NXP Glob Root Certificate authority certificate.",
type=click.Path(exists=True, dir_okay=False),
- required=True,
+ required=False,
)
@click.option(
"-i",
@@ -517,23 +519,38 @@ def check_cot(root_cert: str, intermediate_cert: str, tp_response: str) -> None:
Default file name for TP_RESPONSE is `x_tp_response.bin`.
"""
overall_result = True
- nxp_glob_puk = extract_public_key(root_cert)
- nxp_prod_cert = load_certificate(intermediate_cert)
- assert isinstance(nxp_glob_puk, ec.EllipticCurvePublicKey)
- message = "validating NXP_PROD_CERT signature..."
+ nxp_glob_puk = extract_public_key(root_cert) if root_cert else None
+ if not nxp_glob_puk:
+ click.echo("NXP_GLOB key/cert not specified. NXP_PROD cert verification will be skipped.")
+
+ nxp_prod_cert_data = load_binary(intermediate_cert)
try:
- assert nxp_prod_cert.signature_hash_algorithm
- nxp_glob_puk.verify(
- nxp_prod_cert.signature,
- nxp_prod_cert.tbs_certificate_bytes,
- ec.ECDSA(nxp_prod_cert.signature_hash_algorithm),
- )
- message += "OK"
- except Exception:
- message += "FAILED!"
- overall_result = False
- click.echo(message)
+ nxp_prod_cert = load_certificate_from_data(nxp_prod_cert_data)
+ nxp_prod_puk = nxp_prod_cert.public_key()
+ except SPSDKError as e:
+ logging.debug(str(e))
+ if nxp_glob_puk:
+ raise SPSDKAppError(f"Unable to load NXP_PROD certificate: {str(e)}") from e
+ click.echo("Failed to load NXP_PROD as certificate, attempting to load raw public key")
+ nxp_prod_puk = reconstruct_cryptography_key(key_material=nxp_prod_cert_data)
+ assert isinstance(nxp_prod_puk, ec.EllipticCurvePublicKey)
+
+ if nxp_glob_puk:
+ assert isinstance(nxp_glob_puk, ec.EllipticCurvePublicKey)
+ message = "validating NXP_PROD_CERT signature..."
+ try:
+ assert nxp_prod_cert.signature_hash_algorithm
+ nxp_glob_puk.verify(
+ nxp_prod_cert.signature,
+ nxp_prod_cert.tbs_certificate_bytes,
+ ec.ECDSA(nxp_prod_cert.signature_hash_algorithm),
+ )
+ message += "OK"
+ except Exception:
+ message += "FAILED!"
+ overall_result = False
+ click.echo(message)
message = "Parsing TP_RESPONSE data container..."
try:
@@ -559,7 +576,6 @@ def check_cot(root_cert: str, intermediate_cert: str, tp_response: str) -> None:
assert nxp_die_cert
message = "Validating NXP_DIE_ID_Devattest_CERT signature..."
- nxp_prod_puk = nxp_prod_cert.public_key()
if nxp_die_cert.validate(nxp_prod_puk): # type: ignore
message += "OK"
else:
@@ -568,7 +584,10 @@ def check_cot(root_cert: str, intermediate_cert: str, tp_response: str) -> None:
click.echo(message)
message = "Validating TP_RESPONSE signature..."
- nxp_die_puk_data = nxp_die_cert.get_entry(PayloadType.NXP_DIE_ID_AUTH_PUK).payload
+ try:
+ nxp_die_puk_data = nxp_die_cert.get_entry(PayloadType.NXP_DIE_ATTEST_AUTH_PUK).payload
+ except SPSDKTpError:
+ nxp_die_puk_data = nxp_die_cert.get_entry(PayloadType.NXP_DIE_ID_AUTH_PUK).payload
nxp_die_puk = reconstruct_cryptography_key(nxp_die_puk_data)
if tp_response_container.validate(nxp_die_puk): # type: ignore
message += "OK"
diff --git a/spsdk/apps/utils/common_cli_options.py b/spsdk/apps/utils/common_cli_options.py
index 7b8d1ca5..0ac3decc 100644
--- a/spsdk/apps/utils/common_cli_options.py
+++ b/spsdk/apps/utils/common_cli_options.py
@@ -48,6 +48,19 @@
""",
)
+_sdio_option = click.option(
+ "-sd",
+ "--sdio",
+ metavar="SDIO_PATH|DEV_NAME",
+ help="""SDIO device identifier.
+
+ \b
+ Following formats are supported: device/instance path, device name.
+ device/instance path: device string; e.g. /dev/mcu-sdio.
+ Use 'nxpdevscan' utility to list connected device names.
+""",
+)
+
_lpcusbsio_option = click.option(
"-l",
"--lpcusbsio",
@@ -139,9 +152,22 @@ def spsdk_apps_common_options(options: FC) -> FC:
return options
+def spsdk_plugin_option(options: FC) -> FC:
+ """Plugin click option decorator.
+
+ :return: Click decorator
+ """
+ return click.option(
+ "--plugin",
+ required=False,
+ help="External python file/package containing a custom plugin implementation.",
+ )(options)
+
+
def isp_interfaces(
uart: bool = False,
usb: bool = False,
+ sdio: bool = False,
lpcusbsio: bool = False,
buspal: bool = False,
json_option: bool = True,
@@ -154,6 +180,7 @@ def isp_interfaces(
:param uart: UART interface, defaults to False
:param usb: USB interface, defaults to False
+ :param sdio: SDIO interface, defaults to False
:param lpcusbsio: LPCUSBSIO interface, defaults to False
:param buspal: BUSPAL interface, defaults to False
:param json_option: add -j option, defaults to True
@@ -171,6 +198,8 @@ def decorator(func: Callable[[FC], FC]) -> Callable[[FC], FC]:
options.append(_sdp_uart_option if is_sdp else _uart_option)
if usb:
options.append(_usb_option)
+ if sdio:
+ options.append(_sdio_option)
if lpcusbsio:
options.append(_lpcusbsio_option)
if buspal:
diff --git a/spsdk/apps/utils/spsdk_logger.py b/spsdk/apps/utils/spsdk_logger.py
index b1589e24..456b114d 100644
--- a/spsdk/apps/utils/spsdk_logger.py
+++ b/spsdk/apps/utils/spsdk_logger.py
@@ -72,7 +72,7 @@ def format(self, record: logging.LogRecord) -> str:
if not self.colored:
try:
record.msg = re.sub("\\x1b\[\d{1,3}m", "", record.msg)
- except:
+ except Exception:
# Just ignore all exceptions on this "remove color" operation
pass
return formatter.format(record)
diff --git a/spsdk/apps/utils/utils.py b/spsdk/apps/utils/utils.py
index 9e1c4054..4dfad231 100644
--- a/spsdk/apps/utils/utils.py
+++ b/spsdk/apps/utils/utils.py
@@ -31,6 +31,10 @@
write_file,
)
+WARNING_MSG = """
+!!! THIS IS AN EXPERIMENTAL UTILITY! USE WITH CAUTION !!!
+"""
+
logger = logging.getLogger(__name__)
@@ -92,62 +96,106 @@ def convert(
self.fail(f"{value!r} is not a valid integer", param, ctx)
-def get_interface(
- module: str,
+def get_sdp_interface(
+ port: Optional[str] = None, usb: Optional[str] = None, timeout: int = 5000
+) -> SDPInterface:
+ """Get SDP interface.
+
+ 'port', 'usb' parameters are mutually exclusive; one of them is required.
+
+ :param port: name and speed of the serial port (format: name[,speed]), defaults to None
+ :param usb: PID,VID of the USB interface, defaults to None
+ :param timeout: timeout in milliseconds
+ :return: Selected interface instance
+ :raises SPSDKError: Only one of appropriate interfaces must be specified
+ :raises SPSDKError: Interface couldn't be opened
+ """
+ all_interfaces = (port, usb)
+ count_interfaces = sum(i is not None for i in all_interfaces)
+
+ if count_interfaces == 0:
+ raise SPSDKError("One of '--port', '--usb' must be specified.")
+ if count_interfaces > 1:
+ raise SPSDKError("Only one of '--port', '--usb' must be specified.")
+
+ devices: Union[List[SDPInterfaceModule.RawHid], List[SDPInterfaceModule.Uart]]
+ if port:
+ port_parts = port.split(",")
+ name = port_parts.pop(0)
+ baudrate = int(port_parts.pop(), 0) if port_parts else None
+
+ devices = SDPInterfaceModule.scan_uart(port=name, baudrate=baudrate, timeout=timeout)
+ if len(devices) != 1:
+ raise SPSDKError(f"Cannot ping device on UART port '{name}'.")
+ if usb:
+ vid_pid = usb.replace(",", ":")
+ devices = SDPInterfaceModule.scan_usb(vid_pid)
+ if len(devices) == 0:
+ raise SPSDKError(f"Cannot find USB device '{format_vid_pid(vid_pid)}'")
+ if len(devices) > 1:
+ raise SPSDKError(f"More than one device '{format_vid_pid(vid_pid)}' found")
+ devices[0].timeout = timeout
+
+ assert devices # assert just to satisfy pyright, case if handled at the begging
+ return devices[0]
+
+
+def get_mboot_interface(
port: Optional[str] = None,
usb: Optional[str] = None,
+ sdio: Optional[str] = None,
timeout: int = 5000,
buspal: Optional[str] = None,
lpcusbsio: Optional[str] = None,
-) -> Union[MBootInterface, SDPInterface]:
+) -> MBootInterface:
"""Get appropriate interface.
- 'port' and 'usb' parameters are mutually exclusive; one of them is required.
+ 'port', 'usb', 'sdio', 'lpcusbsio' parameters are mutually exclusive; one of them is required.
- :param module: name of module to get interface from, 'sdp' or 'mboot'
:param port: name and speed of the serial port (format: name[,speed]), defaults to None
:param usb: PID,VID of the USB interface, defaults to None
+ :param sdio: SDIO path of the SDIO interface, defaults to None
:param buspal: buspal interface settings, defaults to None
:param timeout: timeout in milliseconds
:param lpcusbsio: LPCUSBSIO spi or i2c config string
:return: Selected interface instance
- :raises SPSDKError: Only one of 'port' or 'usb' must be specified
- :raises AttributeError: target is not supported
+ :raises SPSDKError: Only one of the appropriate interfaces must be specified
:raises SPSDKError: When SPSDK-specific error occurs
"""
# check that one and only one interface is defined
- all_interfaces = (port, usb, lpcusbsio)
+ all_interfaces = (port, usb, sdio, lpcusbsio)
count_interfaces = sum(i is not None for i in all_interfaces)
- interface_module = {"mboot": MBootInterfaceModule, "sdp": SDPInterfaceModule}[module]
-
- missing_interface_msg = {
- "mboot": "One of '--port', '--usb' or '--lpcusbsio' must be specified.",
- "sdp": "One of '--port', '--usb' must be specified.",
- }[module]
-
- multiple_interfaces_msg = {
- "mboot": "Only one of '--port', '--usb' or '--lpcusbsio' must be specified.",
- "sdp": "Only one of '--port', '--usb' must be specified.",
- }[module]
if count_interfaces == 0:
- raise SPSDKError(missing_interface_msg)
+ raise SPSDKError("One of '--port', '--usb', '--sdio' or '--lpcusbsio' must be specified.")
if count_interfaces > 1:
- raise SPSDKError(multiple_interfaces_msg)
+ raise SPSDKError(
+ "Only one of '--port', '--usb', '--sdio' or '--lpcusbsio' must be specified."
+ )
- devices = []
+ devices: Union[
+ List[MBootInterfaceModule.Uart],
+ List[MBootInterfaceModule.RawHid],
+ List[MBootInterfaceModule.Sdio],
+ List[MBootInterfaceModule.UsbSio],
+ List[MBootInterfaceModule.MBootInterface],
+ ]
if port:
port_parts = port.split(",")
name = port_parts.pop(0)
baudrate = int(port_parts.pop(), 0) if port_parts else None
- if buspal and interface_module is MBootInterfaceModule:
+ if buspal:
props = buspal.split(",")
target = props.pop(0)
if target == "i2c":
- devices = interface_module.scan_buspal_i2c(port=name, timeout=timeout, props=props) # type: ignore
+ devices = MBootInterfaceModule.scan_buspal_i2c(
+ port=name, timeout=timeout, props=props
+ )
elif target == "spi":
- devices = interface_module.scan_buspal_spi(port=name, timeout=timeout, props=props) # type: ignore
+ devices = MBootInterfaceModule.scan_buspal_spi(
+ port=name, timeout=timeout, props=props
+ )
else:
raise SPSDKError(f"Target '{target}' is not supported, should be spi or i2c")
@@ -156,27 +204,68 @@ def get_interface(
f"Error: cannot communicate with BUSPAL target on UART port '{name}'."
)
else:
- devices = interface_module.scan_uart(port=name, baudrate=baudrate, timeout=timeout) # type: ignore
+ devices = MBootInterfaceModule.scan_uart(port=name, baudrate=baudrate, timeout=timeout)
if len(devices) != 1:
raise SPSDKError(f"Cannot ping device on UART port '{name}'.")
if usb:
vid_pid = usb.replace(",", ":")
- devices = interface_module.scan_usb(vid_pid) # type: ignore
+ devices = MBootInterfaceModule.scan_usb(vid_pid)
if len(devices) == 0:
raise SPSDKError(f"Cannot find USB device '{format_vid_pid(vid_pid)}'")
if len(devices) > 1:
raise SPSDKError(f"More than one device '{format_vid_pid(vid_pid)}' found")
devices[0].timeout = timeout
+ if sdio:
+ devices = MBootInterfaceModule.scan_sdio(sdio)
+ if len(devices) == 0:
+ raise SPSDKError(f"Cannot find SDIO device '{sdio}'")
+ if len(devices) > 1:
+ raise SPSDKError(f"More than one device '{sdio}' found")
+ devices[0].timeout = timeout
if lpcusbsio:
- devices = interface_module.scan_usbsio(lpcusbsio, timeout=timeout) # type: ignore
+ devices = MBootInterfaceModule.scan_usbsio(lpcusbsio, timeout=timeout)
if len(devices) != 1:
raise SPSDKError(
f"Cannot initialize USBSIO device '{lpcusbsio}',"
f" exactly one device has to be specified, found: {devices}. "
)
+ assert devices # assert just to satisfy pyright, case if handled at the begging
return devices[0]
+def get_interface(
+ module: str,
+ port: Optional[str] = None,
+ usb: Optional[str] = None,
+ sdio: Optional[str] = None,
+ timeout: int = 5000,
+ buspal: Optional[str] = None,
+ lpcusbsio: Optional[str] = None,
+) -> Union[MBootInterface, SDPInterface]:
+ """Get appropriate interface.
+
+ 'port', 'usb', 'sdio', 'lpcusbsio' parameters are mutually exclusive; one of them is required.
+
+ :param module: name of module to get interface from, 'sdp' or 'mboot'
+ :param port: name and speed of the serial port (format: name[,speed]), defaults to None
+ :param usb: PID,VID of the USB interface, defaults to None
+ :param sdio: SDIO path of the SDIO interface, defaults to None
+ :param buspal: buspal interface settings, defaults to None
+ :param timeout: timeout in milliseconds
+ :param lpcusbsio: LPCUSBSIO spi or i2c config string
+ :return: Selected interface instance
+ :raises SPSDKError: Only one of the appropriate interfaces must be specified
+ :raises SPSDKError: When SPSDK-specific error occurs
+ """
+ if module == "mboot":
+ return get_mboot_interface(
+ port=port, usb=usb, sdio=sdio, timeout=timeout, buspal=buspal, lpcusbsio=lpcusbsio
+ )
+ if module == "sdp":
+ return get_sdp_interface(port=port, usb=usb, timeout=timeout)
+ raise SPSDKError(f"Unknown interface module: {module}. Valid options are: mboot, sdp")
+
+
def _split_string(string: str, length: int) -> list:
"""Split the string into chunks of same length."""
return [string[i : i + length] for i in range(0, len(string), length)]
@@ -329,7 +418,7 @@ def get_key(
raise SPSDKError("Invalid Key size.")
except (SPSDKError, UnicodeDecodeError):
key = load_binary(file_path)
- except:
+ except Exception:
try:
if not key_source.startswith(("0x", "0X")):
key_source = "0x" + key_source
diff --git a/spsdk/crypto/__init__.py b/spsdk/crypto/__init__.py
index c5873556..6f4eca7c 100644
--- a/spsdk/crypto/__init__.py
+++ b/spsdk/crypto/__init__.py
@@ -109,7 +109,7 @@
_PublicKeyTuple = (rsa.RSAPublicKey, ec.EllipticCurvePublicKey)
_PrivateKeyTuple = (rsa.RSAPrivateKey, ec.EllipticCurvePrivateKey)
-# pylint: disable=wrong-import-position # TODO: this whole module needs refactoring
+# pylint: disable=wrong-import-position
from .certificate_management import *
from .keys_management import *
diff --git a/spsdk/crypto/signature_provider.py b/spsdk/crypto/signature_provider.py
index 6eb85adc..e1828fbb 100644
--- a/spsdk/crypto/signature_provider.py
+++ b/spsdk/crypto/signature_provider.py
@@ -13,21 +13,18 @@
"""
import abc
-import importlib
+import getpass
import logging
import math
-from typing import Any, Dict, List, Optional, Union
+from types import ModuleType
+from typing import Any, Dict, List, Optional, Type, Union
from Crypto.PublicKey import ECC
-from Crypto.Signature import DSS
-from cryptography.exceptions import InvalidSignature
-from cryptography.hazmat.backends import default_backend
-from cryptography.hazmat.primitives import serialization
-from cryptography.hazmat.primitives.asymmetric import ec, padding, rsa, utils
from spsdk import crypto
from spsdk.exceptions import SPSDKError, SPSDKUnsupportedOperation, SPSDKValueError
from spsdk.utils.misc import find_file
+from spsdk.utils.plugins import PluginsManager, PluginType
logger = logging.getLogger(__name__)
@@ -77,11 +74,11 @@ def get_types(cls) -> List[str]:
@classmethod
def create(cls, params: Union[str, dict]) -> Optional["SignatureProvider"]:
"""Creates an concrete instance of signature provider."""
+ load_plugins()
if isinstance(params, str):
params = cls.convert_params(params)
- for (
- klass
- ) in cls.__subclasses__(): # pragma: no branch # there always be at least one subclass
+ sp_classes = cls.get_all_signature_providers()
+ for klass in sp_classes: # pragma: no branch # there always be at least one subclass
if klass.sp_type == params["type"]:
del params["type"]
unused_params = set(params) - set(klass.__init__.__code__.co_varnames)
@@ -92,8 +89,25 @@ def create(cls, params: Union[str, dict]) -> Optional["SignatureProvider"]:
)
del params[unused_param]
return klass(**params) # type: ignore #oh dear Mypy
+ logger.info(f"Signature provider of type {params['type']} was not found.")
return None
+ @staticmethod
+ def get_all_signature_providers() -> List[Type["SignatureProvider"]]:
+ """Get list of all available signature providers."""
+
+ def get_subclasses(
+ base_class: Type,
+ ) -> List[Type["SignatureProvider"]]:
+ """Recursively find all subclasses."""
+ subclasses = []
+ for subclass in base_class.__subclasses__():
+ subclasses.append(subclass)
+ subclasses.extend(get_subclasses(subclass))
+ return subclasses
+
+ return get_subclasses(SignatureProvider)
+
class PlainFileSP(SignatureProvider):
"""PlainFileSP is a SignatureProvider implementation that uses plain local files."""
@@ -103,7 +117,7 @@ class PlainFileSP(SignatureProvider):
def __init__(
self,
file_path: str,
- password: str = "", # pylint: disable=unused-argument
+ password: Optional[str] = None,
encoding: str = "PEM", # pylint: disable=unused-argument
hash_alg: Optional[str] = None,
search_paths: Optional[List[str]] = None,
@@ -112,15 +126,17 @@ def __init__(
"""Initialize the plain file signature provider.
:param file_path: Path to private file
- :param password: Password in case of encrypted private file, defaults to ''
+ :param password: Password in case of encrypted private file, defaults to None
:param encoding: Private file encoding, defaults to 'PEM'
:param hash_alg: Hash for the signature, defaults to 'sha256'
+ :param search_paths: List of paths where to search for the file, defaults to None
:param mode: Optionally there could be specified mode of signature algorithm.
For example to switch EC signature to deterministic mode 'deterministic-rfc6979' must be used
:raises SPSDKError: Invalid Private Key
"""
self.file_path = find_file(file_path=file_path, search_paths=search_paths)
- self.private_key = crypto.load_private_key(self.file_path)
+ password_bytes = str.encode(password) if password is not None else None
+ self.private_key = crypto.load_private_key(self.file_path, password=password_bytes)
assert isinstance(self.private_key, crypto._PrivateKeyTuple)
if hash_alg:
hash_alg_name = hash_alg
@@ -149,19 +165,21 @@ def __init__(
@property
def signature_length(self) -> int:
"""Return length of the signature."""
- sig_len = self.private_key.key_size // 8
+ sig_len = math.ceil(self.private_key.key_size / 8)
if isinstance(self.private_key, crypto.EllipticCurvePrivateKey):
sig_len *= 2
return sig_len
def verify_public_key(self, public_key: bytes) -> bool:
"""Verify if given public key matches private key."""
+ from spsdk.utils.crypto.common import crypto_backend, serialize_ecc_signature
+
crypto_public_key = crypto.loaders.load_public_key_from_data(public_key)
assert isinstance(crypto_public_key, crypto._PublicKeyTuple)
data = bytes()
if isinstance(crypto_public_key, crypto.RSAPublicKey):
signature = self._rsa_sign(data)
- is_matching = self._rsa_verify(
+ is_matching = crypto_backend().rsa_verify(
pub_key_mod=crypto_public_key.public_numbers().n,
pub_key_exp=crypto_public_key.public_numbers().e,
signature=signature,
@@ -170,7 +188,10 @@ def verify_public_key(self, public_key: bytes) -> bool:
return is_matching
else: # public_key can be only one of RSAPublicKey | EllipticCurvePublicKey type
signature = self._ecc_sign(data)
- is_matching = self._ecc_verify(public_key=public_key, signature=signature, data=data)
+ signature_data = serialize_ecc_signature(signature, self.signature_length // 2)
+ is_matching = crypto_backend().ecc_verify(
+ public_key=crypto_public_key, signature=signature_data, data=data # type: ignore
+ )
return is_matching
def info(self) -> str:
@@ -198,106 +219,61 @@ def _ecc_sign(self, data: bytes) -> bytes:
"""Return ECC signature."""
assert isinstance(self.private_key, crypto.EllipticCurvePrivateKey)
if self.mode and self.mode == "deterministic-rfc6979":
+ from spsdk.utils.crypto.backend_internal import internal_backend
+
private_key_bytes = self.private_key.private_bytes(
encoding=crypto.Encoding.PEM,
format=crypto.serialization.PrivateFormat.PKCS8,
encryption_algorithm=crypto.serialization.NoEncryption(),
)
crypto_dome_key = ECC.import_key(private_key_bytes)
- hasher = self._get_crypto_algorithm(name=self.hash_alg.name, data=data)
- signer = DSS.new(crypto_dome_key, mode="deterministic-rfc6979")
- signature = signer.sign(hasher)
+ signature = internal_backend.ecc_sign(crypto_dome_key, data)
else:
signature = self.private_key.sign(
data=data, signature_algorithm=crypto.ec.ECDSA(self.hash_alg)
)
return signature
- def _ecc_verify(
- self,
- public_key: bytes,
- signature: bytes,
- data: bytes,
- ) -> bool:
- """Verify (EC)DSA signature.
-
- :param public_key: ECC public key
- :param signature: Signature to verify, r and s coordinates as bytes
- :param data: Data to validate
- :return: True if the signature is valid
- :raises SPSDKError: Signature length is invalid
- """
- assert isinstance(public_key, bytes)
-
- processed_public_key = serialization.load_pem_public_key(public_key, default_backend())
- assert isinstance(processed_public_key, ec.EllipticCurvePublicKey)
- coordinate_size = math.ceil(processed_public_key.key_size / 8)
- if len(signature) != 2 * coordinate_size:
- raise SPSDKError(
- f"Invalid signature size: expected {2 * coordinate_size}, actual: {len(signature)}"
- )
- der_signature = utils.encode_dss_signature(
- int.from_bytes(signature[:coordinate_size], byteorder="big"),
- int.from_bytes(signature[coordinate_size:], byteorder="big"),
- )
- try:
- # pylint: disable=no-value-for-parameter # pylint is mixing RSA and ECC verify methods
- processed_public_key.verify(der_signature, data, ec.ECDSA(self.hash_alg))
- return True
- except InvalidSignature:
- return False
- def _rsa_verify(
- self,
- pub_key_mod: int,
- pub_key_exp: int,
- signature: bytes,
- data: bytes,
- ) -> bool:
- """Verify input data.
-
- :param pub_key_mod: The public key modulus
- :param pub_key_exp: The public key exponent
- :param signature: The signature of input data
- :param data: Input data
- :return: True if signature is valid, False otherwise
- :raises SPSDKError: If algorithm not found
- """
- public_key = rsa.RSAPublicNumbers(pub_key_exp, pub_key_mod).public_key(default_backend())
- assert isinstance(public_key, rsa.RSAPublicKey)
- try:
- public_key.verify(
- signature=signature,
- data=data,
- padding=padding.PKCS1v15(),
- algorithm=self.hash_alg,
- )
- except InvalidSignature:
- return False
+class InteractivePlainFileSP(PlainFileSP):
+ """SignatureProvider implementation that uses plain local file in an "interactive" mode.
- return True
+ If the private key is encrypted, the useer will be promped for password
+ """
- @staticmethod
- def _get_crypto_algorithm(name: str, data: bytes) -> Any:
- """For specified name return Hash algorithm instance.
+ sp_type = "interactive_file"
+
+ def __init__(
+ self,
+ file_path: str,
+ encoding: str = "PEM",
+ hash_alg: Optional[str] = None,
+ search_paths: Optional[List[str]] = None,
+ mode: Optional[str] = None,
+ ) -> None:
+ """Initialize the interactive plain file signature provider.
- :param name: Name of the algorithm (class name), case insensitive
- :param data: parameter for the constructor of the algorithm class
- :return: instance of algorithm class
- :raises SPSDKError: If the algorithm is not found
+ :param file_path: Path to private file
+ :param encoding: Private file encoding, defaults to 'PEM'
+ :param hash_alg: Hash for the signature, defaults to 'sha256'
+ :param search_paths: List of paths where to search for the file, defaults to None
+ :param mode: Optionally there could be specified mode of signature algorithm.
+ For example to switch EC signature to deterministic mode 'deterministic-rfc6979' must be used
+ :raises SPSDKError: Invalid Private Key
"""
- # algo_cls = getattr(Hash, name.upper(), None) # hack: get class object by name
+ password = None
try:
- algo_cls = importlib.import_module(f"Crypto.Hash.{name.upper()}")
- except ModuleNotFoundError as exc:
- raise SPSDKError(f"No module named 'Crypto.Hash.{name.upper()}") from exc
- if algo_cls is None:
- raise SPSDKError(f"Unsupported algorithm: Hash.{name}".format(name=name.upper()))
- return algo_cls.new(data) # type: ignore # pylint: disable=not-callable
+ self.file_path = find_file(file_path=file_path, search_paths=search_paths)
+ self.private_key = crypto.load_private_key(self.file_path)
+ except TypeError:
+ password = getpass.getpass(
+ prompt="Private key is encrypted.Enter password: ", stream=None
+ )
+ super().__init__(file_path, password, encoding, hash_alg, search_paths, mode)
def get_signature_provider(
- sp_cfg: Optional[str], local_file_key: Optional[str], **kwargs: Any
+ sp_cfg: Optional[str] = None, local_file_key: Optional[str] = None, **kwargs: Any
) -> SignatureProvider:
"""Get the signature provider from configuration.
@@ -328,3 +304,10 @@ def get_signature_provider(
raise SPSDKError(f"Cannot create signature provider from: {sp_cfg or local_file_key}")
return signature_provider
+
+
+def load_plugins() -> Dict[str, ModuleType]:
+ """Load all installed signature provider plugins."""
+ plugins_manager = PluginsManager()
+ plugins_manager.load_from_entrypoints(PluginType.name(PluginType.SIGNATURE_PROVIDER))
+ return plugins_manager.plugins
diff --git a/spsdk/dat/dac_packet.py b/spsdk/dat/dac_packet.py
index f1b63976..c0cd3cc4 100644
--- a/spsdk/dat/dac_packet.py
+++ b/spsdk/dat/dac_packet.py
@@ -7,11 +7,14 @@
"""Module with Debug Authentication Challenge (DAC) Packet."""
+import logging
from struct import calcsize, pack, unpack_from
from spsdk.dat.debug_credential import DebugCredential
from spsdk.exceptions import SPSDKValueError
+logger = logging.getLogger(__name__)
+
class DebugAuthenticationChallenge:
"""Base class for DebugAuthenticationChallenge."""
@@ -66,7 +69,7 @@ def info(self) -> str:
def validate_against_dc(self, dc: DebugCredential) -> None:
"""Validate against Debug Credential file.
- :param dc: Debug Credential class to be validate by DAC
+ :param dc: Debug Credential class to be validated by DAC
:raises SPSDKValueError: In case of invalid configuration detected.
"""
if self.version != dc.VERSION and self.socc not in [0x5254049C]:
@@ -81,14 +84,16 @@ def validate_against_dc(self, dc: DebugCredential) -> None:
raise SPSDKValueError(
f"DAC Verification failed: Invalid UUID.\nDAC: {self.uuid.hex()}\nDC: {dc.uuid.hex()}"
)
-
- dc_rotkh = dc.get_rotkh()
- if dc_rotkh and not all(
- self.rotid_rkth_hash[x] == dc_rotkh[x] for x in range(len(self.rotid_rkth_hash))
- ):
- raise SPSDKValueError(
- f"DAC Verification failed: Invalid RoT Hash. \nDAC: {self.rotid_rkth_hash.hex()}\nDC: {dc_rotkh.hex()}"
- )
+ # RKTH is not part of challenge for RW61x devices
+ if self.socc != 0xA:
+ dc_rotkh = dc.get_rotkh()
+ if dc_rotkh and not all(
+ self.rotid_rkth_hash[x] == dc_rotkh[x] for x in range(len(self.rotid_rkth_hash))
+ ):
+ raise SPSDKValueError(
+ f"DAC Verification failed: Invalid RoT Hash. \n"
+ f"DAC: {self.rotid_rkth_hash.hex()}\nDC: {dc_rotkh.hex()}"
+ )
def export(self) -> bytes:
"""Exports the DebugAuthenticationChallenge into bytes."""
@@ -116,7 +121,7 @@ def parse(cls, data: bytes, offset: int = 0) -> "DebugAuthenticationChallenge":
format_head, data, offset
)
# Note: EdgeLock is always 256b SRKH - if P384 these are the first 256b of SHA384(SRKT)
- hash_length = 48 if (socc == 4 and version_minor == 1 and version_major == 2) else 32
+ hash_length = 48 if (socc in [4, 6] and version_minor == 1 and version_major == 2) else 32
format_tail = f"<{hash_length}s3L32s"
(
diff --git a/spsdk/dat/debug_credential.py b/spsdk/dat/debug_credential.py
index 0b53b679..fafeaf0b 100644
--- a/spsdk/dat/debug_credential.py
+++ b/spsdk/dat/debug_credential.py
@@ -36,6 +36,9 @@ class DebugCredential:
0x0001: "LPC550x, LPC55s0x, LPC551x, LPC55s1x, LPC552x, LPC55s2x, LPC55s6",
0x0004: "LPC55s3",
0x0005: "KW45xx/K32W1xx",
+ 0x0006: "MCXN9xx (A0)",
+ 0x0007: "MCXN9xx (A1)",
+ 0x000A: "RW61x (A2)",
0x5254049C: "i.MXRT118x",
}
diff --git a/spsdk/dat/debug_mailbox.py b/spsdk/dat/debug_mailbox.py
index dedd3548..ac06de94 100644
--- a/spsdk/dat/debug_mailbox.py
+++ b/spsdk/dat/debug_mailbox.py
@@ -171,7 +171,7 @@ def get_dbgmlbx_ap(func: Any):
:param func: Decorated function.
"""
- POSSIBLE_DBGMLBX_AP_IX = [0, 2]
+ POSSIBLE_DBGMLBX_AP_IX = [0, 2, 3]
@functools.wraps(func)
def wrapper(self: "DebugMailbox", *args, **kwargs):
diff --git a/spsdk/dat/dm_commands.py b/spsdk/dat/dm_commands.py
index 5c98c5e2..c7f73dd0 100644
--- a/spsdk/dat/dm_commands.py
+++ b/spsdk/dat/dm_commands.py
@@ -71,7 +71,8 @@ def run(self, params: Optional[List[int]] = None) -> List[Any]:
ret = self.dm.spin_read(self.dm.registers["RETURN"]["address"])
logger.debug(f"-> spin_read: {format_value(ret, 32)}")
- new_protocol = bool(ret >> 31) # bit 31 is flag in new protocol version
+ # bit 31 is flag in new protocol version
+ # new_protocol = bool(ret >> 31)
error_indication = bool(ret >> 20) and not bool(self.resplen)
# solve the case that response is in legacy protocol and there is some
# unwanted bits in none expected data. In this case return valid read data.
@@ -202,6 +203,24 @@ def __init__(self, dm: DebugMailbox, paramlen: int) -> None:
super().__init__(dm, id=17, name="DBG_AUTH_RESP", paramlen=paramlen)
+class NxpDebugAuthenticationStart(DebugMailboxCommand):
+ """Class for DebugAuthenticationStart."""
+
+ def __init__(self, dm: DebugMailbox, resplen: int = 26) -> None:
+ """Initialize."""
+ # 26 words == 104 bytes (SHA256 - 32 Bytes)
+ # 30 words == 120 bytes (SHA384 - 48 Bytes)
+ super().__init__(dm, id=18, name="NXP_DBG_AUTH_START", resplen=resplen)
+
+
+class NxpDebugAuthenticationResponse(DebugMailboxCommand):
+ """Class for DebugAuthenticationResponse."""
+
+ def __init__(self, dm: DebugMailbox, paramlen: int) -> None:
+ """Initialize."""
+ super().__init__(dm, id=19, name="NXP_DBG_AUTH_RESP", paramlen=paramlen)
+
+
class StartDebugSessions(DebugMailboxCommand):
"""Class for StartDebugSessions."""
diff --git a/spsdk/data/ahab/sch_ahab.yaml b/spsdk/data/ahab/sch_ahab.yaml
index b33fd455..bc0193ac 100644
--- a/spsdk/data/ahab/sch_ahab.yaml
+++ b/spsdk/data/ahab/sch_ahab.yaml
@@ -30,7 +30,7 @@ properties:
type: string
title: Type of image
description: The final use of image, this setting is changing the style of offsets in final container.
- enum: [xip, non_xip, serial_downloader]
+ enum: [xip, non_xip, serial_downloader, nand]
template_value: xip
output:
type: string
@@ -120,6 +120,11 @@ properties:
The referenced SRK must not have been revoked.
format: file
template_value: my_signing_key.pem
+ signature_provider:
+ type: string
+ title: Signature Provider
+ description: Signature provider configuration in format 'type=;=;=". The signature provider could be used instead of definition of 'signing_key'.
+ template_value: type=file;file_path=my_prv_key.pem
images:
type: array
title: Image array
@@ -307,6 +312,11 @@ properties:
description: Private key used for sign the certificate container.
format: file
template_value: my_cert_signing_key.pem
+ signature_provider:
+ type: string
+ title: Signature Provider
+ description: Signature provider configuration in format 'type=;=;=". The signature provider could be used instead of definition of 'signing_key'.
+ template_value: type=file;file_path=my_prv_key.pem
blob:
type: object
title: Encryption blob
diff --git a/spsdk/data/ahab/sch_signed_msg.yaml b/spsdk/data/ahab/sch_signed_msg.yaml
index 21b0e4ae..058e4571 100644
--- a/spsdk/data/ahab/sch_signed_msg.yaml
+++ b/spsdk/data/ahab/sch_signed_msg.yaml
@@ -84,6 +84,11 @@ properties:
The referenced SRK must not have been revoked.
format: file
template_value: my_signing_key.pem
+ signature_provider:
+ type: string
+ title: Signature Provider
+ description: Signature provider configuration in format 'type=;=;=". The signature provider could be used instead of definition of 'signing_key'.
+ template_value: type=file;file_path=my_prv_key.pem
srk_table:
type: object
diff --git a/spsdk/data/image/bootable_image/database.yaml b/spsdk/data/image/bootable_image/database.yaml
index b8c1e9a4..f1dd7f4f 100644
--- a/spsdk/data/image/bootable_image/database.yaml
+++ b/spsdk/data/image/bootable_image/database.yaml
@@ -23,6 +23,8 @@ devices:
image_version_offset: 0x0600
application_offset: 0x1000
remap_align: 0x40000 # 256 KB
+ rw61x:
+ device_alias: lpc55s3x
rt101x:
attributes:
mem_types:
@@ -42,6 +44,8 @@ devices:
device_alias: rt102x
rt106x:
device_alias: rt102x
+ rt104x:
+ device_alias: rt102x
rt117x:
attributes:
mem_types:
@@ -64,4 +68,3 @@ devices:
fcb_offset: 0x0400
xmcd_offset: 0x0800
ahab_container_offset: 0x1000
-
diff --git a/spsdk/data/image/database.yaml b/spsdk/data/image/database.yaml
index d1e0ccc6..635955ba 100644
--- a/spsdk/data/image/database.yaml
+++ b/spsdk/data/image/database.yaml
@@ -12,6 +12,7 @@ map_tables:
plain: [Plain]
crc: [CRC]
signed: [Signed, signed]
+ nxp_signed: ["NXP Signed", "NXP signed"]
encrypted: ["Encrypted + Signed", encrypted]
devices:
@@ -149,6 +150,7 @@ devices:
plain: Mbi_PlainXipKw45xx
crc: Mbi_CrcXipKw45xx
signed: Mbi_PlainXipSignedKw45xx
+ nxp_signed: Mbi_PlainXipSignedNxpKw45xx
k32w1xx:
images:
@@ -156,6 +158,7 @@ devices:
plain: Mbi_PlainXipKw45xx
crc: Mbi_CrcXipKw45xx
signed: Mbi_PlainXipSignedKw45xx
+ nxp_signed: Mbi_PlainXipSignedNxpKw45xx
lpc553x:
images:
@@ -170,3 +173,27 @@ devices:
ram:
plain: Mbi_PlainRamLpc55s3x
crc: Mbi_CrcRamLpc55s3x
+
+ mcxn9xx:
+ images:
+ int_xip:
+ plain: Mbi_PlainRamMcxNx
+ crc: Mbi_CrcXipMcxNx
+ signed: Mbi_PlainXipSignedMcxNx
+ ext_xip:
+ plain: Mbi_PlainRamMcxNx
+ crc: Mbi_CrcXipMcxNx
+ signed: Mbi_PlainXipSignedMcxNx
+ ram:
+ plain: Mbi_PlainRamMcxNx
+ crc: Mbi_CrcRamMcxNx
+
+ rw61x:
+ images:
+ ext_xip:
+ crc: Mbi_CrcExtXipRw61x
+ signed: Mbi_PlainExtXipSignedRw61x
+ ram:
+ plain: Mbi_PlainRamRw61x
+ crc: Mbi_CrcRamRw61x
+ signed: Mbi_PlainSignedRamRw61x
diff --git a/spsdk/data/image/database_sb31.yaml b/spsdk/data/image/database_sb31.yaml
index 478d050b..23a855c0 100644
--- a/spsdk/data/image/database_sb31.yaml
+++ b/spsdk/data/image/database_sb31.yaml
@@ -5,34 +5,14 @@
devices:
lpc55s3x:
attributes:
- supported_commands:
- [
- erase,
- load,
- execute,
- programFuses,
- programIFR,
- loadCMAC,
- copy,
- loadHashLocking,
- loadKeyBlob,
- configureMemory,
- fillMemory,
- checkFwVersion,
- ]
+ supported_commands: [erase, load, execute, programFuses, programIFR, loadCMAC, copy, loadHashLocking, loadKeyBlob, configureMemory, fillMemory, checkFwVersion]
+ mcxn9xx:
+ device_alias: lpc55s3x
kw45xx:
attributes:
- supported_commands:
- [
- erase,
- load,
- execute,
- programFuses,
- programIFR,
- loadCMAC,
- loadHashLocking,
- fillMemory,
- checkFwVersion,
- ]
+ supported_commands: [erase, load, execute, programFuses, programIFR, loadCMAC, loadHashLocking, fillMemory, checkFwVersion]
k32w1xx:
device_alias: kw45xx
+ rw61x:
+ attributes:
+ supported_commands: [erase, load, execute, programFuses, programIFR, copy, loadKeyBlob, configureMemory, fillMemory, checkFwVersion]
\ No newline at end of file
diff --git a/spsdk/data/image/fcb/database.yaml b/spsdk/data/image/fcb/database.yaml
index 1eb79ef7..45abb563 100644
--- a/spsdk/data/image/fcb/database.yaml
+++ b/spsdk/data/image/fcb/database.yaml
@@ -47,3 +47,7 @@ devices:
attributes:
mem_types:
flexspi_nor: rt118x_flexspi_nor.xml
+ rw61x:
+ attributes:
+ mem_types:
+ flexspi_nor: rw61x_flexspi_nor.xml
\ No newline at end of file
diff --git a/spsdk/data/image/fcb/rw61x_flexspi_nor.xml b/spsdk/data/image/fcb/rw61x_flexspi_nor.xml
new file mode 100644
index 00000000..35fa62ce
--- /dev/null
+++ b/spsdk/data/image/fcb/rw61x_flexspi_nor.xml
@@ -0,0 +1,225 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spsdk/data/image/sch_mbimg.yaml b/spsdk/data/image/sch_mbimg.yaml
index 7f0c3d63..d1d86d7e 100644
--- a/spsdk/data/image/sch_mbimg.yaml
+++ b/spsdk/data/image/sch_mbimg.yaml
@@ -73,16 +73,16 @@ image_subtype:
description: Image subtype determine the image use in MCU (Main application or something else).
template_value: MAIN
-sign_hash_len:
+digest_hash_algo:
type: object
title: Image Manifest Settings
properties:
- manifestSigningHashLength:
- type: number
- title: Manifest signing hash length
- description: Optional Manifest signing hash length to create Certificate v3.1 Manifest.
- enum: [0, 32, 48, 64]
- template_value: 32
+ manifestDigestHashAlgorithm:
+ type: string
+ title: Manifest signing hash algorithm
+ description: Optional Manifest signing hash algorithm name to create Certificate v3.1 Manifest.
+ enum: [sha256, sha384, sha521]
+ template_value: sha256
cert_prv_key:
type: object
@@ -177,21 +177,10 @@ key_store:
type: object
title: Encryption Settings
properties:
- useKeyStore:
- type: boolean
- title: The Key store enabler
- description: Enables using key store on device.
- template_value: false
- deviceKeySource:
- type: string
- title: The Key store location
- description: "Determinate where the keystore is located. There is two options: OTP or KEYSTORE (included in Load to RAM image)."
- enum: [OTP, Keystore]
- template_value: OTP
keyStoreFile:
type: string
title: The Key store data file
- description: Optional KeyStore data file for included keystore (KEYSTORE source)in LoadToRam images.
+ description: Optional KeyStore data file for included keystore in LoadToRam images. If defined the KeyStore is added into MBI.
format: optional_file
template_value: my_key_store_data.bin
@@ -202,8 +191,7 @@ hmac:
outputImageEncryptionKeyFile:
type: string
title: HMAC Key
- description: The HMAC encryption key (file path).
- format: file
+ description: The HMAC encryption key (file path). Could be defined as hex number and also as hex/binary file
template_value: hmac_key.bin
hmac_mandatory:
@@ -213,8 +201,7 @@ hmac_mandatory:
outputImageEncryptionKeyFile:
type: string
title: HMAC Key
- description: The HMAC encryption key (file path).
- format: file
+ description: The HMAC encryption key (file path). Could be defined as hex number and also as hex/binary file
template_value: hmac_key.bin
required: [outputImageEncryptionKeyFile]
@@ -222,11 +209,10 @@ ctr_init_vector:
type: object
title: Encryption Settings
properties:
- ctr_init_vector:
+ CtrInitVector:
type: string
title: The output image encryption initial vector for encryption counter
- description: The initial vector for encryption counter.
- # format: hex
+ description: The initial vector for encryption counter. Could be defined as hex number and also as hex/binary file
template_value: "0xc3df2316fd40b15586cb5ae49483aee2"
app_table:
@@ -259,16 +245,6 @@ app_table:
description: Enabler to load/use the image.
template_value: true
-attach_sign_digest:
- type: object
- title: Signing Settings
- properties:
- attachSignDigest:
- type: boolean
- title: Attach Signature digest
- description: When enabled it added additional signature digest after image (SHA256/384 depends on elliptic curve type for base signing).
- template_value: false
-
elliptic_curves:
type: object
title: Certificate V3.1 Settings
@@ -304,15 +280,6 @@ elliptic_curves:
else:
required: [rootCertificateEllipticCurve]
-nxp_image:
- type: object
- title: Extra Settings
- properties:
- isNxpImage:
- type: boolean
- title: NXP Image type
- description: When is set, the image will be changed to NXP manufacture type.
- template_value: false
no_signature:
type: object
@@ -360,7 +327,7 @@ image_type:
type: string
title: Type of boot image authentication
description: Specification of final master boot image authentication.
- enum: [Plain, CRC, Signed, Encrypted + Signed, encrypted, signed, crc]
+ enum: [Plain, CRC, Signed, Encrypted + Signed, NXP Signed, encrypted, signed, crc]
template_value: Plain
required: [outputImageExecutionTarget, outputImageAuthenticationType]
diff --git a/spsdk/data/image/sch_sb3.yaml b/spsdk/data/image/sch_sb3.yaml
index 9e88ffed..d9267c33 100644
--- a/spsdk/data/image/sch_sb3.yaml
+++ b/spsdk/data/image/sch_sb3.yaml
@@ -34,7 +34,6 @@ sb3_description:
title: Description
description: Description up to 16 characters, longer will be truncated. Stored in SB3.1 manifest.
template_value: This is description of generated SB file.
-
sb3:
type: object
title: Secure Binary v3.1 Settings
diff --git a/spsdk/data/image/xmcd/flexspi_ram_simplified.xml b/spsdk/data/image/xmcd/flexspi_ram_simplified.xml
index 895da207..a0870799 100644
--- a/spsdk/data/image/xmcd/flexspi_ram_simplified.xml
+++ b/spsdk/data/image/xmcd/flexspi_ram_simplified.xml
@@ -2,7 +2,7 @@
diff --git a/spsdk/data/image/xmcd/semc_sdram_simplified.xml b/spsdk/data/image/xmcd/semc_sdram_simplified.xml
index 4607aa71..b53d7923 100644
--- a/spsdk/data/image/xmcd/semc_sdram_simplified.xml
+++ b/spsdk/data/image/xmcd/semc_sdram_simplified.xml
@@ -2,7 +2,7 @@
diff --git a/spsdk/data/nxpdebugmbox/template_config.yaml b/spsdk/data/nxpdebugmbox/template_config.yaml
index e242147d..d25a6367 100644
--- a/spsdk/data/nxpdebugmbox/template_config.yaml
+++ b/spsdk/data/nxpdebugmbox/template_config.yaml
@@ -46,8 +46,11 @@
# Examples list of possible settings:
# 0x0000: i.MXRT595, i.MXRT685,
# 0x0001: LPC550x, LPC55s0x, LPC551x, LPC55s1x, LPC552x, LPC55s2x, LPC55s6x
-# 0x0004: LPC55s3x
+# 0x0004: LPC55s3x, RW61x
# 0x0005: KW45xx/K32W1xx
+# 0x0006: MCXN9xx (A0)
+# 0x0007: MCXN9xx (A1)
+# 0x000A: RW61x (A2)
# 0x5254049C: i.MXRT118x
socc: 0x0001
diff --git a/spsdk/data/nxpdevhsm/database.yaml b/spsdk/data/nxpdevhsm/database.yaml
index 9fb71dca..34bb21e0 100644
--- a/spsdk/data/nxpdevhsm/database.yaml
+++ b/spsdk/data/nxpdevhsm/database.yaml
@@ -6,3 +6,14 @@ devices:
attributes:
key_blob_offset: 0x4
key_blob_command_position: 0
+ devbuff_base_address: 0x20008000
+ mcxn9xx:
+ attributes:
+ key_blob_offset: 0x0
+ key_blob_command_position: -1
+ devbuff_base_address: 0x20007000
+ rw61x:
+ attributes:
+ key_blob_offset: 0xF05C
+ key_blob_command_position: 0
+ devbuff_base_address: 0x20008000
diff --git a/spsdk/data/pfr/cfpa/database.yaml b/spsdk/data/pfr/cfpa/database.yaml
index af7f67ab..1cbe52b9 100644
--- a/spsdk/data/pfr/cfpa/database.yaml
+++ b/spsdk/data/pfr/cfpa/database.yaml
@@ -130,6 +130,25 @@ devices:
INVERSE_VALUE: pfr_reg_inverse_high_half
DCFG_CC_SOCU_DFLT:
INVERSE_VALUE: pfr_reg_inverse_high_half
+ mcxn9xx:
+ revisions:
+ a0:
+ data_file: mcxn9xx_a0.xml
+ latest: a0
+ attributes:
+ address: 0x100_0000
+ seal_start: CFPA_CRC32
+ seal_count: 1
+ mandatory_computed_regs: 1
+ computed_fields:
+ HEADER:
+ INVERSE_VALUE: pfr_reg_inverse_lower_8_bits
+ VENDOR_USAGE:
+ INVERSE_VALUE: pfr_reg_inverse_high_half
+ DCFG_CC_SOCU_NS_PIN:
+ INVERSE_VALUE: pfr_reg_inverse_high_half
+ DCFG_CC_SOCU_NS_DFLT:
+ INVERSE_VALUE: pfr_reg_inverse_high_half
attributes:
computed_registers:
SHA256_DIGEST: ""
diff --git a/spsdk/data/pfr/cfpa/mcxn9xx_a0.xml b/spsdk/data/pfr/cfpa/mcxn9xx_a0.xml
new file mode 100644
index 00000000..4ae406c2
--- /dev/null
+++ b/spsdk/data/pfr/cfpa/mcxn9xx_a0.xml
@@ -0,0 +1,803 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spsdk/data/pfr/cmpa/database.yaml b/spsdk/data/pfr/cmpa/database.yaml
index 2bc4b78e..c5d30a2f 100644
--- a/spsdk/data/pfr/cmpa/database.yaml
+++ b/spsdk/data/pfr/cmpa/database.yaml
@@ -106,6 +106,26 @@ devices:
INVERSE_VALUE: pfr_reg_inverse_high_half
CC_SOCU_DFLT:
INVERSE_VALUE: pfr_reg_inverse_high_half
+ mcxn9xx:
+ revisions:
+ a0:
+ data_file: mcxn9xx_a0.xml
+ latest: a0
+ attributes:
+ address: 0x0100_4000
+ seal_start: CMPA_CMAC0
+ seal_count: 4
+ mandatory_computed_regs: 1
+ grouped_registers:
+ - name: ROTKH
+ width: 384
+ reversed: true
+ config_as_hexstring: true
+ description:
+ ROTKH field is compounded by 12 32-bit fields and contains Root key table hash.
+ For ECC P-256 keys RKTH is a 32-bit SHA-256 digest of four SHA-256 digests computed over
+ four OEM public keys (OEM has four private-public key pairs in case one of its private keys
+ becomes compromised) or in case that ECC P-384 keys are used, RKTH is 48-bit SHA-384 digest.
attributes:
computed_registers:
SHA256_DIGEST: ""
diff --git a/spsdk/data/pfr/cmpa/mcxn9xx_a0.xml b/spsdk/data/pfr/cmpa/mcxn9xx_a0.xml
new file mode 100644
index 00000000..a31660b6
--- /dev/null
+++ b/spsdk/data/pfr/cmpa/mcxn9xx_a0.xml
@@ -0,0 +1,1227 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spsdk/data/pfr/pfrc/rules_lpc55xx.yaml b/spsdk/data/pfr/pfrc/rules_lpc55xx.yaml
index a4c77cab..21a9f5d8 100644
--- a/spsdk/data/pfr/pfrc/rules_lpc55xx.yaml
+++ b/spsdk/data/pfr/pfrc/rules_lpc55xx.yaml
@@ -3,8 +3,7 @@
# SPDX-License-Identifier: BSD-3-Clause
- req_id: "lpc55xx_4.1"
- desc:
- By default (blank device), the RoTKx_EN values are set to 0b00 which means
+ desc: By default (blank device), the RoTKx_EN values are set to 0b00 which means
invalid. When secure boot is enabled (SEC_BOOT_EN != 0) there must be at
least one RoTKx_EN which is set to 0b01 (enabled) to allow device to boot
successfully.
diff --git a/spsdk/data/shadowregs/database.yaml b/spsdk/data/shadowregs/database.yaml
index ff1c5e84..dc5a51f4 100644
--- a/spsdk/data/shadowregs/database.yaml
+++ b/spsdk/data/shadowregs/database.yaml
@@ -37,6 +37,33 @@ devices:
CRC8: comalg_dcfg_cc_socu_crc8
"SEC_BOOT_CFG[5]":
RESERVED: comalg_do_nothing
+ rw61x:
+ revisions:
+ a1:
+ data_file: rw61x_a1.xml
+ latest: a1
+ attributes:
+ address: 0x3012_6000
+ flush_func: rw61x_update_scratch_reg
+ inverted_regs:
+ DCFG_CC_SOCU: DCFG_CC_SOCU_AP
+ computed_fields:
+ DCFG_CC_SOCU:
+ CRC8_AP[7:0]: comalg_dcfg_cc_socu_crc8
+ DCFG_CC_SOCU_NS:
+ CRC8_AP[7:0]: comalg_dcfg_cc_socu_crc8
+ grouped_registers:
+ - name: RKTH
+ width: 384
+ config_as_hexstring: true
+ reversed: true
+ description:
+ ROTKH field is compounded by 12 32-bit fields and contains Root key
+ table hash. For ECC P-256 keys RKTH is a 32-bit SHA-256 digest of four
+ SHA-256 digests computed over four OEM public keys (OEM has four
+ private-public key pairs in case one of its private keys becomes
+ compromised) or in case that ECC P-384 keys are used, RKTH is 48-bit
+ SHA-384 digest.
attributes:
grouped_registers:
- name: OTFAD_KEK_SEED
diff --git a/spsdk/data/shadowregs/rw61x_a1.xml b/spsdk/data/shadowregs/rw61x_a1.xml
new file mode 100644
index 00000000..3aa743b6
--- /dev/null
+++ b/spsdk/data/shadowregs/rw61x_a1.xml
@@ -0,0 +1,613 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spsdk/data/tz_presets/database.yaml b/spsdk/data/tz_presets/database.yaml
index 6d10ef64..5f51e844 100644
--- a/spsdk/data/tz_presets/database.yaml
+++ b/spsdk/data/tz_presets/database.yaml
@@ -51,6 +51,13 @@ devices:
a1:
data_file: nhs52s04.yaml
latest: a1
+ mcxn9xx:
+ revisions:
+ a0:
+ data_file: mcxn9xx_a0.yaml
+ a1:
+ data_file: mcxn9xx_a1.yaml
+ latest: a0
kw45xx:
revisions:
a1:
diff --git a/spsdk/data/tz_presets/mcxn9xx_a0.yaml b/spsdk/data/tz_presets/mcxn9xx_a0.yaml
new file mode 100644
index 00000000..c79a9828
--- /dev/null
+++ b/spsdk/data/tz_presets/mcxn9xx_a0.yaml
@@ -0,0 +1,193 @@
+# Copyright 2023 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+Start of block (tzm_magic): "0x4d2d5a54"
+Secure vector table address (cm33_vtor_addr): "0x0"
+Non-secure vector table address (cm33_vtor_ns_addr): "0x0"
+Interrupt target non-secure register 0 (cm33_nvic_itns0): "0x0"
+Interrupt target non-secure register 1 (cm33_nvic_itns1): "0x0"
+Interrupt target non-secure register 2 (cm33_nvic_itns2): "0x0"
+Interrupt target non-secure register 3 (cm33_nvic_itns3): "0x0"
+Interrupt target non-secure register 4 (cm33_nvic_itns4): "0x0"
+Miscellaneous CM33 settings (cm33_misc_ctrl): "0x0"
+CM33 Non-secure Access Control Register (cm33_nsacr): "0x0"
+CM33 Coprocessor Power Control Register (cm33_cppwr): "0x0"
+CM33 Coprocessor Access Control Register (cm33_cpacr): "0x0"
+MPU Control Register (cm33_mpu_ctrl): "0x0"
+MPU Memory Attribute Indirection Register 0 (cm33_mpu_mair0): "0x0"
+MPU Memory Attribute Indirection Register 1 (cm33_mpu_mair1): "0x0"
+MPU Region 0 Base Address Register (cm33_mpu_rbar0): "0x0"
+MPU Region 0 Limit Address Register (cm33_mpu_rlar0): "0x0"
+MPU Region 1 Base Address Register (cm33_mpu_rbar1): "0x0"
+MPU Region 1 Limit Address Register (cm33_mpu_rlar1): "0x0"
+MPU Region 2 Base Address Register (cm33_mpu_rbar2): "0x0"
+MPU Region 2 Limit Address Register (cm33_mpu_rlar2): "0x0"
+MPU Region 3 Base Address Register (cm33_mpu_rbar3): "0x0"
+MPU Region 3 Limit Address Register (cm33_mpu_rlar3): "0x0"
+MPU Region 4 Base Address Register (cm33_mpu_rbar4): "0x0"
+MPU Region 4 Limit Address Register (cm33_mpu_rlar4): "0x0"
+MPU Region 5 Base Address Register (cm33_mpu_rbar5): "0x0"
+MPU Region 5 Limit Address Register (cm33_mpu_rlar5): "0x0"
+MPU Region 6 Base Address Register (cm33_mpu_rbar6): "0x0"
+MPU Region 6 Limit Address Register (cm33_mpu_rlar6): "0x0"
+MPU Region 7 Base Address Register (cm33_mpu_rbar7): "0x0"
+MPU Region 7 Limit Address Register (cm33_mpu_rlar7): "0x0"
+Non-secure MPU Control Register (cm33_mpu_ctrl_ns): "0x0"
+Non-secure MPU Memory Attribute Indirection Register 0 (cm33_mpu_mair0_ns): "0x0"
+Non-secure MPU Memory Attribute Indirection Register 1 (cm33_mpu_mair1_ns): "0x0"
+Non-secure MPU Region 0 Base Address Register (cm33_mpu_rbar0_ns): "0x0"
+Non-secure MPU Region 0 Limit Address Register (cm33_mpu_rlar0_ns): "0x0"
+Non-secure MPU Region 1 Base Address Register (cm33_mpu_rbar1_ns): "0x0"
+Non-secure MPU Region 1 Limit Address Register (cm33_mpu_rlar1_ns): "0x0"
+Non-secure MPU Region 2 Base Address Register (cm33_mpu_rbar2_ns): "0x0"
+Non-secure MPU Region 2 Limit Address Register (cm33_mpu_rlar2_ns): "0x0"
+Non-secure MPU Region 3 Base Address Register (cm33_mpu_rbar3_ns): "0x0"
+Non-secure MPU Region 3 Limit Address Register (cm33_mpu_rlar3_ns): "0x0"
+Non-secure MPU Region 4 Base Address Register (cm33_mpu_rbar4_ns): "0x0"
+Non-secure MPU Region 4 Limit Address Register (cm33_mpu_rlar4_ns): "0x0"
+Non-secure MPU Region 5 Base Address Register (cm33_mpu_rbar5_ns): "0x0"
+Non-secure MPU Region 5 Limit Address Register (cm33_mpu_rlar5_ns): "0x0"
+Non-secure MPU Region 6 Base Address Register (cm33_mpu_rbar6_ns): "0x0"
+Non-secure MPU Region 6 Limit Address Register (cm33_mpu_rlar6_ns): "0x0"
+Non-secure MPU Region 7 Base Address Register (cm33_mpu_rbar7_ns): "0x0"
+Non-secure MPU Region 7 Limit Address Register (cm33_mpu_rlar7_ns): "0x0"
+SAU Control Register (cm33_sau_ctrl): "0x0"
+SAU Region 0 Base Address Register (cm33_sau_rbar0): "0x0"
+SAU Region 0 Limit Address Register (cm33_sau_rlar0): "0x0"
+SAU Region 1 Base Address Register (cm33_sau_rbar1): "0x0"
+SAU Region 1 Limit Address Register (cm33_sau_rlar1): "0x0"
+SAU Region 2 Base Address Register (cm33_sau_rbar2): "0x0"
+SAU Region 2 Limit Address Register (cm33_sau_rlar2): "0x0"
+SAU Region 3 Base Address Register (cm33_sau_rbar3): "0x0"
+SAU Region 3 Limit Address Register (cm33_sau_rlar3): "0x0"
+SAU Region 4 Base Address Register (cm33_sau_rbar4): "0x0"
+SAU Region 4 Limit Address Register (cm33_sau_rlar4): "0x0"
+SAU Region 5 Base Address Register (cm33_sau_rbar5): "0x0"
+SAU Region 5 Limit Address Register (cm33_sau_rlar5): "0x0"
+SAU Region 6 Base Address Register (cm33_sau_rbar6): "0x0"
+SAU Region 6 Limit Address Register (cm33_sau_rlar6): "0x0"
+SAU Region 7 Base Address Register (cm33_sau_rbar7): "0x0"
+SAU Region 7 Limit Address Register (cm33_sau_rlar7): "0x0"
+FLASH 00 Memory Rule Register 0 (flash00_mem_rule0): "0x0"
+FLASH 00 Memory Rule Register 1 (flash00_mem_rule1): "0x0"
+FLASH 00 Memory Rule Register 2 (flash00_mem_rule2): "0x0"
+FLASH 00 Memory Rule Register 3 (flash00_mem_rule3): "0x0"
+FLASH 01 Memory Rule Register 0 (flash01_mem_rule0): "0x0"
+FLASH 01 Memory Rule Register 1 (flash01_mem_rule1): "0x0"
+FLASH 01 Memory Rule Register 2 (flash01_mem_rule2): "0x0"
+FLASH 01 Memory Rule Register 3 (flash01_mem_rule3): "0x0"
+FLASH 02 Memory Rule Register (flash02_mem_rule): "0x0"
+FLASH 03 Memory Rule Register (flash03_mem_rule): "0x0"
+ROM Memory Rule Register 0 (rom_mem_rule0): "0x33333333"
+ROM Memory Rule Register 1 (rom_mem_rule1): "0x33333333"
+ROM Memory Rule Register 2 (rom_mem_rule2): "0x33333333"
+ROM Memory Rule Register 3 (rom_mem_rule3): "0x33333333"
+RAMX Memory Rule Register 0 (ramx_mem_rule0): "0x0"
+RAMX Memory Rule Register 1 (ramx_mem_rule1): "0x0"
+RAMX Memory Rule Register 2 (ramx_mem_rule2): "0x0"
+RAMX Memory Rule Register 3 (ramx_mem_rule3): "0x0"
+RAMA Memory Rule Register (rama_mem_rule): "0x0"
+RAMB Memory Rule Register (ramb_mem_rule): "0x0"
+RAMC Memory Rule Register 0 (ramc_mem_rule0): "0x0"
+RAMC Memory Rule Register 1 (ramc_mem_rule1): "0x0"
+RAMD Memory Rule Register 0 (ramd_mem_rule0): "0x0"
+RAMD Memory Rule Register 1 (ramd_mem_rule1): "0x0"
+RAME Memory Rule Register 0 (rame_mem_rule0): "0x0"
+RAME Memory Rule Register 1 (rame_mem_rule1): "0x0"
+RAMF Memory Rule Register 0 (ramf_mem_rule0): "0x0"
+RAMF Memory Rule Register 1 (ramf_mem_rule1): "0x0"
+RAMG Memory Rule Register 0 (ramg_mem_rule0): "0x0"
+RAMG Memory Rule Register 1 (ramg_mem_rule1): "0x0"
+RAMH Memory Rule Register 0 (ramh_mem_rule0): "0x0"
+APB Bridge 0 Memory Rule Register 0 (apb_bridge0_mem_rule0): "0x33333333"
+APB Bridge 0 Memory Rule Register 1 (apb_bridge0_mem_rule1): "0x33333333"
+APB Bridge 0 Memory Rule Register 2 (apb_bridge0_mem_rule2): "0x33333333"
+APB Bridge 0 Memory Rule Register 3 (apb_bridge0_mem_rule3): "0x33333333"
+APB Bridge 1 Memory Rule Register 0 (apb_bridge1_mem_rule0): "0x33333333"
+APB Bridge 1 Memory Rule Register 1 (apb_bridge1_mem_rule1): "0x33333333"
+APB Bridge 1 Memory Rule Register 2 (apb_bridge1_mem_rule2): "0x33333333"
+AIPS BRIDGE 0 Peripherals Memory Rule Register 0 (aips_bridge0_mem_rule0): "0x33333333"
+AIPS BRIDGE 0 Peripherals Memory Rule Register 1 (aips_bridge0_mem_rule1): "0x33333333"
+AIPS BRIDGE 0 Peripherals Memory Rule Register 2 (aips_bridge0_mem_rule2): "0x33333333"
+AIPS BRIDGE 0 Peripherals Memory Rule Register 3 (aips_bridge0_mem_rule3): "0x33333333"
+AHB Peripherals 0 Memory Rule Register 0 (ahb_periph0_mem_rule0): "0x33333333"
+AHB Peripherals 0 Memory Rule Register 1 (ahb_periph0_mem_rule1): "0x33333333"
+AHB Peripherals 0 Memory Rule Register 2 (ahb_periph0_mem_rule2): "0x00000003"
+AIPS BRIDGE 1 Peripherals Memory Rule Register 0 (aips_bridge1_mem_rule0): "0x33333333"
+AIPS BRIDGE 1 Peripherals Memory Rule Register 1 (aips_bridge1_mem_rule1): "0x33333333"
+AHB Peripherals 1 Memory Rule Register 0 (ahb_periph1_mem_rule0): "0x33333333"
+AHB Peripherals 1 Memory Rule Register 1 (ahb_periph1_mem_rule1): "0x33333333"
+AHB Peripherals 1 Memory Rule Register 2 (ahb_periph1_mem_rule2): "0x00000003"
+AIPS BRIDGE 2 Peripherals Memory Rule Register 0 (aips_bridge2_mem_rule0): "0x33333333"
+AIPS BRIDGE 2 Peripherals Memory Rule Register 1 (aips_bridge2_mem_rule1): "0x33333333"
+AIPS BRIDGE 3 Peripherals Memory Rule Register 0 (aips_bridge3_mem_rule0): "0x33333333"
+AIPS BRIDGE 3 Peripherals Memory Rule Register 1 (aips_bridge3_mem_rule1): "0x33333333"
+AIPS BRIDGE 3 Peripherals Memory Rule Register 2 (aips_bridge3_mem_rule2): "0x33333333"
+AIPS BRIDGE 3 Peripherals Memory Rule Register 3 (aips_bridge3_mem_rule3): "0x33333333"
+AIPS BRIDGE 4 Peripherals Memory Rule Register 0 (aips_bridge4_mem_rule0): "0x33333333"
+AIPS BRIDGE 4 Peripherals Memory Rule Register 1 (aips_bridge4_mem_rule1): "0x33333333"
+AIPS BRIDGE 4 Peripherals Memory Rule Register 2 (aips_bridge4_mem_rule2): "0x33333333"
+AIPS BRIDGE 4 Peripherals Memory Rule Register 3 (aips_bridge4_mem_rule3): "0x33333333"
+AHB Secure Controller Peripheral Rule Register (ahb_sec_ctrl_periph_rule): "0x00003333"
+FLEXSPI0 Region 0 Memory Rule Register 0 (fspi0_reg0_mem_rule0): "0x0"
+FLEXSPI0 Region 0 Memory Rule Register 1 (fspi0_reg0_mem_rule1): "0x0"
+FLEXSPI0 Region 0 Memory Rule Register 2 (fspi0_reg0_mem_rule2): "0x0"
+FLEXSPI0 Region 0 Memory Rule Register 3 (fspi0_reg0_mem_rule3): "0x0"
+FLEXSPI0 Region 1 Memory Rule Register (fspi0_reg1_mem_rule): "0x0"
+FLEXSPI0 Region 2 Memory Rule Register (fspi0_reg2_mem_rule): "0x0"
+FLEXSPI0 Region 3 Memory Rule Register (fspi0_reg3_mem_rule): "0x0"
+FLEXSPI0 Region 4 Memory Rule Register (fspi0_reg4_mem_rule): "0x0"
+FLEXSPI0 Region 5 Memory Rule Register (fspi0_reg5_mem_rule): "0x0"
+FLEXSPI0 Region 6 Memory Rule Register (fspi0_reg6_mem_rule): "0x0"
+FLEXSPI0 Region 7 Memory Rule Register 0 (fspi0_reg7_mem_rule0): "0x0"
+FLEXSPI0 Region 7 Memory Rule Register 1 (fspi0_reg7_mem_rule1): "0x0"
+FLEXSPI0 Region 7 Memory Rule Register 2 (fspi0_reg7_mem_rule2): "0x0"
+FLEXSPI0 Region 7 Memory Rule Register 3 (fspi0_reg7_mem_rule3): "0x0"
+FLEXSPI0 Region 8 Memory Rule Register (fspi0_reg8_mem_rule): "0x0"
+FLEXSPI0 Region 9 Memory Rule Register (fspi0_reg9_mem_rule): "0x0"
+FLEXSPI0 Region 10 Memory Rule Register (fspi0_reg10_mem_rule): "0x0"
+FLEXSPI0 Region 11 Memory Rule Register (fspi0_reg11_mem_rule): "0x0"
+FLEXSPI0 Region 12 Memory Rule Register (fspi0_reg12_mem_rule): "0x0"
+FLEXSPI0 Region 13 Memory Rule Register (fspi0_reg13_mem_rule): "0x0"
+Secure GPIO Mask Register 0 (sec_gpio_mask0): "0xffffffff"
+Secure GPIO Mask Register 1 (sec_gpio_mask1): "0xffffffff"
+Secure GPIO Mask Register 2 (sec_gpio_mask2): "0x00000fff"
+Secure GPIO Mask Register 3 (sec_gpio_mask3): "0x00ffffff"
+Secure GPIO Mask Register 4 (sec_gpio_mask4): "0x00ffffff"
+Secure GPIO Mask Register 5 (sec_gpio_mask5): "0x000003ff"
+Secure GPIO Mask Register 5 (sec_gpio_mask6): "0xffffffff"
+Secure GPIO Mask Register 5 (sec_gpio_mask7): "0xffffffff"
+Secure GPIO Mask Register 5 (sec_gpio_mask8): "0xffffffff"
+Secure GPIO Mask Register 5 (sec_gpio_mask9): "0xffffffff"
+Secure GPIO Mask Register 5 (sec_gpio_mask10): "0x0fffffff"
+Secure GPIO Mask Lock Register 2 (sec_mask_lock): "0x002aaaaa"
+Master Secure Level Register (master_sec_reg): "0x80000000"
+Master Secure Level Anti-pole Register (master_sec_anti_pol_reg): "0xbfffffff"
+CM33 Lock Control Register 0 (cm33_lock_reg0): "0x800002aa"
+CM33 Lock Control Register 1 (cm33_lock_reg1): "0x800002aa"
+Secure Control Duplicate Register (misc_ctrl_dp_reg): "0x000086aa"
+Secure Control Register (misc_ctrl_reg): "0x000086aa"
+MBC Global Access Control Register 0 (mbc0_memn_glbac0): "0x00006600"
+MBC Global Access Control Register 4 (mbc0_memn_glbac4): "0x00005500"
+MBC Global Access Control Register 5 (mbc0_memn_glbac5): "0x00001100"
+MBC Memory Block Configuration Word 0 (mbc0_dom0_mem0_blk_cfg_w0): "0x0"
+MBC Memory Block Configuration Word 1 (mbc0_dom0_mem0_blk_cfg_w1): "0x0"
+MBC Memory Block Configuration Word 2 (mbc0_dom0_mem0_blk_cfg_w2): "0x0"
+MBC Memory Block Configuration Word 3 (mbc0_dom0_mem0_blk_cfg_w3): "0x0"
+MBC Memory Block Configuration Word 4 (mbc0_dom0_mem0_blk_cfg_w4): "0x0"
+MBC Memory Block Configuration Word 5 (mbc0_dom0_mem0_blk_cfg_w5): "0x0"
+MBC Memory Block Configuration Word 6 (mbc0_dom0_mem0_blk_cfg_w6): "0x0"
+MBC Memory Block Configuration Word 7 (mbc0_dom0_mem0_blk_cfg_w7): "0x0"
+ITRC IRQ Trigger source selector register 0 (itrc_irq_out0_sel0): "0xaaaaaaaa"
+ITRC IRQ Trigger source selector register 1 (itrc_irq_out0_sel1): "0xaaaaaaaa"
+ITRC ELS_RESET Trigger source selector register 0 (itrc_els_reset_out1_sel0): "0xaaaaaaaa"
+ITRC ELS_RESET Trigger source selector register 1 (itrc_els_reset_out1_sel1): "0xaaaaaaaa"
+ITRC PUF_ZEROIZE Trigger source selector register 0 (itrc_puf_zeroize_out2_sel0): "0xaaaaaaaa"
+ITRC PUF_ZEROIZE Trigger source selector register 1 (itrc_puf_zeroize_out2_sel1): "0xaaaaaaaa"
+ITRC RAM_ZEROIZE Trigger source selector register 0 (itrc_ram_zeroize_out3_sel0): "0xaaaaaaaa"
+ITRC RAM_ZEROIZE Trigger source selector register 1 (itrc_ram_zeroize_out3_sel1): "0xaaaaaaaa"
+ITRC CHIP_RESET Trigger source selector register 0 (itrc_chip_reset_out4_sel0): "0xaaaaaaaa"
+ITRC CHIP_RESET Trigger source selector register 1 (itrc_chip_reset_out4_sel1): "0xaaaaaaaa"
+ITRC ITR_OUT Trigger source selector register 0 (itrc_itr_out_out5_sel0): "0xaaaaaaaa"
+ITRC ITR_OUT Trigger source selector register 1 (itrc_itr_out_out5_sel1): "0xaaaaaaaa"
diff --git a/spsdk/data/tz_presets/mcxn9xx_a1.yaml b/spsdk/data/tz_presets/mcxn9xx_a1.yaml
new file mode 100644
index 00000000..6a333358
--- /dev/null
+++ b/spsdk/data/tz_presets/mcxn9xx_a1.yaml
@@ -0,0 +1,249 @@
+# Copyright 2023 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+tart of block (tzm_magic): "0x4d2d5a54"
+Secure vector table address (cm33_vtor_addr): "0x0"
+Non-secure vector table address (cm33_vtor_ns_addr): "0x0"
+Interrupt target non-secure register 0 (cm33_nvic_itns0): "0x0"
+Interrupt target non-secure register 1 (cm33_nvic_itns1): "0x0"
+Interrupt target non-secure register 2 (cm33_nvic_itns2): "0x0"
+Interrupt target non-secure register 3 (cm33_nvic_itns3): "0x0"
+Interrupt target non-secure register 4 (cm33_nvic_itns4): "0x0"
+Miscellaneous CM33 settings (cm33_misc_ctrl): "0x0"
+CM33 Non-secure Access Control Register (cm33_nsacr): "0x0"
+CM33 Coprocessor Power Control Register (cm33_cppwr): "0x0"
+CM33 Coprocessor Access Control Register (cm33_cpacr): "0x0"
+MPU Control Register (cm33_mpu_ctrl): "0x0"
+MPU Memory Attribute Indirection Register 0 (cm33_mpu_mair0): "0x0"
+MPU Memory Attribute Indirection Register 1 (cm33_mpu_mair1): "0x0"
+MPU Region 0 Base Address Register (cm33_mpu_rbar0): "0x0"
+MPU Region 0 Limit Address Register (cm33_mpu_rlar0): "0x0"
+MPU Region 1 Base Address Register (cm33_mpu_rbar1): "0x0"
+MPU Region 1 Limit Address Register (cm33_mpu_rlar1): "0x0"
+MPU Region 2 Base Address Register (cm33_mpu_rbar2): "0x0"
+MPU Region 2 Limit Address Register (cm33_mpu_rlar2): "0x0"
+MPU Region 3 Base Address Register (cm33_mpu_rbar3): "0x0"
+MPU Region 3 Limit Address Register (cm33_mpu_rlar3): "0x0"
+MPU Region 4 Base Address Register (cm33_mpu_rbar4): "0x0"
+MPU Region 4 Limit Address Register (cm33_mpu_rlar4): "0x0"
+MPU Region 5 Base Address Register (cm33_mpu_rbar5): "0x0"
+MPU Region 5 Limit Address Register (cm33_mpu_rlar5): "0x0"
+MPU Region 6 Base Address Register (cm33_mpu_rbar6): "0x0"
+MPU Region 6 Limit Address Register (cm33_mpu_rlar6): "0x0"
+MPU Region 7 Base Address Register (cm33_mpu_rbar7): "0x0"
+MPU Region 7 Limit Address Register (cm33_mpu_rlar7): "0x0"
+Non-secure MPU Control Register (cm33_mpu_ctrl_ns): "0x0"
+Non-secure MPU Memory Attribute Indirection Register 0 (cm33_mpu_mair0_ns): "0x0"
+Non-secure MPU Memory Attribute Indirection Register 1 (cm33_mpu_mair1_ns): "0x0"
+Non-secure MPU Region 0 Base Address Register (cm33_mpu_rbar0_ns): "0x0"
+Non-secure MPU Region 0 Limit Address Register (cm33_mpu_rlar0_ns): "0x0"
+Non-secure MPU Region 1 Base Address Register (cm33_mpu_rbar1_ns): "0x0"
+Non-secure MPU Region 1 Limit Address Register (cm33_mpu_rlar1_ns): "0x0"
+Non-secure MPU Region 2 Base Address Register (cm33_mpu_rbar2_ns): "0x0"
+Non-secure MPU Region 2 Limit Address Register (cm33_mpu_rlar2_ns): "0x0"
+Non-secure MPU Region 3 Base Address Register (cm33_mpu_rbar3_ns): "0x0"
+Non-secure MPU Region 3 Limit Address Register (cm33_mpu_rlar3_ns): "0x0"
+Non-secure MPU Region 4 Base Address Register (cm33_mpu_rbar4_ns): "0x0"
+Non-secure MPU Region 4 Limit Address Register (cm33_mpu_rlar4_ns): "0x0"
+Non-secure MPU Region 5 Base Address Register (cm33_mpu_rbar5_ns): "0x0"
+Non-secure MPU Region 5 Limit Address Register (cm33_mpu_rlar5_ns): "0x0"
+Non-secure MPU Region 6 Base Address Register (cm33_mpu_rbar6_ns): "0x0"
+Non-secure MPU Region 6 Limit Address Register (cm33_mpu_rlar6_ns): "0x0"
+Non-secure MPU Region 7 Base Address Register (cm33_mpu_rbar7_ns): "0x0"
+Non-secure MPU Region 7 Limit Address Register (cm33_mpu_rlar7_ns): "0x0"
+SAU Control Register (cm33_sau_ctrl): "0x0"
+SAU Region 0 Base Address Register (cm33_sau_rbar0): "0x0"
+SAU Region 0 Limit Address Register (cm33_sau_rlar0): "0x0"
+SAU Region 1 Base Address Register (cm33_sau_rbar1): "0x0"
+SAU Region 1 Limit Address Register (cm33_sau_rlar1): "0x0"
+SAU Region 2 Base Address Register (cm33_sau_rbar2): "0x0"
+SAU Region 2 Limit Address Register (cm33_sau_rlar2): "0x0"
+SAU Region 3 Base Address Register (cm33_sau_rbar3): "0x0"
+SAU Region 3 Limit Address Register (cm33_sau_rlar3): "0x0"
+SAU Region 4 Base Address Register (cm33_sau_rbar4): "0x0"
+SAU Region 4 Limit Address Register (cm33_sau_rlar4): "0x0"
+SAU Region 5 Base Address Register (cm33_sau_rbar5): "0x0"
+SAU Region 5 Limit Address Register (cm33_sau_rlar5): "0x0"
+SAU Region 6 Base Address Register (cm33_sau_rbar6): "0x0"
+SAU Region 6 Limit Address Register (cm33_sau_rlar6): "0x0"
+SAU Region 7 Base Address Register (cm33_sau_rbar7): "0x0"
+SAU Region 7 Limit Address Register (cm33_sau_rlar7): "0x0"
+FLASH 00 Memory Rule Register 0 (flash00_mem_rule0): "0x0"
+FLASH 00 Memory Rule Register 1 (flash00_mem_rule1): "0x0"
+FLASH 00 Memory Rule Register 2 (flash00_mem_rule2): "0x0"
+FLASH 00 Memory Rule Register 3 (flash00_mem_rule3): "0x0"
+FLASH 01 Memory Rule Register 0 (flash01_mem_rule0): "0x0"
+FLASH 01 Memory Rule Register 1 (flash01_mem_rule1): "0x0"
+FLASH 01 Memory Rule Register 2 (flash01_mem_rule2): "0x0"
+FLASH 01 Memory Rule Register 3 (flash01_mem_rule3): "0x0"
+FLASH 02 Memory Rule Register (flash02_mem_rule): "0x0"
+FLASH 03 Memory Rule Register (flash03_mem_rule): "0x0"
+ROM Memory Rule Register 0 (rom_mem_rule0): "0x33333333"
+ROM Memory Rule Register 1 (rom_mem_rule1): "0x33333333"
+ROM Memory Rule Register 2 (rom_mem_rule2): "0x33333333"
+ROM Memory Rule Register 3 (rom_mem_rule3): "0x33333333"
+RAMX Memory Rule Register 0 (ramx_mem_rule0): "0x0"
+RAMX Memory Rule Register 1 (ramx_mem_rule1): "0x0"
+RAMX Memory Rule Register 2 (ramx_mem_rule2): "0x0"
+RAMX Memory Rule Register 3 (ramx_mem_rule3): "0x0"
+RAMA Memory Rule Register (rama_mem_rule): "0x0"
+RAMB Memory Rule Register (ramb_mem_rule): "0x0"
+RAMC Memory Rule Register 0 (ramc_mem_rule0): "0x0"
+RAMC Memory Rule Register 1 (ramc_mem_rule1): "0x0"
+RAMD Memory Rule Register 0 (ramd_mem_rule0): "0x0"
+RAMD Memory Rule Register 1 (ramd_mem_rule1): "0x0"
+RAME Memory Rule Register 0 (rame_mem_rule0): "0x0"
+RAME Memory Rule Register 1 (rame_mem_rule1): "0x0"
+RAMF Memory Rule Register 0 (ramf_mem_rule0): "0x0"
+RAMF Memory Rule Register 1 (ramf_mem_rule1): "0x0"
+RAMG Memory Rule Register 0 (ramg_mem_rule0): "0x0"
+RAMG Memory Rule Register 1 (ramg_mem_rule1): "0x0"
+RAMH Memory Rule Register 0 (ramh_mem_rule0): "0x0"
+APB Bridge 0 Memory Rule Register 0 (apb_bridge0_mem_rule0): "0x33333333"
+APB Bridge 0 Memory Rule Register 1 (apb_bridge0_mem_rule1): "0x33333333"
+APB Bridge 0 Memory Rule Register 2 (apb_bridge0_mem_rule2): "0x33333333"
+APB Bridge 0 Memory Rule Register 3 (apb_bridge0_mem_rule3): "0x33333333"
+APB Bridge 1 Memory Rule Register 0 (apb_bridge1_mem_rule0): "0x33333333"
+APB Bridge 1 Memory Rule Register 1 (apb_bridge1_mem_rule1): "0x33333333"
+APB Bridge 1 Memory Rule Register 2 (apb_bridge1_mem_rule2): "0x33333333"
+AIPS BRIDGE 0 Peripherals Memory Rule Register 0 (aips_bridge0_mem_rule0): "0x33333333"
+AIPS BRIDGE 0 Peripherals Memory Rule Register 1 (aips_bridge0_mem_rule1): "0x33333333"
+AIPS BRIDGE 0 Peripherals Memory Rule Register 2 (aips_bridge0_mem_rule2): "0x33333333"
+AIPS BRIDGE 0 Peripherals Memory Rule Register 3 (aips_bridge0_mem_rule3): "0x33333333"
+AHB Peripherals 0 Memory Rule Register 0 (ahb_periph0_mem_rule0): "0x33333333"
+AHB Peripherals 0 Memory Rule Register 1 (ahb_periph0_mem_rule1): "0x33333333"
+AHB Peripherals 0 Memory Rule Register 2 (ahb_periph0_mem_rule2): "0x00000003"
+AIPS BRIDGE 1 Peripherals Memory Rule Register 0 (aips_bridge1_mem_rule0): "0x33333333"
+AIPS BRIDGE 1 Peripherals Memory Rule Register 1 (aips_bridge1_mem_rule1): "0x33333333"
+AHB Peripherals 1 Memory Rule Register 0 (ahb_periph1_mem_rule0): "0x33333333"
+AHB Peripherals 1 Memory Rule Register 1 (ahb_periph1_mem_rule1): "0x33333333"
+AHB Peripherals 1 Memory Rule Register 2 (ahb_periph1_mem_rule2): "0x00000003"
+AIPS BRIDGE 2 Peripherals Memory Rule Register 0 (aips_bridge2_mem_rule0): "0x33333333"
+AIPS BRIDGE 2 Peripherals Memory Rule Register 1 (aips_bridge2_mem_rule1): "0x33333333"
+AIPS BRIDGE 3 Peripherals Memory Rule Register 0 (aips_bridge3_mem_rule0): "0x33333333"
+AIPS BRIDGE 3 Peripherals Memory Rule Register 1 (aips_bridge3_mem_rule1): "0x33333333"
+AIPS BRIDGE 3 Peripherals Memory Rule Register 2 (aips_bridge3_mem_rule2): "0x33333333"
+AIPS BRIDGE 3 Peripherals Memory Rule Register 3 (aips_bridge3_mem_rule3): "0x33333333"
+AIPS BRIDGE 4 Peripherals Memory Rule Register 0 (aips_bridge4_mem_rule0): "0x33333333"
+AIPS BRIDGE 4 Peripherals Memory Rule Register 1 (aips_bridge4_mem_rule1): "0x33333333"
+AIPS BRIDGE 4 Peripherals Memory Rule Register 2 (aips_bridge4_mem_rule2): "0x33333333"
+AIPS BRIDGE 4 Peripherals Memory Rule Register 3 (aips_bridge4_mem_rule3): "0x33333333"
+AHB Secure Controller Peripheral Rule Register (ahb_sec_ctrl_periph_rule): "0x00003333"
+FLEXSPI0 Region 0 Memory Rule Register 0 (fspi0_reg0_mem_rule0): "0x0"
+FLEXSPI0 Region 0 Memory Rule Register 1 (fspi0_reg0_mem_rule1): "0x0"
+FLEXSPI0 Region 0 Memory Rule Register 2 (fspi0_reg0_mem_rule2): "0x0"
+FLEXSPI0 Region 0 Memory Rule Register 3 (fspi0_reg0_mem_rule3): "0x0"
+FLEXSPI0 Region 1 Memory Rule Register (fspi0_reg1_mem_rule): "0x0"
+FLEXSPI0 Region 2 Memory Rule Register (fspi0_reg2_mem_rule): "0x0"
+FLEXSPI0 Region 3 Memory Rule Register (fspi0_reg3_mem_rule): "0x0"
+FLEXSPI0 Region 4 Memory Rule Register (fspi0_reg4_mem_rule): "0x0"
+FLEXSPI0 Region 5 Memory Rule Register (fspi0_reg5_mem_rule): "0x0"
+FLEXSPI0 Region 6 Memory Rule Register (fspi0_reg6_mem_rule): "0x0"
+FLEXSPI0 Region 7 Memory Rule Register 0 (fspi0_reg7_mem_rule0): "0x0"
+FLEXSPI0 Region 7 Memory Rule Register 1 (fspi0_reg7_mem_rule1): "0x0"
+FLEXSPI0 Region 7 Memory Rule Register 2 (fspi0_reg7_mem_rule2): "0x0"
+FLEXSPI0 Region 7 Memory Rule Register 3 (fspi0_reg7_mem_rule3): "0x0"
+FLEXSPI0 Region 8 Memory Rule Register (fspi0_reg8_mem_rule): "0x0"
+FLEXSPI0 Region 9 Memory Rule Register (fspi0_reg9_mem_rule): "0x0"
+FLEXSPI0 Region 10 Memory Rule Register (fspi0_reg10_mem_rule): "0x0"
+FLEXSPI0 Region 11 Memory Rule Register (fspi0_reg11_mem_rule): "0x0"
+FLEXSPI0 Region 12 Memory Rule Register (fspi0_reg12_mem_rule): "0x0"
+FLEXSPI0 Region 13 Memory Rule Register (fspi0_reg13_mem_rule): "0x0"
+Secure GPIO Mask Register 0 (sec_gpio_mask0): "0xffffffff"
+Secure GPIO Mask Register 1 (sec_gpio_mask1): "0xffffffff"
+Secure GPIO Mask Register 5 (sec_gpio_mask6): "0xffffffff"
+Secure GPIO Mask Register 5 (sec_gpio_mask7): "0xffffffff"
+Secure GPIO Mask Register 5 (sec_gpio_mask8): "0xffffffff"
+Secure GPIO Mask Register 5 (sec_gpio_mask9): "0xffffffff"
+Secure GPIO Mask Register 5 (sec_gpio_mask10): "0x0fffffff"
+Secure GPIO Mask Lock Register 2 (sec_mask_lock): "0x002aaaaa"
+Master Secure Level Register (master_sec_reg): "0x80000000"
+Master Secure Level Anti-pole Register (master_sec_anti_pol_reg): "0xbfffffff"
+CM33 Lock Control Register 0 (cm33_lock_reg0): "0x800002aa"
+CM33 Lock Control Register 1 (cm33_lock_reg1): "0x800002aa"
+Secure Control Duplicate Register (misc_ctrl_dp_reg): "0x000086aa"
+Secure Control Register (misc_ctrl_reg): "0x000086aa"
+MBC Global Access Control Register 0 (mbc0_memn_glbac0): "0x00006600"
+MBC Global Access Control Register 4 (mbc0_memn_glbac4): "0x00005500"
+MBC Global Access Control Register 5 (mbc0_memn_glbac5): "0x00001100"
+MBC Memory Block Configuration Word 0 (mbc0_dom0_mem0_blk_cfg_w0): "0x0"
+MBC Memory Block Configuration Word 1 (mbc0_dom0_mem0_blk_cfg_w1): "0x0"
+MBC Memory Block Configuration Word 2 (mbc0_dom0_mem0_blk_cfg_w2): "0x0"
+MBC Memory Block Configuration Word 3 (mbc0_dom0_mem0_blk_cfg_w3): "0x0"
+MBC Memory Block Configuration Word 4 (mbc0_dom0_mem0_blk_cfg_w4): "0x0"
+MBC Memory Block Configuration Word 5 (mbc0_dom0_mem0_blk_cfg_w5): "0x0"
+MBC Memory Block Configuration Word 6 (mbc0_dom0_mem0_blk_cfg_w6): "0x0"
+MBC Memory Block Configuration Word 7 (mbc0_dom0_mem0_blk_cfg_w7): "0x0"
+ITRC IRQ Trigger source selector register 0 (itrc_irq_out0_sel0): "0xaaaaaaaa"
+ITRC IRQ Trigger source selector register 1 (itrc_irq_out0_sel1): "0xaaaaaaaa"
+ITRC CSS_RESET Trigger source selector register 0 (itrc_css_reset_out1_sel0): "0xaaaaaaaa"
+ITRC CSS_RESET Trigger source selector register 1 (itrc_css_reset_out1_sel1): "0xaaaaaaaa"
+ITRC PUF_ZEROIZE Trigger source selector register 0 (itrc_puf_zeroize_out2_sel0): "0xaaaaaaaa"
+ITRC PUF_ZEROIZE Trigger source selector register 1 (itrc_puf_zeroize_out2_sel1): "0xaaaaaaaa"
+ITRC RAM_ZEROIZE Trigger source selector register 0 (itrc_ram_zeroize_out3_sel0): "0xaaaaaaaa"
+ITRC RAM_ZEROIZE Trigger source selector register 1 (itrc_ram_zeroize_out3_sel1): "0xaaaaaaaa"
+ITRC CHIP_RESET Trigger source selector register 0 (itrc_chip_reset_out4_sel0): "0xaaaaaaaa"
+ITRC CHIP_RESET Trigger source selector register 1 (itrc_chip_reset_out4_sel1): "0xaaaaaaaa"
+ITRC ITR_OUT Trigger source selector register 0 (itrc_itr_out_out5_sel0): "0xaaaaaaaa"
+ITRC ITR_OUT Trigger source selector register 1 (itrc_itr_out_out5_sel1): "0xaaaaaaaa"
+ITRC ITR_OUT Trigger source selector register 0 (itrc_itr_out_out6_sel0): "0xaaaaaaaa"
+ITRC ITR_OUT Trigger source selector register 1 (itrc_itr_out_out6_sel1): "0xaaaaaaaa"
+ITRC IRQ Trigger source selector register 0 (itrc_irq_out0_sel0_1): "0xaaaaaaaa"
+ITRC IRQ Trigger source selector register 1 (itrc_irq_out0_sel1_1): "0xaaaaaaaa"
+ITRC CSS_RESET Trigger source selector register 0 (itrc_css_reset_out1_sel0_1): "0xaaaaaaaa"
+ITRC CSS_RESET Trigger source selector register 1 (itrc_css_reset_out1_sel1_1): "0xaaaaaaaa"
+ITRC PUF_ZEROIZE Trigger source selector register 0 (itrc_puf_zeroize_out2_sel0_1): "0xaaaaaaaa"
+ITRC PUF_ZEROIZE Trigger source selector register 1 (itrc_puf_zeroize_out2_sel1_1): "0xaaaaaaaa"
+ITRC RAM_ZEROIZE Trigger source selector register 0 (itrc_ram_zeroize_out3_sel0_1): "0xaaaaaaaa"
+ITRC RAM_ZEROIZE Trigger source selector register 1 (itrc_ram_zeroize_out3_sel1_1): "0xaaaaaaaa"
+ITRC CHIP_RESET Trigger source selector register 0 (itrc_chip_reset_out4_sel0_1): "0xaaaaaaaa"
+ITRC CHIP_RESET Trigger source selector register 1 (itrc_chip_reset_out4_sel1_1): "0xaaaaaaaa"
+ITRC ITR_OUT Trigger source selector register 0 (itrc_itr_out_out5_sel0_1): "0xaaaaaaaa"
+ITRC ITR_OUT Trigger source selector register 1 (itrc_itr_out_out5_sel1_1): "0xaaaaaaaa"
+ITRC ITR_OUT Trigger source selector register 0 (itrc_itr_out_out6_sel0_1): "0xaaaaaaaa"
+ITRC ITR_OUT Trigger source selector register 1 (itrc_itr_out_out6_sel1_1): "0xaaaaaaaa"
+ITRC IRQ Trigger source selector register 0 (itrc_irq_out0_sel0_2): "0xa0002aaa"
+ITRC IRQ Trigger source selector register 1 (itrc_irq_out0_sel1_2): "0xa0002aaa"
+ITRC CSS_RESET Trigger source selector register 0 (itrc_css_reset_out1_sel0_2): "0xa0002aaa"
+ITRC CSS_RESET Trigger source selector register 1 (itrc_css_reset_out1_sel1_2): "0xa0002aaa"
+ITRC PUF_ZEROIZE Trigger source selector register 0 (itrc_puf_zeroize_out2_sel0_2): "0xa0002aaa"
+ITRC PUF_ZEROIZE Trigger source selector register 1 (itrc_puf_zeroize_out2_sel1_2): "0xa0002aaa"
+ITRC RAM_ZEROIZE Trigger source selector register 0 (itrc_ram_zeroize_out3_sel0_2): "0xa0002aaa"
+ITRC RAM_ZEROIZE Trigger source selector register 1 (itrc_ram_zeroize_out3_sel1_2): "0xa0002aaa"
+ITRC CHIP_RESET Trigger source selector register 0 (itrc_chip_reset_out4_sel0_2): "0xa0002aaa"
+ITRC CHIP_RESET Trigger source selector register 1 (itrc_chip_reset_out4_sel1_2): "0xa0002aaa"
+ITRC ITR_OUT Trigger source selector register 0 (itrc_itr_out_out5_sel0_2): "0xa0002aaa"
+ITRC ITR_OUT Trigger source selector register 1 (itrc_itr_out_out5_sel1_2): "0xa0002aaa"
+ITRC ITR_OUT Trigger source selector register 0 (itrc_itr_out_out6_sel0_2): "0xa0002aaa"
+ITRC ITR_OUT Trigger source selector register 1 (itrc_itr_out_out6_sel1_2): "0xa0002aaa"
+GPIO0 Pin Control Non-Secure (gpio0_pcns): "0x00000000"
+GPIO0 Pin Control Non-Privilege (gpio0_pcnp): "0x00000000"
+GPIO0 Interrupt Control Non-Secure (gpio0_icns): "0x00000000"
+GPIO0 Interrupt Control Non-Privilege (gpio0_icnp): "0x00000000"
+GPIO0 Lock Register (gpio0_lock): "0x0000000f"
+GPIO1 Pin Control Non-Secure (gpio1_pcns): "0x00000000"
+GPIO1 Pin Control Non-Privilege (gpio1_pcnp): "0x00000000"
+GPIO1 Interrupt Control Non-Secure (gpio1_icns): "0x00000000"
+GPIO1 Interrupt Control Non-Privilege (gpio1_icnp): "0x00000000"
+GPIO1 Lock Register (gpio1_lock): "0x00000000"
+GPIO2 Pin Control Non-Secure (gpio2_pcns): "0x00000000"
+GPIO2 Pin Control Non-Privilege (gpio2_pcnp): "0x00000000"
+GPIO2 Interrupt Control Non-Secure (gpio2_icns): "0x00000000"
+GPIO2 Interrupt Control Non-Privilege (gpio2_icnp): "0x00000000"
+GPIO2 Lock Register (gpio2_lock): "0x00000000"
+GPIO3 Pin Control Non-Secure (gpio3_pcns): "0x00000000"
+GPIO3 Pin Control Non-Privilege (gpio3_pcnp): "0x00000000"
+GPIO3 Interrupt Control Non-Secure (gpio3_icns): "0x00000000"
+GPIO3 Interrupt Control Non-Privilege (gpio3_icnp): "0x00000000"
+GPIO3 Lock Register (gpio3_lock): "0x00000000"
+GPIO4 Pin Control Non-Secure (gpio4_pcns): "0x00000000"
+GPIO4 Pin Control Non-Privilege (gpio4_pcnp): "0x00000000"
+GPIO4 Interrupt Control Non-Secure (gpio4_icns): "0x00000000"
+GPIO4 Interrupt Control Non-Privilege (gpio4_icnp): "0x00000000"
+GPIO4 Lock Register (gpio4_lock): "0x00000000"
+GPIO5 Pin Control Non-Secure (gpio5_pcns): "0x00000000"
+GPIO5 Pin Control Non-Privilege (gpio5_pcnp): "0x00000000"
+GPIO5 Interrupt Control Non-Secure (gpio5_icns): "0x00000000"
+GPIO5 Interrupt Control Non-Privilege (gpio5_icnp): "0x00000000"
+GPIO5 Lock Register (gpio5_lock): "0x00000000"
diff --git a/spsdk/data/utils/sch_crypto.yaml b/spsdk/data/utils/sch_crypto.yaml
index 59a1ca54..171e0097 100644
--- a/spsdk/data/utils/sch_crypto.yaml
+++ b/spsdk/data/utils/sch_crypto.yaml
@@ -122,37 +122,38 @@ certificate_v31:
type: string
title: Binary Certificate
description: Optionally the certificate could be defined as a pre-generated binary block.
- In case that is defined, all other configuration for certification block is omitted expect the 'signingCertificatePrivateKeyFile' or 'iskSignProvider'
+ In case that is defined, all other configuration for certification block must be deleted ('useIsk', 'mainRootCertPrivateKeyFile', 'signingCertificateFile', 'signingCertificateConstraint', 'signCertData')
+ In case that ISK is defined, certicate block must be deleted
format: file
template_value: my_isk_cert.bin
useIsk:
type: boolean
title: Use ISK for signature certification
- description: Enable ISK type of signature certification. Unused when 'binaryCertificateBlock' is defined
+ description: Enable ISK type of signature certification. Don't use when 'binaryCertificateBlock' is defined
template_value: false
mainRootCertPrivateKeyFile:
type: string
title: Main root Certification Private Key
- description: Path to Main root Certification Private Key. Unused when 'binaryCertificateBlock' is defined
+ description: Path to Main root Certification Private Key. Don't use when 'binaryCertificateBlock' is defined
format: file
template_value: main_cert_prv_key.pem
signingCertificateFile:
type: string
title: Signing Certificate
- description: Path to Signing Certificate. Unused when 'binaryCertificateBlock' is defined
+ description: Path to Signing Certificate. Don't use when 'binaryCertificateBlock' is defined
format: file
template_value: sign_cert.pem
signingCertificateConstraint:
type: [string, number]
title: Signing certificate constrain
- description: Signing certificate constrain number. Unused when 'binaryCertificateBlock' is defined
+ description: Signing certificate constrain number. Don't use when 'binaryCertificateBlock' is defined
format: number
default: 0
template_value: 0
signCertData:
type: string
title: Signing Certificate data
- description: Path to Signing Certificate data. Unused when 'binaryCertificateBlock' is defined
+ description: Path to Signing Certificate data. Don't use when 'binaryCertificateBlock' is defined
format: optional_file
template_value: sign_cert.bin
signingCertificatePrivateKeyFile:
@@ -249,7 +250,14 @@ certificate_root_keys:
- allOf:
- required: [rootCertificate0File]
- anyOf:
- - required: [mainCertPrivateKeyFile]
+ - allOf:
+ - required: [mainCertPrivateKeyFile]
+ - not:
+ required: [signProvider]
+ - allOf:
+ - required: [signProvider]
+ - not:
+ required: [mainCertPrivateKeyFile]
- anyOf:
- required: [mainRootCertId]
- required: [mainCertChainId]
diff --git a/spsdk/debuggers/debug_probe.py b/spsdk/debuggers/debug_probe.py
index cade20d2..9de41aca 100644
--- a/spsdk/debuggers/debug_probe.py
+++ b/spsdk/debuggers/debug_probe.py
@@ -409,14 +409,14 @@ def __del__(self) -> None:
except NotImplementedError:
pass
- def get_ap_list(self, filter: Optional[List[int]] = None) -> Dict[int, int]:
+ def get_ap_list(self, ap_filter: Optional[List[int]] = None) -> Dict[int, int]:
"""Gets the dictionary of AP IDR's active in target.
- :param filter: List of AP be scanned - otherwise all range will be used[0-255].
+ :param ap_filter: List of AP be scanned - otherwise all range will be used[0-255].
:return: Dictionary with active AP's. Key is index of AP, value is IDR value.
"""
ret: Dict[int, int] = {}
- for i in filter or range(256):
+ for i in ap_filter or range(256):
try:
idr = self.coresight_reg_read(
access_port=True,
diff --git a/spsdk/debuggers/debug_probe_jlink.py b/spsdk/debuggers/debug_probe_jlink.py
index 068c5afb..bfa490d3 100644
--- a/spsdk/debuggers/debug_probe_jlink.py
+++ b/spsdk/debuggers/debug_probe_jlink.py
@@ -132,10 +132,21 @@ def open(self) -> None:
serial_no=self.hardware_id,
ip_addr=self.options.get("ip_address") if self.options else None,
)
- self.pylink.set_tif(pylink.enums.JLinkInterfaces.SWD)
+ if self.options.get("use_jtag") is None:
+ self.pylink.set_tif(pylink.enums.JLinkInterfaces.SWD)
+ else:
+ logger.warning(
+ "Experimental support for JTAG on RW61x."
+ "The implementation may have bugs and lack features."
+ )
+ self.pylink.set_speed(100)
+ self.pylink.set_tif(pylink.enums.JLinkInterfaces.JTAG)
self.pylink.coresight_configure()
self.pylink.set_speed(speed=value_to_int(self.options.get("frequency", 100)))
# Power Up the system and debug and clear sticky errors
+ if self.options.get("use_jtag") is not None:
+ # Currently clear_sticky_errors has been defined only for SWD (uncleared for JTAG-DP)
+ self.coresight_reg_write(access_port=False, addr=4, data=0x50000F20)
self.clear_sticky_errors()
self.power_up_target()
@@ -231,4 +242,7 @@ def _reinit_jlink_target(self) -> None:
if not self.disable_reinit:
assert self.pylink
self.pylink.coresight_configure()
+ if self.options.get("use_jtag") is not None:
+ # Currently clear_sticky_errors has been defined only for SWD (uncleared for JTAG-DP)
+ self.coresight_reg_write(access_port=False, addr=4, data=0x50000F20)
self._reinit_target()
diff --git a/spsdk/debuggers/debug_probe_pyocd.py b/spsdk/debuggers/debug_probe_pyocd.py
index 7479bf0e..04155fa2 100644
--- a/spsdk/debuggers/debug_probe_pyocd.py
+++ b/spsdk/debuggers/debug_probe_pyocd.py
@@ -10,14 +10,12 @@
from time import sleep
from typing import Dict, List, Optional
-import pylink
import pyocd
from pyocd.core.exceptions import Error as PyOCDError
from pyocd.core.helpers import ConnectHelper
from pyocd.core.session import Session
from pyocd.coresight.dap import DPConnector
from pyocd.probe.debug_probe import DebugProbe as PyOCDDebugProbe
-from pyocd.probe.jlink_probe import JLinkProbe
from spsdk.exceptions import SPSDKError
@@ -60,6 +58,7 @@ def __init__(self, hardware_id: str, options: Optional[Dict] = None) -> None:
The PyOCD initialization function for SPSDK library to support various DEBUG PROBES.
"""
super().__init__(hardware_id, options)
+ self.probe: PyOCDDebugProbe = None
set_logger(logging.root.level)
@@ -104,7 +103,7 @@ def open(self) -> None:
:raises SPSDKDebugProbeError: The PyOCD cannot establish communication with target
"""
try:
- self.probe: PyOCDDebugProbe = ConnectHelper.choose_probe(
+ self.probe = ConnectHelper.choose_probe(
blocking=False,
return_first=True,
unique_id=self.hardware_id,
diff --git a/spsdk/dk6/__init__.py b/spsdk/dk6/__init__.py
new file mode 100644
index 00000000..f2a6f0b0
--- /dev/null
+++ b/spsdk/dk6/__init__.py
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+#
+# Copyright 2022-2023 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+"""Top-level package for dk6_tools."""
diff --git a/spsdk/dk6/commands.py b/spsdk/dk6/commands.py
new file mode 100644
index 00000000..aace7a79
--- /dev/null
+++ b/spsdk/dk6/commands.py
@@ -0,0 +1,389 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+#
+# Copyright 2022-2023 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+"""DK6 Device Commands."""
+from struct import unpack_from
+from typing import Dict, Type, Union
+
+from spsdk.utils.easy_enum import Enum
+
+
+class StatusCode(Enum):
+ """DK6 Command Status Codes."""
+
+ OK = (0x00, "Success")
+ MEMORY_INVALID_MODE = (0xEF, "Memory invalid mode")
+ MEMORY_BAD_STATE = (0xF0, "Memory bad state")
+ MEMORY_TOO_LONG = (0xF1, "Memory too long")
+ MEMORY_OUT_OF_RANGE = (0xF2, "Memory out of range")
+ MEMORY_ACCESS_INVALID = (0xF3, "Memory access invalid")
+ MEMORY_NOT_SUPPORTED = (0xF4, "Memory not supported")
+ MEMORY_INVALID = (0xF5, "Memory invalid")
+ NO_RESPONSE = (0xF6, "No response")
+ AUTH_ERROR = (0xF7, "Not authorized")
+ TEST_ERROR = (0xF8, "Test Error")
+ READ_FAIL = (0xF9, "Read fail")
+ USER_INTERRUPT = (0xFA, "User interrupt")
+ ASSERT_FAIL = (0xFB, "Assertion fail")
+ CRC_ERROR = (0xFC, "CRC Error")
+ INVALID_RESPONSE = (0xFD, "Invalid response")
+ WRITE_FAIL = (0xFE, "Write fail")
+ NOT_SUPPORTED = (0xFF, "Not supported")
+
+
+class ResponseTag(Enum):
+ """DK6 Responses to Commands."""
+
+ RESET = (0x15, "ResetResponse", "Reset Response")
+ EXECUTE = (0x22, "ExecuteResponse", "Execute Response")
+ SET_BAUD = (0x28, "SetBaudResponse", "Set Baud Response")
+ GET_CHIPID = (0x33, "GetChipIdResponse", "Get Chip ID Response")
+ MEM_OPEN = (0x41, "MemOpenResponse", "Memory Open Response")
+ MEM_ERASE = (0x43, "MemEraseResponse", "Memory Erase Response")
+ MEM_BLANK_CHECK = (0x45, "MemBlankCheckResponse", "Memory Blank Check Response")
+ MEM_READ = (0x47, "MemReadResponse", "Memory Read Response")
+ MEM_WRITE = (0x49, "MemoryWriteResponse", "Memory Write Response")
+ MEM_CLOSE = (0x4B, "MemoryCloseResponse", "Memory Close Response")
+ MEM_GET_INFO = (0x4D, "MemoryGetInfoResponse", "Memory Get Info Response")
+ UNLOCK_ISP = (0x4F, "UnlockISPResponse", "Unlock ISP Response")
+
+
+class CommandTag(Enum):
+ """DK6 Commands."""
+
+ RESET = (0x14, "ResetCommand", "Reset Command")
+ EXECUTE = (0x21, "ExecuteCommand", "Execute Command")
+ SET_BAUD = (0x27, "SetBaudCommand", "Set Baud Command")
+ GET_CHIPID = (0x32, "GetChipIdCommand", "Get Chip ID Command")
+ MEM_OPEN = (0x40, "MemOpenCommand", "Memory Open Command")
+ MEM_ERASE = (0x42, "MemEraseCommand", "Memory Erase Command")
+ MEM_BLANK_CHECK = (0x44, "MemBlankCheckCommand", "Memory Blank Check Command")
+ MEM_READ = (0x46, "MemReadCommand", "Memory Read Command")
+ MEM_WRITE = (0x48, "MemoryWriteCommand", "Memory Write Command")
+ MEM_CLOSE = (0x4A, "MemoryCloseCommand", "Memory Close Command")
+ MEM_GET_INFO = (0x4C, "MemoryGetInfoCommand", "Memory Get Info Command")
+ UNLOCK_ISP = (0x4E, "UnlockISPCommand", "Unlock ISP Command")
+
+
+class MemoryId(Enum):
+ """DK6 Memory IDs."""
+
+ FLASH = (0x00, "FLASH")
+ PSECT = (0x01, "PSECT")
+ pFLASH = (0x02, "pFLASH")
+ Config = (0x03, "Config")
+ EFUSE = (0x04, "EFUSE")
+ ROM = (0x05, "ROM")
+ RAM0 = (0x06, "RAM0")
+ RAM1 = (0x07, "RAM1")
+
+
+class MemoryType(Enum):
+ """DK6 Memory Types."""
+
+ ROM = (0x00, "ROM", "Read only memory")
+ FLASH = (0x01, "FLASH", "FLASH memory")
+ RAM = (0x02, "RAM", "RAM")
+ EFUSE = (0x05, "EFUSE (OTP)", "EFUSE (OTP)")
+
+
+class MemoryAccessValues(Enum):
+ """DK6 Memory Access Values."""
+
+ READ = (0x00, "Read Enabled")
+ WRITE = (0x01, "Write Enabled")
+ ERASE = (0x02, "Erase Enabled")
+ ERASE_ALL = (0x03, "Erase All Enabled")
+ BLANK_CHECK_ENABLED = (0x04, "Blank Check Enabled")
+ ALL = (0x0F, "All is available")
+
+
+class CmdPacket:
+ """DK6 command packet format class."""
+
+ def __init__(self, data: bytes) -> None:
+ """Initialize the Command Packet object.
+
+ :param data: Command data, defaults to None
+ """
+ self.data = data
+
+ def __eq__(self, obj: object) -> bool:
+ return isinstance(obj, CmdPacket) and vars(obj) == vars(self)
+
+ def __ne__(self, obj: object) -> bool:
+ return not self.__eq__(obj)
+
+ def __str__(self) -> str:
+ return "<" + self.info() + ">"
+
+ def info(self) -> str:
+ """Get object info."""
+ return "CMDPacket[" + ", ".join(f"{b:02X}" for b in self.data) + "]"
+
+ def to_bytes(self) -> Union[bytes, None]:
+ """Serialize CmdPacket into bytes.
+
+ :return: Serialized object into bytes
+ """
+ return self.data
+
+
+class CmdResponse:
+ """DK6 response base format class."""
+
+ MSG_OFFSET = 1
+
+ def __init__(self, cmd_type: int, raw_data: bytes) -> None:
+ """Initialize the Command Response object.
+
+ :param header: Header for the response
+ :param raw_data: Response data
+ """
+ assert isinstance(raw_data, (bytes, bytearray))
+ self.type = cmd_type
+ self.status = raw_data[0]
+ self.raw_data = raw_data
+
+ def __eq__(self, obj: object) -> bool:
+ return isinstance(obj, CmdResponse) and vars(obj) == vars(self)
+
+ def __ne__(self, obj: object) -> bool:
+ return not self.__eq__(obj)
+
+ def __str__(self) -> str:
+ return "<" + self.info() + ">"
+
+ def info(self) -> str:
+ """Get object info."""
+ return (
+ f"Status=0x{self.status:02X}"
+ + f"Type=0x{self.type:02X}"
+ + " ["
+ + ", ".join(f"{b:02X}" for b in self.raw_data)
+ + "]"
+ )
+
+
+class GenericResponse(CmdResponse):
+ """DK6 generic response format class."""
+
+ def info(self) -> str:
+ """Get object info."""
+ tag = ResponseTag.name(self.type)
+ status = StatusCode.get(self.status, f"Unknown[0x{self.status:08X}]")
+ return f"Tag={tag}, Status={status}"
+
+
+class IspUnlockResponse(CmdResponse):
+ """ISP Unlock response format class."""
+
+ def __init__(self, cmd_type: int, raw_data: bytes) -> None:
+ """Initialize the Command Response object.
+
+ :param header: Header for the response
+ :param raw_data: Response data
+ """
+ super().__init__(cmd_type, raw_data)
+ self.authenticated = self.status == StatusCode.OK
+
+ def info(self) -> str:
+ """Get object info."""
+ tag = ResponseTag.name(self.type)
+ status = StatusCode.get(self.status, f"Unknown[0x{self.status:08X}]")
+ return f"Tag={tag}, Status={status}, Authenticated={self.authenticated}"
+
+
+class GetChipIdResponse(CmdResponse):
+ """Chip get info response format class."""
+
+ FORMAT = " None:
+ """Initialize the Flash-Read-Once response object.
+
+ :param header: Header for the response
+ :param raw_data: Response data
+ """
+ super().__init__(cmd_type, raw_data)
+ if self.status == StatusCode.OK:
+ (self.chip_id, self.chip_version) = unpack_from(self.FORMAT, raw_data, self.MSG_OFFSET)
+
+ def info(self) -> str:
+ """Get object info."""
+ tag = ResponseTag.name(self.type)
+ status = StatusCode.get(self.status, f"Unknown[0x{self.status:08X}]")
+ if self.status == StatusCode.OK:
+ return f"Tag={tag}, Status={status}, ChipID={hex(self.chip_id)}, ChipVersion={hex(self.chip_version)}"
+ return f"Tag={tag}, Status={status}"
+
+
+class MemGetInfoResponse(CmdResponse):
+ """Memory get info response format class."""
+
+ FORMAT = " None:
+ """Initialize the Flash-Read-Once response object.
+
+ :param header: Header for the response
+ :param raw_data: Response data
+ """
+ super().__init__(cmd_type, raw_data)
+ if self.status == StatusCode.OK:
+ self.mem_name = raw_data[self.MEM_NAME_OFFSET :].decode("ascii")
+ (
+ self.memory_id,
+ self.base_addr,
+ self.length,
+ self.sector_size,
+ self.mem_type,
+ self.access,
+ ) = unpack_from(self.FORMAT, raw_data, self.MSG_OFFSET)
+
+ def info(self) -> str:
+ """Get object info."""
+ tag = ResponseTag.name(self.type)
+ status = StatusCode.get(self.status, f"Unknown[0x{self.status:08X}]")
+ if self.status == StatusCode.OK:
+ memory_id = MemoryId.get(self.memory_id)
+ mem_type = MemoryType.get(self.mem_type)
+ access = MemoryAccessValues.get(self.access)
+ return (
+ f"Tag={tag}, Status={status}, MemName = {self.mem_name}, "
+ + f"MemoryId={memory_id}, BaseAddress={hex(self.base_addr)}, "
+ + f"Length={hex(self.length)}, SectorSize={hex(self.sector_size)}, "
+ + f"MemoryType={mem_type}, Access={access}"
+ )
+ return f"Tag={tag}, Status={status}"
+
+
+class MemOpenResponse(CmdResponse):
+ """Memory open response format class."""
+
+ FORMAT = " None:
+ """Initialize the Command Response object.
+
+ :param header: Header for the response
+ :param raw_data: Response data
+ """
+ super().__init__(cmd_type, raw_data)
+ if self.status == StatusCode.OK:
+ self.handle = unpack_from(self.FORMAT, raw_data, self.MSG_OFFSET)
+
+ def info(self) -> str:
+ """Get object info."""
+ tag = ResponseTag.name(self.type)
+ status = StatusCode.get(self.status, f"Unknown[0x{self.status:08X}]")
+ if self.status == StatusCode.OK:
+ return f"Tag={tag}, Status={status}, Handle={self.handle}"
+ return f"Tag={tag}, Status={status}"
+
+
+class MemReadResponse(CmdResponse):
+ """Memory open response format class."""
+
+ def __init__(self, cmd_type: int, raw_data: bytes) -> None:
+ """Initialize the Command Response object.
+
+ :param header: Header for the response
+ :param raw_data: Response data
+ """
+ super().__init__(cmd_type, raw_data)
+ self.data = b""
+ if self.status == StatusCode.OK:
+ self.data = self.raw_data[self.MSG_OFFSET :]
+
+ def info(self) -> str:
+ """Get object info."""
+ tag = ResponseTag.name(self.type)
+ status = StatusCode.get(self.status, f"Unknown[0x{self.status:08X}]")
+ data = ", ".join(f"{b:02X}" for b in self.data)
+ return f"Tag={tag}, Status={status}, Data={data}"
+
+
+class MemWriteResponse(CmdResponse):
+ """Memory open response format class."""
+
+ def info(self) -> str:
+ """Get object info."""
+ tag = ResponseTag.name(self.type)
+ status = StatusCode.get(self.status, f"Unknown[0x{self.status:08X}]")
+ return f"Tag={tag}, Status={status}"
+
+
+class MemEraseResponse(CmdResponse):
+ """Memory open response format class."""
+
+ def info(self) -> str:
+ """Get object info."""
+ tag = ResponseTag.name(self.type)
+ status = StatusCode.get(self.status, f"Unknown[0x{self.status:08X}]")
+ return f"Tag={tag}, Status={status}"
+
+
+class MemBlankCheckResponse(CmdResponse):
+ """Memory open response format class."""
+
+ def info(self) -> str:
+ """Get object info."""
+ tag = ResponseTag.name(self.type)
+ status = StatusCode.get(self.status, f"Unknown[0x{self.status:08X}]")
+ return f"Tag={tag}, Status={status}"
+
+
+class MemCloseResponse(CmdResponse):
+ """DK6 memory close response format class."""
+
+ def info(self) -> str:
+ """Get object info."""
+ tag = ResponseTag.name(self.type)
+ status = StatusCode.get(self.status, f"Unknown[0x{self.status:08X}]")
+ return f"Tag={tag}, Status={status}"
+
+
+def parse_cmd_response(
+ data: bytes, frame_type: int
+) -> Union[
+ CmdResponse,
+ GenericResponse,
+ GetChipIdResponse,
+ MemOpenResponse,
+ MemEraseResponse,
+ MemBlankCheckResponse,
+ MemReadResponse,
+ MemWriteResponse,
+ MemCloseResponse,
+ MemGetInfoResponse,
+ IspUnlockResponse,
+]:
+ """Parse command response.
+
+ :param data: Input data in bytes
+ :param frame_type: Frame Type
+ :return: De-serialized object from data
+ """
+ known_response: Dict[int, Type[CmdResponse]] = {
+ ResponseTag.RESET: GenericResponse,
+ ResponseTag.EXECUTE: GenericResponse,
+ ResponseTag.SET_BAUD: GenericResponse,
+ ResponseTag.GET_CHIPID: GetChipIdResponse,
+ ResponseTag.MEM_OPEN: MemOpenResponse,
+ ResponseTag.MEM_ERASE: MemEraseResponse,
+ ResponseTag.MEM_BLANK_CHECK: MemBlankCheckResponse,
+ ResponseTag.MEM_READ: MemReadResponse,
+ ResponseTag.MEM_WRITE: MemWriteResponse,
+ ResponseTag.MEM_CLOSE: MemCloseResponse,
+ ResponseTag.MEM_GET_INFO: MemGetInfoResponse,
+ ResponseTag.UNLOCK_ISP: IspUnlockResponse,
+ }
+
+ if frame_type in known_response:
+ return known_response[frame_type](frame_type, data)
+ return CmdResponse(frame_type, data)
diff --git a/spsdk/dk6/dk6device.py b/spsdk/dk6/dk6device.py
new file mode 100644
index 00000000..0e14b9e6
--- /dev/null
+++ b/spsdk/dk6/dk6device.py
@@ -0,0 +1,473 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+#
+# Copyright 2022-2023 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+"""DK6 Device high level API."""
+import logging
+from types import TracebackType
+from typing import Callable, Dict, List, Optional, Type, Union
+
+from spsdk import SPSDKError
+from spsdk.utils.easy_enum import Enum
+
+from .commands import (
+ GetChipIdResponse,
+ MemGetInfoResponse,
+ MemoryAccessValues,
+ MemoryId,
+ MemoryType,
+ StatusCode,
+)
+from .interface import Uart
+from .protocol import DK6Protocol
+from .serial_device import SerialDevice
+
+logger = logging.getLogger(__name__)
+
+
+MAX_MEM_ID = 9
+
+MAC_MEM_ADDR = 0x9FC70
+DEV_TYPE_ADDR = 0x9FC60
+MAC_LEN = 8
+DEV_LEN = 4
+
+
+class DK6ChipIdInternal(Enum):
+ """DK6 Internal chip ID."""
+
+ JN5189 = (0x88888888, "JN5189 ESx")
+ QN9090 = (0x1240C686, "QN9090")
+ K32W041 = (0x1300C686, "K32W041")
+ K32W061 = (0x1440C686, "K32W061")
+
+
+class DK6DeviceId(Enum):
+ """DK6 Device IDs."""
+
+ JN5188 = (5188, "JN5188")
+ JN5189 = (5189, "JN5189")
+ QN9030 = (9030, "QN9030")
+ QN9090 = (9090, "QN9090")
+ K32W041 = (32041, "K32W041")
+ K32W061 = (32061, "K32W061")
+ UNKNOWN = (0, "UNKNOWN")
+
+
+class DK6Memory:
+ """Class that holds information about the DK6 devices memory."""
+
+ def __init__(
+ self,
+ base_address: int,
+ length: int,
+ sector_size: int,
+ mem_type: MemoryType,
+ mem_name: str,
+ mem_id: MemoryId,
+ access: MemoryAccessValues,
+ ) -> None:
+ """DK6Memory Constructor.
+
+ :param base_address: Memory base address
+ :param length: Memory length
+ :param sector_size: Memory sector size
+ :param mem_type: Memory type
+ :param mem_name: Memory name
+ :param mem_id: Memory ID
+ :param access: Memory access
+ """
+ self.base_address = base_address
+ self.length = length
+ self.sector_size = sector_size
+ self.mem_type = mem_type
+ self.mem_name = mem_name
+ self.mem_id = mem_id
+ self.access = access
+
+ def __str__(self) -> str:
+ return (
+ f"\tMemoryId={MemoryId.get(self.mem_id)}\n"
+ f"\tBaseAddress={hex(self.base_address)}\n"
+ f"\tLength={hex(self.length)}\n"
+ f"\tSectorSize={hex(self.sector_size)}\n"
+ f"\tMemoryType={MemoryType.get(self.mem_type)}\n"
+ f"\tAccess={MemoryAccessValues.get(self.access)}\n"
+ )
+
+ def __repr__(self) -> str:
+ """Return obj representation.
+
+ :return: return obj str
+ """
+ return self.__str__()
+
+ @property
+ def end_address(self) -> int:
+ """End address of Memory.
+
+ :return: End address
+ """
+ return self.base_address + self.length
+
+
+def check_memory(
+ memory: DK6Memory,
+ access: MemoryAccessValues,
+ length: int,
+ relative: bool,
+ address: int,
+) -> int:
+ """Check memory range and return sanitized address value.
+
+ :param memory: DK6Memory
+ :param access: access type
+ :param length: length of data
+ :param relative: true if address is relative to base address
+ :param address: memory address
+ :raises SPSDKError: if memory ID is not supported
+ :raises SPSDKError: if access is not allowed
+ :raises SPSDKError: if the memory range is invalid
+ :return: Sanitized memory address
+ """
+ if memory is None:
+ raise SPSDKError("Memory ID is not supported")
+
+ if access > memory.access:
+ raise SPSDKError(f"Access {access} is not allowed. Only allowed is {hex(memory.access)}")
+
+ if relative:
+ address += memory.base_address
+ mem_check = (address + length) > memory.end_address
+ else:
+ mem_check = ((address + length) > memory.end_address) or (address < memory.base_address)
+
+ if mem_check:
+ raise SPSDKError(
+ f"Invalid range. The range is {hex(memory.base_address)}:{hex(memory.end_address)}"
+ f" or 0:{hex(memory.length)} in relative mode"
+ )
+
+ return address
+
+
+class DK6Device:
+ """Class that represents DK6 device.
+
+ It's a high level class that encapsulates communication interface and protocol
+ """
+
+ def __init__(
+ self,
+ device: SerialDevice,
+ ) -> None:
+ """DK6Device constructor.
+
+ :param device: SerialDevice that will be used for communication
+ :param baudrate: communication baudrate, defaults to 115200
+ """
+ self.memories: Dict[int, DK6Memory] = {}
+ self.chip_id: Union[GetChipIdResponse, None] = None
+ self.uart = Uart(device)
+ self.protocol = DK6Protocol(self.uart)
+ self.mac_addr: Union[None, bytes] = None
+ self.dev_type: Union[None, DK6DeviceId] = None
+ self.initialized = False
+
+ def __del__(self) -> None:
+ logger.info("Closing DK6 device")
+ self.close()
+
+ def __enter__(self) -> "DK6Device":
+ return self
+
+ def __exit__(
+ self,
+ exception_type: Optional[Type[BaseException]] = None,
+ exception_value: Optional[BaseException] = None,
+ traceback: Optional[TracebackType] = None,
+ ) -> None:
+ logger.info("Closing DK6 device")
+ self.close()
+
+ def _split_data(self, data: bytes) -> List[bytes]:
+ """Split data to send if necessary.
+
+ :param data: Data to send
+ :return: List of data splices
+ """
+ max_packet_size = self.protocol.MAX_PAYLOAD_SIZE
+ return [data[i : i + max_packet_size] for i in range(0, len(data), max_packet_size)]
+
+ def close(self) -> None:
+ """Close UART device.
+
+ :raises: SPSDKError: When the device cannot be closed
+ """
+ if self.uart:
+ self.uart.close()
+ self.initialized = False
+
+ def add_memory(self, memory: DK6Memory) -> None:
+ """Add memory to the list of available memories.
+
+ :param memory: DK6Memory
+ """
+ self.memories.update({memory.mem_id: memory})
+
+ def get_memory(self, memory_id: MemoryId) -> DK6Memory:
+ """Get DK6Memory based on memory_id.
+
+ :param memory_id: MemoryId of the desired memory
+ :raises SPSDKError: When the memory cannot be fetched
+ :return: DK6Memory
+ """
+ if self.memories:
+ memory = self.memories.get(memory_id)
+ if memory:
+ return memory
+ raise SPSDKError(f"Memory with {memory_id} is not fetched")
+
+ def get_mac_str(self) -> str:
+ """Get MAC address in string format.
+
+ :return: string containing MAC address FF:FF..
+ """
+ if self.mac_addr:
+ return ":".join(f"{b:02X}" for b in self.mac_addr)
+ else:
+ return "N/A"
+
+ def add_memory_from_response(self, memory_response: MemGetInfoResponse) -> None:
+ """Add memory from MemGetInfoResponse.
+
+ :param memory_response: MemGetInfoResponse
+ """
+ if memory_response.status == StatusCode.OK:
+ memory = DK6Memory(
+ base_address=memory_response.base_addr,
+ length=memory_response.length,
+ sector_size=memory_response.sector_size,
+ mem_type=memory_response.mem_type,
+ mem_name=memory_response.mem_name,
+ mem_id=memory_response.memory_id,
+ access=memory_response.access,
+ )
+ self.add_memory(memory)
+
+ def init(self) -> None:
+ """Initialize DK6 device for communication.
+
+ 1. Unlock ISP default
+ 2. Get device information
+ 3. Unlock ISP with default key
+ 4. Get info about memories
+ """
+ if not self.initialized:
+ logger.info("Initializing device... Sending UNLOCK ISP default")
+ self.protocol.unlock_isp_default()
+ logger.info("Obtaining device information")
+ self.chip_id = self.protocol.get_device_information()
+ logger.info("Unlocking ISP")
+ self.protocol.unlock_isp()
+
+ logger.info("Getting information about memories")
+ for mem_id in range(MAX_MEM_ID):
+ mem_info = self.protocol.mem_get_info(mem_id)
+ self.add_memory_from_response(mem_info)
+
+ self.protocol.mem_close()
+
+ logger.info("Reading MAC address")
+ self.protocol.mem_open(MemoryId.Config)
+ response = self.protocol.mem_read(MAC_MEM_ADDR, MAC_LEN)
+ self.mac_addr = response.data
+ self.protocol.mem_close()
+
+ logger.info("Reading device type")
+ self.protocol.mem_open(MemoryId.Config)
+ response = self.protocol.mem_read(DEV_TYPE_ADDR, DEV_LEN)
+ try:
+ self.dev_type = DK6DeviceId.from_int(int.from_bytes(response.data, "little"))
+ except SPSDKError:
+ self.dev_type = DK6DeviceId.UNKNOWN
+
+ self.protocol.mem_close()
+ self.initialized = True
+ else:
+ logger.info("Skipping Initialization, device is already initialized")
+
+ def read_memory(
+ self,
+ memory_id: MemoryId,
+ address: int,
+ length: int,
+ access: MemoryAccessValues = MemoryAccessValues.WRITE,
+ progress_callback: Optional[Callable[[int, int], None]] = None,
+ relative: bool = False,
+ ) -> bytes:
+ """Read memory from the DK6 device.
+
+ 1. Make a validation of the read request
+ 2. Open memory in given access mode
+ 3. Split read request to chunks of max(MAX_PAYLOAD_SIZE, requested_len)
+ 4. Read data
+ 5. Close memory
+
+ :param memory_id: MemoryID of the memory to be used
+ :param address: start address
+ :param length: length of data
+ :param access: memory access value, defaults to MemoryAccessValues.WRITE
+ :param progress_callback: progress callback used in CLI, defaults to None
+ :param relative: True if address is relative to the memory base address
+ :raises SPSDKError: Memory ID is not supported
+ :raises SPSDKError: Access is not allowed
+ :raises SPSDKError: Invalid range
+ :return: Read data
+ """
+ memory = self.get_memory(memory_id)
+ address = check_memory(memory, access, length, relative, address)
+ logger.info(f"READ command, memory {memory_id}, address {address}, length {length}")
+ self.protocol.mem_open(memory_id, access)
+
+ payload_size = self.protocol.MAX_PAYLOAD_SIZE
+ packets = length // payload_size
+ remainder = length % payload_size
+
+ if remainder:
+ packets += 1
+
+ data = b""
+
+ for idx in range(packets):
+ if idx == packets - 1 and remainder:
+ data_len = remainder
+ else:
+ data_len = payload_size
+ response = self.protocol.mem_read(address + idx * payload_size, data_len)
+ data += response.data
+ if progress_callback:
+ progress_callback(len(data), length)
+ self.protocol.mem_close()
+
+ return data
+
+ def write_memory(
+ self,
+ memory_id: MemoryId,
+ address: int,
+ length: int,
+ data: bytes,
+ access: MemoryAccessValues = MemoryAccessValues.ALL,
+ progress_callback: Optional[Callable[[int, int], None]] = None,
+ relative: bool = False,
+ ) -> None:
+ """Write memory to the DK6 device.
+
+ 1. Make a validation of the read request
+ 2. Open memory in given access mode
+ 3. Split write request to chunks of max(MAX_PAYLOAD_SIZE, requested_len)
+ 4. Write data
+ 5. Close memory
+
+ :param memory_id: MemoryID of the memory to be used
+ :param address: start address
+ :param length: length of data
+ :param data: data to be written
+ :param access: memory access value, defaults to MemoryAccessValues.WRITE
+ :param progress_callback: progress callback used in CLI, defaults to None
+ :param relative: True if address is relative to the memory base address
+ :raises SPSDKError: Memory ID is not supported
+ :raises SPSDKError: Access is not allowed
+ :raises SPSDKError: Invalid range
+ :raises SPSDKError: No response from device
+ """
+ memory = self.get_memory(memory_id)
+
+ address = check_memory(memory, access, length, relative, address)
+
+ self.protocol.mem_open(memory_id, access)
+
+ data_chunks = self._split_data(data)
+
+ total_sent = 0
+ total_to_send = len(data)
+
+ try:
+ for data_chunk in data_chunks:
+ status = self.protocol.mem_write(
+ address + total_sent, len(data_chunk), data_chunk
+ ).status
+ if status != StatusCode.OK:
+ raise SPSDKError("Sending of data failed")
+ total_sent += len(data_chunk)
+ if progress_callback:
+ progress_callback(total_sent, total_to_send)
+
+ except TimeoutError as exc:
+ logger.error("RX: No Response, Timeout Error !")
+ raise SPSDKError("No Response from Device") from exc
+
+ self.protocol.mem_close()
+
+ def erase_memory(
+ self,
+ memory_id: MemoryId,
+ address: int,
+ length: int,
+ access: MemoryAccessValues = MemoryAccessValues.ALL,
+ progress_callback: Optional[Callable[[int, int], None]] = None,
+ relative: bool = False,
+ verify: bool = False,
+ ) -> None:
+ """Erase memory of DK6 device.
+
+ # 1. Make a validation of the read request
+ # 2. Open memory in given access mode
+ # 4. Erase data
+ # 5. Optionally verify with blank check
+ # 6. Close memory
+
+ :param memory_id: MemoryID of the memory to be used
+ :param address: start address
+ :param length: length of data
+ :param access: memory access value, defaults to MemoryAccessValues.WRITE
+ :param progress_callback: progress callback used in CLI, defaults to None
+ :param relative: True if address is relative to the memory base address
+ :param verify: True for erase verification by memory blank check
+ :raises SPSDKError: Memory ID is not supported
+ :raises SPSDKError: Access is not allowed
+ :raises SPSDKError: Invalid range
+ :raises SPSDKError: No response from device
+ """
+ memory = self.get_memory(memory_id)
+
+ if progress_callback:
+ progress_callback(1, 4)
+
+ address = check_memory(memory, access, length, relative, address)
+
+ self.protocol.mem_open(memory_id, access)
+ result = self.protocol.mem_erase(address, length)
+ if result.status != StatusCode.OK:
+ raise SPSDKError("Memory erase failed")
+
+ if progress_callback:
+ progress_callback(3, 4)
+ if verify:
+ result_check = self.protocol.mem_blank_check(address, length)
+ if result_check.status != StatusCode.OK:
+ raise SPSDKError("Memory blank check failed")
+ self.protocol.mem_close()
+
+ if progress_callback:
+ progress_callback(4, 4)
+
+ def reset(self) -> None:
+ """Resets device."""
+ result = self.protocol.reset()
+
+ if result.status != StatusCode.OK:
+ raise SPSDKError("Reset failed")
diff --git a/spsdk/dk6/driver.py b/spsdk/dk6/driver.py
new file mode 100644
index 00000000..77805d43
--- /dev/null
+++ b/spsdk/dk6/driver.py
@@ -0,0 +1,275 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+#
+# Copyright 2022-2023 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+"""DK6 Drivers backend interface."""
+import logging
+import time
+from enum import Enum
+from typing import List, Union
+
+from spsdk import SPSDKError
+from spsdk.dk6.serial_device import SerialDevice
+
+logger = logging.getLogger(__name__)
+
+DELAY_ISP_IO_TOGGLE_WAIT_MS = 100
+
+# FTDI sequence in format PIN, BITMODE, MS_WAIT
+FTDI_ISP_SEQUENCE = [
+ (0xC0, 0x20, 10),
+ (0xC4, 0x20, DELAY_ISP_IO_TOGGLE_WAIT_MS),
+ (0xCC, 0x20, 10),
+ (0x0C, 0x20, 10),
+ (0x00, 0x00, 10),
+]
+
+
+def generate_pyftdi_url(serial_number: str, address: int = 1) -> str:
+ """Generates URL for PyFTDI from serial number.
+
+ :param serial_number: serial number from USBDeviceDescriptor
+ :param address: interface number
+ :return: url for PyFTDI
+ """
+ return f"ftdi://::{serial_number}/{address}"
+
+
+class Backend(Enum):
+ """Backend selection."""
+
+ PYFTDI = 1
+ PYLIBFTDI = 2
+ FTD2xx = 3
+ PYSERIAL = 4
+
+
+class DeviceInfo:
+ """Device info class.
+
+ Contains information about the connected device
+ """
+
+ def __init__(
+ self,
+ device_id: Union[str, int],
+ vid: int,
+ pid: int,
+ sn: str,
+ description: str,
+ address: int,
+ backend: Backend,
+ ):
+ """Device info constructor.
+
+ :param device_id: Device ID
+ :param vid: USB VID
+ :param pid: USB PID
+ :param sn: Serial number
+ :param description: description
+ :param address: device address
+ :param backend: backend
+ """
+ self.device_id = device_id
+ self.vid = vid
+ self.pid = pid
+ self.sn = sn
+ self.description = description
+ self.address = address
+ self.backend = backend
+
+ def __str__(self) -> str:
+ return (
+ f"DEVICE ID: {self.device_id}, VID: {hex(self.vid)}, PID: {hex(self.pid)}, Serial number: {self.sn}, "
+ + f"Description: {self.description}, Address: {self.address}, Backend: {self.backend}"
+ )
+
+
+class DriverInterface:
+ """Interface to FTDI backends.
+
+ Supported backends are: pyftdi, pylibftdi and ftdi2xx
+ """
+
+ def __init__(self, backend: Backend) -> None:
+ """Initialize driver interface and serial interface based on backend.
+
+ :param backend: supported backend name
+ """
+ self.backend = backend
+ self.initialized = False
+
+ logger.info(f"Initializing backend {backend}")
+ if self.backend == Backend.PYFTDI:
+ from pyftdi import ftdi
+
+ self.driver = ftdi.Ftdi()
+ self.dev = None
+
+ elif self.backend == Backend.PYLIBFTDI:
+ from pylibftdi import Device, Driver
+
+ self.dev = Device()
+ self.driver = Driver()
+ else:
+ self.dev = None
+ self.driver = None
+
+ def go_to_isp(self, device_id: str) -> None:
+ """Send a sequence that goes to ISP mode using FTDI bitbang device."""
+ logger.info("Sending bitbang sequence to ISP mode")
+ if self.backend == Backend.PYFTDI:
+ from pyftdi import ftdi
+
+ url = generate_pyftdi_url(device_id)
+
+ self.driver.open_bitbang_from_url(url)
+ for ins in FTDI_ISP_SEQUENCE:
+ bitmode = ftdi.Ftdi.BitMode.CBUS if ins[1] == 0x20 else ftdi.Ftdi.BitMode.RESET
+ self.driver.set_bitmode(ins[0], bitmode)
+ time.sleep(ins[2] / 1000)
+
+ elif self.backend == Backend.FTD2xx:
+ import ftd2xx as ftd
+
+ if self.dev is None:
+ logger.info("Initializing serial first before ISP bitbang for D2XX backend")
+
+ self.dev = ftd.open(int(device_id))
+ for ins in FTDI_ISP_SEQUENCE:
+ self.dev.setBitMode(ins[0], ins[1])
+ time.sleep(ins[2] / 1000)
+ self.dev.close()
+
+ else:
+ logger.error("Selected backend does not have method for ISP sequence")
+
+ def list_devices(self) -> List[DeviceInfo]:
+ """Returns a list of devices that are connected for selected backend.
+
+ :return: List of devices
+ """
+ devices_info = []
+ logger.info("Enumerating DK6 devices")
+ if self.backend == Backend.PYFTDI:
+ devices_list = self.driver.list_devices()
+ for device in devices_list:
+ device_info = DeviceInfo(
+ device[0].sn,
+ device[0].vid,
+ device[0].pid,
+ device[0].sn,
+ device[0].description,
+ device[0].address,
+ self.backend,
+ )
+ devices_info.append(device_info)
+
+ elif self.backend == Backend.FTD2xx:
+ import ftd2xx as ftd
+
+ device_count = ftd.createDeviceInfoList()
+ for n in range(device_count):
+ dev_dict = ftd.getDeviceInfoDetail(n)
+ dev_info = DeviceInfo(
+ device_id=dev_dict.get("index"),
+ vid=0,
+ pid=0,
+ sn=dev_dict.get("serial"),
+ description=dev_dict.get("description"),
+ address=dev_dict.get("id"),
+ backend=self.backend,
+ )
+ devices_info.append(dev_info)
+
+ elif self.backend == Backend.PYSERIAL:
+ import serial.tools.list_ports
+
+ ports = serial.tools.list_ports.comports()
+
+ for port in ports:
+ dev_info = DeviceInfo(
+ device_id=port.device,
+ vid=port.vid,
+ pid=port.pid,
+ sn=port.serial_number,
+ description=port.description,
+ address=port.location,
+ backend=self.backend,
+ )
+ devices_info.append(dev_info)
+
+ else:
+ logger.error("Selected backend does not implement method for listing devices")
+
+ return devices_info
+
+ def init_serial(self, device_id: str, baudrate: int = 115200, timeout: int = 5000) -> None:
+ """Initialize serial device.
+
+ :param device_id: device ID
+ :param baudrate: UART baudrate, defaults to 115200
+ :param timeout: read and write timeout, defaults to 5000 ms
+ :raises SPSDKError: if invalid device_id is provided
+ """
+ logger.info(
+ f"Initializing serial device for dev: {device_id}, baudrate: {baudrate} and timeout: {timeout}"
+ )
+ if self.initialized:
+ logger.info("Serial already initialized, skipping initialization")
+ return
+
+ if self.backend == Backend.PYFTDI:
+ import pyftdi.serialext
+
+ timeout //= 1000
+ url = generate_pyftdi_url(device_id)
+ self.dev = pyftdi.serialext.serial_for_url(
+ url, baudrate=baudrate, timeout=timeout, write_timeout=timeout
+ )
+ self.dev.reset_input_buffer()
+ self.dev.reset_output_buffer()
+ self.initialized = True
+
+ elif self.backend == Backend.PYLIBFTDI:
+ from pylibftdi import Device
+
+ self.dev = Device(device_id=device_id)
+ self.initialized = True
+
+ elif self.backend == Backend.FTD2xx:
+ import ftd2xx as ftd
+
+ try:
+ device_id_int = int(device_id)
+ except ValueError as exc:
+ raise SPSDKError("Invalid value for FTD2xx DEVICE_ID, it must be int") from exc
+ self.dev = ftd.open(device_id_int)
+ self.dev.resetPort()
+ self.dev.setBaudRate(baudrate)
+ self.dev.setTimeouts(timeout, timeout)
+ self.initialized = True
+
+ elif self.backend == Backend.PYSERIAL:
+ import serial
+
+ timeout //= 1000
+ self.dev = serial.Serial(
+ port=device_id,
+ baudrate=baudrate,
+ timeout=timeout,
+ write_timeout=timeout,
+ )
+ self.initialized = True
+
+ def get_serial(self) -> SerialDevice:
+ """Return serial device.
+
+ :raises SPSDKError: if serial device is not initialized
+ :return: Serial device based on backend
+ """
+ if not self.initialized or not self.dev:
+ raise SPSDKError("Serial device is not initialized")
+ return self.dev
diff --git a/spsdk/dk6/interface.py b/spsdk/dk6/interface.py
new file mode 100644
index 00000000..6ccdd8e5
--- /dev/null
+++ b/spsdk/dk6/interface.py
@@ -0,0 +1,237 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+#
+# Copyright 2022-2023 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+"""DK6 UART communication interface."""
+import logging
+import struct
+from time import sleep
+from typing import Any, Union
+
+from crcmod.predefined import mkPredefinedCrcFun
+
+from spsdk import SPSDKError
+
+from .commands import CmdPacket, CommandTag, parse_cmd_response
+from .serial_device import SerialDevice
+
+logger = logging.getLogger(__name__)
+
+
+def calc_crc(data: bytes) -> int:
+ """Calculate CRC from the data.
+
+ :param data: data to calculate CRC from
+ :return: calculated CRC
+ """
+ crc_function = mkPredefinedCrcFun("crc-32")
+ return crc_function(data)
+
+
+def to_int(data: bytes, little_endian: bool = False) -> int:
+ """Convert bytes into single integer.
+
+ :param data: bytes to convert
+ :param little_endian: indicate byte ordering in data, defaults to True
+ :return: integer
+ """
+ byte_order = "little" if little_endian else "big"
+ return int.from_bytes(data, byteorder=byte_order) # type: ignore[arg-type]
+
+
+class Uart:
+ """UART interface for DK6 devices."""
+
+ FRAME_START_BYTE = 0x00
+
+ FLAG_SIZE = 1
+ LENGTH_SIZE = 2
+ FRAME_TYPE_SIZE = 1
+ CHECKSUM_SIZE = 4
+
+ HEADER_SIZE = FLAG_SIZE + LENGTH_SIZE + FRAME_TYPE_SIZE + CHECKSUM_SIZE
+
+ @property
+ def is_opened(self) -> bool:
+ """Return True if device is open, False otherwise."""
+ return self.device.is_opened
+
+ def __init__(
+ self,
+ device: SerialDevice,
+ ) -> None:
+ """Initialize the UART interface.
+
+ :param port: name of the serial port, defaults to None
+ :raises McuBootConnectionError: when the port could not be opened
+ """
+ self.device = device
+ # self.device.baudrate = baudrate
+
+ def open(self) -> None:
+ """Open the UART interface.
+
+ :raises SPSDKError: In any case of fail of UART open operation.
+ """
+ try:
+ self.device.open()
+ except Exception as exc:
+ raise SPSDKError(f"Cannot open UART interface: {exc}") from exc
+
+ def close(self) -> None:
+ """Close the UART interface.
+
+ :raises SPSDKError: In any case of fail of UART close operation.
+ """
+ try:
+ self.device.close()
+ except Exception as exc:
+ raise SPSDKError(f"Cannot close UART interface: {exc}") from exc
+
+ def read(self) -> Any:
+ """Read data from device.
+
+ :return: CmdResponse
+ :raises SPSDKError: Did not receive correct frame start byte
+ :raises SPSDKError: When received invalid CRC
+ """
+ flag = to_int(self._read_default(self.FLAG_SIZE))
+ if flag != self.FRAME_START_BYTE:
+ raise SPSDKError("Did not receive correct frame start byte")
+
+ length = to_int(self._read_default(self.LENGTH_SIZE))
+ frame_type = to_int(self._read_default(self.FRAME_TYPE_SIZE))
+
+ data = self._read_default(length - self.HEADER_SIZE)
+ crc = to_int(self._read_default(self.CHECKSUM_SIZE))
+
+ calculated_crc = self.calc_frame_crc(data, frame_type)
+ if crc != calculated_crc:
+ raise SPSDKError("Received invalid CRC")
+
+ logger.debug(
+ f"<-READ flag: {hex(flag)}, length: {hex(length)}, "
+ f"frame_type: {hex(frame_type)}, data: <{' '.join(f'{b:02x}' for b in data)}>,"
+ f" crc: {hex(crc)}"
+ )
+ return parse_cmd_response(data, frame_type)
+
+ def write(self, frame_type: CommandTag, packet: Union[CmdPacket, bytes, None]) -> None:
+ """Write data to the device; data might be in form of 'CmdPacket' or bytes.
+
+ :param frame_type: CommandTag
+ :param packet: Packet to send
+ :raises AttributeError: frame type is incorrect
+ """
+ if isinstance(packet, CmdPacket):
+ packet = packet.to_bytes()
+
+ frame = self.create_frame(packet, frame_type)
+ # logger.debug(f"Packet {packet}, frame type; {frame_type}")
+ # logger.debug(f"->WRITE: frame: {frame}")
+ self._send_frame(frame)
+
+ def _read_default(self, length: int) -> bytes:
+ """Read 'length' amount of bytes from device, this function can be overridden in child class.
+
+ :param length: Number of bytes to read
+ :type length: int
+ :raises SPSDKError: When read fails
+ :return: Data read from the device
+ """
+ return self._read(length)
+
+ def _read(self, length: int) -> bytes:
+ """Read 'length' amount for bytes from device.
+
+ :param length: Number of bytes to read
+ :return: Data read from the device
+ :raises TimeoutError: Time-out
+ :raises SPSDKError: When reading data from device fails
+ """
+ try:
+ data = self.device.read(length)
+ except Exception as e:
+ raise SPSDKError(str(e)) from e
+ if not data:
+ raise TimeoutError()
+ logger.debug(f"<-READ: <{' '.join(f'{b:02x}' for b in data)}>")
+ return data
+
+ def _write(self, data: bytes) -> None:
+ """Send data to device.
+
+ :param data: Data to send
+ :raises SPSDKError: When sending the data fails
+ """
+ logger.debug(f"->WRITE: [{' '.join(f'{b:02x}' for b in data)}]")
+ sleep(0.01) # Sleep 10 ms before writing to prevent buffer overrun
+ try:
+ self.device.write(data)
+ except Exception as e:
+ raise SPSDKError(str(e)) from e
+
+ def _send_frame(self, frame: bytes) -> None:
+ """Send a frame to UART.
+
+ :param frame: Data to send
+ :param wait_for_ack: Wait for ACK frame from device, defaults to True
+ """
+ self._write(frame)
+
+ @staticmethod
+ def create_frame(data: Union[bytes, None], frame_type: Union[int, CommandTag]) -> bytes:
+ """Encapsulate data into frame.
+
+ :param data: payload data
+ :param frame_type: frame type
+ :return: frame
+ """
+ crc = Uart.calc_frame_crc(data, frame_type)
+ if data:
+ # print(f"Data length {len(data) + Uart.HEADER_SIZE}")
+ frame = struct.pack(
+ f">BHB{len(data)}BI",
+ Uart.FRAME_START_BYTE,
+ len(data) + Uart.HEADER_SIZE,
+ frame_type,
+ *data,
+ crc,
+ )
+ else:
+ frame = struct.pack(
+ ">BHBI",
+ Uart.FRAME_START_BYTE,
+ Uart.HEADER_SIZE,
+ frame_type,
+ crc,
+ )
+
+ return frame
+
+ @staticmethod
+ def calc_frame_crc(data: Union[bytes, None], frame_type: Union[int, CommandTag]) -> int:
+ """Calculate the CRC of a frame.
+
+ :param data: frame data
+ :param frame_type: frame type
+ :return: calculated CRC
+ """
+ if data:
+ crc_data = struct.pack(
+ f">BHB{len(data)}B",
+ Uart.FRAME_START_BYTE,
+ len(data) + Uart.HEADER_SIZE,
+ frame_type,
+ *data,
+ )
+ else:
+ crc_data = struct.pack(
+ ">BHB",
+ Uart.FRAME_START_BYTE,
+ Uart.HEADER_SIZE,
+ frame_type,
+ )
+ return calc_crc(crc_data)
diff --git a/spsdk/dk6/protocol.py b/spsdk/dk6/protocol.py
new file mode 100644
index 00000000..0e0a8e60
--- /dev/null
+++ b/spsdk/dk6/protocol.py
@@ -0,0 +1,283 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+#
+# Copyright 2022-2023 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+"""DK6 Communication protocol."""
+import logging
+import struct
+import time
+from typing import Union
+
+from spsdk.utils.easy_enum import Enum
+
+from .commands import (
+ CmdPacket,
+ CommandTag,
+ GenericResponse,
+ GetChipIdResponse,
+ IspUnlockResponse,
+ MemBlankCheckResponse,
+ MemCloseResponse,
+ MemEraseResponse,
+ MemGetInfoResponse,
+ MemOpenResponse,
+ MemoryAccessValues,
+ MemoryId,
+ MemReadResponse,
+ MemWriteResponse,
+)
+from .interface import Uart
+
+logger = logging.getLogger(__name__)
+
+
+DEFAULT_KEY = b"\x11\x22\x33\x44\x55\x66\x77\x88\x11\x22\x33\x44\x55\x66\x77\x88"
+
+
+class IspMode(Enum):
+ """DK6 ISP modes."""
+
+ DEFAULT = (0x00, "Default")
+ START_ISP = (0x01, "Start ISP Functionality")
+ UNLOCK_DEVICE = (0x7F, "Unlock device")
+ EXTENDED_ISP_UNLOCK = (0x80, "Extended unlock")
+
+
+class DK6Protocol:
+ """Class implementing communication protocol for the DK6 devices."""
+
+ MAX_PAYLOAD_SIZE = 512 # max size of the payload, depends on the device buffer size
+
+ def __init__(self, device: Uart) -> None:
+ """DK6Protocol constructor.
+
+ :param device: serial device that will be used for communication.
+ """
+ self.uart = device
+
+ def unlock_isp_default(self) -> IspUnlockResponse:
+ """Sends unlock ISP sequence in default mode.
+
+ It means that only Get device info command will work.
+
+ :return: IspUnlockResponse
+ """
+ self.uart.write(CommandTag.UNLOCK_ISP, b"\x00")
+ response = self.uart.read()
+ logger.debug(response.info())
+
+ return response
+
+ def unlock_isp(
+ self, mode: IspMode = IspMode.START_ISP, key: bytes = DEFAULT_KEY
+ ) -> IspUnlockResponse:
+ """Unlocks ISP with the key.
+
+ If the key is not provided, default will be used.
+
+ :param mode: Unlock ISP mode, defaults to IspMode.START_ISP
+ :param key: default key or signed unlock key, defaults to DEFAULT_KEY
+ :return: IspUnlockResponse
+ """
+ data = struct.pack(
+ f" GetChipIdResponse:
+ """Get device information.
+
+ :return: GetChipIdResponse containing chip ID and chip (ROM) version
+ """
+ self.uart.write(CommandTag.GET_CHIPID, None)
+ response = self.uart.read()
+ logger.debug(response.info())
+
+ return response
+
+ def mem_get_info(self, memory_id: Union[MemoryId, int] = MemoryId.FLASH) -> MemGetInfoResponse:
+ """Get memory info about specified memory ID.
+
+ :param memory_id: memory ID, defaults to MemoryId.FLASH
+ :return: MemGetInfoResponse containing information like size, length etc.
+ """
+ data = struct.pack(
+ " MemOpenResponse:
+ """Open given memory in the specified accesss mode.
+
+ :param memory_id: memory that will be opened, defaults to MemoryId.FLASH
+ :param access: access mode, defaults to MemoryAccessValues.READ
+ :return: MemOpenResponse containing handle
+ """
+ data = struct.pack(
+ " MemReadResponse:
+ """Read from memory.
+
+ :param address: start address
+ :param length: length of data to be read in bytes
+ :param handle: handle that was returned by mem_open, defaults to 0
+ :param mode: Read mode, defaults to 0
+ :return: MemReadResponse containing read data
+ """
+ data = struct.pack(" MemWriteResponse:
+ """Write to memory.
+
+ :param address: start address
+ :param length: number of bytes to be written
+ :param data: data to be written
+ :param handle: handle returned by open memory command, defaults to 0
+ :param mode: write mode, defaults to 0
+ :return: MemWriteResponse
+ """
+ frame = struct.pack(f" MemCloseResponse:
+ """Close the memory. Finalize writing of the memory.
+
+ :param handle: handle returned by open memory command, defaults to 0
+ :return: MemCloseResponse
+ """
+ self.uart.write(CommandTag.MEM_CLOSE, handle.to_bytes(1, "big"))
+ response = self.uart.read()
+ logger.debug(response.info())
+
+ return response
+
+ def mem_erase(
+ self, address: int, length: int, handle: int = 0, mode: int = 0
+ ) -> MemEraseResponse:
+ """This command erases a region of the selected memory.
+
+ :param address: start address
+ :param length: number of bytes to be erased
+ :param handle: handle returned by open memory command, defaults to 0
+ :param mode: erase mode, defaults to 0
+ :return: MemEraseResponse
+ """
+ frame = struct.pack(" MemBlankCheckResponse:
+ """This command checks if a region of the selected memory has been erased.
+
+ :param address: start address
+ :param length: number of bytes to be erased
+ :param handle: handle returned by open memory command, defaults to 0
+ :param mode: erase mode, defaults to 0
+ :return: MemEraseResponse
+ """
+ frame = struct.pack(" GenericResponse:
+ """Sets baudrate.
+
+ :param baudrate: int value of baudrate to be set
+ :return: GenericResponse
+ """
+ data = struct.pack(
+ " GenericResponse:
+ """Resets device.
+
+ :return: GenericResponse
+ """
+ self.uart.write(CommandTag.RESET, None)
+ response = self.uart.read()
+ logger.debug(response.info())
+
+ return response
+
+ def execute(self, address: int) -> GenericResponse:
+ """This command executes (runs) code in flash or RAM.
+
+ The response is sent before execution jumps to the provided address.
+
+ :param address: Memory address to start execution from
+ :return: GenericResponse
+ """
+ data = struct.pack(" bool:
+ """Indicates whether interface is open."""
+
+ @property
+ def baudrate(self) -> None:
+ """Set baud rate of the device."""
+
+ def __init__(self) -> None:
+ """Initialize the Interface object.
+
+ :param reopen: Reopen the interface after reset, defaults to False
+ """
+
+ def open(self) -> None:
+ """Open the interface."""
+
+ def close(self) -> None:
+ """Close the interface."""
+
+ @abc.abstractmethod
+ def read(self, length: int) -> bytes:
+ """Read data from the device."""
+
+ def write(self, data: bytes) -> None:
+ """Write a packet to the device."""
diff --git a/spsdk/image/ahab/ahab_container.py b/spsdk/image/ahab/ahab_container.py
index 422349b4..40dd7cbd 100644
--- a/spsdk/image/ahab/ahab_container.py
+++ b/spsdk/image/ahab/ahab_container.py
@@ -23,22 +23,15 @@
from spsdk import version as spsdk_version
from spsdk.apps.utils.utils import get_key
-from spsdk.crypto import (
- EllipticCurvePublicKey,
- Encoding,
- PrivateKey,
- PublicKey,
- RSAPrivateKey,
- RSAPublicKey,
- _PrivateKeyTuple,
-)
+from spsdk.crypto import EllipticCurvePublicKey, Encoding, PublicKey, RSAPrivateKey, RSAPublicKey
from spsdk.crypto.keys_management import (
recreate_ecc_public_key,
recreate_rsa_public_key,
save_ecc_public_key,
save_rsa_public_key,
)
-from spsdk.crypto.loaders import extract_public_key, load_private_key, load_private_key_from_data
+from spsdk.crypto.loaders import extract_public_key
+from spsdk.crypto.signature_provider import SignatureProvider, get_signature_provider
from spsdk.exceptions import SPSDKError, SPSDKLengthError, SPSDKParsingError, SPSDKValueError
from spsdk.image.ahab import AHAB_DATABASE_FILE, AHAB_SCH_FILE
from spsdk.image.ahab.ahab_abstract_interfaces import (
@@ -46,7 +39,7 @@
HeaderContainer,
HeaderContainerInversed,
)
-from spsdk.utils.crypto.common import crypto_backend, get_matching_key_id
+from spsdk.utils.crypto.common import crypto_backend, get_matching_key_id, serialize_ecc_signature
from spsdk.utils.database import Database
from spsdk.utils.easy_enum import Enum
from spsdk.utils.images import BinaryImage
@@ -79,6 +72,8 @@
IMAGE_TYPE_XIP = "xip"
IMAGE_TYPE_NON_XIP = "non_xip"
IMAGE_TYPE_SERIAL_DOWNLOADER = "serial_downloader"
+IMAGE_TYPE_NAND = "nand"
+IMAGE_TYPE_NAND_OFFSETS = {0: -0x400, 0x400: 0x400}
class AHABTags(Enum):
@@ -475,11 +470,11 @@ def parse(parent: "AHABContainer", binary: bytes, offset: int = 0) -> "ImageArra
"""
binary_size = len(binary)
# Just updates offsets from AHAB Image start As is feature of none xip containers
- container_offset = (
- parent.container_offset
- if parent.parent.image_type in (IMAGE_TYPE_NON_XIP, IMAGE_TYPE_SERIAL_DOWNLOADER)
- else 0
- )
+ container_offset = 0
+ if parent.parent.image_type in (IMAGE_TYPE_NON_XIP, IMAGE_TYPE_SERIAL_DOWNLOADER):
+ container_offset = parent.container_offset
+ elif parent.parent.image_type in (IMAGE_TYPE_NAND):
+ container_offset = IMAGE_TYPE_NAND_OFFSETS[parent.container_offset]
ImageArrayEntry._check_fixed_input_length(binary[offset:])
(
@@ -495,11 +490,11 @@ def parse(parent: "AHABContainer", binary: bytes, offset: int = 0) -> "ImageArra
ImageArrayEntry._format(), binary[offset : offset + ImageArrayEntry.fixed_length()]
)
- if image_offset + image_size - 1 > binary_size:
+ if image_offset + image_size + container_offset - 1 > binary_size:
raise SPSDKLengthError(
"Container data image is out of loaded binary:"
- f"Image entry record has end of image at 0x{hex(image_offset+image_size-1)},"
- f" but the loaded image length has only 0x{hex(binary_size)}B size."
+ f"Image entry record has end of image at {hex(image_offset+image_size-1)},"
+ f" but the loaded image length has only {hex(binary_size)}B size."
)
image = binary[
container_offset + image_offset : container_offset + image_offset + image_size
@@ -1095,7 +1090,7 @@ def create_config(self, index: int, data_path: str) -> CM:
srk.store_public_key(os.path.join(data_path, filename))
cfg_srks.append(filename)
- ret_cfg["image_array"] = cfg_srks
+ ret_cfg["srk_array"] = cfg_srks
return ret_cfg
@staticmethod
@@ -1141,16 +1136,18 @@ class ContainerSignature(HeaderContainer):
VERSION = 0x00
def __init__(
- self, signature_data: Optional[bytes] = None, signing_key: Optional[PrivateKey] = None
+ self,
+ signature_data: Optional[bytes] = None,
+ signature_provider: Optional[SignatureProvider] = None,
) -> None:
"""Class object initializer.
:param signature_data: signature.
- :param signing_key: Key use to sign the image.
+ :param signature_provider: Signature provider use to sign the image.
"""
super().__init__(tag=self.TAG, length=-1, version=self.VERSION)
self._signature_data = signature_data or b""
- self._signing_key = signing_key
+ self._signature_provider = signature_provider
self.length = len(self)
def __eq__(self, other: object) -> bool:
@@ -1161,8 +1158,10 @@ def __eq__(self, other: object) -> bool:
return False
def __len__(self) -> int:
- if (not self._signature_data or len(self._signature_data) == 0) and self._signing_key:
- return super().__len__() + crypto_backend().sign_size(self._signing_key)
+ if (
+ not self._signature_data or len(self._signature_data) == 0
+ ) and self._signature_provider:
+ return super().__len__() + self._signature_provider.signature_length
sign_data_len = len(self._signature_data)
if sign_data_len == 0:
@@ -1197,18 +1196,17 @@ def sign(self, data_to_sign: bytes) -> None:
:param data_to_sign: Data to be signed by store private key
:raises SPSDKError: Missing private key or raw signature data.
"""
- if not self._signing_key and len(self._signature_data) == 0:
+ if not self._signature_provider and len(self._signature_data) == 0:
raise SPSDKError(
"The Signature container doesn't have specified the private tey to sign."
)
- if self._signing_key:
- if isinstance(self._signing_key, RSAPrivateKey):
- self._signature_data = crypto_backend().rsa_sign(self._signing_key, data_to_sign) # type: ignore
- else:
- self._signature_data = crypto_backend().ecc_sign(
- self._signing_key, data_to_sign # type: ignore
- )
+ if self._signature_provider:
+ signature = self._signature_provider.sign(data_to_sign)
+ assert signature
+ self._signature_data = serialize_ecc_signature(
+ signature, self._signature_provider.signature_length // 2
+ )
def export(self) -> bytes:
"""Export signature data that is part of Signature Block.
@@ -1276,10 +1274,13 @@ def load_from_config(
:param search_paths: List of paths where to search for the file, defaults to None
:return: Container signature object.
"""
- signing_key_cfg = config.get("signing_key")
- assert signing_key_cfg
- signing_key_path = find_file(signing_key_cfg, search_paths=search_paths)
- return ContainerSignature(signing_key=load_private_key(signing_key_path))
+ signature_provider = get_signature_provider(
+ sp_cfg=config.get("signature_provider"),
+ local_file_key=config.get("signing_key"),
+ search_paths=search_paths,
+ )
+ assert signature_provider
+ return ContainerSignature(signature_provider=signature_provider)
class Certificate(HeaderContainer):
@@ -1344,15 +1345,15 @@ def __init__(
permissions: int = 0,
uuid: Optional[bytes] = None,
public_key: Optional[SRKRecord] = None,
- signing_key: Optional[PrivateKey] = None,
+ signature_provider: Optional[SignatureProvider] = None,
):
"""Class object initializer.
:param permissions: used to indicate what a certificate can be used for.
:param uuid: optional 128-bit unique identifier.
:param public_key: public Key. SRK record entry describing the key.
- :param signing_key: signing key for certificate. Signature is calculated over
- all data from beginning of the certificate up to but not including the signature.
+ :param signature_provider: Signature provider for certificate. Signature is calculated over
+ all data from beginning of the certificate up to, but not including the signature.
"""
tag = AHABTags.CERTIFICATE_UUID if uuid else AHABTags.CERTIFICATE_NON_UUID
super().__init__(tag=tag, length=-1, version=self.VERSION)
@@ -1360,7 +1361,7 @@ def __init__(
self.signature_offset = -1
self._uuid = uuid
self.public_key = public_key
- self._signing_key = signing_key
+ self._signature_provider = signature_provider
self.signature = b""
def __eq__(self, other: object) -> bool:
@@ -1390,8 +1391,8 @@ def __len__(self) -> int:
assert self.public_key
uuid_len = len(self._uuid) if self._uuid else 0
sign_size = (
- crypto_backend().sign_size(self._signing_key)
- if self._signing_key
+ self._signature_provider.signature_length
+ if self._signature_provider
else len(self.signature)
)
return super().__len__() + uuid_len + len(self.public_key) + sign_size
@@ -1435,7 +1436,7 @@ def create_config_permissions(self, srk_set: str) -> List[str]:
def self_sign(self) -> None:
"""Sign self by the signature key and store result into _signature field."""
assert self.public_key
- if self._signing_key:
+ if self._signature_provider:
data_to_sign = (
pack(
self._format(),
@@ -1448,11 +1449,14 @@ def self_sign(self) -> None:
)
+ self.public_key.export()
)
- if isinstance(self._signing_key, RSAPrivateKey):
- self.signature = crypto_backend().rsa_sign(self._signing_key, data_to_sign) # type: ignore
+ signature = self._signature_provider.sign(data_to_sign)
+ assert signature
+
+ if isinstance(self._signature_provider, RSAPrivateKey):
+ self.signature = signature
else:
- self.signature = crypto_backend().ecc_sign(
- self._signing_key, data_to_sign # type: ignore
+ self.signature = serialize_ecc_signature(
+ signature, self._signature_provider.signature_length // 2
)
def update_fields(self) -> None:
@@ -1461,14 +1465,11 @@ def update_fields(self) -> None:
self.public_key.update_fields()
self.tag = AHABTags.CERTIFICATE_UUID if self._uuid else AHABTags.CERTIFICATE_NON_UUID
self.signature_offset = (
- super().__len__() + len(self._uuid) if self._uuid else 0 + len(self.public_key)
- )
- self.length = (
- crypto_backend().sign_size(self._signing_key)
- if self._signing_key
- else len(self.signature) + self.signature_offset
+ super().__len__() + (len(self._uuid) if self._uuid else 0) + len(self.public_key)
)
- self.self_sign()
+ self.length = len(self)
+ if not self.signature:
+ self.self_sign()
def export(self) -> bytes:
"""Export container certificate object into bytes.
@@ -1492,7 +1493,7 @@ def export(self) -> bytes:
# if uuid is present, insert it into the cert data
if self._uuid:
cert = cert[: self.UUID_OFFSET] + self._uuid + cert[self.UUID_OFFSET :]
-
+ assert self.length == len(cert)
return cert
def validate(self) -> None:
@@ -1507,20 +1508,23 @@ def validate(self) -> None:
raise SPSDKValueError("Certificate: Missing public key.")
self.public_key.validate()
- if not (self._signing_key and self.signature):
- if self._signing_key is None or not isinstance(self._signing_key, _PrivateKeyTuple):
- raise SPSDKValueError(f"Certificate: Invalid signing key. {str(self._signing_key)}")
- if self.signature is None or len(self.signature) != crypto_backend().sign_size(
- self._signing_key
- ):
- raise SPSDKValueError(f"Certificate: Missing signature. {str(self._signing_key)}")
- if len(self.signature) != crypto_backend().sign_size(self._signing_key):
+ if not self.signature:
+ raise SPSDKValueError("Signature must be provided")
+
+ if self._signature_provider:
+ if not isinstance(self._signature_provider, SignatureProvider):
+ raise SPSDKValueError(
+ f"Certificate: Invalid signature provider. {str(self._signature_provider)}"
+ )
+
+ if len(self.signature) != self._signature_provider.signature_length:
raise SPSDKValueError(
f"Certificate: Invalid signature length. "
- f"{len(self.signature)} != {crypto_backend().sign_size(self._signing_key)}"
+ f"{len(self.signature)} != {self._signature_provider.signature_length}"
)
+
expected_signature_offset = (
- super().__len__() + len(self._uuid) if self._uuid else 0 + len(self.public_key)
+ super().__len__() + (len(self._uuid) if self._uuid else 0) + len(self.public_key)
)
if self.signature_offset != expected_signature_offset:
raise SPSDKValueError(
@@ -1595,7 +1599,7 @@ def create_config(self, index: int, data_path: str, srk_set: str = "none") -> CM
filename = f"container{index}_certificate_public_key_{self.public_key.get_key_name()}.PEM"
self.public_key.store_public_key(os.path.join(data_path, filename))
ret_cfg["public_key"] = filename
- ret_cfg["signing_key"] = "N/A"
+ ret_cfg["signature_provider"] = "N/A"
return ret_cfg
@@ -1616,17 +1620,17 @@ def load_from_config(
cert_uuid = value_to_bytes(cert_uuid_raw) if cert_uuid_raw else None
cert_public_key_path = config.get("public_key")
assert isinstance(cert_public_key_path, str)
- cert_signing_key_path = config.get("signing_key")
- assert isinstance(cert_signing_key_path, str)
+ cert_signature_provider = get_signature_provider(
+ config.get("signature_provider"), config.get("signing_key"), search_paths=search_paths
+ )
cert_public_key_path = find_file(cert_public_key_path, search_paths=search_paths)
cert_public_key = extract_public_key(cert_public_key_path)
- cert_signing_key = load_binary(cert_signing_key_path, search_paths=search_paths)
cert_srk_rec = SRKRecord.create_from_key(cert_public_key)
return Certificate(
permissions=Certificate.create_permissions(cert_permissions_list),
uuid=cert_uuid,
public_key=cert_srk_rec,
- signing_key=load_private_key_from_data(cert_signing_key),
+ signature_provider=cert_signature_provider,
)
@@ -2080,8 +2084,8 @@ def check_offset(name: str, min_offset: int, offset: int) -> None:
if "flag_used_srk_id" in data.keys() and self.signature and self.srk_table:
public_keys = self.srk_table.get_source_keys()
if public_keys:
- assert self.signature._signing_key
- srk_pair_id = get_matching_key_id(public_keys, self.signature._signing_key)
+ assert self.signature._signature_provider
+ srk_pair_id = get_matching_key_id(public_keys, self.signature._signature_provider)
if srk_pair_id != data["flag_used_srk_id"]:
raise SPSDKValueError(
f"Signature Block: Configured SRK ID ({data['flag_used_srk_id']})"
@@ -2146,9 +2150,9 @@ def load_from_config(
)
# Container Signature
- signing_key_cfg = config.get("signing_key")
+ srk_set = config.get("srk_set", "none")
signature_block.signature = (
- ContainerSignature.load_from_config(config, search_paths) if signing_key_cfg else None
+ ContainerSignature.load_from_config(config, search_paths) if srk_set != "none" else None
)
# Certificate Block
@@ -2869,7 +2873,12 @@ class AHABImage:
The image consists of multiple AHAB containers.
"""
- IMAGE_TYPES = [IMAGE_TYPE_XIP, IMAGE_TYPE_NON_XIP, IMAGE_TYPE_SERIAL_DOWNLOADER]
+ IMAGE_TYPES = [
+ IMAGE_TYPE_XIP,
+ IMAGE_TYPE_NON_XIP,
+ IMAGE_TYPE_SERIAL_DOWNLOADER,
+ IMAGE_TYPE_NAND,
+ ]
def __init__(
self,
@@ -2960,6 +2969,8 @@ def __len__(self) -> int:
if self.image_type in (IMAGE_TYPE_NON_XIP, IMAGE_TYPE_SERIAL_DOWNLOADER):
# Just updates offsets from AHAB Image start As is feature of none xip containers
length += container.container_offset
+ elif self.image_type in (IMAGE_TYPE_NAND):
+ length += IMAGE_TYPE_NAND_OFFSETS[container.container_offset]
lengths.append(length)
return max(lengths)
@@ -3017,9 +3028,14 @@ def image_info(self) -> BinaryImage:
# Add also all data images
for img_ix, image_entry in enumerate(container.image_array):
offset = image_entry.image_offset
+
if self.image_type in (IMAGE_TYPE_NON_XIP, IMAGE_TYPE_SERIAL_DOWNLOADER):
# Just updates offsets from AHAB Image start As is feature of none xip containers
offset += container.container_offset
+ elif self.image_type in (IMAGE_TYPE_NAND):
+ # Just updates offsets from AHAB Image start As is feature of none xip containers
+ offset += IMAGE_TYPE_NAND_OFFSETS[container.container_offset]
+
data_image = BinaryImage(
name=f"Container {cnt_ix} AHAB Data Image {img_ix}",
binary=image_entry.image,
@@ -3083,9 +3099,10 @@ def load_from_config(
"config" content array of containers configurations.
- :raises SPSDKValueError: if the count of AHAB containers is invalid.
:param config: array of AHAB containers configuration dictionaries.
:param search_paths: List of paths where to search for the file, defaults to None
+ :raises SPSDKValueError: if the count of AHAB containers is invalid.
+ :raises SPSDKParsingError: Cannot parse input binary AHAB container.
:return: initialized AHAB Image.
"""
containers_config: List[Dict[str, Any]] = config["containers"]
@@ -3101,7 +3118,20 @@ def load_from_config(
assert isinstance(binary_container, dict)
path = binary_container.get("path")
assert path
- container = AHABContainer.parse(ahab, load_binary(path, search_paths=search_paths))
+ image_type_bck = ahab.image_type
+ ahab_bin = load_binary(path, search_paths=search_paths)
+ container = None
+ for image_type in AHABImage.IMAGE_TYPES:
+ try:
+ ahab.image_type = image_type
+ container = AHABContainer.parse(ahab, ahab_bin)
+ break
+ except SPSDKError:
+ pass
+ finally:
+ ahab.image_type = image_type_bck
+ if not container:
+ raise SPSDKParsingError("AHAB Container parsing failed.")
else:
container = AHABContainer.load_from_config(ahab, container_config["container"])
container.container_offset = ahab.ahab_address_map[i]
@@ -3118,6 +3148,7 @@ def parse(self, binary: bytes) -> None:
for address in self.ahab_address_map:
try:
+ logger.debug(f"Trying to parse container at address: {hex(address)}")
container = AHABContainer.parse(self, binary, address)
self.ahab_containers.append(container)
except SPSDKParsingError:
@@ -3218,7 +3249,7 @@ def create_srk_hash_blhost_script(self, container_ix: int = 0) -> str:
srkh = srk_table.compute_srk_hash()
if len(srkh) != fuses_count * fuses_size:
- SPSDKError(
+ raise SPSDKError(
f"The SRK hash length ({len(srkh)}) doesn't fit to fuses space ({fuses_count*fuses_size})."
)
ret = (
diff --git a/spsdk/image/bee.py b/spsdk/image/bee.py
index 1208b13b..f8d22014 100644
--- a/spsdk/image/bee.py
+++ b/spsdk/image/bee.py
@@ -57,7 +57,7 @@ def _struct_format(cls) -> str:
return cls._FORMAT # _FORMAT class constant must be defined in child class
@classmethod
- def _size(cls) -> int:
+ def get_size(cls) -> int:
""":return: size of the exported binary data in bytes."""
return calcsize(cls._struct_format())
@@ -67,7 +67,7 @@ def __eq__(self, other: Any) -> bool:
@property
def size(self) -> int:
""":return: size of the exported binary data in bytes."""
- return self._size()
+ return self.get_size()
def info(self) -> str:
"""Info method.
@@ -101,7 +101,7 @@ def parse(cls, data: bytes, offset: int = 0) -> Any:
:return: instance created from binary data; this method returns just `0`
:raises SPSDKError: If size of the data is not sufficient
"""
- if len(data) - offset < cls._size():
+ if len(data) - offset < cls.get_size():
raise SPSDKError("Insufficient size of the data")
return 0
@@ -201,7 +201,7 @@ class BeeProtectRegionBlock(BeeBaseClass):
SIZE = 0x100
@classmethod
- def _size(cls) -> int:
+ def get_size(cls) -> int:
""":return: size of the exported binary data in bytes."""
return cls.SIZE
@@ -460,7 +460,7 @@ def _struct_format(cls) -> str:
)
@classmethod
- def _size(cls) -> int:
+ def get_size(cls) -> int:
""":return: size of the exported binary data in bytes."""
return cls.SIZE
@@ -561,7 +561,7 @@ def parse(cls, data: bytes, offset: int = 0, sw_key: bytes = b"") -> "BeeRegionH
if len(sw_key) != 16:
raise SPSDKError("Invalid sw key")
aes_ecb = AES.new(sw_key, AES.MODE_ECB)
- decr_data = aes_ecb.decrypt(data[offset : offset + BeeKIB._size()])
+ decr_data = aes_ecb.decrypt(data[offset : offset + BeeKIB.get_size()])
kib = BeeKIB.parse(decr_data)
aes_cbc = AES.new(kib.kib_key, AES.MODE_CBC, kib.kib_iv)
decr_data = aes_cbc.decrypt(
diff --git a/spsdk/image/bootable_image/bimg.py b/spsdk/image/bootable_image/bimg.py
index f7fe11c0..1333a2d8 100644
--- a/spsdk/image/bootable_image/bimg.py
+++ b/spsdk/image/bootable_image/bimg.py
@@ -30,7 +30,7 @@
BIMG_CLASSES = [
"BootableImageRtxxx",
- "BootableImageLpc55s3x",
+ "BootableImageLpc55s3xRw61x",
"BootableImageRt101x",
"BootableImageRt10xx",
"BootableImageRt11xx",
@@ -471,8 +471,8 @@ def get_supported_families() -> List[str]:
return [x for x in full_list if re.match(r"[rR][tT][\dxX]{3}$", x)]
-class BootableImageLpc55s3x(BootableImage):
- """Bootable Image class for LPC55S3x devices."""
+class BootableImageLpc55s3xRw61x(BootableImage):
+ """Bootable Image class for LPC55S3x and Rw61x devices."""
IMAGE_PATTERN = BinaryPattern("ones")
@@ -485,7 +485,7 @@ def __init__(
image_version: Optional[int] = None,
application: Optional[bytes] = None,
) -> None:
- """Bootable Image constructor for Lpc55s3x devices.
+ """Bootable Image constructor for Lpc55s3x and Rw61x devices.
:param mem_type: Used memory type.
:param fcb: FCB block, defaults to None
@@ -565,8 +565,12 @@ def get_supported_families() -> List[str]:
:return: List of families.
"""
full_list = BootableImage.get_supported_families()
- # filter out just LPC55S3x
- return [x for x in full_list if re.match(r"[lL][pP][cC]55[sS]3[\dxX]$", x)]
+ # filter out just LPC55S3x and Rw61x
+ return [
+ x
+ for x in full_list
+ if re.match(r"[lL][pP][cC]55[sS]3[\dxX]$", x) or re.match(r"[rR][wW]61[\dxX]$", x)
+ ]
class BootableImageRt101x(BootableImage):
@@ -869,7 +873,6 @@ def parse(self, binary: bytes) -> None:
# XMCD
offset = self.bimg_descr["xmcd_offset"]
size = self._get_xmcd_size(binary[offset : offset + XMCDHeader.SIZE])
- self.xmcd_obj
if size > 0:
self.xmcd = binary[offset:size]
self.xmcd_obj = XMCD(self.family, self.revision)
diff --git a/spsdk/image/hab/csf_builder.py b/spsdk/image/hab/csf_builder.py
index 21a9b8cc..b465acfa 100644
--- a/spsdk/image/hab/csf_builder.py
+++ b/spsdk/image/hab/csf_builder.py
@@ -106,7 +106,7 @@ def check_config_section_params(cls, section_data: SectionConfig) -> None:
"""
for param, is_mandatory in cls.CONFIGURATION_PARAMS.items():
if is_mandatory and section_data.options.get(param) is None:
- raise SPSDKError(f"Mandatory parameter is not defined")
+ raise SPSDKError("Mandatory parameter is not defined")
additional_params = list(
set(key.lower() for key in section_data.options.keys())
@@ -122,7 +122,7 @@ def parse(config: SectionConfig, search_paths: Optional[List[str]] = None) -> "S
:param config: Section config
:param search_paths: List of paths where to search for the file, defaults to None
- "return: Parsed command instance
+ :return: Parsed command instance
"""
@abstractmethod
@@ -301,7 +301,7 @@ class SecCsfInstallCsfk(SecCommand):
def __init__(
self,
csfk_file_path: str,
- certificate_format: Optional[EnumCertFormat],
+ certificate_format: Optional[EnumCertFormat] = None,
) -> None:
"""Install CSF class constructor.
@@ -316,7 +316,7 @@ def __init__(
if certificate_format == EnumCertFormat.SRK:
raise SPSDKValueError(f"Invalid certificate format: {EnumCertFormat.SRK}")
if certificate_format is None:
- certificate_format == EnumCertFormat.X509
+ certificate_format = EnumCertFormat.X509
self.certificate_format = certificate_format
@staticmethod
@@ -594,12 +594,12 @@ def __init__(
self.engine = engine
self.engine_config = engine_config
if verification_index is None:
- raise SPSDKValueError(f"Verification index must be defined.")
+ raise SPSDKValueError("Verification index must be defined.")
if verification_index != self.KEY_IDX_AUT_DAT_FAST_AUTH and (
verification_index < self.KEY_IDX_AUT_DAT_MIN
or verification_index > self.KEY_IDX_AUT_DAT_MAX
):
- raise SPSDKValueError(f"Key index must have valid value.")
+ raise SPSDKValueError("Key index must have valid value.")
self.verification_index = verification_index
self.private_key = private_key
self.key_pass = key_pass
@@ -914,7 +914,7 @@ def __init__(
if source_index is None:
raise SPSDKValueError("Source index must be specified")
if source_index > 3:
- raise SPSDKValueError(f"Source index must be equal or lower than 3")
+ raise SPSDKValueError("Source index must be equal or lower than 3")
self.source_index = source_index
if target_index is None:
raise SPSDKValueError("Target index must be specified")
@@ -1023,9 +1023,9 @@ def __init__(
"""
super().__init__()
if verification_index is None:
- raise SPSDKValueError(f"Verification index must be defined.")
+ raise SPSDKValueError("Verification index must be defined.")
if verification_index >= 6:
- raise SPSDKValueError(f"Verification index must be lower than 6.")
+ raise SPSDKValueError("Verification index must be lower than 6.")
self.verification_index = verification_index
self.engine = engine if engine is not None else EnumEngine.ANY
self.engine_config = engine_config if engine_config is not None else 0
@@ -1034,7 +1034,7 @@ def __init__(
self.mac_len = mac_len if mac_len is not None else 16
if self.mac_len < 4 or self.mac_len > 16 or self.mac_len % 2:
raise SPSDKValueError(
- f"Invalid mac length. Valid options are 4, 6, 8, 10, 12, 14 and 16."
+ "Invalid mac length. Valid options are 4, 6, 8, 10, 12, 14 and 16."
)
self.nonce = nonce
self._dek: Optional[bytes] = None
@@ -1168,7 +1168,8 @@ def __init__(
:param search_paths: List of paths where to search for the file, defaults to None
:param timestamp: Signature timestamp
"""
- self.reset()
+ self.header: Optional[SecCsfHeader] = None
+ self.commands: List[SecCommand] = []
self.bd_config = bd_config
self.is_encrypted = self.bd_config.options.flags == 0x0C
self.is_authenticated = self.bd_config.options.flags == 0x08
@@ -1181,8 +1182,8 @@ def __init__(
def reset(self) -> None:
"""Reset builder into its initial state."""
- self.header: Optional[SecCsfHeader] = None
- self.commands: List[SecCommand] = []
+ self.header = None
+ self.commands = []
def get_command(self, command_id: int, raise_exc: bool = True) -> Optional[SecCommand]:
"""Get command by command id.
@@ -1458,7 +1459,7 @@ def _determine_private_key_path(self, cert_file_path: str) -> Optional[str]:
:param cert_file_path: Path to certificate file
:return: Path to private key file
"""
- logger.debug(f"Trying to determine the private key path.")
+ logger.debug("Trying to determine the private key path.")
keys_dir = self._get_keys_dir(cert_file_path)
cert_file_name = os.path.basename(cert_file_path)
cert_file, cert_extension = os.path.splitext(cert_file_name)
@@ -1478,7 +1479,7 @@ def _determine_key_pass_path(self, cert_file_path: str) -> Optional[str]:
:param cert_file_path: Path to certificate file
:return: Path to key pass file
"""
- logger.debug(f"Trying to determine the key pass path.")
+ logger.debug("Trying to determine the key pass path.")
keys_dir = self._get_keys_dir(cert_file_path)
key_pass_file = os.path.join(keys_dir, "key_pass.txt")
if not os.path.isfile(key_pass_file):
diff --git a/spsdk/image/hab/hab_container.py b/spsdk/image/hab/hab_container.py
index 96c4064b..23810228 100644
--- a/spsdk/image/hab/hab_container.py
+++ b/spsdk/image/hab/hab_container.py
@@ -17,7 +17,7 @@
from spsdk.image.hab.hab_binary_image import HabBinaryImage, HabSegment
from spsdk.image.images import BootImgRT
from spsdk.utils.images import BinaryImage
-from spsdk.utils.misc import BinaryPattern, load_binary
+from spsdk.utils.misc import load_binary
logger = logging.getLogger(__name__)
@@ -156,7 +156,7 @@ def _calculate_csf_offset(image_len: int) -> int:
def parse(cls, binary: bytes) -> "HabContainer":
"""Parse existing binary into HAB container object.
- :param binary:Binary to be parsed
+ :param binary: Binary to be parsed
"""
rt_img = BootImgRT.parse(binary)
# IVT
diff --git a/spsdk/image/hab_audit_log.py b/spsdk/image/hab_audit_log.py
index ee2fea93..17b8affe 100644
--- a/spsdk/image/hab_audit_log.py
+++ b/spsdk/image/hab_audit_log.py
@@ -20,8 +20,7 @@
from .commands import parse_command
from .header import CmdTag
-# Absolute path, where the executable hab audit code is located.
-CPU_DATA_SUB_DIR = os.path.join(os.path.dirname(__file__), "data", "cpu_data")
+# NOTE HAB Audit log executables have been moved to spsdk/examples/data/hab_audit
# pylint: disable=too-few-public-methods
@@ -290,7 +289,9 @@ def parse_hab_log(hab_sts: int, hab_cfg: int, hab_state: int, data: bytes) -> Li
return result
-def hab_audit_xip_app(cpu_data: CpuData, mboot: McuBoot, read_log_only: bool) -> Optional[bytes]:
+def hab_audit_xip_app(
+ cpu_data: CpuData, mboot: McuBoot, read_log_only: bool, hab_audit_path: str
+) -> Optional[bytes]:
"""Authenticate the application in external FLASH.
The function loads application into RAM and invokes its function, that authenticates the application and read the
@@ -300,6 +301,7 @@ def hab_audit_xip_app(cpu_data: CpuData, mboot: McuBoot, read_log_only: bool) ->
:param read_log_only: true to read HAB log without invoking authentication; False to authenticate and read-log
It is recommended to call the function firstly with parameter `True` and second time with parameter False to
see the difference.
+ :param hab_audit_path: Path to directory with HAB audit log executables
:return: bytes contains result of the hab log, otherwise returns None when an error occurred
:raises SPSDKError: When flashloader is not running
:raises SPSDKError: When given cpu data were not provided
@@ -319,12 +321,8 @@ def hab_audit_xip_app(cpu_data: CpuData, mboot: McuBoot, read_log_only: bool) ->
evk_exec_hab_audit_base = cpu_data.base_address
evk_exec_hab_audit_start = cpu_data.start_address
- # get main directory in absolute format
- main_dir_absolute = os.path.dirname(__file__)
- # get hab_audit_executable bin file directory
- exec_hab_audit_path = os.path.join(
- os.path.dirname(main_dir_absolute), "data", "cpu_data", cpu_data_bin_dir
- )
+ exec_hab_audit_path = os.path.join(hab_audit_path, cpu_data_bin_dir)
+
if not os.path.isfile(exec_hab_audit_path):
print("\nHAB logger not supported for the processor")
return None
diff --git a/spsdk/image/mbi_mixin.py b/spsdk/image/mbi_mixin.py
index 52ba7a9b..c2aefa60 100644
--- a/spsdk/image/mbi_mixin.py
+++ b/spsdk/image/mbi_mixin.py
@@ -9,14 +9,16 @@
"""Master Boot Image."""
import logging
+import os
import struct
-from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union
+from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, TypeVar, Union
from crcmod.predefined import mkPredefinedCrcFun
from spsdk import SPSDKError
+from spsdk.apps.utils.utils import get_key
from spsdk.crypto.signature_provider import SignatureProvider, get_signature_provider
-from spsdk.exceptions import SPSDKUnsupportedOperation
+from spsdk.exceptions import SPSDKParsingError, SPSDKUnsupportedOperation, SPSDKValueError
from spsdk.image.keystore import KeySourceType, KeyStore
from spsdk.image.trustzone import TrustZone, TrustZoneType
from spsdk.utils.crypto import crypto_backend
@@ -24,7 +26,14 @@
from spsdk.utils.crypto.common import serialize_ecc_signature
from spsdk.utils.easy_enum import Enum
from spsdk.utils.images import BinaryImage
-from spsdk.utils.misc import align_block, find_file, load_binary, load_configuration, value_to_int
+from spsdk.utils.misc import (
+ align_block,
+ find_file,
+ load_binary,
+ load_configuration,
+ value_to_int,
+ write_file,
+)
logger = logging.getLogger(__name__)
@@ -36,32 +45,45 @@ class MasterBootImageManifest:
FORMAT = "<4s4L"
FORMAT_VERSION = 0x0001_0000
DIGEST_PRESENT_FLAG = 0x8000_0000
+ HASH_TYPE_MASK = 0x0F
+ SUPPORTED_ALGORITHMS = ["sha256", "sha384", "sha512"]
def __init__(
- self, firmware_version: int, trust_zone: TrustZone, sign_hash_len: Optional[int] = None
+ self,
+ firmware_version: int,
+ trust_zone: Optional[TrustZone],
+ digest_hash_algo: Optional[str] = None,
) -> None:
"""Initialize MBI Manifest object.
:param firmware_version: firmware version
- :param sign_hash_len: length of hash used for singing, defaults to None
+ :param digest_hash_algo: Digest hash algorithm, defaults to None
:param trust_zone: TrustZone instance, defaults to None
"""
self.firmware_version = firmware_version
- self.sign_hash_len = sign_hash_len
+ if digest_hash_algo and digest_hash_algo not in self.SUPPORTED_ALGORITHMS:
+ raise SPSDKValueError(f"Unsupported digest hash algorithm: {digest_hash_algo}")
+ self.digest_hash_algo = digest_hash_algo
self.trust_zone = trust_zone
- self.total_length = self._calculate_length()
self.flags = self._calculate_flags()
+ self.total_length = self._calculate_length()
def _calculate_length(self) -> int:
length = struct.calcsize(self.FORMAT)
- length += len(self.trust_zone.export())
+ if self.trust_zone:
+ length += len(self.trust_zone.export())
return length
def _calculate_flags(self) -> int:
- if not self.sign_hash_len:
+ if not self.digest_hash_algo:
return 0
- hash_len_types = {0: 0, 32: 1, 48: 2, 64: 3}
- return self.DIGEST_PRESENT_FLAG | hash_len_types[self.sign_hash_len]
+ hash_algo_types = {None: 0, "sha256": 1, "sha384": 2, "sha512": 3}
+ return self.DIGEST_PRESENT_FLAG | hash_algo_types[self.digest_hash_algo]
+
+ @staticmethod
+ def get_hash_size(algorithm: str) -> int:
+ """Get hash size by used algorithm."""
+ return {"sha256": 32, "sha384": 48, "sha512": 64}.get(algorithm, 0)
def export(self) -> bytes:
"""Serialize MBI Manifest."""
@@ -73,7 +95,110 @@ def export(self) -> bytes:
self.total_length,
self.flags,
)
- return data + self.trust_zone.export()
+ if self.trust_zone:
+ data += self.trust_zone.export()
+ return data
+
+ @staticmethod
+ def parse(family: str, data: bytes) -> "MasterBootImageManifest":
+ """Parse the binary to Master Boot Image Manifest.
+
+ :param family: Device family.
+ :param data: Binary Image with MBI Manifest.
+ :raises SPSDKParsingError: Invalid header is detected.
+ :return: MBI Manifest object
+ """
+ (magic, version, fw_version, total_length, flags) = struct.unpack(
+ MasterBootImageManifest.FORMAT, data[: struct.calcsize(MasterBootImageManifest.FORMAT)]
+ )
+ assert isinstance(magic, bytes)
+ if magic != MasterBootImageManifest.MAGIC:
+ raise SPSDKParsingError(
+ "MBI Manifest: Invalid MAGIC marker detected when parsing:"
+ f" {magic.hex()} != {MasterBootImageManifest.MAGIC.hex()}"
+ )
+ if version != MasterBootImageManifest.FORMAT_VERSION:
+ raise SPSDKParsingError(
+ "MBI Manifest: Invalid MANIFEST VERSION detected when parsing:"
+ f" {version} != {MasterBootImageManifest.FORMAT_VERSION}"
+ )
+ if total_length >= len(data):
+ raise SPSDKParsingError(
+ "MBI Manifest: Invalid Input data length:" f" {total_length} < {len(data)}"
+ )
+
+ manifest_len = struct.calcsize(MasterBootImageManifest.FORMAT)
+ tz_data_len = total_length - manifest_len
+ tz = None
+ if tz_data_len > 0:
+ tz = TrustZone.from_binary(family=family, raw_data=data[manifest_len:total_length])
+
+ hash_algo = None
+ if flags & MasterBootImageManifest.DIGEST_PRESENT_FLAG:
+ hash_algo = {0: None, 1: "sha256", 2: "sha384", 3: "sha512"}[
+ flags & MasterBootImageManifest.HASH_TYPE_MASK
+ ]
+
+ return MasterBootImageManifest(
+ firmware_version=fw_version, trust_zone=tz, digest_hash_algo=hash_algo
+ )
+
+
+class MasterBootImageManifestMcxNx(MasterBootImageManifest):
+ """MasterBootImage Manifest used in mcxnx devices."""
+
+ def __init__(
+ self,
+ firmware_version: int,
+ trust_zone: Optional[TrustZone],
+ digest_hash_algo: Optional[str] = None,
+ ) -> None:
+ """Initialize MBI Manifest object.
+
+ :param firmware_version: firmware version
+ :param digest_hash_algo: Digest hash algorithm, defaults to None
+ :param trust_zone: TrustZone instance, defaults to None
+ """
+ super().__init__(firmware_version, trust_zone, digest_hash_algo)
+ self.crc = 0
+
+ def export(self) -> bytes:
+ """Serialize MBI Manifest."""
+ data = super().export()
+ data += struct.pack(" "MasterBootImageManifestMcxNx":
+ """Parse the binary to Master Boot Image Manifest.
+
+ :param family: Device family.
+ :param data: Binary Image with MBI Manifest.
+ :raises SPSDKParsingError: Invalid header is detected.
+ :return: MBI Manifest object
+ """
+ manifest = MasterBootImageManifest.parse(family=family, data=data)
+ crc = int.from_bytes(data[manifest.total_length - 4 : manifest.total_length], "little")
+ mcx_manifest = MasterBootImageManifestMcxNx(
+ firmware_version=manifest.firmware_version,
+ trust_zone=manifest.trust_zone,
+ digest_hash_algo=manifest.digest_hash_algo,
+ )
+ mcx_manifest.crc = crc
+ return mcx_manifest
+
+ def _calculate_length(self) -> int:
+ return super()._calculate_length() + 4
+
+ def compute_crc(self, image: bytes) -> None:
+ """Compute and add CRC field.
+
+ :param image: Image data to be used to compute CRC
+ """
+ self.crc = mkPredefinedCrcFun("crc-32-mpeg")(image)
+
+
+T_Manifest = TypeVar("T_Manifest", MasterBootImageManifest, MasterBootImageManifestMcxNx)
class MultipleImageEntry:
@@ -150,6 +275,15 @@ def export_entry(self) -> bytes:
result += struct.pack(" "MultipleImageEntry":
+ """Parse relocation table entry from binary form."""
+ (src_addr, dst_addr, size, flags) = struct.unpack("<4I", data[: 4 * 4])
+ if src_addr + size > len(data):
+ raise SPSDKParsingError("The image doesn't fit into given data")
+
+ return MultipleImageEntry(data[src_addr : src_addr + size], dst_addr, flags)
+
def export_image(self) -> bytes:
"""Binary image aligned to the 4-bytes boundary."""
return align_block(self.image, 4)
@@ -165,6 +299,7 @@ class MultipleImageTable:
def __init__(self) -> None:
"""Initialize the Multiple Image Table."""
self._entries: List[MultipleImageEntry] = []
+ self.start_address = 0
@property
def header_version(self) -> int:
@@ -210,6 +345,7 @@ def export(self, start_addr: int) -> bytes:
"""
if not self._entries:
raise SPSDKError("There must be at least one entry for export")
+ self.start_address = start_addr
src_addr = start_addr
result = bytes()
for entry in self.entries:
@@ -221,6 +357,28 @@ def export(self, start_addr: int) -> bytes:
result += self.reloc_table(start_addr + len(result))
return result
+ @staticmethod
+ def parse(data: bytes) -> Optional["MultipleImageTable"]:
+ """Parse binary to get the Multiple application table.
+
+ :param data: Data bytes where the application is looked for
+ :raises SPSDKParsingError: The application table parsing fails.
+
+ :return: Multiple application table if detected.
+ """
+ (marker, header_version, n_entries, start_address) = struct.unpack(
+ "<4I", data[-struct.calcsize("<4I") :]
+ )
+ if marker != 0x4C54424C or header_version != MultipleImageTable().header_version:
+ return None
+
+ app_table = MultipleImageTable()
+ app_table.start_address = start_address
+ for n in range(n_entries):
+ app_table.add_entry(MultipleImageEntry.parse(data[: -16 * (1 + n)]))
+
+ return app_table
+
# ****************************************************************************************************
# Mbi Mixins
@@ -233,6 +391,7 @@ class Mbi_Mixin:
VALIDATION_SCHEMAS: List[str] = []
NEEDED_MEMBERS: List[str] = []
+ PRE_PARSED: List[str] = []
def mix_len(self) -> int: # pylint: disable=no-self-use
"""Compute length of individual mixin.
@@ -241,6 +400,13 @@ def mix_len(self) -> int: # pylint: disable=no-self-use
"""
return 0
+ def mix_app_len(self) -> int: # pylint: disable=no-self-use
+ """Compute application data length of individual mixin.
+
+ :return: Application data length of atomic Mixin.
+ """
+ return -1
+
@classmethod
def mix_get_extra_validation_schemas(cls) -> List[Dict[str, Any]]:
"""Get extra-non standard validation schemas from mixin.
@@ -264,6 +430,13 @@ def mix_parse(self, data: bytes) -> None:
:param data: Final Image in bytes.
"""
+ def mix_get_config(self, output_folder: str) -> Dict[str, Any]:
+ """Get the configuration of the mixin.
+
+ :param output_folder: Output folder to store files.
+ """
+ return {}
+
class Mbi_MixinApp(Mbi_Mixin):
"""Master Boot Image Trust Zone class."""
@@ -290,6 +463,18 @@ def mix_load_from_config(self, config: Dict[str, Any]) -> None:
"""
self.load_binary_image_file(config["inputImageFile"])
+ def mix_get_config(self, output_folder: str) -> Dict[str, Any]:
+ """Get the configuration of the mixin.
+
+ :param output_folder: Output folder to store files.
+ """
+ filename = "application.bin"
+ assert self.app
+ write_file(self.app, os.path.join(output_folder, filename), mode="wb")
+ config: Dict[str, Any] = {}
+ config["inputImageFile"] = filename
+ return config
+
def load_binary_image_file(self, path: str) -> None:
"""Load binary image from file (S19,HEX,BIN).
@@ -310,11 +495,14 @@ def load_binary_image_file(self, path: str) -> None:
class Mbi_MixinTrustZone(Mbi_Mixin):
"""Master Boot Image Trust Zone class."""
- VALIDATION_SCHEMAS: List[str] = ["tz", "family"]
- NEEDED_MEMBERS: List[str] = ["tz"]
+ VALIDATION_SCHEMAS: List[str] = ["tz"]
+ NEEDED_MEMBERS: List[str] = ["tz", "family"]
+ PRE_PARSED: List[str] = ["cert_block"]
+ family: str
tz: TrustZone
search_paths: Optional[List[str]]
+ cert_block: Optional[Union[CertBlockV2, CertBlockV31]]
def mix_len(self) -> int:
"""Get length of TrustZone array.
@@ -323,14 +511,14 @@ def mix_len(self) -> int:
"""
return len(self.tz.export())
- def _load_preset_file(self, preset_file: str, family: str) -> None:
+ def _load_preset_file(self, preset_file: str) -> None:
_preset_file = find_file(preset_file, search_paths=self.search_paths)
try:
tz_config = load_configuration(_preset_file)
self.tz = TrustZone.from_config(tz_config)
except SPSDKError:
tz_bin = load_binary(_preset_file)
- self.tz = TrustZone.from_binary(family=family, raw_data=tz_bin)
+ self.tz = TrustZone.from_binary(family=self.family, raw_data=tz_bin)
def mix_load_from_config(self, config: Dict[str, Any]) -> None:
"""Load configuration from dictionary.
@@ -341,13 +529,52 @@ def mix_load_from_config(self, config: Dict[str, Any]) -> None:
if enabled_trustzone:
trustzone_preset_file = config.get("trustZonePresetFile", None)
if trustzone_preset_file:
- family = config.get("family", None)
- self._load_preset_file(trustzone_preset_file, family)
+ self._load_preset_file(trustzone_preset_file)
else:
self.tz = TrustZone.enabled()
else:
self.tz = TrustZone.disabled()
+ def mix_get_config(self, output_folder: str) -> Dict[str, Any]:
+ """Get the configuration of the mixin.
+
+ :param output_folder: Output folder to store files.
+ """
+ config: Dict[str, Any] = {}
+ config["enableTrustZone"] = False if self.tz.type == TrustZoneType.DISABLED else True
+ if self.tz.type == TrustZoneType.CUSTOM:
+ filename = "trust_zone.bin"
+ write_file(self.tz.export(), os.path.join(output_folder, filename), mode="wb")
+ config["trustZonePresetFile"] = filename
+
+ return config
+
+ def mix_parse(self, data: bytes) -> None:
+ """Parse the binary to individual fields.
+
+ :param data: Final Image in bytes.
+ """
+ tz_type = Mbi_MixinIvt.get_tz_type(data)
+ if tz_type not in TrustZoneType:
+ raise SPSDKParsingError("Invalid TrustZone type")
+
+ if tz_type == TrustZoneType.CUSTOM:
+ # load custom data
+ tz_data_size = TrustZone.get_preset_data_size(self.family)
+ if hasattr(self, "cert_block"):
+ assert self.cert_block
+ tz_offset = Mbi_MixinIvt.get_cert_block_offset(data) + self.cert_block.expected_size
+ tz_data = data[tz_offset : tz_offset + tz_data_size]
+ else:
+ tz_data = data[-tz_data_size:]
+ tz = TrustZone.from_binary(family=self.family, raw_data=tz_data)
+ elif tz_type == TrustZoneType.ENABLED:
+ tz = TrustZone.enabled()
+ else:
+ tz = TrustZone.disabled()
+
+ self.tz = tz
+
class Mbi_MixinTrustZoneMandatory(Mbi_MixinTrustZone):
"""Master Boot Image Trust Zone class for LPC55s3x family."""
@@ -359,8 +586,7 @@ def mix_load_from_config(self, config: Dict[str, Any]) -> None:
"""
trustzone_preset_file = config.get("trustZonePresetFile", None)
if trustzone_preset_file:
- family = config.get("family", None)
- self._load_preset_file(trustzone_preset_file, family)
+ self._load_preset_file(trustzone_preset_file)
else:
self.tz = TrustZone.enabled()
@@ -390,6 +616,23 @@ def mix_load_from_config(self, config: Dict[str, Any]) -> None:
assert value is not None
self.load_address = value_to_int(value)
+ def mix_get_config(self, output_folder: str) -> Dict[str, Any]:
+ """Get the configuration of the mixin.
+
+ :param output_folder: Output folder to store files.
+ """
+ config: Dict[str, Any] = {}
+ assert self.load_address is not None
+ config["outputImageExecutionAddress"] = hex(self.load_address)
+ return config
+
+ def mix_parse(self, data: bytes) -> None:
+ """Parse the binary to individual fields.
+
+ :param data: Final Image in bytes.
+ """
+ self.load_address = Mbi_MixinIvt.get_load_address(data)
+
class Mbi_MixinFwVersion(Mbi_Mixin):
"""Master Boot Image FirmWare Version class."""
@@ -407,6 +650,22 @@ def mix_load_from_config(self, config: Dict[str, Any]) -> None:
"""
self.firmware_version = value_to_int(config.get("firmwareVersion", 0))
+ def mix_get_config(self, output_folder: str) -> Dict[str, Any]:
+ """Get the configuration of the mixin.
+
+ :param output_folder: Output folder to store files.
+ """
+ config: Dict[str, Any] = {}
+ config["firmwareVersion"] = self.firmware_version
+ return config
+
+ def mix_parse(self, data: bytes) -> None:
+ """Parse the binary to individual fields.
+
+ :param data: Final Image in bytes.
+ """
+ self.firmware_version = Mbi_MixinIvt.get_fw_version(data)
+
class Mbi_MixinImageSubType(Mbi_Mixin):
"""Master Boot Image SubType class."""
@@ -417,6 +676,12 @@ class Mbi_ImageSubTypeKw45xx(Enum):
MAIN = (0x00, "MAIN", "Default (main) application image")
NBU = (0x01, "NBU", "NBU (Narrowband Unit) image")
+ class Mbi_ImageSubTypeMcxn9xx(Enum):
+ """Supported MAIN and NBU subtypes for MCXN9xx."""
+
+ MAIN = (0x00, "MAIN", "Default (main) application image")
+ RECOVERY = (0x01, "RECOVERY", "Recovery image")
+
VALIDATION_SCHEMAS: List[str] = ["image_subtype"]
NEEDED_MEMBERS: List[str] = ["image_subtype"]
@@ -429,19 +694,44 @@ def mix_load_from_config(self, config: Dict[str, Any]) -> None:
"""
self.set_image_subtype(config.get("outputImageSubtype", "MAIN"))
+ def mix_get_config(self, output_folder: str) -> Dict[str, Any]:
+ """Get the configuration of the mixin.
+
+ :param output_folder: Output folder to store files.mb_xip_384_384_recovery_crctest
+ """
+ config: Dict[str, Any] = {}
+ assert self.image_subtype is not None
+ config["outputImageSubtype"] = Mbi_MixinImageSubType.Mbi_ImageSubTypeKw45xx.name(
+ self.image_subtype
+ )
+ return config
+
def set_image_subtype(self, image_subtype: Optional[Union[str, int]]) -> None:
"""Convert string value to int by enum table and store to class."""
if image_subtype is None:
- self.image_subtype = Mbi_MixinImageSubType.Mbi_ImageSubTypeKw45xx.MAIN
+ self.image_subtype = (
+ Mbi_MixinImageSubType.Mbi_ImageSubTypeKw45xx.MAIN
+ or Mbi_MixinImageSubType.Mbi_ImageSubTypeMcxn9xx.MAIN
+ )
else:
- image_subtype = Mbi_MixinImageSubType.Mbi_ImageSubTypeKw45xx.get(image_subtype)
+ image_subtype = Mbi_MixinImageSubType.Mbi_ImageSubTypeKw45xx.get(
+ image_subtype
+ ) or Mbi_MixinImageSubType.Mbi_ImageSubTypeMcxn9xx.get(image_subtype)
self.image_subtype = (
image_subtype
if isinstance(image_subtype, int)
else Mbi_MixinImageSubType.Mbi_ImageSubTypeKw45xx.MAIN
+ or Mbi_MixinImageSubType.Mbi_ImageSubTypeMcxn9xx.MAIN
)
+ def mix_parse(self, data: bytes) -> None:
+ """Parse the binary to individual fields.
+
+ :param data: Final Image in bytes.
+ """
+ self.image_subtype = Mbi_MixinIvt.get_sub_type(data)
+
class Mbi_MixinIvt(Mbi_Mixin):
"""Master Boot Image Interrupt Vector table class."""
@@ -452,6 +742,14 @@ class Mbi_MixinIvt(Mbi_Mixin):
IVT_CRC_CERTIFICATE_OFFSET = 0x28
IVT_LOAD_ADDR_OFFSET = 0x34
+ IVT_IMAGE_FLAGS_IMAGE_TYPE_MASK = 0x3F
+ IVT_IMAGE_FLAGS_TZ_TYPE_MASK = 0x03
+ IVT_IMAGE_FLAGS_TZ_TYPE_SHIFT = 13
+ IVT_IMAGE_FLAGS_FW_VER_MASK = 0xFFFF
+ IVT_IMAGE_FLAGS_FW_VER_SHIFT = 16
+ IVT_IMAGE_FLAGS_SUB_TYPE_MASK = 0x03
+ IVT_IMAGE_FLAGS_SUB_TYPE_SHIFT = 6
+
# flag indication presence of boot image version (Used by LPC55s3x)
_BOOT_IMAGE_VERSION_FLAG = 0x400
# flag that image contains relocation table
@@ -477,11 +775,11 @@ def create_flags(self) -> int:
:return: Image type flags
"""
- flags = (self.tz.type << 8) + int(self.IMAGE_TYPE[0])
+ flags = (self.tz.type << self.IVT_IMAGE_FLAGS_TZ_TYPE_SHIFT) + int(self.IMAGE_TYPE[0])
if hasattr(self, "image_subtype"):
assert self.image_subtype is not None
- flags |= self.image_subtype << 6
+ flags |= self.image_subtype << self.IVT_IMAGE_FLAGS_SUB_TYPE_SHIFT
if hasattr(self, "user_hw_key_enabled") and self.user_hw_key_enabled:
flags |= self._HW_USER_KEY_EN_FLAG
@@ -536,6 +834,24 @@ def update_ivt(
return bytes(data)
+ def clean_ivt(self, app_data: bytes) -> bytes:
+ """Clean IVT table from added information.
+
+ :param app_data: Application data that should be cleaned.
+ :return: Cleaned application image
+ """
+ data = bytearray(app_data)
+ # Total length of image
+ data[self.IVT_IMAGE_LENGTH_OFFSET : self.IVT_IMAGE_LENGTH_OFFSET + 4] = bytes(4)
+ # flags
+ data[self.IVT_IMAGE_FLAGS_OFFSET : self.IVT_IMAGE_FLAGS_OFFSET + 4] = bytes(4)
+ # CRC value or Certification block offset
+ data[self.IVT_CRC_CERTIFICATE_OFFSET : self.IVT_CRC_CERTIFICATE_OFFSET + 4] = bytes(4)
+ # Execution address
+ data[self.IVT_LOAD_ADDR_OFFSET : self.IVT_LOAD_ADDR_OFFSET + 4] = bytes(4)
+
+ return bytes(data)
+
def update_crc_val_cert_offset(self, app_data: bytes, crc_val_cert_offset: int) -> bytes:
"""Update value just of CRC/Certificate offset field.
@@ -549,6 +865,156 @@ def update_crc_val_cert_offset(self, app_data: bytes, crc_val_cert_offset: int)
)
return data
+ @staticmethod
+ def check_total_length(data: bytes) -> None:
+ """Check total length field from raw data.
+
+ :param data: Raw MBI image data.
+ :raises SPSDKParsingError: Insufficient length of image has been detected.
+ """
+ total_len = int.from_bytes(
+ data[Mbi_MixinIvt.IVT_IMAGE_LENGTH_OFFSET : Mbi_MixinIvt.IVT_IMAGE_LENGTH_OFFSET + 4],
+ "little",
+ )
+
+ if total_len < len(data):
+ raise SPSDKParsingError("Insufficient length of input raw data!")
+
+ @staticmethod
+ def get_flags(data: bytes) -> int:
+ """Get the Image flags from raw data.
+
+ During getting of flags, the length is also validated.
+
+ :param data: Raw MBI image data.
+ :return: Image Flags
+ """
+ Mbi_MixinIvt.check_total_length(data)
+
+ flags = int.from_bytes(
+ data[Mbi_MixinIvt.IVT_IMAGE_FLAGS_OFFSET : Mbi_MixinIvt.IVT_IMAGE_FLAGS_OFFSET + 4],
+ "little",
+ )
+
+ return flags
+
+ @staticmethod
+ def get_cert_block_offset(data: bytes) -> int:
+ """Get the certificate block offset from raw data.
+
+ During getting of flags, the length is also validated.
+
+ :param data: Raw MBI image data.
+ :return: Certificate block offset
+ """
+ Mbi_MixinIvt.check_total_length(data)
+
+ return int.from_bytes(
+ data[
+ Mbi_MixinIvt.IVT_CRC_CERTIFICATE_OFFSET : Mbi_MixinIvt.IVT_CRC_CERTIFICATE_OFFSET
+ + 4
+ ],
+ "little",
+ )
+
+ @staticmethod
+ def get_load_address(data: bytes) -> int:
+ """Get the load address from raw data.
+
+ During getting of flags, the length is also validated.
+
+ :param data: Raw MBI image data.
+ :return: Load address
+ """
+ Mbi_MixinIvt.check_total_length(data)
+
+ return int.from_bytes(
+ data[Mbi_MixinIvt.IVT_LOAD_ADDR_OFFSET : Mbi_MixinIvt.IVT_LOAD_ADDR_OFFSET + 4],
+ "little",
+ )
+
+ @staticmethod
+ def get_image_type(data: bytes) -> int:
+ """Get the Image type from raw data.
+
+ :param data: Raw MBI image data.
+ :return: Image type
+ """
+ return Mbi_MixinIvt.get_flags(data) & Mbi_MixinIvt.IVT_IMAGE_FLAGS_IMAGE_TYPE_MASK
+
+ @staticmethod
+ def get_tz_type(data: bytes) -> int:
+ """Get the Image TrustZone type settings from raw data.
+
+ :param data: Raw MBI image data.
+ :return: TrustZone type.
+ """
+ flags = Mbi_MixinIvt.get_flags(data)
+ return (
+ flags >> Mbi_MixinIvt.IVT_IMAGE_FLAGS_TZ_TYPE_SHIFT
+ ) & Mbi_MixinIvt.IVT_IMAGE_FLAGS_TZ_TYPE_MASK
+
+ @staticmethod
+ def get_fw_version(data: bytes) -> int:
+ """Get the Image firmware version from raw data.
+
+ :param data: Raw MBI image data.
+ :return: Firmware version.
+ """
+ flags = Mbi_MixinIvt.get_flags(data)
+ if flags & Mbi_MixinIvt._BOOT_IMAGE_VERSION_FLAG == 0:
+ return 0
+
+ return (
+ flags >> Mbi_MixinIvt.IVT_IMAGE_FLAGS_FW_VER_SHIFT
+ ) & Mbi_MixinIvt.IVT_IMAGE_FLAGS_FW_VER_MASK
+
+ @staticmethod
+ def get_sub_type(data: bytes) -> int:
+ """Get the Image sub type from raw data.
+
+ :param data: Raw MBI image data.
+ :return: Image sub type.
+ """
+ flags = Mbi_MixinIvt.get_flags(data)
+
+ return (
+ flags >> Mbi_MixinIvt.IVT_IMAGE_FLAGS_SUB_TYPE_SHIFT
+ ) & Mbi_MixinIvt.IVT_IMAGE_FLAGS_SUB_TYPE_MASK
+
+ @staticmethod
+ def get_hw_key_enabled(data: bytes) -> bool:
+ """Get the HW key enabled setting from raw data.
+
+ :param data: Raw MBI image data.
+ :return: HW key enabled or not.
+ """
+ flags = Mbi_MixinIvt.get_flags(data)
+
+ return bool(flags & Mbi_MixinIvt._HW_USER_KEY_EN_FLAG)
+
+ @staticmethod
+ def get_key_store_presented(data: bytes) -> int:
+ """Get the KeyStore present flag from raw data.
+
+ :param data: Raw MBI image data.
+ :return: KeyStore is included or not.
+ """
+ flags = Mbi_MixinIvt.get_flags(data)
+
+ return bool(flags & Mbi_MixinIvt._KEY_STORE_FLAG)
+
+ @staticmethod
+ def get_app_table_presented(data: bytes) -> int:
+ """Get the Multiple Application table present flag from raw data.
+
+ :param data: Raw MBI image data.
+ :return: Multiple Application table is included or not.
+ """
+ flags = Mbi_MixinIvt.get_flags(data)
+
+ return bool(flags & Mbi_MixinIvt._RELOC_TABLE_FLAG)
+
class Mbi_MixinRelocTable(Mbi_Mixin):
"""Master Boot Image Relocation table class."""
@@ -584,6 +1050,25 @@ def mix_load_from_config(self, config: Dict[str, Any]) -> None:
)
self.app_table.add_entry(image_entry)
+ def mix_get_config(self, output_folder: str) -> Dict[str, Any]:
+ """Get the configuration of the mixin.
+
+ :param output_folder: Output folder to store files.
+ """
+ config: Dict[str, Any] = {}
+ if self.app_table:
+ cfg_table = []
+ for entry in self.app_table.entries:
+ entry_cfg: Dict[str, Union[str, int]] = {}
+ entry_cfg["destAddress"] = entry.dst_addr
+ filename = f"mit_{hex(entry.dst_addr)}.bin"
+ write_file(entry.image, os.path.join(output_folder, filename))
+ entry_cfg["binary"] = filename
+ entry_cfg["load"] = entry.is_load
+ cfg_table.append(entry_cfg)
+ config["applicationTable"] = cfg_table
+ return config
+
def mix_validate(self) -> None:
"""Validate the setting of image.
@@ -612,6 +1097,18 @@ def get_app_data(self) -> bytes:
ret += self.app_table.export(len(self.app))
return ret
+ def disassembly_app_data(self, data: bytes) -> bytes:
+ """Disassembly Application data to application and optionally Multiple Application Table.
+
+ :return: Application data without Multiple Application Table which will be stored in class.
+ """
+ app_size = len(data)
+ app_table = MultipleImageTable.parse(data)
+ if app_table:
+ self.app_table = app_table
+ app_size = app_table.start_address
+ return data[:app_size]
+
class Mbi_MixinManifest(Mbi_MixinTrustZoneMandatory):
"""Master Boot Image Manifest class."""
@@ -619,9 +1116,12 @@ class Mbi_MixinManifest(Mbi_MixinTrustZoneMandatory):
manifest_class = MasterBootImageManifest
manifest: Optional[MasterBootImageManifest]
- VALIDATION_SCHEMAS: List[str] = ["tz", "family", "firmware_version", "sign_hash_len"]
- NEEDED_MEMBERS: List[str] = ["manifest", "firmware_version"]
+ VALIDATION_SCHEMAS: List[str] = ["tz", "firmware_version", "digest_hash_algo"]
+ NEEDED_MEMBERS: List[str] = ["manifest", "firmware_version", "cert_block", "family"]
+ PRE_PARSED: List[str] = ["cert_block"]
+ family: str
+ cert_block: Optional[Union[CertBlockV2, CertBlockV31]]
firmware_version: Optional[int]
def mix_len(self) -> int:
@@ -630,7 +1130,14 @@ def mix_len(self) -> int:
:return: Length of Manifest block.
"""
assert self.manifest
- return self.manifest.total_length
+
+ hash_length = 0
+ if self.manifest.flags & self.manifest.DIGEST_PRESENT_FLAG:
+ hash_algo = {1: "sha256", 2: "sha384", 3: "sha512"}[
+ self.manifest.flags & self.manifest.HASH_TYPE_MASK
+ ]
+ hash_length = self.manifest.get_hash_size(hash_algo)
+ return self.manifest.total_length + hash_length
def mix_load_from_config(self, config: Dict[str, Any]) -> None:
"""Load configuration from dictionary.
@@ -639,12 +1146,31 @@ def mix_load_from_config(self, config: Dict[str, Any]) -> None:
"""
super().mix_load_from_config(config)
self.firmware_version = value_to_int(config.get("firmwareVersion", 0))
- sign_hash_len_raw = config.get("manifestSigningHashLength", None)
- sign_hash_len = value_to_int(sign_hash_len_raw) if sign_hash_len_raw else None
+ digest_hash_algorithm = config.get("manifestDigestHashAlgorithm", None)
+ # Backward compatibility code (in case that new manifestDigestHashAlgorithm doesn't exist
+ # try to load old one ):
+ if not digest_hash_algorithm:
+ digest_hash_algorithm_length = config.get("manifestSigningHashLength", None)
+ if digest_hash_algorithm_length:
+ digest_hash_algorithm = {32: "sha256", 48: "sha384", 64: "sha512"}[
+ digest_hash_algorithm_length
+ ]
+
self.manifest = self.manifest_class(
- self.firmware_version, self.tz, sign_hash_len=sign_hash_len
+ self.firmware_version, self.tz, digest_hash_algo=digest_hash_algorithm
)
+ def mix_get_config(self, output_folder: str) -> Dict[str, Any]:
+ """Get the configuration of the mixin.
+
+ :param output_folder: Output folder to store files.
+ """
+ assert self.manifest
+ config = super().mix_get_config(output_folder=output_folder)
+ config["firmwareVersion"] = self.firmware_version
+ config["manifestDigestHashAlgorithm"] = self.manifest.digest_hash_algo
+ return config
+
def mix_validate(self) -> None:
"""Validate the setting of image.
@@ -654,6 +1180,27 @@ def mix_validate(self) -> None:
if not self.manifest:
raise SPSDKError("The Image manifest must exists.")
+ def mix_parse(self, data: bytes) -> None:
+ """Parse the binary to individual fields.
+
+ :param data: Final Image in bytes.
+ """
+ assert isinstance(self.cert_block, CertBlockV31)
+ manifest_offset = Mbi_MixinIvt.get_cert_block_offset(data) + self.cert_block.expected_size
+ self.manifest = self.manifest_class.parse(self.family, data[manifest_offset:])
+ self.firmware_version = self.manifest.firmware_version
+ if self.manifest.trust_zone:
+ self.tz = self.manifest.trust_zone
+ else:
+ super().mix_parse(data)
+
+
+class Mbi_MixinManifestMcxNx(Mbi_MixinManifest):
+ """Master Boot Image Manifest class for mcxn9xx device."""
+
+ manifest_class = MasterBootImageManifestMcxNx
+ manifest: Optional[MasterBootImageManifestMcxNx]
+
class Mbi_MixinCertBlockV2(Mbi_Mixin):
"""Master Boot Image certification block V2 class."""
@@ -661,9 +1208,12 @@ class Mbi_MixinCertBlockV2(Mbi_Mixin):
VALIDATION_SCHEMAS: List[str] = ["cert_prv_key"]
NEEDED_MEMBERS: List[str] = ["cert_block", "signature_provider"]
- cert_block: Optional[CertBlockV2]
+ cert_block: Optional[Union[CertBlockV2, CertBlockV31]]
signature_provider: Optional[SignatureProvider]
search_paths: Optional[List[str]]
+ total_len: Any
+ key_store: Optional[KeyStore]
+ HMAC_SIZE: int
def mix_len(self) -> int:
"""Get length of Certificate Block V2.
@@ -692,6 +1242,16 @@ def mix_load_from_config(self, config: Dict[str, Any]) -> None:
search_paths=self.search_paths,
)
+ def mix_get_config(self, output_folder: str) -> Dict[str, Any]:
+ """Get the configuration of the mixin.
+
+ :param output_folder: Output folder to store files.
+ """
+ assert self.cert_block
+ config = self.cert_block.get_config(output_folder=output_folder)
+ config["mainCertPrivateKeyFile"] = "Cannot get from parse"
+ return config
+
def mix_validate(self) -> None:
"""Validate the setting of image.
@@ -701,6 +1261,7 @@ def mix_validate(self) -> None:
raise SPSDKError("Certification block is missing")
if not self.signature_provider:
raise SPSDKError("Signature provider is not defined")
+ assert isinstance(self.cert_block, CertBlockV2)
public_key = self.cert_block.certificates[-1].public_key
try:
result = self.signature_provider.verify_public_key(public_key.dump())
@@ -712,6 +1273,21 @@ def mix_validate(self) -> None:
except SPSDKUnsupportedOperation:
logger.warning("Signature provider could not verify the integrity of private key pair.")
+ def mix_parse(self, data: bytes) -> None:
+ """Parse the binary to individual fields.
+
+ :param data: Final Image in bytes.
+ """
+ offset = Mbi_MixinIvt.get_cert_block_offset(data)
+ if hasattr(self, "hmac_key"):
+ offset += self.HMAC_SIZE
+ if Mbi_MixinIvt.get_key_store_presented(data):
+ offset += KeyStore.KEY_STORE_SIZE
+
+ self.cert_block = CertBlockV2.parse(data, offset)
+ self.cert_block.alignment = 4
+ self.signature_provider = None
+
class Mbi_MixinCertBlockV31(Mbi_Mixin):
"""Master Boot Image certification block V3.1 class."""
@@ -723,7 +1299,7 @@ class Mbi_MixinCertBlockV31(Mbi_Mixin):
]
NEEDED_MEMBERS: List[str] = ["cert_block", "signature_provider"]
- cert_block: Optional[CertBlockV31]
+ cert_block: Optional[Union[CertBlockV2, CertBlockV31]]
signature_provider: Optional[SignatureProvider]
search_paths: Optional[List[str]]
@@ -761,6 +1337,15 @@ def mix_load_from_config(self, config: Dict[str, Any]) -> None:
search_paths=self.search_paths,
)
+ def mix_get_config(self, output_folder: str) -> Dict[str, Any]:
+ """Get the configuration of the mixin.
+
+ :param output_folder: Output folder to store files.
+ """
+ assert self.cert_block
+ config = self.cert_block.get_config(output_folder)
+ return config
+
def mix_validate(self) -> None:
"""Validate the setting of image.
@@ -772,6 +1357,14 @@ def mix_validate(self) -> None:
if not self.signature_provider:
raise SPSDKError("Signature provider is missing")
+ def mix_parse(self, data: bytes) -> None:
+ """Parse the binary to individual fields.
+
+ :param data: Final Image in bytes.
+ """
+ self.cert_block = CertBlockV31.parse(data, Mbi_MixinIvt.get_cert_block_offset(data))
+ self.signature_provider = None
+
class Mbi_MixinHwKey(Mbi_Mixin):
"""Master Boot Image HW key user modes enable class."""
@@ -788,6 +1381,15 @@ def mix_load_from_config(self, config: Dict[str, Any]) -> None:
"""
self.user_hw_key_enabled = config["enableHwUserModeKeys"]
+ def mix_get_config(self, output_folder: str) -> Dict[str, Any]:
+ """Get the configuration of the mixin.
+
+ :param output_folder: Output folder to store files.
+ """
+ config: Dict[str, Any] = {}
+ config["enableHwUserModeKeys"] = True if self.user_hw_key_enabled else False
+ return config
+
def mix_validate(self) -> None:
"""Validate the setting of image.
@@ -796,6 +1398,13 @@ def mix_validate(self) -> None:
if not isinstance(self.user_hw_key_enabled, bool):
raise SPSDKError("User HW Key is not Boolean type.")
+ def mix_parse(self, data: bytes) -> None:
+ """Parse the binary to individual fields.
+
+ :param data: Final Image in bytes.
+ """
+ self.user_hw_key_enabled = Mbi_MixinIvt.get_hw_key_enabled(data)
+
class Mbi_MixinKeyStore(Mbi_Mixin):
"""Master Boot Image KeyStore class."""
@@ -806,6 +1415,8 @@ class Mbi_MixinKeyStore(Mbi_Mixin):
key_store: Optional[KeyStore]
hmac_key: Optional[bytes]
search_paths: Optional[List[str]]
+ HMAC_OFFSET: int
+ HMAC_SIZE: int
def mix_len(self) -> int:
"""Get length of KeyStore block.
@@ -818,22 +1429,38 @@ def mix_len(self) -> int:
else 0
)
+ def mix_app_len(self) -> int: # pylint: disable=no-self-use
+ """Compute application data length of individual mixin.
+
+ :return: Application data length of atomic Mixin.
+ """
+ return 0
+
def mix_load_from_config(self, config: Dict[str, Any]) -> None:
"""Load configuration from dictionary.
:param config: Dictionary with configuration fields.
"""
- key_source = KeySourceType.get(config.get("deviceKeySource", "OTP"))
- use_key_store = config.get("useKeyStore", False)
key_store_file = config.get("keyStoreFile", None)
- if use_key_store and key_source == KeySourceType.KEYSTORE:
- key_store_data = (
- load_binary(key_store_file, search_paths=self.search_paths)
- if key_store_file
- else bytes(KeyStore.KEY_STORE_SIZE)
- )
- self.key_store = KeyStore(key_source, key_store_data) # type: ignore
+ self.key_store = None
+ if key_store_file:
+ key_store_data = load_binary(key_store_file, search_paths=self.search_paths)
+ self.key_store = KeyStore(KeySourceType.KEYSTORE, key_store_data)
+
+ def mix_get_config(self, output_folder: str) -> Dict[str, Any]:
+ """Get the configuration of the mixin.
+
+ :param output_folder: Output folder to store files.
+ """
+ config: Dict[str, Any] = {}
+ file_name = None
+ if self.key_store:
+ file_name = "key_store.bin"
+ write_file(self.key_store.export(), os.path.join(output_folder, file_name), mode="wb")
+
+ config["keyStoreFile"] = file_name
+ return config
def mix_validate(self) -> None:
"""Validate the setting of image.
@@ -843,6 +1470,20 @@ def mix_validate(self) -> None:
if self.key_store and not self.hmac_key: # pylint: disable=no-member
raise SPSDKError("When is used KeyStore, the HMAC key MUST by also used.")
+ def mix_parse(self, data: bytes) -> None:
+ """Parse the binary to individual fields.
+
+ :param data: Final Image in bytes.
+ """
+ key_store_present = Mbi_MixinIvt.get_key_store_presented(data)
+ self.key_store = None
+ if key_store_present:
+ key_store_offset = self.HMAC_OFFSET + self.HMAC_SIZE
+ self.key_store = KeyStore(
+ KeySourceType.KEYSTORE,
+ data[key_store_offset : key_store_offset + KeyStore.KEY_STORE_SIZE],
+ )
+
class Mbi_MixinHmac(Mbi_Mixin):
"""Master Boot Image HMAC class."""
@@ -858,6 +1499,7 @@ class Mbi_MixinHmac(Mbi_Mixin):
hmac_key: Optional[bytes]
search_paths: Optional[List[str]]
+ dek: Optional[str]
def mix_len(self) -> int:
"""Get length of HMAC block.
@@ -866,6 +1508,13 @@ def mix_len(self) -> int:
"""
return self.HMAC_SIZE if self.hmac_key else 0
+ def mix_app_len(self) -> int: # pylint: disable=no-self-use
+ """Compute application data length of individual mixin.
+
+ :return: Application data length of atomic Mixin.
+ """
+ return 0
+
def mix_load_from_config(self, config: Dict[str, Any]) -> None:
"""Load configuration from dictionary.
@@ -873,11 +1522,18 @@ def mix_load_from_config(self, config: Dict[str, Any]) -> None:
"""
hmac_key_raw = config.get("outputImageEncryptionKeyFile")
if hmac_key_raw:
- hmac_key = load_binary(hmac_key_raw, search_paths=self.search_paths)
- if len(hmac_key) == (2 * self.HMAC_SIZE):
- self.hmac_key = bytes.fromhex(hmac_key.decode("utf-8"))
- else:
- self.hmac_key = hmac_key
+ self.hmac_key = get_key(
+ hmac_key_raw, expected_size=self.HMAC_SIZE, search_paths=self.search_paths
+ )
+
+ def mix_get_config(self, output_folder: str) -> Dict[str, Any]:
+ """Get the configuration of the mixin.
+
+ :param output_folder: Output folder to store files.
+ """
+ config: Dict[str, Any] = {}
+ config["outputImageEncryptionKeyFile"] = "The HMAC key cannot be restored"
+ return config
def mix_validate(self) -> None:
"""Validate the setting of image.
@@ -903,6 +1559,18 @@ def compute_hmac(self, data: bytes) -> bytes:
assert len(result) == self.HMAC_SIZE
return result
+ def mix_parse(self, data: bytes) -> None:
+ """Parse the binary to individual fields.
+
+ :param data: Final Image in bytes.
+ """
+ if self.dek:
+ self.hmac_key = get_key(
+ key_source=self.dek,
+ expected_size=self._HMAC_KEY_LENGTH,
+ search_paths=self.search_paths,
+ )
+
class Mbi_MixinHmacMandatory(Mbi_MixinHmac):
"""Master Boot Image HMAC class (Mandatory use)."""
@@ -924,20 +1592,37 @@ class Mbi_MixinCtrInitVector(Mbi_Mixin):
VALIDATION_SCHEMAS: List[str] = ["ctr_init_vector"]
NEEDED_MEMBERS: List[str] = ["ctr_init_vector"]
+ PRE_PARSED: List[str] = ["cert_block"]
# length of counter initialization vector
_CTR_INIT_VECTOR_SIZE = 16
ctr_init_vector: bytes
+ search_paths: Optional[List[str]]
+ cert_block: Optional[Union[CertBlockV2, CertBlockV31]]
+ HMAC_SIZE: int
def mix_load_from_config(self, config: Dict[str, Any]) -> None:
"""Load configuration from dictionary.
:param config: Dictionary with configuration fields.
"""
- hex_val = config.get("CtrInitVector", None)
- ctr_init_vector = bytes.fromhex(hex_val.replace("0x", "")) if hex_val else None
+ ctr_init_vector_cfg = config.get("CtrInitVector", None)
+ ctr_init_vector = (
+ get_key(ctr_init_vector_cfg, self._CTR_INIT_VECTOR_SIZE, self.search_paths)
+ if ctr_init_vector_cfg
+ else None
+ )
self.store_ctr_init_vector(ctr_init_vector)
+ def mix_get_config(self, output_folder: str) -> Dict[str, Any]:
+ """Get the configuration of the mixin.
+
+ :param output_folder: Output folder to store files.
+ """
+ config: Dict[str, Any] = {}
+ config["CtrInitVector"] = self.ctr_init_vector.hex()
+ return config
+
def mix_validate(self) -> None:
"""Validate the setting of image.
@@ -955,75 +1640,18 @@ def store_ctr_init_vector(self, ctr_iv: Optional[bytes] = None) -> None:
"""
self.ctr_init_vector = ctr_iv or crypto_backend().random_bytes(self._CTR_INIT_VECTOR_SIZE)
+ def mix_parse(self, data: bytes) -> None:
+ """Parse the binary to individual fields.
-class Mbi_MixinSignDigest(Mbi_Mixin):
- """Master Boot Image Signature Digest."""
-
- VALIDATION_SCHEMAS: List[str] = ["attach_sign_digest"]
- NEEDED_MEMBERS: List[str] = ["attach_sign_digest"]
- SIGN_DIGEST_VALUES: Dict[str, int] = {"sha256": 32, "sha384": 48}
-
- attach_sign_digest: Optional[str]
- cert_block: Optional[CertBlockV31]
- signature_provider: Optional[SignatureProvider]
-
- def mix_len(self) -> int:
- """Get length of Signature digest block.
-
- :return: Length of Signature digest block.
- """
- return self.SIGN_DIGEST_VALUES[self.attach_sign_digest] if self.attach_sign_digest else 0
-
- def mix_load_from_config(self, config: Dict[str, Any]) -> None:
- """Load configuration from dictionary.
-
- :param config: Dictionary with configuration fields.
- """
- attach_sign_digest = config.get("attachSignDigest", False)
- self.attach_sign_digest = self.get_sign_digest() if attach_sign_digest else None
-
- def mix_validate(self) -> None:
- """Validate the setting of image.
-
- raise SPSDKError: Invalid HW key enabled member type.
- """
- if self.attach_sign_digest and self.attach_sign_digest not in ["sha256", "sha384"]:
- raise SPSDKError(
- f"Invalid value for Signature Digest: {self.attach_sign_digest} MUST be one of ['sha256', 'sha384']."
- )
-
- def get_sign_digest(self) -> Optional[str]:
- """Get sign digest type from signature provider.
-
- :raises SPSDKError: Missing defined signature provider in class.
- :return: Type of signature digest.
- """
- if not self.signature_provider:
- raise SPSDKError("MBI: Signature Digest needs to has defined signature provider.")
- return "sha256" if self.signature_provider.signature_length // 2 == 32 else "sha384"
-
-
-class Mbi_MixinNXPImage(Mbi_Mixin):
- """Master Boot Image 'Image Type Changer' to NXP Image type."""
-
- VALIDATION_SCHEMAS: List[str] = ["nxp_image"]
- NEEDED_MEMBERS: List[str] = ["IMAGE_TYPE"]
- SIGNED_XIP_NXP_IMAGE = (0x08, "Plain Signed XIP Image NXP Key")
-
- IMAGE_TYPE: Tuple[int, str]
-
- def mix_load_from_config(self, config: Dict[str, Any]) -> None:
- """Load configuration from dictionary.
-
- :param config: Dictionary with configuration fields.
+ :param data: Final Image in bytes.
"""
- nxp_image_type = config.get("IsNxpImage", False)
- if nxp_image_type:
- self.change_to_nxp_image()
-
- def change_to_nxp_image(self) -> None:
- """Calling this changed to NXP image."""
- self.IMAGE_TYPE = self.SIGNED_XIP_NXP_IMAGE
+ assert isinstance(self.cert_block, CertBlockV2)
+ iv_offset = Mbi_MixinIvt.get_cert_block_offset(data) + self.cert_block.expected_size + 56
+ if hasattr(self, "hmac_key"):
+ iv_offset += self.HMAC_SIZE
+ if Mbi_MixinIvt.get_key_store_presented(data):
+ iv_offset += KeyStore.KEY_STORE_SIZE
+ self.ctr_init_vector = data[iv_offset : iv_offset + self._CTR_INIT_VECTOR_SIZE]
class Mbi_MixinNoSignature(Mbi_Mixin):
@@ -1057,36 +1685,48 @@ def collect_data(self) -> bytes: # pylint: disable=no-self-use
"""
return bytes()
- def encrypt(self, raw_image: bytes) -> bytes: # pylint: disable=no-self-use
+ def disassemble_image(self, image: bytes) -> None: # pylint: disable=no-self-use
+ """Disassemble image to individual parts from image.
+
+ :param image: Image.
+ """
+
+ def encrypt(self, image: bytes, revert: bool = False) -> bytes: # pylint: disable=no-self-use
"""Encrypt image if needed.
- :param raw_image: Input raw image to encrypt.
+ :param image: Input raw image to encrypt.
+ :param revert: Revert the operation if possible.
:return: Encrypted image.
"""
- return raw_image
+ return image
- def post_encrypt(self, image: bytes) -> bytes: # pylint: disable=no-self-use
+ def post_encrypt(
+ self, image: bytes, revert: bool = False
+ ) -> bytes: # pylint: disable=no-self-use
"""Optionally do some post encrypt image updates.
:param image: Encrypted image.
+ :param revert: Revert the operation if possible.
:return: Updated encrypted image.
"""
return image
- def sign(self, image: bytes) -> bytes: # pylint: disable=no-self-use
+ def sign(self, image: bytes, revert: bool = False) -> bytes: # pylint: disable=no-self-use
"""Sign image (by signature or CRC).
:param image: Image to sign.
+ :param revert: Revert the operation if possible.
:return: Optionally signed image.
"""
return image
- def finalize(self, image: bytes) -> bytes: # pylint: disable=no-self-use
+ def finalize(self, image: bytes, revert: bool = False) -> bytes: # pylint: disable=no-self-use
"""Finalize the image for export.
This part could add HMAC/KeyStore etc.
:param image: Input image.
+ :param revert: Revert the operation if possible.
:return: Finalized image suitable for export.
"""
return image
@@ -1098,19 +1738,32 @@ class Mbi_ExportMixinAppTrustZone(Mbi_ExportMixin):
app: Optional[bytes]
tz: TrustZone
total_len: Any
- update_ivt: Callable
- get_app_data: Callable
+ update_ivt: Callable[[bytes, int, int], bytes]
+ clean_ivt: Callable[[bytes], bytes]
+ get_app_data: Callable[[], bytes]
+ disassembly_app_data: Callable[[bytes], bytes]
def collect_data(self) -> bytes:
"""Collect application data and TrustZone including update IVT.
:return: Image with updated IVT and added TrustZone.
"""
- # reveal_type(self.update_ivt)
assert self.app and self.tz
app = self.get_app_data() if hasattr(self, "get_app_data") else self.app
return self.update_ivt(app + self.tz.export(), self.total_len, 0)
+ def disassemble_image(self, image: bytes) -> None: # pylint: disable=no-self-use
+ """Disassemble image to individual parts from image.
+
+ :param image: Image.
+ """
+ tz_len = len(self.tz.export())
+ if tz_len:
+ image = image[:-tz_len]
+ if hasattr(self, "disassembly_app_data"):
+ image = self.disassembly_app_data(image)
+ self.app = self.clean_ivt(image)
+
class Mbi_ExportMixinAppTrustZoneCertBlock(Mbi_ExportMixin):
"""Export Mixin to handle simple application data, TrustZone and Certification block."""
@@ -1119,16 +1772,18 @@ class Mbi_ExportMixinAppTrustZoneCertBlock(Mbi_ExportMixin):
tz: TrustZone
total_len: Any
app_len: Any
- update_ivt: Callable
- cert_block: Optional[CertBlockV2]
- get_app_data: Callable
+ update_ivt: Callable[[bytes, int, int], bytes]
+ clean_ivt: Callable[[bytes], bytes]
+ cert_block: Optional[Union[CertBlockV2, CertBlockV31]]
+ get_app_data: Callable[[], bytes]
+ disassembly_app_data: Callable[[bytes], bytes]
def collect_data(self) -> bytes:
"""Collect application data and TrustZone including update IVT.
:return: Image with updated IVT and added TrustZone.
"""
- assert self.app and self.tz and self.cert_block
+ assert self.app and self.tz and self.cert_block and isinstance(self.cert_block, CertBlockV2)
self.cert_block.alignment = 4
self.cert_block.image_length = self.app_len
logger.info(f"RKTH: {self.cert_block.rkht.hex()}")
@@ -1139,17 +1794,28 @@ def collect_data(self) -> bytes:
len(app),
)
+ def disassemble_image(self, image: bytes) -> None: # pylint: disable=no-self-use
+ """Disassemble image to individual parts from image.
+
+ :param image: Image.
+ """
+ image = image[: -Mbi_MixinIvt.get_cert_block_offset(image)]
+ if hasattr(self, "disassembly_app_data"):
+ image = self.disassembly_app_data(image)
+ self.app = self.clean_ivt(image)
+
class Mbi_ExportMixinAppCertBlockManifest(Mbi_ExportMixin):
"""Export Mixin to handle simple application data, Certification block and Manifest."""
app: Optional[bytes]
total_len: Any
- app_len: Any
- update_ivt: Callable
- get_app_data: Callable
- cert_block: Optional[CertBlockV31]
- manifest: Optional[MasterBootImageManifest] # type: ignore # we don't use regular bound method
+ update_ivt: Callable[[bytes, int, int], bytes]
+ clean_ivt: Callable[[bytes], bytes]
+ get_app_data: Callable[[], bytes]
+ cert_block: Optional[Union[CertBlockV2, CertBlockV31]]
+ manifest: Optional[T_Manifest] # type: ignore # we don't use regular bound method
+ disassembly_app_data: Callable[[bytes], bytes]
def collect_data(self) -> bytes:
"""Collect application data, Certification Block and Manifest including update IVT.
@@ -1162,25 +1828,70 @@ def collect_data(self) -> bytes:
"Either application data or certification block or manifest is missing"
)
app = self.get_app_data() if hasattr(self, "get_app_data") else self.app
- return self.update_ivt(
+ assert len(self.manifest.export()) == self.manifest.total_length
+ image = self.update_ivt(
app + self.cert_block.export() + self.manifest.export(),
self.total_len,
len(app),
)
+ # in case of McuNx manifest add crc
+ if isinstance(self.manifest, MasterBootImageManifestMcxNx):
+ self.manifest.compute_crc(image[:-4])
+ image = self.update_ivt(
+ app + self.cert_block.export() + self.manifest.export(),
+ self.total_len,
+ len(app),
+ )
+ return image
+
+ def disassemble_image(self, image: bytes) -> None: # pylint: disable=no-self-use
+ """Disassemble image to individual parts from image.
+
+ :param image: Image.
+ """
+ image = image[: -Mbi_MixinIvt.get_cert_block_offset(image)]
+ if hasattr(self, "disassembly_app_data"):
+ image = self.disassembly_app_data(image)
+ self.app = self.clean_ivt(image)
+
+ def finalize(self, image: bytes, revert: bool = False) -> bytes:
+ """Finalize the image for export by adding HMAC a optionally KeyStore.
+
+ :param image: Input image.
+ :param revert: Revert the operation if possible.
+ :return: Finalized image suitable for export.
+ """
+ ret = image
+ if (
+ self.manifest
+ and self.manifest.flags
+ and self.manifest.DIGEST_PRESENT_FLAG
+ and self.manifest.digest_hash_algo
+ ):
+ if revert:
+ ret = ret[: -self.manifest.get_hash_size(self.manifest.digest_hash_algo)]
+ else:
+ ret += crypto_backend().hash(image, self.manifest.digest_hash_algo)
+ return ret
+
class Mbi_ExportMixinCrcSign(Mbi_ExportMixin):
"""Export Mixin to handle sign by CRC."""
IVT_CRC_CERTIFICATE_OFFSET: int
- update_crc_val_cert_offset: Callable
+ update_crc_val_cert_offset: Callable[[bytes, int], bytes]
- def sign(self, image: bytes) -> bytes:
+ def sign(self, image: bytes, revert: bool = False) -> bytes:
"""Do simple calculation of CRC and return updated image with it.
:param image: Input raw image.
+ :param revert: Revert the operation if possible.
:return: Image enriched by CRC in IVT table.
"""
+ if revert:
+ return image
+
# calculate CRC using MPEG2 specification over all of data (app and trustzone)
# expect for 4 bytes at CRC_BLOCK_OFFSET
crc32_function = mkPredefinedCrcFun("crc-32-mpeg")
@@ -1195,13 +1906,23 @@ class Mbi_ExportMixinRsaSign(Mbi_ExportMixin):
"""Export Mixin to handle sign by RSA."""
signature_provider: Optional[SignatureProvider]
+ no_signature: Optional[bool]
+ cert_block: Optional[Union[CertBlockV31, CertBlockV2]]
- def sign(self, image: bytes) -> bytes:
+ def sign(self, image: bytes, revert: bool = False) -> bytes:
"""Do calculation of RSA signature and return updated image with it.
:param image: Input raw image.
+ :param revert: Revert the operation if possible.
:return: Image enriched by RSA signature at end of image.
"""
+ if hasattr(self, "no_signature") and self.no_signature:
+ return image
+
+ if revert:
+ assert self.cert_block and isinstance(self.cert_block, CertBlockV2)
+ return image[: -self.cert_block.signature_size]
+
assert self.signature_provider
signature = self.signature_provider.sign(image)
return image + signature
@@ -1212,15 +1933,25 @@ class Mbi_ExportMixinEccSign(Mbi_ExportMixin):
signature_provider: Optional[SignatureProvider]
no_signature: Optional[bool]
+ cert_block: Optional[Union[CertBlockV31, CertBlockV2]]
- def sign(self, image: bytes) -> bytes:
+ def sign(self, image: bytes, revert: bool = False) -> bytes:
"""Do calculation of ECC signature and return updated image with it.
:param image: Input raw image.
+ :param revert: Revert the operation if possible.
:return: Image enriched by ECC signature at end of image.
"""
if hasattr(self, "no_signature") and self.no_signature:
return image
+
+ if revert:
+ assert self.cert_block and isinstance(self.cert_block, CertBlockV31)
+ if self.cert_block.signature_size == 0:
+ return image
+
+ return image[: -self.cert_block.signature_size]
+
assert self.signature_provider
signature = self.signature_provider.sign(image)
assert signature
@@ -1232,35 +1963,26 @@ def sign(self, image: bytes) -> bytes:
class Mbi_ExportMixinHmacKeyStoreFinalize(Mbi_ExportMixin):
"""Export Mixin to handle finalize by HMAC and optionally KeyStore."""
- compute_hmac: Callable
+ compute_hmac: Callable[[bytes], bytes]
HMAC_OFFSET: int
+ HMAC_SIZE: int
key_store: Optional[KeyStore]
- def finalize(self, image: bytes) -> bytes:
+ def finalize(self, image: bytes, revert: bool = False) -> bytes:
"""Finalize the image for export by adding HMAC a optionally KeyStore.
:param image: Input image.
+ :param revert: Revert the operation if possible.
:return: Finalized image suitable for export.
"""
+ if revert:
+ end_of_hmac_keystore = self.HMAC_OFFSET + self.HMAC_SIZE
+ if Mbi_MixinIvt.get_key_store_presented(image):
+ end_of_hmac_keystore += KeyStore.KEY_STORE_SIZE
+ return image[: self.HMAC_OFFSET] + image[end_of_hmac_keystore:]
+
hmac_keystore = self.compute_hmac(image[: self.HMAC_OFFSET])
if self.key_store:
hmac_keystore += self.key_store.export()
return image[: self.HMAC_OFFSET] + hmac_keystore + image[self.HMAC_OFFSET :]
-
-
-class Mbi_ExportMixinSignDigestFinalize(Mbi_ExportMixin):
- """Export Mixin to handle finalize by Signature digest."""
-
- attach_sign_digest: Optional[str]
-
- def finalize(self, image: bytes) -> bytes:
- """Finalize the image for export by adding HMAC a optionally KeyStore.
-
- :param image: Input image.
- :return: Finalized image suitable for export.
- """
- ret = image
- if self.attach_sign_digest:
- ret += crypto_backend().hash(image, self.attach_sign_digest)
- return ret
diff --git a/spsdk/image/mbimg.py b/spsdk/image/mbimg.py
index 56ff87f0..1fef6d89 100644
--- a/spsdk/image/mbimg.py
+++ b/spsdk/image/mbimg.py
@@ -8,54 +8,26 @@
"""Master Boot Image."""
-
+import datetime
+import logging
import os
from copy import deepcopy
from inspect import isclass
-from typing import Any, Dict, List, Optional, Set, Tuple, Type, Union
+from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Type, Union
from Crypto.Cipher import AES
from spsdk.crypto.signature_provider import SignatureProvider
-from spsdk.exceptions import SPSDKValueError
-from spsdk.image import IMG_DATA_FOLDER, MBIMG_SCH_FILE
+from spsdk.exceptions import SPSDKParsingError, SPSDKValueError
+from spsdk.image import IMG_DATA_FOLDER, MBIMG_SCH_FILE, mbi_mixin
from spsdk.image.exceptions import SPSDKUnsupportedImageType
from spsdk.image.keystore import KeySourceType, KeyStore
-from spsdk.image.mbi_mixin import (
- MasterBootImageManifest,
- Mbi_ExportMixinAppCertBlockManifest,
- Mbi_ExportMixinAppTrustZone,
- Mbi_ExportMixinAppTrustZoneCertBlock,
- Mbi_ExportMixinCrcSign,
- Mbi_ExportMixinEccSign,
- Mbi_ExportMixinHmacKeyStoreFinalize,
- Mbi_ExportMixinRsaSign,
- Mbi_ExportMixinSignDigestFinalize,
- Mbi_Mixin,
- Mbi_MixinApp,
- Mbi_MixinCertBlockV2,
- Mbi_MixinCertBlockV31,
- Mbi_MixinCtrInitVector,
- Mbi_MixinFwVersion,
- Mbi_MixinHmacMandatory,
- Mbi_MixinHwKey,
- Mbi_MixinImageSubType,
- Mbi_MixinIvt,
- Mbi_MixinKeyStore,
- Mbi_MixinLoadAddress,
- Mbi_MixinManifest,
- Mbi_MixinNoSignature,
- Mbi_MixinNXPImage,
- Mbi_MixinRelocTable,
- Mbi_MixinSignDigest,
- Mbi_MixinTrustZone,
- Mbi_MixinTrustZoneMandatory,
- MultipleImageTable,
-)
-from spsdk.image.trustzone import TrustZone
+from spsdk.image.trustzone import TrustZone, TrustZoneType
from spsdk.utils.crypto.cert_blocks import CertBlockV2, CertBlockV31
-from spsdk.utils.misc import align_block, get_key_by_val, load_configuration
-from spsdk.utils.schema_validator import ConfigTemplate, ValidationSchemas, check_config
+from spsdk.utils.misc import align_block, get_key_by_val, load_configuration, write_file
+from spsdk.utils.schema_validator import CommentedConfig, ValidationSchemas, check_config
+
+logger = logging.getLogger(__name__)
PLAIN_IMAGE = (0x00, "Plain Image (either XIP or Load-to-RAM)")
SIGNED_RAM_IMAGE = (0x01, "Plain Signed Load-to-RAM Image")
@@ -63,9 +35,12 @@
ENCRYPTED_RAM_IMAGE = (0x03, "Encrypted Load-to-RAM Image")
SIGNED_XIP_IMAGE = (0x04, "Plain Signed XIP Image")
CRC_XIP_IMAGE = (0x05, "Plain CRC XIP Image")
+SIGNED_XIP_NXP_IMAGE = (0x08, "Plain Signed XIP Image NXP Keys")
DEVICE_FILE = os.path.join(IMG_DATA_FOLDER, "database.yaml")
+DEBUG_TRACE_ENABLE = False
+
# pylint: disable=too-many-ancestors
def get_mbi_class(config: Dict[str, Any]) -> Type["MasterBootImage"]:
@@ -162,7 +137,7 @@ def mbi_generate_config_templates(family: str) -> Dict[str, str]:
override["family"] = family
override["outputImageExecutionTarget"] = target
override["outputImageAuthenticationType"] = authentication
- yaml_data = ConfigTemplate(
+ yaml_data = CommentedConfig(
f"Master Boot Image Configuration template for {family}, {mbi_cls.IMAGE_TYPE[1]}.",
schemas,
override,
@@ -188,25 +163,36 @@ class MasterBootImage:
IMAGE_TYPE = PLAIN_IMAGE
+ app: Optional[bytes]
+ app_table: Optional[mbi_mixin.MultipleImageTable]
+ collect_data: Callable[[], bytes]
+ encrypt: Any # encrypt(self, raw_image: bytes, revert: bool = False) -> bytes
+ post_encrypt: Any # post_encrypt(self, image: bytes, revert: bool = False) -> bytes
+ sign: Any # sign(self, image: bytes, revert: bool = False) -> bytes
+ finalize: Any # finalize(self, image: bytes, revert: bool = False) -> bytes
+ disassemble_image: Callable[[bytes], None]
+
@classmethod
- def _get_mixins(cls) -> List[Type[Mbi_Mixin]]:
+ def _get_mixins(cls) -> List[Type[mbi_mixin.Mbi_Mixin]]:
"""Get the list of Mbi Mixin classes.
:return: List of Mbi_Mixins.
"""
- return [x for x in cls.__bases__ if issubclass(x, Mbi_Mixin)]
+ return [x for x in cls.__bases__ if issubclass(x, mbi_mixin.Mbi_Mixin)]
def __init__(self) -> None:
"""Initialization of MBI."""
# Check if all needed class instance members are available (validation of class due to mixin problems)
self.search_paths: Optional[List[str]] = None
+ self.family = "Unknown"
+ self.dek: Optional[str] = None
for base in self._get_mixins():
for member in base.NEEDED_MEMBERS:
assert hasattr(self, member)
@property
def total_len(self) -> int:
- """Compute final application data length.
+ """Compute Master Boot Image data length.
:return: Final image data length.
"""
@@ -217,11 +203,17 @@ def total_len(self) -> int:
@property
def app_len(self) -> int:
- """Application data length.
+ """Compute application data length.
- :return: Application data length.
+ :return: Final image data length.
"""
- return self.total_len
+ ret = 0
+ for base in self._get_mixins():
+ mix_app_len = base.mix_app_len(self) # type: ignore
+ if mix_app_len < 0:
+ mix_app_len = base.mix_len(self) # type: ignore
+ ret += mix_app_len
+ return ret
def load_from_config(
self, config: Dict[str, Any], search_paths: Optional[List[str]] = None
@@ -232,15 +224,10 @@ def load_from_config(
:param search_paths: List of paths where to search for the file, defaults to None
"""
self.search_paths = search_paths
+ self.family = config.get("family", "Unknown")
for base in self._get_mixins():
base.mix_load_from_config(self, config) # type: ignore
- collect_data: Any # collect_data(self) -> bytes
- encrypt: Any # encrypt(self, raw_image: bytes) -> bytes
- post_encrypt: Any # post_encrypt(self, image: bytes) -> bytes
- sign: Any # sign(self, image: bytes) -> bytes
- finalize: Any # finalize(self, image: bytes) -> bytes
-
def export(self) -> bytes:
"""Export final bootable image.
@@ -250,24 +237,134 @@ def export(self) -> bytes:
self.validate()
# 2: Collect all input data into raw image
raw_image = self.collect_data()
+ if DEBUG_TRACE_ENABLE:
+ write_file(raw_image, "export_1_collect.bin", mode="wb")
# 3: Optionally encrypt the image
encrypted_image = self.encrypt(raw_image)
+ if DEBUG_TRACE_ENABLE:
+ write_file(encrypted_image, "export_2_encrypt.bin", mode="wb")
# 4: Optionally do some post encrypt image updates
encrypted_image = self.post_encrypt(encrypted_image)
+ if DEBUG_TRACE_ENABLE:
+ write_file(encrypted_image, "export_3_post_encrypt.bin", mode="wb")
# 5: Optionally sign image
signed_image = self.sign(encrypted_image)
+ if DEBUG_TRACE_ENABLE:
+ write_file(signed_image, "export_4_signed.bin", mode="wb")
# 6: Finalize image
final_image = self.finalize(signed_image)
+ if DEBUG_TRACE_ENABLE:
+ write_file(final_image, "export_5_finalized.bin", mode="wb")
return final_image
- def parse(self, data: bytes) -> None:
+ @staticmethod
+ def parse(family: str, data: bytes, dek: Optional[str] = None) -> "MasterBootImage":
"""Parse the final image to individual fields.
- :param data: Final Image in bytes.
- :raises NotImplementedError: Derived class has to implement this method
+ :param family: Device family
+ :param data: Final Image in bytes
+ :param dek: The decryption key for encrypted images
+ :raises SPSDKParsingError: Cannot determinate the decoding class
+ :return: MBI parsed class
+ """
+ # 1: Get the right class to parse MBI
+ mbi_classes = get_mbi_classes(family)
+ image_type = mbi_mixin.Mbi_MixinIvt.get_image_type(data=data)
+ authentication = None
+ target = None
+ mbi_cls_type = None
+ for cls_info in mbi_classes.values():
+ if cls_info[0].IMAGE_TYPE[0] == image_type:
+ mbi_cls_type = cls_info[0]
+ target = cls_info[1]
+ authentication = cls_info[2]
+ logger.info(
+ "Detected MBI image:\n"
+ f" Authentication: {authentication}\n"
+ f" Target: {target}"
+ )
+ break
+
+ if mbi_cls_type == None:
+ raise SPSDKParsingError("Unsupported MBI type detected.")
+
+ assert mbi_cls_type
+ mbi_cls = mbi_cls_type()
+ mbi_cls.family = family
+ mbi_cls.dek = dek
+
+ # 2: Parse individual mixins what is possible
+ # Solve the order - Wait for the mixins that depends on other and run another round
+ mixins_src = mbi_cls._get_mixins()
+ while mixins_src:
+ mixins = mixins_src.copy()
+ mixins_src.clear()
+ for mixin in mixins:
+ logger.debug(f"Parsing: Mixin {mixin.__name__}.")
+ for pre_parsed in mixin.PRE_PARSED:
+ if hasattr(mbi_cls, pre_parsed) and getattr(mbi_cls, pre_parsed) == None:
+ logger.debug(
+ f"Parsing: Mixin {mixin.__name__} has to wait to parse {pre_parsed} mixin."
+ )
+ mixins_src.append(mixin)
+ continue
+ mixin.mix_parse(mbi_cls, data) # type: ignore
+
+ # 3: Revert finalize operation of image
+ image = mbi_cls.finalize(data, revert=True)
+ if DEBUG_TRACE_ENABLE:
+ write_file(image, "parse_1_revert_finalize.bin", mode="wb")
+ # 4: Revert optional sign of image
+ unsigned_image = mbi_cls.sign(image, revert=True)
+ if DEBUG_TRACE_ENABLE:
+ write_file(unsigned_image, "parse_2_revert_sign.bin", mode="wb")
+ # 5: Revert optional some post encrypt image updates
+ encrypted_image = mbi_cls.post_encrypt(unsigned_image, revert=True)
+ if DEBUG_TRACE_ENABLE:
+ write_file(encrypted_image, "parse_3_revert_post_encrypt.bin", mode="wb")
+ # 6: Revert optional encryption of the image
+ decrypted_image = mbi_cls.encrypt(encrypted_image, revert=True)
+ if DEBUG_TRACE_ENABLE:
+ write_file(decrypted_image, "parse_4_revert_encrypt.bin", mode="wb")
+ # 7: Disassembly rest of image
+ mbi_cls.disassemble_image(decrypted_image)
+
+ return mbi_cls
+
+ def create_config(self, output_folder: str) -> None:
+ """Create configuration file and its data files from the MBI class.
+
+ :param output_folder: Output folder to store the parsed data
"""
- raise NotImplementedError("Derived class has to implement this method.")
+ cfg_values: Dict[str, Union[str, int]] = {}
+ for mixin in self._get_mixins():
+ cfg_values.update(mixin.mix_get_config(self, output_folder)) # type: ignore
+ mbi_classes = get_mbi_classes(self.family)
+ for mbi_class in mbi_classes.values():
+ if mbi_class[0].__name__ == self.__class__.__name__:
+ target = mbi_class[1]
+ authentication = mbi_class[2]
+ break
+
+ assert target and authentication
+
+ val_schemas = self.get_validation_schemas()
+ cfg_values["family"] = self.family
+ cfg_values["outputImageExecutionTarget"] = target
+ cfg_values["outputImageAuthenticationType"] = authentication
+
+ yaml_data = CommentedConfig(
+ main_title=(
+ f"Master Boot Image ({self.__class__.__name__}) recreated configuration from :"
+ f"{datetime.datetime.now().strftime('%d/%m/%Y %H:%M:%S')}."
+ ),
+ schemas=val_schemas,
+ values=cfg_values,
+ export_template=False,
+ ).export_to_yaml()
+
+ write_file(yaml_data, os.path.join(output_folder, "mbi_config.yaml"))
@classmethod
def get_supported_families(cls) -> List[str]:
@@ -321,7 +418,11 @@ def validate(self) -> None:
# pylint: disable=invalid-name
# pylint: disable=abstract-method
class Mbi_PlainXip(
- MasterBootImage, Mbi_MixinApp, Mbi_MixinIvt, Mbi_MixinTrustZone, Mbi_ExportMixinAppTrustZone
+ MasterBootImage,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinTrustZone,
+ mbi_mixin.Mbi_ExportMixinAppTrustZone,
):
"""Master Boot Plain XiP Image for LPC55xxx family."""
@@ -338,11 +439,11 @@ def __init__(self, app: Optional[bytes] = None, trust_zone: Optional[TrustZone]
class Mbi_CrcXip(
MasterBootImage,
- Mbi_MixinApp,
- Mbi_MixinIvt,
- Mbi_MixinTrustZone,
- Mbi_ExportMixinAppTrustZone,
- Mbi_ExportMixinCrcSign,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinTrustZone,
+ mbi_mixin.Mbi_ExportMixinAppTrustZone,
+ mbi_mixin.Mbi_ExportMixinCrcSign,
):
"""Master Boot CRC XiP Image for LPC55xxx family."""
@@ -361,12 +462,12 @@ def __init__(self, app: Optional[bytes] = None, trust_zone: Optional[TrustZone]
class Mbi_CrcRam(
MasterBootImage,
- Mbi_MixinApp,
- Mbi_MixinIvt,
- Mbi_MixinTrustZone,
- Mbi_MixinLoadAddress,
- Mbi_ExportMixinAppTrustZone,
- Mbi_ExportMixinCrcSign,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinTrustZone,
+ mbi_mixin.Mbi_MixinLoadAddress,
+ mbi_mixin.Mbi_ExportMixinAppTrustZone,
+ mbi_mixin.Mbi_ExportMixinCrcSign,
):
"""Master Boot CRC RAM Image for LPC55xxx family."""
@@ -392,12 +493,12 @@ def __init__(
class Mbi_SignedXip(
MasterBootImage,
- Mbi_MixinApp,
- Mbi_MixinIvt,
- Mbi_MixinTrustZone,
- Mbi_MixinCertBlockV2,
- Mbi_ExportMixinAppTrustZoneCertBlock,
- Mbi_ExportMixinRsaSign,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinTrustZone,
+ mbi_mixin.Mbi_MixinCertBlockV2,
+ mbi_mixin.Mbi_ExportMixinAppTrustZoneCertBlock,
+ mbi_mixin.Mbi_ExportMixinRsaSign,
):
"""Master Boot Signed XiP Image for LPC55xxx family."""
@@ -426,13 +527,13 @@ def __init__(
class Mbi_SignedRam(
MasterBootImage,
- Mbi_MixinApp,
- Mbi_MixinIvt,
- Mbi_MixinTrustZone,
- Mbi_MixinLoadAddress,
- Mbi_MixinCertBlockV2,
- Mbi_ExportMixinAppTrustZoneCertBlock,
- Mbi_ExportMixinRsaSign,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinTrustZone,
+ mbi_mixin.Mbi_MixinLoadAddress,
+ mbi_mixin.Mbi_MixinCertBlockV2,
+ mbi_mixin.Mbi_ExportMixinAppTrustZoneCertBlock,
+ mbi_mixin.Mbi_ExportMixinRsaSign,
):
"""Master Boot Signed RAM Image for LPC55xxx family."""
@@ -469,12 +570,12 @@ def __init__(
class Mbi_PlainRamRtxxx(
MasterBootImage,
- Mbi_MixinApp,
- Mbi_MixinIvt,
- Mbi_MixinTrustZone,
- Mbi_MixinLoadAddress,
- Mbi_MixinHwKey,
- Mbi_ExportMixinAppTrustZone,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinTrustZone,
+ mbi_mixin.Mbi_MixinLoadAddress,
+ mbi_mixin.Mbi_MixinHwKey,
+ mbi_mixin.Mbi_ExportMixinAppTrustZone,
):
"""Master Boot Plain Image for RTxxx."""
@@ -501,18 +602,18 @@ def __init__(
class Mbi_PlainSignedRamRtxxx(
MasterBootImage,
- Mbi_MixinApp,
- Mbi_MixinRelocTable,
- Mbi_MixinLoadAddress,
- Mbi_MixinIvt,
- Mbi_MixinTrustZone,
- Mbi_MixinCertBlockV2,
- Mbi_MixinHmacMandatory,
- Mbi_MixinKeyStore,
- Mbi_MixinHwKey,
- Mbi_ExportMixinAppTrustZoneCertBlock,
- Mbi_ExportMixinRsaSign,
- Mbi_ExportMixinHmacKeyStoreFinalize,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinRelocTable,
+ mbi_mixin.Mbi_MixinLoadAddress,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinTrustZone,
+ mbi_mixin.Mbi_MixinCertBlockV2,
+ mbi_mixin.Mbi_MixinHmacMandatory,
+ mbi_mixin.Mbi_MixinKeyStore,
+ mbi_mixin.Mbi_MixinHwKey,
+ mbi_mixin.Mbi_ExportMixinAppTrustZoneCertBlock,
+ mbi_mixin.Mbi_ExportMixinRsaSign,
+ mbi_mixin.Mbi_ExportMixinHmacKeyStoreFinalize,
):
"""Master Boot Plain Signed RAM Image for RTxxx family."""
@@ -521,7 +622,7 @@ class Mbi_PlainSignedRamRtxxx(
def __init__(
self,
app: Optional[bytes] = None,
- app_table: Optional[MultipleImageTable] = None,
+ app_table: Optional[mbi_mixin.MultipleImageTable] = None,
trust_zone: Optional[TrustZone] = None,
load_addr: Optional[int] = None,
cert_block: Optional[CertBlockV2] = None,
@@ -553,26 +654,17 @@ def __init__(
self.user_hw_key_enabled = hwk
super().__init__()
- @property
- def app_len(self) -> int:
- """Application data length.
-
- :return: Application data length.
- """
- assert self.cert_block
- return self.get_app_length() + len(self.cert_block.export()) + len(self.tz.export())
-
class Mbi_CrcRamRtxxx(
MasterBootImage,
- Mbi_MixinApp,
- Mbi_MixinRelocTable,
- Mbi_MixinLoadAddress,
- Mbi_MixinIvt,
- Mbi_MixinTrustZone,
- Mbi_MixinHwKey,
- Mbi_ExportMixinAppTrustZone,
- Mbi_ExportMixinCrcSign,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinRelocTable,
+ mbi_mixin.Mbi_MixinLoadAddress,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinTrustZone,
+ mbi_mixin.Mbi_MixinHwKey,
+ mbi_mixin.Mbi_ExportMixinAppTrustZone,
+ mbi_mixin.Mbi_ExportMixinCrcSign,
):
"""Master Boot CRC RAM Image for RTxxx family."""
@@ -581,7 +673,7 @@ class Mbi_CrcRamRtxxx(
def __init__(
self,
app: Optional[bytes] = None,
- app_table: Optional[MultipleImageTable] = None,
+ app_table: Optional[mbi_mixin.MultipleImageTable] = None,
trust_zone: Optional[TrustZone] = None,
load_addr: Optional[int] = None,
hwk: bool = False,
@@ -604,18 +696,18 @@ def __init__(
class Mbi_EncryptedRamRtxxx(
MasterBootImage,
- Mbi_MixinApp,
- Mbi_MixinRelocTable,
- Mbi_MixinLoadAddress,
- Mbi_MixinIvt,
- Mbi_MixinTrustZone,
- Mbi_MixinCertBlockV2,
- Mbi_MixinHwKey,
- Mbi_MixinKeyStore,
- Mbi_MixinHmacMandatory,
- Mbi_MixinCtrInitVector,
- Mbi_ExportMixinRsaSign,
- Mbi_ExportMixinHmacKeyStoreFinalize,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinRelocTable,
+ mbi_mixin.Mbi_MixinLoadAddress,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinTrustZone,
+ mbi_mixin.Mbi_MixinCertBlockV2,
+ mbi_mixin.Mbi_MixinHwKey,
+ mbi_mixin.Mbi_MixinKeyStore,
+ mbi_mixin.Mbi_MixinHmacMandatory,
+ mbi_mixin.Mbi_MixinCtrInitVector,
+ mbi_mixin.Mbi_ExportMixinRsaSign,
+ mbi_mixin.Mbi_ExportMixinHmacKeyStoreFinalize,
):
"""Master Boot Encrypted RAM Image for RTxxx family."""
@@ -624,7 +716,7 @@ class Mbi_EncryptedRamRtxxx(
def __init__(
self,
app: Optional[bytes] = None,
- app_table: Optional[MultipleImageTable] = None,
+ app_table: Optional[mbi_mixin.MultipleImageTable] = None,
trust_zone: Optional[TrustZone] = None,
load_addr: Optional[int] = None,
cert_block: Optional[CertBlockV2] = None,
@@ -666,43 +758,90 @@ def collect_data(self) -> bytes:
:return: Collected raw image.
"""
assert self.cert_block
- self.cert_block.alignment = 4 # type: ignore # this value is used by elf-to-sb-gui
+ self.cert_block.alignment = 4 # type: ignore
self.img_len = (
self.total_len + self.cert_block.signature_size + 56 + 16
) # Encrypted IVT + IV
- return self.update_ivt(
+ image = self.update_ivt(
app_data=self.get_app_data() + self.tz.export(),
total_len=self.img_len,
crc_val_cert_offset=self.get_app_length(),
)
+ return image
+
+ def disassemble_image(self, image: bytes) -> None: # pylint: disable=no-self-use
+ """Disassemble image to individual parts from image.
- def encrypt(self, raw_image: bytes) -> bytes:
+ :param image: Image.
+ """
+ # Re -parse decrypted TZ if needed
+ if self.tz.type == TrustZoneType.CUSTOM:
+ self.tz = TrustZone.from_binary(
+ family=self.family, raw_data=image[-TrustZone.get_preset_data_size(self.family) :]
+ )
+
+ tz_len = len(self.tz.export())
+ if tz_len:
+ image = image[:-tz_len]
+ if hasattr(self, "disassembly_app_data"):
+ image = self.disassembly_app_data(image)
+ self.app = self.clean_ivt(image)
+
+ def encrypt(self, image: bytes, revert: bool = False) -> bytes:
"""Encrypt image if needed.
- :param raw_image: Input raw image to encrypt.
+ :param image: Input raw image to encrypt.
+ :param revert: Revert the operation if possible.
:return: Encrypted image.
"""
+ if revert and not (self.hmac_key and self.ctr_init_vector):
+ logger.warning("Cannot parse the encrypted image without decrypting key!")
+ return image
+
assert self.hmac_key and self.ctr_init_vector
key = self.hmac_key
if not self.key_store or self.key_store.key_source == KeySourceType.OTP:
key = KeyStore.derive_enc_image_key(key)
aes = AES.new(key, AES.MODE_CTR, initial_value=self.ctr_init_vector, nonce=bytes())
- return aes.encrypt(raw_image + self.tz.export())
+ logger.debug(f"Encryption key: {self.hmac_key.hex()}")
+ logger.debug(f"Encryption IV: {self.ctr_init_vector.hex()}")
- def post_encrypt(self, image: bytes) -> bytes:
+ if revert:
+ decrypted_data = aes.decrypt(image)
+ return decrypted_data
+
+ encrypted_data = aes.encrypt(image + self.tz.export())
+ return encrypted_data
+
+ def post_encrypt(self, image: bytes, revert: bool = False) -> bytes:
"""Optionally do some post encrypt image updates.
:param image: Encrypted image.
+ :param revert: Revert the operation if possible.
:return: Updated encrypted image.
"""
- assert self.cert_block
+ assert self.cert_block and isinstance(self.cert_block, CertBlockV2)
+ if revert:
+ cert_blk_offset = mbi_mixin.Mbi_MixinIvt.get_cert_block_offset(image)
+ cert_blk_size = self.cert_block.expected_size
+ # Restore original part of encrypted IVT
+ org_image = image[
+ cert_blk_offset + cert_blk_size : cert_blk_offset + cert_blk_size + 56
+ ]
+ # Add rest of original encrypted image
+ org_image += image[56:cert_blk_offset]
+ # optionally add TrustZone data
+ org_image += image[cert_blk_offset + cert_blk_size + 56 + 16 :]
+ return org_image
+
enc_ivt = self.update_ivt(
app_data=image[: self.HMAC_OFFSET],
total_len=self.img_len,
crc_val_cert_offset=self.get_app_length(),
)
+
# Create encrypted cert block (Encrypted IVT table + IV)
encrypted_header = image[:56] + self.ctr_init_vector
@@ -710,7 +849,6 @@ def post_encrypt(self, image: bytes) -> bytes:
len(image) + len(self.cert_block.export()) + len(encrypted_header)
)
enc_cert = self.cert_block.export() + encrypted_header
-
return (
enc_ivt
+ image[self.HMAC_OFFSET : self.get_app_length()] # header # encrypted image
@@ -721,11 +859,11 @@ def post_encrypt(self, image: bytes) -> bytes:
class Mbi_PlainXipRtxxx(
MasterBootImage,
- Mbi_MixinApp,
- Mbi_MixinIvt,
- Mbi_MixinTrustZone,
- Mbi_MixinHwKey,
- Mbi_ExportMixinAppTrustZone,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinTrustZone,
+ mbi_mixin.Mbi_MixinHwKey,
+ mbi_mixin.Mbi_ExportMixinAppTrustZone,
):
"""Master Boot Plain XiP Image for RTxxx."""
@@ -746,14 +884,14 @@ def __init__(
class Mbi_PlainSignedXipRtxxx(
MasterBootImage,
- Mbi_MixinApp,
- Mbi_MixinIvt,
- Mbi_MixinLoadAddress,
- Mbi_MixinTrustZone,
- Mbi_MixinCertBlockV2,
- Mbi_MixinHwKey,
- Mbi_ExportMixinAppTrustZoneCertBlock,
- Mbi_ExportMixinRsaSign,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinLoadAddress,
+ mbi_mixin.Mbi_MixinTrustZone,
+ mbi_mixin.Mbi_MixinCertBlockV2,
+ mbi_mixin.Mbi_MixinHwKey,
+ mbi_mixin.Mbi_ExportMixinAppTrustZoneCertBlock,
+ mbi_mixin.Mbi_ExportMixinRsaSign,
):
"""Master Boot Plain Signed XiP Image for RTxxx family."""
@@ -788,13 +926,13 @@ def __init__(
class Mbi_CrcXipRtxxx(
MasterBootImage,
- Mbi_MixinApp,
- Mbi_MixinIvt,
- Mbi_MixinLoadAddress,
- Mbi_MixinTrustZone,
- Mbi_MixinHwKey,
- Mbi_ExportMixinAppTrustZone,
- Mbi_ExportMixinCrcSign,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinLoadAddress,
+ mbi_mixin.Mbi_MixinTrustZone,
+ mbi_mixin.Mbi_MixinHwKey,
+ mbi_mixin.Mbi_ExportMixinAppTrustZone,
+ mbi_mixin.Mbi_ExportMixinCrcSign,
):
"""Master Boot CRC XiP Image for RTxxx."""
@@ -826,12 +964,12 @@ def __init__(
########################################################################################################################
class Mbi_PlainRamLpc55s3x(
MasterBootImage,
- Mbi_MixinApp,
- Mbi_MixinIvt,
- Mbi_MixinTrustZoneMandatory,
- Mbi_MixinLoadAddress,
- Mbi_MixinFwVersion,
- Mbi_ExportMixinAppTrustZone,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinTrustZoneMandatory,
+ mbi_mixin.Mbi_MixinLoadAddress,
+ mbi_mixin.Mbi_MixinFwVersion,
+ mbi_mixin.Mbi_ExportMixinAppTrustZone,
):
"""Master Boot Plain RAM Image for LPC55s3x family."""
@@ -859,13 +997,13 @@ def __init__(
class Mbi_CrcRamLpc55s3x(
MasterBootImage,
- Mbi_MixinApp,
- Mbi_MixinIvt,
- Mbi_MixinTrustZoneMandatory,
- Mbi_MixinLoadAddress,
- Mbi_MixinFwVersion,
- Mbi_ExportMixinAppTrustZone,
- Mbi_ExportMixinCrcSign,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinTrustZoneMandatory,
+ mbi_mixin.Mbi_MixinLoadAddress,
+ mbi_mixin.Mbi_MixinFwVersion,
+ mbi_mixin.Mbi_ExportMixinAppTrustZone,
+ mbi_mixin.Mbi_ExportMixinCrcSign,
):
"""Master Boot CRC RAM Image for LPC55s3x family."""
@@ -895,14 +1033,14 @@ def __init__(
class Mbi_PlainXipSignedLpc55s3x(
MasterBootImage,
- Mbi_MixinApp,
- Mbi_MixinIvt,
- Mbi_MixinCertBlockV31,
- Mbi_MixinManifest,
- Mbi_MixinLoadAddress,
- Mbi_MixinFwVersion,
- Mbi_ExportMixinAppCertBlockManifest,
- Mbi_ExportMixinEccSign,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinCertBlockV31,
+ mbi_mixin.Mbi_MixinManifest,
+ mbi_mixin.Mbi_MixinLoadAddress,
+ mbi_mixin.Mbi_MixinFwVersion,
+ mbi_mixin.Mbi_ExportMixinAppCertBlockManifest,
+ mbi_mixin.Mbi_ExportMixinEccSign,
):
"""Master Boot Signed XIP Image for LPC55s3x family."""
@@ -914,7 +1052,7 @@ def __init__(
firmware_version: int = 0,
load_addr: int = 0,
cert_block: Optional[CertBlockV31] = None,
- manifest: Optional[MasterBootImageManifest] = None,
+ manifest: Optional[mbi_mixin.MasterBootImageManifest] = None,
signature_provider: Optional[SignatureProvider] = None,
) -> None:
"""Constructor for Master Boot Signed XIP Image for LPC55s3x family.
@@ -938,13 +1076,13 @@ def __init__(
class Mbi_CrcXipLpc55s3x(
MasterBootImage,
- Mbi_MixinApp,
- Mbi_MixinIvt,
- Mbi_MixinTrustZoneMandatory,
- Mbi_MixinLoadAddress,
- Mbi_MixinFwVersion,
- Mbi_ExportMixinAppTrustZone,
- Mbi_ExportMixinCrcSign,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinTrustZoneMandatory,
+ mbi_mixin.Mbi_MixinLoadAddress,
+ mbi_mixin.Mbi_MixinFwVersion,
+ mbi_mixin.Mbi_ExportMixinAppTrustZone,
+ mbi_mixin.Mbi_ExportMixinCrcSign,
):
"""Master Boot CRC XiP Image for LPC55s3x family."""
@@ -977,12 +1115,12 @@ def __init__(
########################################################################################################################
class Mbi_PlainXipKw45xx(
MasterBootImage,
- Mbi_MixinApp,
- Mbi_MixinIvt,
- Mbi_MixinLoadAddress,
- Mbi_MixinTrustZoneMandatory,
- Mbi_MixinImageSubType,
- Mbi_ExportMixinAppTrustZone,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinLoadAddress,
+ mbi_mixin.Mbi_MixinTrustZoneMandatory,
+ mbi_mixin.Mbi_MixinImageSubType,
+ mbi_mixin.Mbi_ExportMixinAppTrustZone,
):
"""Master Boot Plain RAM Image for KW45xx/K32W1xx family."""
@@ -992,7 +1130,7 @@ def __init__(
load_addr: Optional[int] = None,
trust_zone: Optional[TrustZone] = None,
firmware_version: int = 0,
- image_subtype: Optional[Mbi_MixinImageSubType.Mbi_ImageSubTypeKw45xx] = None,
+ image_subtype: Optional[mbi_mixin.Mbi_MixinImageSubType.Mbi_ImageSubTypeKw45xx] = None,
) -> None:
"""Constructor for Master Boot Plain RAM Image for KW45xx/K32W1xx family.
@@ -1012,18 +1150,14 @@ def __init__(
class Mbi_PlainXipSignedKw45xx(
MasterBootImage,
- Mbi_MixinApp,
- Mbi_MixinIvt,
- Mbi_MixinLoadAddress,
- Mbi_MixinCertBlockV31,
- Mbi_MixinManifest,
- Mbi_MixinImageSubType,
- Mbi_MixinSignDigest,
- Mbi_MixinNXPImage,
- Mbi_MixinNoSignature,
- Mbi_ExportMixinAppCertBlockManifest,
- Mbi_ExportMixinEccSign,
- Mbi_ExportMixinSignDigestFinalize,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinLoadAddress,
+ mbi_mixin.Mbi_MixinCertBlockV31,
+ mbi_mixin.Mbi_MixinManifest,
+ mbi_mixin.Mbi_MixinNoSignature,
+ mbi_mixin.Mbi_ExportMixinAppCertBlockManifest,
+ mbi_mixin.Mbi_ExportMixinEccSign,
):
"""Master Boot Signed XIP Image for KW45xx/K32W1xx family."""
@@ -1035,11 +1169,56 @@ def __init__(
load_addr: Optional[int] = None,
firmware_version: int = 0,
cert_block: Optional[CertBlockV31] = None,
- manifest: Optional[MasterBootImageManifest] = None,
+ manifest: Optional[mbi_mixin.MasterBootImageManifest] = None,
signature_provider: Optional[SignatureProvider] = None,
- image_subtype: Optional[Mbi_MixinImageSubType.Mbi_ImageSubTypeKw45xx] = None,
- attach_sign_digest: Optional[bool] = None,
- nxp_image: Optional[bool] = None,
+ no_signature: Optional[bool] = None,
+ ) -> None:
+ """Constructor for Master Boot Signed XIP Image for KW45xx/K32W1xx family.
+
+ :param app: Application image data, defaults to None
+ :param load_addr: Load/Execution address of image, defaults to 0
+ :param firmware_version: Firmware version of image, defaults to 0
+ :param cert_block: Certification block of image, defaults to None
+ :param manifest: Manifest of image, defaults to None
+ :param signature_provider: Signature provider to sign final image, defaults to None
+ :param nxp_image: If it set, the image is generated as NXP.
+ :param no_signature: If it set, the signature is not appended
+ """
+ self.app = align_block(app) if app else None
+ self.load_address = load_addr
+ self.no_signature = no_signature
+ self.firmware_version = firmware_version
+ self.cert_block = cert_block
+ self.manifest = manifest
+ self.signature_provider = signature_provider
+ super().__init__()
+
+
+class Mbi_PlainXipSignedNxpKw45xx(
+ MasterBootImage,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinLoadAddress,
+ mbi_mixin.Mbi_MixinCertBlockV31,
+ mbi_mixin.Mbi_MixinManifest,
+ mbi_mixin.Mbi_MixinImageSubType,
+ mbi_mixin.Mbi_MixinNoSignature,
+ mbi_mixin.Mbi_ExportMixinAppCertBlockManifest,
+ mbi_mixin.Mbi_ExportMixinEccSign,
+):
+ """Master Boot Signed XIP Image by NXP Keys for KW45xx/K32W1xx family."""
+
+ IMAGE_TYPE = SIGNED_XIP_NXP_IMAGE
+
+ def __init__(
+ self,
+ app: Optional[bytes] = None,
+ load_addr: Optional[int] = None,
+ firmware_version: int = 0,
+ cert_block: Optional[CertBlockV31] = None,
+ manifest: Optional[mbi_mixin.MasterBootImageManifest] = None,
+ signature_provider: Optional[SignatureProvider] = None,
+ image_subtype: Optional[mbi_mixin.Mbi_MixinImageSubType.Mbi_ImageSubTypeKw45xx] = None,
no_signature: Optional[bool] = None,
) -> None:
"""Constructor for Master Boot Signed XIP Image for KW45xx/K32W1xx family.
@@ -1051,8 +1230,6 @@ def __init__(
:param manifest: Manifest of image, defaults to None
:param signature_provider: Signature provider to sign final image, defaults to None
:param image_subtype: Selection of image subtype (MAIN/NBU), default to None(MAIN)
- :param attach_sign_digest: Additional signature digest.
- Possible values are: None, 'sha256' and 'sha384', defaults to None
:param nxp_image: If it set, the image is generated as NXP.
:param no_signature: If it set, the signature is not appended
"""
@@ -1064,21 +1241,18 @@ def __init__(
self.manifest = manifest
self.signature_provider = signature_provider
self.set_image_subtype(image_subtype)
- self.attach_sign_digest = self.get_sign_digest() if attach_sign_digest else None
- if nxp_image:
- self.change_to_nxp_image()
super().__init__()
class Mbi_CrcXipKw45xx(
MasterBootImage,
- Mbi_MixinApp,
- Mbi_MixinIvt,
- Mbi_MixinLoadAddress,
- Mbi_MixinTrustZoneMandatory,
- Mbi_MixinImageSubType,
- Mbi_ExportMixinAppTrustZone,
- Mbi_ExportMixinCrcSign,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinLoadAddress,
+ mbi_mixin.Mbi_MixinTrustZoneMandatory,
+ mbi_mixin.Mbi_MixinImageSubType,
+ mbi_mixin.Mbi_ExportMixinAppTrustZone,
+ mbi_mixin.Mbi_ExportMixinCrcSign,
):
"""Master Boot CRC XiP Image for KW45xx/K32W1xx family."""
@@ -1090,7 +1264,7 @@ def __init__(
load_addr: Optional[int] = None,
trust_zone: Optional[TrustZone] = None,
firmware_version: int = 0,
- image_subtype: Optional[Mbi_MixinImageSubType.Mbi_ImageSubTypeKw45xx] = None,
+ image_subtype: Optional[mbi_mixin.Mbi_MixinImageSubType.Mbi_ImageSubTypeKw45xx] = None,
) -> None:
"""Constructor for Master Boot CRC XiP Image for KW45xx/K32W1xx family.
@@ -1106,3 +1280,356 @@ def __init__(
self.firmware_version = firmware_version
self.set_image_subtype(image_subtype)
super().__init__()
+
+
+########################################################################################################################
+# Master Boot Image Class (MCXNX)
+########################################################################################################################
+class Mbi_CrcXipMcxNx(
+ MasterBootImage,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinLoadAddress,
+ mbi_mixin.Mbi_MixinTrustZoneMandatory,
+ mbi_mixin.Mbi_MixinFwVersion,
+ mbi_mixin.Mbi_ExportMixinAppTrustZone,
+ mbi_mixin.Mbi_ExportMixinCrcSign,
+):
+ """Master Boot CRC XiP Image for mcxnx family."""
+
+ IMAGE_TYPE = CRC_XIP_IMAGE
+
+ def __init__(
+ self,
+ app: Optional[bytes] = None,
+ trust_zone: Optional[TrustZone] = None,
+ firmware_version: int = 0,
+ load_addr: Optional[int] = None,
+ ) -> None:
+ """Constructor for Master Boot CRC XiP Image for mcxnx family.
+
+ :param app: Application image data, defaults to None
+ :param trust_zone: TrustZone object, defaults to None
+ :param load_addr: Load/Execution address in RAM of image, defaults to 0
+ :param firmware_version: Firmware version of image, defaults to 0
+ """
+ self.app = align_block(app) if app else None
+ self.tz = trust_zone or TrustZone.enabled()
+ self.firmware_version = firmware_version
+ self.load_address = load_addr
+ self.app_ext_memory_align = 0x1000
+ super().__init__()
+
+
+class Mbi_PlainXipSignedMcxNx(
+ MasterBootImage,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinCertBlockV31,
+ mbi_mixin.Mbi_MixinManifestMcxNx,
+ mbi_mixin.Mbi_MixinImageSubType,
+ mbi_mixin.Mbi_MixinLoadAddress,
+ mbi_mixin.Mbi_MixinFwVersion,
+ mbi_mixin.Mbi_ExportMixinAppCertBlockManifest,
+ mbi_mixin.Mbi_ExportMixinEccSign,
+):
+ """Master Boot Signed XIP Image for mcxnx family."""
+
+ IMAGE_TYPE = SIGNED_XIP_IMAGE
+
+ def __init__(
+ self,
+ app: Optional[bytes] = None,
+ firmware_version: int = 0,
+ cert_block: Optional[CertBlockV31] = None,
+ manifest: Optional[mbi_mixin.MasterBootImageManifestMcxNx] = None,
+ signature_provider: Optional[SignatureProvider] = None,
+ image_subtype: Optional[mbi_mixin.Mbi_MixinImageSubType.Mbi_ImageSubTypeMcxn9xx] = None,
+ load_addr: Optional[int] = None,
+ ) -> None:
+ """Constructor for Master Boot Signed XIP Image for mcxnx family.
+
+ :param app: Application image data, defaults to None
+ :param firmware_version: Firmware version of image, defaults to 0
+ :param cert_block: Certification block of image, defaults to None
+ :param manifest: Manifest of image, defaults to None
+ :param signature_provider: Signature provider to sign final image, defaults to None
+ :param image_subtype: Selection of image subtype (MAIN/RECOVERY), default to None(MAIN)
+ :param load_addr: Load/Execution address in RAM of image, defaults to 0
+ """
+ self.app = align_block(app) if app else None
+ self.firmware_version = firmware_version
+ self.cert_block = cert_block
+ self.manifest = manifest
+ self.signature_provider = signature_provider
+ self.set_image_subtype(image_subtype)
+ self.load_address = load_addr
+ self.app_ext_memory_align = 0x1000
+ super().__init__()
+
+
+class Mbi_PlainRamMcxNx(
+ MasterBootImage,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinTrustZoneMandatory,
+ mbi_mixin.Mbi_MixinLoadAddress,
+ mbi_mixin.Mbi_MixinFwVersion,
+ mbi_mixin.Mbi_ExportMixinAppTrustZone,
+):
+ """Master Boot Plain RAM Image for mcxnx family."""
+
+ def __init__(
+ self,
+ app: Optional[bytes] = None,
+ trust_zone: Optional[TrustZone] = None,
+ load_addr: int = 0,
+ firmware_version: int = 0,
+ ) -> None:
+ """Constructor for Master Boot Plain RAM Image for mcxnx family.
+
+ :param app: Application image data, defaults to None
+ :param trust_zone: TrustZone object, defaults to None
+ :param load_addr: Load/Execution address in RAM of image, defaults to 0
+ :param firmware_version: Firmware version of image, defaults to 0
+ """
+ self.app = align_block(app) if app else None
+ self.tz = trust_zone or TrustZone.enabled()
+ self.load_address = load_addr
+ self.firmware_version = firmware_version
+ self.app_ext_memory_align = 0x1000
+ super().__init__()
+
+
+class Mbi_CrcRamMcxNx(
+ MasterBootImage,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinTrustZoneMandatory,
+ mbi_mixin.Mbi_MixinLoadAddress,
+ mbi_mixin.Mbi_MixinFwVersion,
+ mbi_mixin.Mbi_ExportMixinAppTrustZone,
+ mbi_mixin.Mbi_ExportMixinCrcSign,
+):
+ """Master Boot CRC RAM Image for mcxnx family."""
+
+ IMAGE_TYPE = CRC_RAM_IMAGE
+
+ def __init__(
+ self,
+ app: Optional[bytes] = None,
+ trust_zone: Optional[TrustZone] = None,
+ load_addr: int = 0,
+ firmware_version: int = 0,
+ ) -> None:
+ """Constructor for Master Boot Signed RAM Image for mcxnx family.
+
+ :param app: Application image data, defaults to None
+ :param trust_zone: TrustZone object, defaults to None
+ :param load_addr: Load/Execution address in RAM of image, defaults to 0
+ :param firmware_version: Firmware version of image, defaults to 0
+ """
+ self.app = align_block(app) if app else None
+ self.tz = trust_zone or TrustZone.enabled()
+ self.load_address = load_addr
+ self.firmware_version = firmware_version
+ super().__init__()
+
+
+########################################################################################################################
+# Master Boot Image Class (RW61x)
+########################################################################################################################
+class Mbi_PlainRamRw61x(
+ MasterBootImage,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinTrustZoneMandatory,
+ mbi_mixin.Mbi_MixinLoadAddress,
+ mbi_mixin.Mbi_MixinFwVersion,
+ mbi_mixin.Mbi_ExportMixinAppTrustZone,
+):
+ """Master Boot Plain RAM Image for RW61x family."""
+
+ def __init__(
+ self,
+ app: Optional[bytes] = None,
+ trust_zone: Optional[TrustZone] = None,
+ load_addr: int = 0,
+ firmware_version: int = 0,
+ ) -> None:
+ """Constructor for Master Boot Plain RAM Image for RW61x family.
+
+ :param app: Application image data, defaults to None
+ :param trust_zone: TrustZone object, defaults to None
+ :param load_addr: Load/Execution address in RAM of image, defaults to 0
+ :param firmware_version: Firmware version of image, defaults to 0
+ """
+ self.app = align_block(app) if app else None
+ self.tz = trust_zone or TrustZone.enabled()
+ self.firmware_version = firmware_version
+ self.load_address = load_addr
+ super().__init__()
+
+
+class Mbi_CrcRamRw61x(
+ MasterBootImage,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinTrustZoneMandatory,
+ mbi_mixin.Mbi_MixinLoadAddress,
+ mbi_mixin.Mbi_MixinFwVersion,
+ mbi_mixin.Mbi_ExportMixinAppTrustZone,
+ mbi_mixin.Mbi_ExportMixinCrcSign,
+):
+ """Master Boot CRC RAM Image for RW61x family."""
+
+ IMAGE_TYPE = CRC_RAM_IMAGE
+
+ def __init__(
+ self,
+ app: Optional[bytes] = None,
+ trust_zone: Optional[TrustZone] = None,
+ load_addr: int = 0,
+ firmware_version: int = 0,
+ ) -> None:
+ """Constructor for Master Boot Signed RAM Image for RW61x family.
+
+ :param app: Application image data, defaults to None
+ :param trust_zone: TrustZone object, defaults to None
+ :param load_addr: Load/Execution address in RAM of image, defaults to 0
+ :param firmware_version: Firmware version of image, defaults to 0
+ """
+ self.app = align_block(app) if app else None
+ self.tz = trust_zone or TrustZone.enabled()
+ self.load_address = load_addr
+ self.firmware_version = firmware_version
+ super().__init__()
+
+
+class Mbi_PlainSignedRamRw61x(
+ MasterBootImage,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinCertBlockV31,
+ mbi_mixin.Mbi_MixinManifest,
+ mbi_mixin.Mbi_MixinLoadAddress,
+ mbi_mixin.Mbi_MixinFwVersion,
+ mbi_mixin.Mbi_ExportMixinAppCertBlockManifest,
+ mbi_mixin.Mbi_ExportMixinEccSign,
+):
+ """Master Boot Plain Signed RAM Image for RW61x family."""
+
+ IMAGE_TYPE = SIGNED_RAM_IMAGE
+
+ def __init__(
+ self,
+ app: Optional[bytes] = None,
+ load_addr: int = 0,
+ firmware_version: int = 0,
+ trust_zone: Optional[TrustZone] = None,
+ cert_block: Optional[CertBlockV31] = None,
+ manifest: Optional[mbi_mixin.MasterBootImageManifest] = None,
+ signature_provider: Optional[SignatureProvider] = None,
+ ) -> None:
+ """Constructor for Master Boot Plain Signed RAM Image for RTxxx family.
+
+ :param app: Application image data, defaults to None
+ :param load_addr: Load/Execution address in RAM of image, defaults to 0
+ :param firmware_version: Firmware version of image, defaults to 0
+ :param trust_zone: TrustZone object, defaults to None
+ :param cert_block: Certification block of image, defaults to None
+ :param manifest: Manifest of image, defaults to None
+ :param signature_provider: Signature provider to sign final image, defaults to None
+ """
+ self.app = align_block(app) if app else None
+ self.app_ext_memory_align = 0x1000
+
+ self.load_address = load_addr
+ self.firmware_version = firmware_version
+ self.tz = trust_zone or TrustZone.enabled()
+ self.cert_block = cert_block
+ self.manifest = manifest
+ self.signature_provider = signature_provider
+ super().__init__()
+
+
+class Mbi_PlainExtXipSignedRw61x(
+ MasterBootImage,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinCertBlockV31,
+ mbi_mixin.Mbi_MixinManifest,
+ mbi_mixin.Mbi_MixinLoadAddress,
+ mbi_mixin.Mbi_MixinFwVersion,
+ mbi_mixin.Mbi_ExportMixinAppCertBlockManifest,
+ mbi_mixin.Mbi_ExportMixinEccSign,
+):
+ """Master Boot Signed XIP Image stored in external memory for RW61x family."""
+
+ IMAGE_TYPE = SIGNED_XIP_IMAGE
+
+ def __init__(
+ self,
+ app: Optional[bytes] = None,
+ load_addr: int = 0,
+ firmware_version: int = 0,
+ trust_zone: Optional[TrustZone] = None,
+ cert_block: Optional[CertBlockV31] = None,
+ manifest: Optional[mbi_mixin.MasterBootImageManifest] = None,
+ signature_provider: Optional[SignatureProvider] = None,
+ ) -> None:
+ """Constructor for Master Boot Signed XIP Image for RW61x family.
+
+ :param app: Application image data, defaults to None
+ :param load_addr: Load/Execution address of image, defaults to 0
+ :param firmware_version: Firmware version of image, defaults to 0
+ :param trust_zone: TrustZone object, defaults to None
+ :param cert_block: Certification block of image, defaults to None
+ :param manifest: Manifest of image, defaults to None
+ :param signature_provider: Signature provider to sign final image, defaults to None
+ """
+ self.app = align_block(app) if app else None
+ self.app_ext_memory_align = 0x1000
+ self.load_address = load_addr
+ self.firmware_version = firmware_version
+ self.tz = trust_zone or TrustZone.enabled()
+ self.cert_block = cert_block
+ self.manifest = manifest
+ self.signature_provider = signature_provider
+ super().__init__()
+
+
+class Mbi_CrcExtXipRw61x(
+ MasterBootImage,
+ mbi_mixin.Mbi_MixinApp,
+ mbi_mixin.Mbi_MixinIvt,
+ mbi_mixin.Mbi_MixinTrustZoneMandatory,
+ mbi_mixin.Mbi_MixinLoadAddress,
+ mbi_mixin.Mbi_MixinFwVersion,
+ mbi_mixin.Mbi_ExportMixinAppTrustZone,
+ mbi_mixin.Mbi_ExportMixinCrcSign,
+):
+ """Master Boot CRC XiP Image for RW61x family."""
+
+ IMAGE_TYPE = CRC_XIP_IMAGE
+
+ def __init__(
+ self,
+ app: Optional[bytes] = None,
+ trust_zone: Optional[TrustZone] = None,
+ load_addr: int = 0,
+ firmware_version: int = 0,
+ ) -> None:
+ """Constructor for Master Boot CRC XiP Image stored in external memory for RW61x family.
+
+ :param app: Application image data, defaults to None
+ :param trust_zone: TrustZone object, defaults to None
+ :param load_addr: Load/Execution address of image, defaults to 0
+ :param firmware_version: Firmware version of image, defaults to 0
+ """
+ self.app = align_block(app) if app else None
+ self.app_ext_memory_align = 0x1000
+ self.tz = trust_zone or TrustZone.enabled()
+ self.load_address = load_addr
+ self.firmware_version = firmware_version
+ super().__init__()
diff --git a/spsdk/image/trustzone.py b/spsdk/image/trustzone.py
index 78f26117..95d4992d 100644
--- a/spsdk/image/trustzone.py
+++ b/spsdk/image/trustzone.py
@@ -12,6 +12,7 @@
from typing import Any, Dict, List, Optional
from spsdk import SPSDKError
+from spsdk.exceptions import SPSDKValueError
from spsdk.image import TZ_SCH_FILE
from spsdk.utils.database import Database
from spsdk.utils.easy_enum import Enum
@@ -24,9 +25,9 @@
class TrustZoneType(Enum):
"""Enum defining various types of TrustZone types."""
- ENABLED = (0x00, "TrustZone enabled with default settings")
- CUSTOM = (0x20, "TrustZone enabled with custom settings")
- DISABLED = (0x40, "Disabled")
+ ENABLED = (0x0, "TrustZone enabled with default settings")
+ CUSTOM = (0x1, "TrustZone enabled with custom settings")
+ DISABLED = (0x2, "Disabled")
class TrustZone:
@@ -131,6 +132,21 @@ def __init__(
f"{[item for item in self.customs if item not in self.presets]}"
)
+ @classmethod
+ def get_preset_data_size(cls, family: str, revision: str = "latest") -> int:
+ """Get size of preset data in binary form.
+
+ :param family: Family description.
+ :param revision: Chip revision specification, as default, latest is used.
+ :raises SPSDKValueError: Family or revision is not supported.
+ :return: Size of TZ data.
+ """
+ database = cls.load_database()
+ file_name = database.devices.get_by_name(family).revisions.get(revision).data_file
+ if not file_name:
+ raise SPSDKValueError(f"Data file for {family} does't exist!")
+ return len(load_configuration(os.path.join(TrustZone.PRESET_DIR, file_name))) * 4
+
@classmethod
def get_validation_schemas_family(cls) -> List[Dict[str, Any]]:
"""Create the validation schema just for supported families.
@@ -258,17 +274,25 @@ def _get_preset_file(self) -> str:
def _load_presets(self) -> dict:
"""Load default TrustZone settings for given family and revision."""
- return load_configuration(self._get_preset_file())
+ presets = load_configuration(self._get_preset_file())
+ # Unify the values format
+ return {name: format_value(value_to_int(value), 32) for name, value in presets.items()}
def _parse_raw_data(self, raw_data: bytes) -> dict:
"""Parse raw data into 'customizations' format."""
- if len(self.presets) != len(raw_data) // 4:
+ if len(self.presets) > len(raw_data) // 4:
raise SPSDKError(
"Trustzone binary file has incorrect raw_data length\n"
f"Expected: {len(self.presets)}, Got: {len(raw_data) // 4}"
)
- registers = struct.unpack(f"<{len(raw_data) // 4}L", raw_data)
+ if len(self.presets) != len(raw_data) // 4:
+ logger.warning(
+ "Trustzone binary file has incorrect raw_data length\n"
+ f"Expected: {len(self.presets)}, Got: {len(raw_data) // 4}"
+ )
+
+ registers = struct.unpack(f"<{len(self.presets)}L", raw_data[: len(self.presets) * 4])
customs = {name: format_value(registers[i], 32) for i, name in enumerate(self.presets)}
return customs
@@ -282,10 +306,9 @@ def _custom_export(self) -> bytes:
raise SPSDKError("Preset data not present")
if self.customs is None:
raise SPSDKError("Data not present")
- logger.info(f"{len(self.presets)} registers loaded from defaults")
- logger.debug(self.presets)
- logger.info(f"{len(self.customs)} modifications provided")
- logger.debug(self.customs)
+ modifications = set(self.customs.items()) - set(self.presets.items())
+ logger.info(f"{len(modifications)} modifications provided")
+ logger.debug(str(modifications).replace(", ", "\n"))
data = self.presets
data.update(self.customs)
registers = [value_to_int(item) for item in data.values()]
diff --git a/spsdk/image/xmcd/xmcd.py b/spsdk/image/xmcd/xmcd.py
index b6d2eea8..1ede8495 100644
--- a/spsdk/image/xmcd/xmcd.py
+++ b/spsdk/image/xmcd/xmcd.py
@@ -326,12 +326,12 @@ def _load_block_registers(
:param mem_type: Used memory type.
:param config_type: Config type: either simplified or full.
:param revision: Chip revision specification, as default, latest is used.
- :raises SPSDKValueError: Unknown mem_type or config type
+ :raises SPSDKKeyError: Unknown mem_type or config type
"""
try:
block_config = XMCD.get_memory_types(family, revision)[mem_type][config_type]
- except KeyError:
- raise SPSDKValueError(f"Unsupported combination: {mem_type}:{config_type}")
+ except KeyError as exc:
+ raise SPSDKKeyError(f"Unsupported combination: {mem_type}:{config_type}") from exc
block_file_path = os.path.join(XMCD_DATA_FOLDER, block_config)
regs = Registers(family, base_endianness="little")
regs.load_registers_from_xml(block_file_path, filter_reg=filter_reg)
diff --git a/spsdk/mboot/interfaces/__init__.py b/spsdk/mboot/interfaces/__init__.py
index 85a130b1..64a4dc88 100644
--- a/spsdk/mboot/interfaces/__init__.py
+++ b/spsdk/mboot/interfaces/__init__.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#
-# Copyright (c) 2019-2022 NXP
+# Copyright (c) 2019-2023 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
@@ -10,6 +10,7 @@
from .base import Interface, MBootInterface
from .buspal_i2c import scan_buspal_i2c
from .buspal_spi import scan_buspal_spi
+from .sdio import Sdio, scan_sdio
from .uart import Uart, scan_uart
from .usb import RawHid, scan_usb
-from .usbsio import UsbSioI2C, UsbSioSPI, scan_usbsio, scan_usbsio_i2c, scan_usbsio_spi
+from .usbsio import UsbSio, UsbSioI2C, UsbSioSPI, scan_usbsio, scan_usbsio_i2c, scan_usbsio_spi
diff --git a/spsdk/mboot/interfaces/buspal_i2c.py b/spsdk/mboot/interfaces/buspal_i2c.py
index c65ad71a..004d6c43 100644
--- a/spsdk/mboot/interfaces/buspal_i2c.py
+++ b/spsdk/mboot/interfaces/buspal_i2c.py
@@ -122,7 +122,7 @@ def _send_frame(
retry_cnt -= 1
self._send_frame(frames, wait_for_ack, retry_cnt)
else:
- raise SPSDKError("Failed retrying reading the I2C header frame")
+ raise SPSDKError("Failed retrying reading the I2C header frame") from error
def _read_default(self, size: int) -> bytes:
"""Read 'length' amount of bytes from BUSPAL I2C device.
diff --git a/spsdk/mboot/interfaces/buspal_spi.py b/spsdk/mboot/interfaces/buspal_spi.py
index 357a6e85..9cf13366 100644
--- a/spsdk/mboot/interfaces/buspal_spi.py
+++ b/spsdk/mboot/interfaces/buspal_spi.py
@@ -169,7 +169,7 @@ def _send_frame(
retry_cnt -= 1
self._send_frame(frames, wait_for_ack, retry_cnt)
else:
- raise SPSDKError("Failed retrying reading the SPI header frame")
+ raise SPSDKError("Failed retrying reading the SPI header frame") from error
def _read_default(self, size: int) -> bytes:
"""Read 'length' amount of bytes from BUSPAL SPI device.
diff --git a/spsdk/mboot/interfaces/sdio.py b/spsdk/mboot/interfaces/sdio.py
new file mode 100644
index 00000000..b3e23b85
--- /dev/null
+++ b/spsdk/mboot/interfaces/sdio.py
@@ -0,0 +1,429 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+#
+# Copyright 2022-2023 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+"""Module for serial communication with a target device using MBoot protocol."""
+
+import logging
+import os
+import struct
+import time
+from io import FileIO
+from typing import List, Optional, Tuple, Union
+
+from crcmod.predefined import mkPredefinedCrcFun
+
+from spsdk.mboot.commands import CmdPacket, CmdResponse, parse_cmd_response
+from spsdk.mboot.exceptions import McuBootConnectionError, McuBootDataAbortError, McuBootError
+from spsdk.utils.easy_enum import Enum
+from spsdk.utils.misc import Timeout
+
+from .base import MBootInterface
+
+logger = logging.getLogger(__name__)
+
+########################################################################################################################
+# Devices
+########################################################################################################################
+
+SDIO_DEVICES = {
+ # NAME | VID | PID
+ "RW61x": (0x0471, 0x0209),
+}
+
+
+def scan_sdio(device_path: Optional[str] = None) -> List["Sdio"]:
+ """Scan connected SDIO devices.
+
+ :param device_path: device path string
+ :return: matched SDIO device
+ """
+ if device_path is None:
+ logger.debug("No sdio path")
+ return []
+ try:
+ logger.debug(f"Checking path: {device_path}")
+ interface = Sdio(path=device_path)
+ interface.open()
+ interface.close()
+ return [interface] if interface else []
+ except Exception as e: # pylint: disable=broad-except
+ logger.debug(f"{type(e).__name__}: {e}")
+ return []
+
+
+def calc_crc(data: bytes) -> int:
+ """Calculate CRC from the data.
+
+ :param data: data to calculate CRC from
+ :return: calculated CRC
+ """
+ crc_function = mkPredefinedCrcFun("xmodem")
+ return crc_function(data)
+
+
+########################################################################################################################
+# SDIO Interface Class
+########################################################################################################################
+class FPType(Enum):
+ """Type of frames used in serial communication."""
+
+ ACK = 0xA1
+ NACK = 0xA2
+ ABORT = 0xA3
+ CMD = 0xA4
+ DATA = 0xA5
+ PING = 0xA6
+ PINGR = 0xA7
+
+
+class Sdio(MBootInterface):
+ """SDIO interface."""
+
+ FRAME_START_BYTE = 0x5A
+ FRAME_START_BYTE_NOT_READY = 0x00
+
+ @property
+ def name(self) -> str:
+ """Get the name of the device.
+
+ :return: Name of the device.
+ """
+ for name, value in SDIO_DEVICES.items():
+ if value[0] == self.vid and value[1] == self.pid:
+ return name
+ return "Unknown"
+
+ @property
+ def is_opened(self) -> bool:
+ """Indicates whether device is open.
+
+ :return: True if device is open, False othervise.
+ """
+ return self.device is not None and self._opened
+
+ def __init__(self, path: Optional[str] = None) -> None:
+ """Initialize the SDIO interface object.
+
+ :raises McuBootConnectionError: when the path is empty
+ """
+ super().__init__()
+ self._opened = False
+ # Temporarily use hard code until there is a way to retrive VID/PID
+ self.vid = 0x0471
+ self.pid = 0x0209
+ self.timeout = 2000
+ if path is None:
+ raise McuBootConnectionError("No SDIO device path")
+ self.path = path
+ self.is_blocking = False
+ self.device: Optional[FileIO] = None
+
+ def info(self) -> str:
+ """Return information about the SDIO interface."""
+ return f"{self.name:s} (0x{self.vid:04X}, 0x{self.pid:04X})"
+
+ def open(self) -> None:
+ """Open the interface with non-blocking mode.
+
+ :raises McuBootError: if non-blocking mode is not available
+ :raises McuBootConnectionError: if no device path is available
+ :raises McuBootConnectionError: if no device is available
+ :raises McuBootConnectionError: if the device can not be opened
+ """
+ if self.is_blocking:
+ logger.debug("open with blocking mode")
+ self.open_blocking()
+ return
+
+ logger.debug("Open Interface with non-blocking mode.")
+ if not hasattr(os, "set_blocking"):
+ raise McuBootError("Opening in non-blocking mode is available only on Linux")
+ if not self._opened:
+ try:
+ self.device = open(self.path, "rb+", buffering=0)
+ if self.device is None:
+ raise McuBootConnectionError("No device available")
+ # pylint: disable=no-member # this is available only on Unix
+ os.set_blocking(self.device.fileno(), False) # type: ignore
+ self._opened = True
+ except Exception as error:
+ raise McuBootConnectionError(
+ f"Unable to open device '{self.path}' VID={self.vid} PID={self.pid}"
+ ) from error
+
+ def open_blocking(self) -> None:
+ """Open the interface with blocking mode.
+
+ :raises McuBootConnectionError: if no device is available
+ :raises McuBootConnectionError: if the device can not be opened
+ """
+ logger.debug("Open Interface")
+ if not self._opened:
+ try:
+ self.device = open(self.path, "rb+", buffering=0)
+ self._opened = True
+ except Exception as error:
+ raise McuBootConnectionError(
+ f"Unable to open device '{self.path}' VID={self.vid} PID={self.pid}"
+ ) from error
+
+ def close(self) -> None:
+ """Close the interface.
+
+ :raises McuBootConnectionError: if no device is available
+ :raises McuBootConnectionError: if the device can not be opened
+ """
+ logger.debug("Close Interface")
+ if not self.device:
+ raise McuBootConnectionError("No device available")
+ if self._opened:
+ try:
+ self.device.close()
+ self._opened = False
+ except Exception as error:
+ raise McuBootConnectionError(
+ f"Unable to close device '{self.path}' VID={self.vid} PID={self.pid}"
+ ) from error
+
+ def write(self, packet: Union[CmdPacket, bytes]) -> None:
+ """Write data to the SDIO interface; data might be in form of 'CmdPacket' or bytes.
+
+ :param packet: Data to send
+ :raises McuBootError: Raises an error if packet type is incorrect
+ :raises McuBootConnectionError: Raises an error if device is not opened for writing
+ :raises McuBootConnectionError: Raises an error if device is not available
+ """
+ if not self.device:
+ raise McuBootConnectionError("No device available")
+ if not self.is_opened:
+ raise McuBootConnectionError("Device is opened for writing")
+
+ if isinstance(packet, CmdPacket):
+ data = packet.to_bytes(padding=False)
+ frame_type = FPType.CMD
+ elif isinstance(packet, (bytes, bytearray)):
+ data = packet
+ frame_type = FPType.DATA
+ else:
+ raise McuBootError("Packet has to be either 'CmdPacket' or 'bytes'")
+
+ frame = self._create_frame(data, frame_type)
+ self._send_frame(frame, wait_for_ack=True)
+
+ def _write(self, data: bytes) -> None:
+ """Send data to device with non-blocking mode.
+
+ :param data: Data to send
+ :raises McuBootConnectionError: Raises an error if device is not available
+ :raises McuBootConnectionError: When sending the data fails
+ :raises TimeoutError: When timeout occurs
+ """
+ if not self.device:
+ raise McuBootConnectionError("No device available")
+
+ if self.is_blocking:
+ logger.debug("_write with blocking mode")
+ self._write_blocking(data)
+ return
+
+ logger.debug("_write with non-blocking mode")
+ logger.debug(f"[{' '.join(f'{b:02x}' for b in data)}]")
+ tx_len = len(data)
+ timeout = Timeout(self.timeout)
+ while tx_len > 0:
+ try:
+ wr_count = self.device.write(data)
+ time.sleep(0.05)
+ data = data[wr_count:]
+ tx_len -= wr_count
+ except Exception as e:
+ raise McuBootConnectionError(str(e)) from e
+ if timeout.overflow():
+ raise TimeoutError()
+
+ def _write_blocking(self, data: bytes) -> None:
+ """Send data to device with blocking mode.
+
+ :param data: Data to send
+ :raises McuBootConnectionError: Raises an error if device is not available
+ :raises McuBootConnectionError: When sending the data fails
+ """
+ if not self.device:
+ raise McuBootConnectionError("No device available")
+
+ logger.debug(f"[{' '.join(f'{b:02x}' for b in data)}]")
+ try:
+ self.device.write(data)
+ except Exception as e:
+ raise McuBootConnectionError(str(e)) from e
+
+ def read(self) -> Union[CmdResponse, bytes]:
+ """Read data on the IN endpoint associated to the HID interface.
+
+ :return: Return CmdResponse object.
+ :raises McuBootConnectionError: Raises an error if device is not opened for reading
+ :raises McuBootConnectionError: Raises if device is not available
+ :raises McuBootDataAbortError: Raises if reading fails
+ :raises TimeoutError: When timeout occurs
+ """
+ if not self.is_opened:
+ raise McuBootConnectionError("Device is not opened for reading")
+ if not self.device:
+ raise McuBootConnectionError("Device not available")
+
+ raw_data = self._read(1024)
+ if not raw_data:
+ logger.error("Cannot read from SDIO device")
+ raise TimeoutError()
+
+ _, frame_type = self._parse_frame_header(raw_data)
+ length, crc = struct.unpack_from(" bytes:
+ """Read 'length' amount for bytes from device with non-blocking mode.
+
+ :param length: Number of bytes to read
+ :return: Data read from the device
+ :raises TimeoutError: When timeout occurs
+ :raises McuBootConnectionError: When reading data from device fails
+ :raises McuBootConnectionError: Raises if device is not available
+ """
+ if not self.device:
+ raise McuBootConnectionError("Device not available")
+
+ if self.is_blocking:
+ logger.debug("_read with blocking mode")
+ data = self._read_blocking(length)
+ return data
+
+ has_data = 0
+ no_data_continuous = 0
+ logger.debug("_read with non-blocking mode")
+ data = bytearray()
+ timeout = Timeout(self.timeout, "ms")
+ while len(data) < length:
+ try:
+ buf = self.device.read(length)
+ except Exception as e:
+ raise McuBootConnectionError(str(e)) from e
+
+ if buf is None:
+ time.sleep(0.05) # delay for access device
+ if has_data != 0:
+ no_data_continuous = no_data_continuous + 1
+ else:
+ data.extend(buf)
+ logger.debug("expend buf")
+ has_data = has_data + 1
+ no_data_continuous = 0
+
+ if no_data_continuous > 5:
+ break
+ if timeout.overflow():
+ logger.debug("SDIO interface : read timeout")
+ break
+ if not data:
+ raise TimeoutError()
+ logger.debug(f"<{' '.join(f'{b:02x}' for b in data)}>")
+ return bytes(data)
+
+ def _read_blocking(self, length: int) -> bytes:
+ """Read 'length' amount for bytes from device with blocking mode.
+
+ :param length: Number of bytes to read
+ :return: Data read from the device
+ :raises TimeoutError: When timeout occurs
+ :raises McuBootConnectionError: When reading data from device fails
+ :raises McuBootConnectionError: Raises if device is not available
+ """
+ if not self.device:
+ raise McuBootConnectionError("Device not available")
+
+ try:
+ data = self.device.read(length)
+ except Exception as e:
+ raise McuBootConnectionError(str(e)) from e
+ if not data:
+ raise TimeoutError()
+ logger.debug(f"<{' '.join(f'{b:02x}' for b in data)}>")
+ return data
+
+ def _send_ack(self) -> None:
+ ack_frame = struct.pack(" None:
+ """Send a frame to SDIO.
+
+ :param frame: Data to send
+ :param wait_for_ack: Wait for ACK frame from device, defaults to True
+ """
+ self._write(frame)
+ if wait_for_ack:
+ data = self._read(2)
+ self._parse_frame_header(data, FPType.ACK)
+
+ def _parse_frame_header(
+ self, frame: bytes, expected_frame_type: Optional[int] = None
+ ) -> Tuple[int, int]:
+ """Read frame header and frame type. Return them as tuple of integers.
+
+ :param expected_frame_type: Check if the frame_type is exactly as expected
+ :return: Tuple of integers representing frame header and frame type
+ :raises McuBootDataAbortError: Target sens Data Abort frame
+ :raises McuBootConnectionError: Unexpected frame header or frame type (if specified)
+ :raises McuBootConnectionError: When received invalid ACK
+ """
+ header, frame_type = struct.unpack_from(" bytes:
+ """Encapsulate data into frame."""
+ crc = self._calc_frame_crc(data, frame_type)
+ frame = struct.pack(
+ f" int:
+ """Calculate the CRC of a frame.
+
+ :param data: frame data
+ :param frame_type: frame type
+ :return: calculated CRC
+ """
+ crc_data = struct.pack(
+ f" None:
except Exception as e:
raise McuBootConnectionError(str(e)) from e
+ if _bytes_written < 0 or _bytes_written < len(raw_data):
+ raise McuBootConnectionError(
+ f"Invalid size of written bytes has been detected: {_bytes_written} != {len(raw_data)}"
+ )
+
def read(self) -> Union[CmdResponse, bytes]:
"""Read data on the IN endpoint associated to the HID interface.
diff --git a/spsdk/mboot/mcuboot.py b/spsdk/mboot/mcuboot.py
index 52a71362..1a147fad 100644
--- a/spsdk/mboot/mcuboot.py
+++ b/spsdk/mboot/mcuboot.py
@@ -230,6 +230,8 @@ def _send_data(
logger.error(f"RX: {e}")
if expect_response:
response = self._device.read()
+ else:
+ self._status_code = StatusCode.SENDING_OPERATION_CONDITION_ERROR
if expect_response:
assert isinstance(response, CmdResponse)
@@ -243,7 +245,7 @@ def _send_data(
return False
logger.info(f"CMD: Successfully Send {total_sent} out of {total_to_send} Bytes")
- return True
+ return total_sent == total_to_send
def _get_max_packet_size(self) -> int:
"""Get max packet size.
@@ -723,19 +725,30 @@ def reset(self, timeout: int = 2000, reopen: bool = True) -> bool:
logger.info("CMD: Reset MCU")
cmd_packet = CmdPacket(CommandTag.RESET, CommandFlag.NONE)
ret_val = False
- if self._process_cmd(cmd_packet).status == StatusCode.SUCCESS:
- self.close()
- ret_val = True
- if reopen:
- if not self.reopen:
- raise McuBootError("reopen is not supported")
- time.sleep(timeout / 1000)
- try:
- self.open()
- except SPSDKError as e:
- ret_val = False
- if self._cmd_exception:
- raise McuBootConnectionError("reopen failed") from e
+ status = self._process_cmd(cmd_packet).status
+ self.close()
+ ret_val = True
+
+ if status not in [StatusCode.NO_RESPONSE, StatusCode.SUCCESS]:
+ ret_val = False
+ if self._cmd_exception:
+ raise McuBootConnectionError("Reset command failed")
+
+ if status == StatusCode.NO_RESPONSE:
+ logger.warning("Did not receive response from reset command, ignoring it")
+ self._status_code = 0
+
+ if reopen:
+ if not self.reopen:
+ raise McuBootError("reopen is not supported")
+ time.sleep(timeout / 1000)
+ try:
+ self.open()
+ except SPSDKError as e:
+ ret_val = False
+ if self._cmd_exception:
+ raise McuBootConnectionError("reopen failed") from e
+
return ret_val
def flash_erase_all_unsecure(self) -> bool:
diff --git a/spsdk/sbfile/sb2/bd_ebnf_grammar.txt b/spsdk/sbfile/sb2/bd_ebnf_grammar.txt
index 01601269..50d8ba63 100644
--- a/spsdk/sbfile/sb2/bd_ebnf_grammar.txt
+++ b/spsdk/sbfile/sb2/bd_ebnf_grammar.txt
@@ -23,7 +23,6 @@ source_value ::= STRING_LITERAL
option_list ::= IDENT '=' const_expr (',' IDENT '=' const_expr )*
-# keyblob_block ::= KEYBLOB '(' int_const_expr ')' '{' keyblob_contents* '}'
keyblob_block ::= KEYBLOB '(' int_const_expr ')' '{' keyblob_contents '}'
keyblob_contents ::= '(' option_list* ')'
@@ -128,6 +127,11 @@ enable_stmt ::= ENABLE AT_INT_LITERAL int_const_expr
reset_stmt ::= RESET
+ver_check_stmt ::= VERSION_CHECK sec_or_nsec int_const_expr
+
+sec_or_nsec ::= SEC
+| NSEC
+
const_expr ::= STRING_LITERAL
| bool_expr
diff --git a/spsdk/sbfile/sb2/bd_grammer.txt b/spsdk/sbfile/sb2/bd_grammer.txt
index 3ba59e7e..51f8e7fd 100644
--- a/spsdk/sbfile/sb2/bd_grammer.txt
+++ b/spsdk/sbfile/sb2/bd_grammer.txt
@@ -161,6 +161,11 @@ enable_stmt ::= ENABLE AT_INT_LITERAL int_const_expr
reset_stmt ::= RESET
+ver_check_stmt ::= VERSION_CHECK sec_or_nsec int_const_expr
+
+sec_or_nsec ::= SEC
+| NSEC
+
const_expr ::= STRING_LITERAL
| bool_expr
diff --git a/spsdk/sbfile/sb2/images.py b/spsdk/sbfile/sb2/images.py
index f4e6590b..8a23bd4f 100644
--- a/spsdk/sbfile/sb2/images.py
+++ b/spsdk/sbfile/sb2/images.py
@@ -15,12 +15,14 @@
from spsdk import SPSDKError
from spsdk.apps.utils import get_key
from spsdk.crypto.loaders import load_certificate_as_bytes
+from spsdk.crypto.signature_provider import SignatureProvider
+from spsdk.exceptions import SPSDKUnsupportedOperation
from spsdk.utils.crypto import CertBlockV2, Counter, crypto_backend
from spsdk.utils.crypto.abstract import BaseClass
from spsdk.utils.crypto.backend_internal import internal_backend
from spsdk.utils.crypto.certificate import Certificate
from spsdk.utils.crypto.common import calc_cypher_block_count
-from spsdk.utils.misc import find_first, load_binary, load_text, write_file
+from spsdk.utils.misc import find_first, load_text, write_file
from . import sb_21_helper as elf2sb_helper21
from . import sly_bd_parser as bd_parser
@@ -132,7 +134,7 @@ def __init__(
self._kek = kek
# Set Flags value
self._signed = signed
- self._private_key_pem_data: Optional[bytes] = None
+ self._signature_provider: Optional[SignatureProvider] = None
flags = 0x08 if self.signed else 0x04
# Set private attributes
self._dek: bytes = advanced_params.dek
@@ -184,17 +186,20 @@ def kek(self) -> bytes:
return self._kek
@property
- def private_key_pem_data(self) -> Optional[bytes]:
- """Return private key data for signed images, decrypted in PEM format."""
- return self._private_key_pem_data
+ def signature_provider(self) -> Optional[SignatureProvider]:
+ """Signature provider instance to sign the final image.
- @private_key_pem_data.setter
- def private_key_pem_data(self, value: bytes) -> None:
- """Setter to be used for signed images.
+ None if not assigned yet.
+ """
+ return self._signature_provider
+
+ @signature_provider.setter
+ def signature_provider(self, value: SignatureProvider) -> None:
+ """Signature provider setter.
- :param: key for signing the image; decrypted binary data in PEM format
+ :param value: Signature provider to sign final image
"""
- self._private_key_pem_data = value
+ self._signature_provider = value
@property
def signed(self) -> bool:
@@ -372,16 +377,26 @@ def export(self, padding: Optional[bytes] = None) -> bytes:
data += sect.export(dek=self.dek, mac=self.mac, counter=counter)
# Add Signature data
if self.signed:
- private_key_pem_data = self.private_key_pem_data
- if private_key_pem_data is None:
- raise SPSDKError("Private key not assigned, cannot sign the image")
- certificate_block = self.cert_block
- if not (
- (certificate_block is not None)
- and certificate_block.verify_private_key(private_key_pem_data)
- ):
- raise SPSDKError("Invalid certificate block")
- data += crypto_backend().rsa_sign(private_key_pem_data, data)
+ if self.signature_provider is None:
+ raise SPSDKError("Signature provider is not assigned, cannot sign the image.")
+ if self.cert_block is None:
+ raise SPSDKError("Certificate block is not assigned.")
+
+ public_key = self.cert_block.certificates[-1].public_key
+ try:
+ result = self.signature_provider.verify_public_key(public_key.dump())
+ if not result:
+ raise SPSDKError(
+ "Signature verification failed, public key does not match to certificate"
+ )
+ logger.debug("The verification of private key pair integrity has been successful.")
+ except SPSDKUnsupportedOperation:
+ logger.warning(
+ "Signature provider could not verify the integrity of private key pair."
+ )
+
+ data += self.signature_provider.sign(data)
+
if len(data) != self.raw_size:
raise SPSDKError("Invalid length of exported data")
return data
@@ -495,8 +510,8 @@ def __init__(
:param sections: Boot sections
"""
self._kek = kek
- self._private_key_pem_data: Optional[
- bytes
+ self._signature_provider: Optional[
+ SignatureProvider
] = None # this should be assigned for export, not needed for parsing
self._dek = advanced_params.dek
self._mac = advanced_params.mac
@@ -510,7 +525,7 @@ def __init__(
timestamp=advanced_params.timestamp,
)
self._cert_block: Optional[CertBlockV2] = None
- self._boot_sections: List[BootSectionV2] = []
+ self.boot_sections: List[BootSectionV2] = []
# ...
for section in sections:
self.add_boot_section(section)
@@ -536,20 +551,20 @@ def kek(self) -> bytes:
return self._kek
@property
- def private_key_pem_data(self) -> Optional[bytes]:
- """Return binary data of private key for signing; decrypted binary data in PEM format.
+ def signature_provider(self) -> Optional[SignatureProvider]:
+ """Signature provider instance to sign the final image.
- None if not assigned yet or image not signed.
+ None if not assigned yet.
"""
- return self._private_key_pem_data
+ return self._signature_provider
- @private_key_pem_data.setter
- def private_key_pem_data(self, value: bytes) -> None:
- """Setter.
+ @signature_provider.setter
+ def signature_provider(self, value: SignatureProvider) -> None:
+ """Signature provider setter.
- :param: key for signing the image; decrypted binary data in PEM format
+ :param value: Signature provider to sign final image
"""
- self._private_key_pem_data = value
+ self._signature_provider = value
@property
def cert_block(self) -> Optional[CertBlockV2]:
@@ -596,26 +611,26 @@ def raw_size(self) -> int:
raise SPSDKError("Certificate block is not signed")
size += cert_blk.signature_size
# Boot Sections
- for boot_section in self._boot_sections:
+ for boot_section in self.boot_sections:
size += boot_section.raw_size
return size
def __len__(self) -> int:
- return len(self._boot_sections)
+ return len(self.boot_sections)
def __getitem__(self, key: int) -> BootSectionV2:
- return self._boot_sections[key]
+ return self.boot_sections[key]
def __setitem__(self, key: int, value: BootSectionV2) -> None:
- self._boot_sections[key] = value
+ self.boot_sections[key] = value
def __iter__(self) -> Iterator[BootSectionV2]:
- return self._boot_sections.__iter__()
+ return self.boot_sections.__iter__()
def update(self) -> None:
"""Update BootImageV21."""
- if self._boot_sections:
- self._header.first_boot_section_id = self._boot_sections[0].uid
+ if self.boot_sections:
+ self._header.first_boot_section_id = self.boot_sections[0].uid
# calculate first boot tag block
data_size = self._header.SIZE + self.HEADER_MAC_SIZE + self.KEY_BLOB_SIZE
cert_blk = self.cert_block
@@ -633,7 +648,7 @@ def update(self) -> None:
)
# Get HMAC count
self._header.max_section_mac_count = 0
- for boot_sect in self._boot_sections:
+ for boot_sect in self.boot_sections:
boot_sect.is_last = True # unified with elftosb
self._header.max_section_mac_count += boot_sect.hmac_count
# Update certificates block header
@@ -652,7 +667,7 @@ def info(self) -> str:
nfo += "::::::::::::::::::::::::::::::: CERTIFICATES BLOCK ::::::::::::::::::::::::::::::::::::\n"
nfo += self.cert_block.info()
nfo += "::::::::::::::::::::::::::::::::::: BOOT SECTIONS ::::::::::::::::::::::::::::::::::::\n"
- for index, section in enumerate(self._boot_sections):
+ for index, section in enumerate(self.boot_sections):
nfo += f"[ SECTION: {index} | UID: 0x{section.uid:08X} ]\n"
nfo += section.info()
return nfo
@@ -665,7 +680,7 @@ def add_boot_section(self, section: BootSectionV2) -> None:
"""
if not isinstance(section, BootSectionV2):
raise SPSDKError("Section is not instance of BootSectionV2 class")
- self._boot_sections.append(section)
+ self.boot_sections.append(section)
# pylint: disable=too-many-locals
def export(
@@ -684,12 +699,12 @@ def export(
:raises SPSDKError: Raised when there is no debug info
"""
# validate params
- if not self._boot_sections:
+ if not self.boot_sections:
raise SPSDKError("At least one Boot Section must be added")
if self.cert_block is None:
raise SPSDKError("Certificate is not assigned")
- if self.private_key_pem_data is None:
- raise SPSDKError("Private key not assigned, cannot sign the image")
+ if self.signature_provider is None:
+ raise SPSDKError("Signature provider is not assigned, cannot sign the image")
# Update internals
if dbg_info is not None:
dbg_info.append("[sb_file]")
@@ -710,7 +725,7 @@ def export(
if not self._header.nonce:
raise SPSDKError("Invalid header's nonce")
counter = Counter(self._header.nonce, calc_cypher_block_count(bs_offset))
- for sect in self._boot_sections:
+ for sect in self.boot_sections:
bs_data += sect.export(
dek=self.dek, mac=self.mac, counter=counter, dbg_info=bs_dbg_info
)
@@ -720,7 +735,7 @@ def export(
dbg_info.append("[header]")
dbg_info.append(signed_data.hex())
# Add HMAC data
- first_bs_hmac_count = self._boot_sections[0].hmac_count
+ first_bs_hmac_count = self.boot_sections[0].hmac_count
hmac_data = bs_data[CmdHeader.SIZE : CmdHeader.SIZE + (first_bs_hmac_count * 32) + 32]
hmac = crypto_backend().hmac(self.mac, hmac_data)
signed_data += hmac
@@ -742,10 +757,20 @@ def export(
# Add SHA-256 of Bootable sections if requested
if self.header.flags & self.FLAGS_SHA_PRESENT_BIT:
signed_data += internal_backend.hash(bs_data)
+
# Add Signature data
- if not self.cert_block.verify_private_key(self.private_key_pem_data):
- raise SPSDKError("Private key does not match certificate")
- signature = crypto_backend().rsa_sign(self.private_key_pem_data, signed_data)
+ public_key = self.cert_block.certificates[-1].public_key
+ try:
+ result = self.signature_provider.verify_public_key(public_key.dump())
+ if not result:
+ raise SPSDKError(
+ "Signature verification failed, public key does not match to certificate"
+ )
+ logger.debug("The verification of private key pair integrity has been successful.")
+ except SPSDKUnsupportedOperation:
+ logger.warning("Signature provider could not verify the integrity of private key pair.")
+
+ signature = self.signature_provider.sign(signed_data)
if dbg_info:
dbg_info.append("[signature]")
dbg_info.append(signature.hex())
@@ -859,7 +884,7 @@ def parse(
def generate_SB21( # pylint: disable=invalid-name
bd_file_path: str,
key_file_path: str,
- private_key_file_path: str,
+ signature_provider: SignatureProvider,
signing_certificate_file_paths: List[str],
root_key_certificate_paths: List[str],
hoh_out_path: str,
@@ -869,8 +894,7 @@ def generate_SB21( # pylint: disable=invalid-name
:param bd_file_path: path to BD file.
:param key_file_path: path to key file.
- :param private_key_file_path: path to private key file for signing. This key
- relates to last certificate from signing certificate chain.
+ :param signature_provider: Signature provider to sign final image
:param signing_certificate_file_paths: signing certificate chain.
:param root_key_certificate_paths: paths to root key certificate(s) for
verifying other certificates. Only 4 root key certificates are allowed,
@@ -915,7 +939,7 @@ def generate_SB21( # pylint: disable=invalid-name
"flags", BootImageV21.FLAGS_SHA_PRESENT_BIT | BootImageV21.FLAGS_ENCRYPTED_SIGNED_BIT
)
if (
- private_key_file_path is None
+ signature_provider is None
or signing_certificate_file_paths is None
or root_key_certificate_paths is None
):
@@ -1015,7 +1039,7 @@ def generate_SB21( # pylint: disable=invalid-name
# We have our secure binary, now we attach to it the certificate block and
# the private key content
secure_binary.cert_block = cert_block
- secure_binary.private_key_pem_data = load_binary(private_key_file_path)
+ secure_binary.signature_provider = signature_provider
if hoh_out_path is None:
hoh_out_path = os.path.join(os.getcwd(), "hash.bin")
diff --git a/spsdk/sbfile/sb31/commands.py b/spsdk/sbfile/sb31/commands.py
index 0995d330..932e9a7f 100644
--- a/spsdk/sbfile/sb31/commands.py
+++ b/spsdk/sbfile/sb31/commands.py
@@ -687,6 +687,12 @@ class _KeyWraps(BuiltinEnum):
NXP_CUST_KEK_INT_SK = 16
NXP_CUST_KEK_EXT_SK = 17
+ class _KeyWrapsV2(BuiltinEnum):
+ """KeyWrap IDs used by the CmdLoadKeyBlob command for mcxnx family."""
+
+ NXP_CUST_KEK_INT_SK = 18
+ NXP_CUST_KEK_EXT_SK = 19
+
class KeyTypes(BuiltinEnum):
"""KeyTypes for NXP_CUST_KEK_INT_SK, NXP_CUST_KEK_EXT_SK."""
@@ -701,7 +707,7 @@ def get_key_id(cls, family: str, key_name: KeyTypes) -> int:
:param key_name: NXP_CUST_KEK_INT_SK or NXP_CUST_KEK_EXT_SK
:return: integer value representing key
"""
- key_wraps = cls._KeyWraps
+ key_wraps = cls._KeyWrapsV2 if "mcxn" in family.lower() else cls._KeyWraps
return key_wraps[key_name.name].value
def __init__(self, offset: int, data: bytes, key_wrap_id: int) -> None:
diff --git a/spsdk/shadowregs/shadowregs.py b/spsdk/shadowregs/shadowregs.py
index 0ae7d3a0..13806b38 100644
--- a/spsdk/shadowregs/shadowregs.py
+++ b/spsdk/shadowregs/shadowregs.py
@@ -175,7 +175,8 @@ def write_reg(base_address: int, reg: RegsRegister) -> None:
write_reg(self.offset, sub_reg)
else:
write_reg(self.offset, reg=reg)
-
+ # execute flash function handler if defined for a platfrom
+ self.flush_func_handler()
except SPSDKError as exc:
raise SPSDKError(f"The set shadow register failed({str(exc)}).") from exc
@@ -338,6 +339,20 @@ def reg_antipolize_dst_handler(val: int, context: Any) -> int:
new_val = val ^ 0xFFFFFFFF
return new_val
+ def flush_func_handler(self) -> None:
+ """A function to determine and execute the flush-func handler.
+
+ :param self: Input Value.
+ :raises SPSDKError: Raises when the computing routine is not found.
+ """
+ flush_func = self.config.get_device_value("flush_func", device=self.device)
+ if flush_func:
+ if hasattr(self, flush_func):
+ method_ref = getattr(self, flush_func)
+ method_ref()
+ else:
+ raise SPSDKError(f"The '{flush_func}' function doesn't exists.")
+
def reg_computed_fields_handler(self, val: bytes, context: Any) -> bytes:
"""Recalculate all fields for given register value.
@@ -409,6 +424,15 @@ def comalg_dcfg_cc_socu_test_en(self, val: int) -> int:
return val | 0x80000000
+ def rw61x_update_scratch_reg(self) -> None:
+ """Function updates scracth register for RW61x, This enables the shadow register functionality.
+
+ :param self: Input Value.
+ """
+ addr = 0x5003B498
+ value = 0xA7C56B9E
+ self._write_shadow_reg(addr=addr, data=value, verify_mask=True)
+
@staticmethod
def comalg_do_nothing(val: int) -> int:
"""Function that do nothing.
diff --git a/spsdk/tp/adapters/utils.py b/spsdk/tp/adapters/utils.py
index 83d7ee56..0a5e44b5 100644
--- a/spsdk/tp/adapters/utils.py
+++ b/spsdk/tp/adapters/utils.py
@@ -84,7 +84,7 @@ def detect_new_usb_path(
logger.info("No changes were detected")
return None
- raise SPSDKTpError(f"USB device detected malfunctioned")
+ raise SPSDKTpError("USB device detected malfunctioned")
def update_usb_path(tptarget: TpTargetBlHost, new_usb_path: Optional[bytes]) -> None:
diff --git a/spsdk/utils/crypto/backend_openssl.py b/spsdk/utils/crypto/backend_openssl.py
index 2e05f88e..85b5e64b 100644
--- a/spsdk/utils/crypto/backend_openssl.py
+++ b/spsdk/utils/crypto/backend_openssl.py
@@ -322,6 +322,18 @@ def ecc_verify(
:return: True if the signature is valid
:raises SPSDKError: Signature length is invalid
"""
+
+ def get_std_hash(key_size: int) -> str:
+ standard_hashes = {
+ "SHA256": [163, 192, 224, 233, 256],
+ "SHA384": [283, 384],
+ "SHA512": [409, 512, 521, 570, 571],
+ }
+ for k, v in standard_hashes.items():
+ if key_size in v:
+ return k
+ raise SPSDKError(f"Unsupported key size ({key_size}), to get standard hash")
+
if isinstance(public_key, bytes):
processed_public_key = serialization.load_pem_public_key(public_key, default_backend())
if isinstance(public_key, ec.EllipticCurvePublicKey):
@@ -332,7 +344,8 @@ def ecc_verify(
raise SPSDKError(
f"Invalid signature size: expected {2 * coordinate_size}, actual: {len(signature)}"
)
- hash_name = algorithm or f"sha{processed_public_key.key_size}"
+
+ hash_name = algorithm or get_std_hash(processed_public_key.key_size)
der_signature = utils.encode_dss_signature(
int.from_bytes(signature[:coordinate_size], byteorder="big"),
int.from_bytes(signature[coordinate_size:], byteorder="big"),
diff --git a/spsdk/utils/crypto/cert_blocks.py b/spsdk/utils/crypto/cert_blocks.py
index 79221dcb..4aac2e92 100644
--- a/spsdk/utils/crypto/cert_blocks.py
+++ b/spsdk/utils/crypto/cert_blocks.py
@@ -15,9 +15,8 @@
from typing import Any, Dict, List, Optional, Sequence, Union
from Crypto.PublicKey import ECC
-from ruamel.yaml import CommentedMap as CM
-from spsdk import SPSDKError, crypto
+from spsdk import SPSDKError
from spsdk.crypto import loaders
from spsdk.crypto.loaders import load_certificate_as_bytes
from spsdk.crypto.signature_provider import SignatureProvider, get_signature_provider
@@ -234,6 +233,11 @@ def raw_size(self) -> int:
size += self.RKH_SIZE * self.RKHT_SIZE
return misc.align(size, self.alignment)
+ @property
+ def expected_size(self) -> int:
+ """Expected size of binary block."""
+ return self.raw_size
+
@property
def image_length(self) -> int:
"""Image length in bytes."""
@@ -475,6 +479,37 @@ def from_config(
return cert_block
+ def get_config(self, output_folder: str) -> Dict[str, Any]:
+ """Create configuration of Certificate V2 from object.
+
+ :param output_folder: Output folder to store possible files.
+ :return: Configuration dictionary.
+ """
+
+ def create_certificate_cfg(root_id: int, chain_id: int) -> Optional[str]:
+ if len(self._cert) <= chain_id:
+ return None
+
+ file_name = f"certificate{root_id}_depth{chain_id}.der"
+ misc.write_file(
+ self._cert[chain_id].dump(), os.path.join(output_folder, file_name), mode="wb"
+ )
+ return file_name
+
+ cfg: Dict[str, Optional[Union[str, int]]] = {}
+ cfg["imageBuildNumber"] = self.header.build_number
+ used_cert_id = self.rkh_index
+ assert used_cert_id is not None
+ cfg["mainRootCertId"] = used_cert_id
+
+ cfg[f"rootCertificate{used_cert_id}File"] = create_certificate_cfg(used_cert_id, 0)
+ for chain_ix in range(4):
+ cfg[f"chainCertificate{used_cert_id}File{chain_ix}"] = create_certificate_cfg(
+ used_cert_id, chain_ix + 1
+ )
+
+ return cfg
+
########################################################################################################################
# Certificate Block Class for SB 3.1
@@ -632,9 +667,9 @@ def _calculate_flags(self) -> int:
if self.used_root_cert:
flags |= self.used_root_cert << 8
flags |= len(self.root_certs) << 4
- if self.root_certs[0].curve in ["NIST P-256", "p256"]:
+ if self.root_certs[0].curve in ["NIST P-256", "p256", "secp256r1"]:
flags |= 1 << 0
- if self.root_certs[0].curve in ["NIST P-384", "p384"]:
+ if self.root_certs[0].curve in ["NIST P-384", "p384", "secp384r1"]:
flags |= 1 << 1
return flags
@@ -786,7 +821,7 @@ def info(self) -> str:
if self.user_data:
info += f"User data: {self.user_data.hex()}\n"
else:
- info += f"User data: Not included\n"
+ info += "User data: Not included\n"
info += f"Type: {isk_type}\n"
info += f"Public Key: {str(self.isk_cert)}\n"
return info
@@ -797,9 +832,9 @@ def _calculate_flags(self) -> None:
if self.user_data:
self.flags |= 1 << 31
assert self.isk_cert
- if self.isk_cert.curve in ["NIST P-256", "p256"]:
+ if self.isk_cert.curve in ["NIST P-256", "p256", "secp256r1"]:
self.flags |= 1 << 0
- if self.isk_cert.curve in ["NIST P-384", "p384"]:
+ if self.isk_cert.curve in ["NIST P-384", "p384", "secp384r1"]:
self.flags |= 1 << 1
def create_isk_signature(self, key_record_data: bytes, force: bool = False) -> None:
@@ -875,8 +910,6 @@ def __init__(
user_data: Optional[bytes] = None,
) -> None:
"""The Constructor for Certificate block."""
- # workaround for base MasterBootImage
- self.signature_size = 0
self.header = CertificateBlockHeader(version)
self.root_key_record = RootKeyRecord(
ca_flag=ca_flag, used_root_cert=used_root_cert, root_certs=root_certs
@@ -898,6 +931,15 @@ def calculate(self) -> None:
"""Calculate all internal members."""
self.root_key_record.calculate()
+ @property
+ def signature_size(self) -> int:
+ """Size of the signature in bytes."""
+ # signature size is same as public key data
+ if self.isk_certificate:
+ return len(self.isk_certificate.isk_public_key_data)
+
+ return len(self.root_key_record.root_public_key)
+
@property
def expected_size(self) -> int:
"""Expected size of binary block."""
@@ -931,8 +973,6 @@ def export(self) -> bytes:
isk_cert_data = self.isk_certificate.export()
self.header.cert_block_size += len(isk_cert_data)
header_data = self.header.export()
- if len(header_data + key_record_data + isk_cert_data) != self.expected_size:
- raise SPSDKError("Size if binary differs from expected size.")
return header_data + key_record_data + isk_cert_data
@classmethod
@@ -1057,18 +1097,15 @@ def generate_config_template() -> str:
).export_to_yaml()
return yaml_data
- def create_config(self, data_path: str) -> str:
- """Create configuration of the Certification block Image.
+ def get_config(self, output_folder: str) -> Dict[str, Any]:
+ """Create configuration dictionary of the Certification block Image.
- :param data_path: Path to store the data files of configuration.
+ :param output_folder: Path to store the data files of configuration.
:return: Configuration dictionary.
"""
- cfg: Dict[str, Union[str, int]] = {}
+ cfg: Dict[str, Optional[Union[str, int]]] = {}
cfg["mainRootCertPrivateKeyFile"] = "N/A"
- cfg["iskSignProvider"] = "N/A"
cfg["signingCertificatePrivateKeyFile"] = "N/A"
- cfg["containerOutputFile"] = "N/A"
- cfg["binaryCertificateBlock"] = "N/A"
for i in range(self.root_key_record.number_of_certificates):
key: Optional[ECC.EccKey] = None
if i == self.root_key_record.used_root_cert:
@@ -1077,7 +1114,7 @@ def create_config(self, data_path: str) -> str:
if i < len(self.root_key_record.root_certs) and self.root_key_record.root_certs[i]:
key = convert_to_ecc_key(self.root_key_record.root_certs[i])
if key:
- key_file_name = os.path.join(data_path, f"rootCertificate{i}File.pub")
+ key_file_name = os.path.join(output_folder, f"rootCertificate{i}File.pub")
misc.write_file(key.export_key(format="PEM"), key_file_name)
cfg[f"rootCertificate{i}File"] = f"rootCertificate{i}File.pub"
else:
@@ -1087,27 +1124,31 @@ def create_config(self, data_path: str) -> str:
cfg["mainRootCertId"] = self.root_key_record.used_root_cert
if self.isk_certificate and self.root_key_record.ca_flag == 0:
- cfg["useIsk"] = "true"
+ cfg["useIsk"] = True
assert self.isk_certificate.isk_cert
key = self.isk_certificate.isk_cert
- key_file_name = os.path.join(data_path, "signingCertificateFile.pub")
+ key_file_name = os.path.join(output_folder, "signingCertificateFile.pub")
misc.write_file(key.export_key(format="PEM"), key_file_name)
- cfg[f"signingCertificateFile"] = "signingCertificateFile.pub"
+ cfg["signingCertificateFile"] = "signingCertificateFile.pub"
cfg["signingCertificateConstraint"] = self.isk_certificate.constraints
if self.isk_certificate.user_data:
- key_file_name = os.path.join(data_path, "isk_user_data.bin")
+ key_file_name = os.path.join(output_folder, "isk_user_data.bin")
misc.write_file(self.isk_certificate.user_data, key_file_name, mode="wb")
cfg["signCertData"] = "isk_user_data.bin"
- else:
- cfg["signCertData"] = "N/A"
+
else:
- cfg["useIsk"] = "false"
- cfg["signingCertificateFile"] = "N/A"
- cfg["signingCertificateConstraint"] = "N/A"
- cfg["signCertData"] = "N/A"
+ cfg["useIsk"] = False
+
+ return cfg
+ def create_config(self, data_path: str) -> str:
+ """Create configuration of the Certification block Image.
+
+ :param data_path: Path to store the data files of configuration.
+ :return: Configuration in string.
+ """
+ cfg = self.get_config(data_path)
val_schemas = CertBlockV31.get_validation_schemas()
- val_schemas.append(ValidationSchemas.get_schema_file(CRYPTO_SCH_FILE)["cert_block_output"])
yaml_data = CommentedConfig(
main_title=(
@@ -1146,8 +1187,8 @@ def get_main_cert_index(config: Dict[str, Any], search_paths: Optional[List[str]
cert_id = root_cert_id if root_cert_id is not None else cert_chain_id
try:
cert_id = int(cert_id) # type: ignore[arg-type]
- except ValueError:
- raise SPSDKValueError(f"A certificate index is not a number: {cert_id}")
+ except ValueError as exc:
+ raise SPSDKValueError(f"A certificate index is not a number: {cert_id}") from exc
if found_cert_id is not None and found_cert_id != cert_id:
logger.warning("Defined certificate does not match the private key.")
return cert_id
@@ -1162,15 +1203,16 @@ def find_main_cert_index(
:param search_paths: List of paths where to search for the file, defaults to None
:return: List of root certificates.
"""
- private_key_file = config.get("mainCertPrivateKeyFile")
- if not private_key_file:
- return None
try:
- private_key_file_path = misc.find_file(private_key_file, search_paths=search_paths)
- except SPSDKError:
- logger.debug(f"A private key file {private_key_file} could not be found.")
+ signature_provider = get_signature_provider(
+ sp_cfg=config.get("signProvider"),
+ local_file_key=config.get("mainCertPrivateKeyFile"),
+ search_paths=search_paths,
+ )
+ except SPSDKError as exc:
+ logger.debug(f"A signature provider could not be created: {exc}")
return None
- private_key = crypto.load_private_key(private_key_file_path)
+
root_certificates = find_root_certificates(config)
public_keys = []
for root_crt_file in root_certificates:
@@ -1180,7 +1222,7 @@ def find_main_cert_index(
except SPSDKError:
continue
try:
- idx = get_matching_key_id(public_keys, private_key)
+ idx = get_matching_key_id(public_keys, signature_provider)
return idx
except ValueError:
return None
diff --git a/spsdk/utils/crypto/common.py b/spsdk/utils/crypto/common.py
index b535aa21..b962c3c1 100644
--- a/spsdk/utils/crypto/common.py
+++ b/spsdk/utils/crypto/common.py
@@ -15,7 +15,8 @@
from cryptography.x509 import Certificate
from spsdk import SPSDKError
-from spsdk.crypto import PrivateKey, PublicKey
+from spsdk.crypto import EllipticCurvePublicKey, Encoding, PublicFormat, PublicKey
+from spsdk.crypto.signature_provider import SignatureProvider
from spsdk.sbfile.misc import SecBootBlckSize
from ...exceptions import SPSDKValueError
@@ -120,17 +121,25 @@ def ecc_public_numbers_to_bytes(
return x_bytes + y_bytes
-def get_matching_key_id(public_keys: List[PublicKey], private_key: PrivateKey) -> int:
+def get_matching_key_id(public_keys: List[PublicKey], signature_provider: SignatureProvider) -> int:
"""Get index of public key that match to given private key.
:param public_keys: List of public key used to find the match for the private key.
- :param private_key: Private key used to try to match public key index.
+ :param signature_provider: Signature provider used to try to match public key index.
:raises SPSDKValueError: No match found.
:return: Index of public key.
"""
- public_key_to_compare = private_key.public_key()
for i, public_key in enumerate(public_keys):
- if public_key.public_numbers() == public_key_to_compare.public_numbers():
+ if isinstance(public_key, RSAPublicKey):
+ public_key_bytes = public_key.public_bytes(
+ encoding=Encoding.DER, format=PublicFormat.PKCS1
+ )
+ if isinstance(public_key, EllipticCurvePublicKey):
+ public_key_bytes = public_key.public_bytes(
+ encoding=Encoding.PEM, format=PublicFormat.SubjectPublicKeyInfo
+ )
+
+ if signature_provider.verify_public_key(public_key_bytes):
return i
raise SPSDKValueError("There is no match of private key in given list.")
diff --git a/spsdk/utils/crypto/iee.py b/spsdk/utils/crypto/iee.py
index ef0cec37..4878bf36 100644
--- a/spsdk/utils/crypto/iee.py
+++ b/spsdk/utils/crypto/iee.py
@@ -390,6 +390,7 @@ def calculate_tweak(address: int, master: Optional[MasterId] = None) -> bytes:
class Iee:
"""IEE: Inline Encryption Engine."""
+ IEE_DATA_UNIT = 0x1000
IEE_KEY_BLOBS_SIZE = 384
def __init__(self) -> None:
@@ -411,24 +412,27 @@ def add_key_blob(self, key_blob: IeeKeyBlob) -> None:
self._key_blobs.append(key_blob)
def encrypt_image(self, image: bytes, base_addr: int) -> bytes:
- """Encrypt image.
+ """Encrypt image with all available keyblobs.
:param image: plain image to be encrypted
:param base_addr: where the image will be located in target processor
:return: encrypted image
"""
- image_end = base_addr + len(image) - 1
- for key_blob in self._key_blobs:
- if key_blob.matches_range(base_addr, image_end):
- logger.debug(
- f"Encrypting image {hex(base_addr)}:{hex(image_end)} with keyblob: \n{key_blob.info()}"
- )
- return key_blob.encrypt_image(base_addr, image)
+ encrypted_data = bytearray(image)
+ addr = base_addr
+ for block in split_data(image, self.IEE_DATA_UNIT):
+ for key_blob in self._key_blobs:
+ if key_blob.matches_range(addr, addr + len(block)):
+ logger.debug(
+ f"Encrypting {hex(addr)}:{hex(len(block) + addr)}"
+ f" with keyblob: \n {key_blob.info()}"
+ )
+ encrypted_data[
+ addr - base_addr : len(block) + addr - base_addr
+ ] = key_blob.encrypt_image(addr, block)
+ addr += len(block)
- logger.debug(
- f"Image {hex(base_addr)}:{hex(image_end)} does not lie in any keyblob, keeping it unencrypted"
- )
- return image
+ return bytes(encrypted_data)
def get_key_blobs(self) -> bytes:
"""Get key blobs.
@@ -490,7 +494,7 @@ def __init__(
:param key_blobs: Optional Key blobs to add to IEE, defaults to None
:raises SPSDKValueError: Unsupported family
"""
- self._key_blobs: List[IeeKeyBlob] = []
+ super().__init__()
if family not in self.get_supported_families():
raise SPSDKValueError(f"Unsupported family{family} by IEE")
@@ -744,13 +748,15 @@ def load_from_config(
master = MasterId[master]
ibkek1 = get_key(
config.get(
- "ibkek1", "0x000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"
+ "ibkek1",
+ "0x000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F",
),
32,
)
ibkek2 = get_key(
config.get(
- "ibkek2", "0x202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"
+ "ibkek2",
+ "0x202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F",
),
32,
)
@@ -767,6 +773,7 @@ def load_from_config(
binaries = None
if data_blobs:
# start address to calculate offset from keyblob, min from keyblob or data blob address
+ # pylint: disable-next=nested-min-max
start_address = min(
min([value_to_int(addr.get("address", 0xFFFFFFFF)) for addr in data_blobs]),
start_address,
diff --git a/spsdk/utils/crypto/otfad.py b/spsdk/utils/crypto/otfad.py
index d9dc9b71..7f62c854 100644
--- a/spsdk/utils/crypto/otfad.py
+++ b/spsdk/utils/crypto/otfad.py
@@ -25,9 +25,9 @@
from spsdk.utils.images import BinaryImage
from spsdk.utils.misc import (
align_block,
- find_file,
load_binary,
reverse_bits_in_bytes,
+ split_data,
value_to_bytes,
value_to_int,
)
@@ -166,7 +166,7 @@ def plain_data(self) -> bytes:
result += pack(" bytes:
# pylint: disable=invalid-name
def export(
- self, kek: Union[bytes, str], iv: bytes = bytes([0xA6] * 8), byte_swap_cnt: int = 0
+ self,
+ kek: Union[bytes, str],
+ iv: bytes = bytes([0xA6] * 8),
+ byte_swap_cnt: int = 0,
) -> bytes:
"""Creates key wrap for the key blob.
@@ -270,13 +273,20 @@ def matches_range(self, image_start: int, image_end: int) -> bool:
"""
return self.contains_addr(image_start) and self.contains_addr(image_end)
- def encrypt_image(self, base_address: int, data: bytes, byte_swap: bool) -> bytes:
+ def encrypt_image(
+ self,
+ base_address: int,
+ data: bytes,
+ byte_swap: bool,
+ counter_value: Optional[int] = None,
+ ) -> bytes:
"""Encrypt specified data.
:param base_address: of the data in target memory; must be >= self.start_addr
:param data: to be encrypted (e.g. plain image); base_address + len(data) must be <= self.end_addr
:param byte_swap: this probably depends on the flash device, how bytes are organized there
True should be used for FLASH on EVK RT6xx; False for FLASH on EVK RT5xx
+ :param counter_value: Optional counter value, if not specified start address of keyblob will be used
:return: encrypted data
:raises SPSDKError: If start address is not valid
"""
@@ -289,14 +299,17 @@ def encrypt_image(self, base_address: int, data: bytes, byte_swap: bool) -> byte
# Support dual image boot, do not raise exception
if not self.matches_range(base_address, base_address + data_len - 1):
logger.warning(
- f"Image address range is not within key blob: {hex(self.start_addr)}-{hex(self.end_addr)}."
+ f"Image address range is not within key blob: "
+ f"{hex(self.start_addr)}-{hex(self.end_addr)}."
" Ignore this if flash remap feature is used"
)
-
result = bytes()
# SPSDK-936 change base address to start address of keyblob to allow flash remap on RT5xx/RT6xx
+ if not counter_value:
+ counter_value = self.start_addr
+
counter = Counter(
- self._get_ctr_nonce(), ctr_value=self.start_addr, ctr_byteorder_encoding="big"
+ self._get_ctr_nonce(), ctr_value=counter_value, ctr_byteorder_encoding="big"
)
for index in range(0, data_len, 16):
@@ -338,6 +351,8 @@ def is_encrypted(self) -> bool:
class Otfad:
"""OTFAD: On-the-Fly AES Decryption Module."""
+ OTFAD_DATA_UNIT = 0x400
+
def __init__(self) -> None:
"""Constructor."""
self._key_blobs: List[KeyBlob] = []
@@ -357,7 +372,7 @@ def add_key_blob(self, key_blob: KeyBlob) -> None:
self._key_blobs.append(key_blob)
def encrypt_image(self, image: bytes, base_addr: int, byte_swap: bool) -> bytes:
- """Encrypt image.
+ """Encrypt image with all available keyblobs.
:param image: plain image to be encrypted
:param base_addr: where the image will be located in target processor
@@ -365,16 +380,21 @@ def encrypt_image(self, image: bytes, base_addr: int, byte_swap: bool) -> bytes:
True should be used for FLASH on EVK RT6xx; False for FLASH on EVK RT5xx
:return: encrypted image
"""
- image_end = base_addr + len(image) - 1
- for key_blob in self._key_blobs:
- if key_blob.matches_range(base_addr, image_end) and key_blob.is_encrypted:
- return key_blob.encrypt_image(base_addr, image, byte_swap)
+ encrypted_data = bytearray(image)
+ addr = base_addr
+ for block in split_data(image, self.OTFAD_DATA_UNIT):
+ for key_blob in self._key_blobs:
+ if key_blob.matches_range(addr, addr + len(block)):
+ logger.debug(
+ f"Encrypting {hex(addr)}:{hex(len(block) + addr)}"
+ f" with keyblob: \n {key_blob.info()}"
+ )
+ encrypted_data[
+ addr - base_addr : len(block) + addr - base_addr
+ ] = key_blob.encrypt_image(addr, block, byte_swap, counter_value=addr)
+ addr += len(block)
- logger.debug(
- f"The image address range {hex(base_addr)}:{hex(image_end)}"
- "does not match to valid key blob, skipping encryption"
- )
- return image
+ return bytes(encrypted_data)
def get_key_blobs(self) -> bytes:
"""Get key blobs.
@@ -607,7 +627,7 @@ def get_blhost_script_otp_kek(self, index: int = 1) -> str:
otfad_cfg.find_bitfield(
self.database.get_device_value("otfad_enable_bitfield", self.family)
).set_value(1)
- except SPSDKRegsErrorBitfieldNotFound as e:
+ except SPSDKRegsErrorBitfieldNotFound:
logger.debug(f"Bitfield for OTFAD ENABLE not found for {self.family}")
if scramble_enabled:
@@ -677,11 +697,12 @@ def export_image(
for binary in binaries.sub_images:
if binary.binary:
binary.binary = self.encrypt_image(
- binary.binary, table_address + binary.absolute_address, swap_bytes
+ binary.binary,
+ table_address + binary.absolute_address,
+ swap_bytes,
)
for segment in binary.sub_images:
if segment.binary:
- segment.absolute_address
segment.binary = self.encrypt_image(
segment.binary,
segment.absolute_address + table_address,
@@ -831,8 +852,10 @@ def load_from_config(
data_blobs: Optional[List[Dict]] = config.get("data_blobs")
binaries = None
if data_blobs:
+ # pylint: disable-next=nested-min-max
start_address = min(
- min([value_to_int(addr["address"]) for addr in data_blobs]), start_address
+ min([value_to_int(addr["address"]) for addr in data_blobs]),
+ start_address,
)
binaries = BinaryImage(
filepath_from_config(
diff --git a/spsdk/utils/database.py b/spsdk/utils/database.py
index 8ede80f2..00b5b0e9 100644
--- a/spsdk/utils/database.py
+++ b/spsdk/utils/database.py
@@ -192,7 +192,7 @@ def __init__(self, path: str, index: Optional[int] = None) -> None:
except (SPSDKValueError, SPSDKTypeError) as exc:
if exc.description:
exc.description += f"File path: {self.path}"
- raise SPSDKError("Database can not be created")
+ raise SPSDKError("Database can not be created") from exc
self.attributes: dict = config.get("attributes", {})
@classmethod
diff --git a/spsdk/utils/devicedescription.py b/spsdk/utils/devicedescription.py
index 86044ea7..b24a4595 100644
--- a/spsdk/utils/devicedescription.py
+++ b/spsdk/utils/devicedescription.py
@@ -131,6 +131,45 @@ def info(self) -> str:
)
+class SDIODeviceDescription(DeviceDescription):
+ """Simple container holding information about SDIO device.
+
+ This container should be used instead of any SDIO API related objects, as
+ this container will be the same all the time compared to specific SDIO API
+ implementations.
+ """
+
+ def __init__(
+ self,
+ vid: int,
+ pid: int,
+ path: str,
+ ) -> None:
+ """Constructor.
+
+ :param vid: Vendor ID
+ :param pid: Product ID
+
+ See :py:func:`get_usb_device_name` function to getg the name from
+ VID and PID.
+ See :py:func:`convert_usb_path` function to provide a proper path string.
+ """
+ self.vid = vid
+ self.pid = pid
+ self.path = path
+
+ def info(self) -> str:
+ """Returns a formatted device description string.
+
+ :return: Text information of SDIO device.
+ """
+ return (
+ f"Vendor ID: 0x{self.vid:04x}\n"
+ f"Product ID: 0x{self.pid:04x}\n"
+ f"Path: {self.path}\n"
+ )
+
+
class SIODeviceDescription(DeviceDescription):
"""Simple container holding information about LIBUSBSIO device.
diff --git a/spsdk/utils/misc.py b/spsdk/utils/misc.py
index de55f404..e6921a68 100644
--- a/spsdk/utils/misc.py
+++ b/spsdk/utils/misc.py
@@ -11,11 +11,22 @@
import math
import os
import re
-import sys
import time
from math import ceil
from struct import pack, unpack
-from typing import Callable, Dict, Generator, Iterable, Iterator, List, Optional, TypeVar, Union
+from typing import (
+ Any,
+ Callable,
+ Dict,
+ Generator,
+ Iterable,
+ Iterator,
+ List,
+ Optional,
+ Type,
+ TypeVar,
+ Union,
+)
from spsdk import SPSDKError
from spsdk.exceptions import SPSDKValueError
@@ -811,7 +822,7 @@ def load_configuration(path: str) -> dict:
raise SPSDKError(f"Unable to load '{path}'.")
-def split_data(data: bytearray, size: int) -> Generator[bytes, None, None]:
+def split_data(data: Union[bytearray, bytes], size: int) -> Generator[bytes, None, None]:
"""Split data into chunks of size.
:param bytearray data: array of bytes to be split
@@ -829,37 +840,17 @@ def get_hash(text: Union[str, bytes]) -> str:
return hashlib.sha1(text).digest().hex()[:8]
-def import_source(source: str) -> None:
- """Import Python source file directly.
+TS = TypeVar("TS", bound="SingletonMeta") # pylint: disable=invalid-name
- :param source: A path to python source file or existing module name
- Accepted values are:
- - an absolute path to py file
- - a path to py file, relative to current working directory
- - installed package/module name
- and more, and more
- :raises SPSDKError: If importing of source file failed
- """
- from importlib.util import ( # pylint: disable=import-outside-toplevel
- find_spec,
- module_from_spec,
- spec_from_file_location,
- )
- if not os.path.isfile(source):
- spec = find_spec(name=source)
- else:
- module_name = os.path.splitext(os.path.basename(source))[0]
- spec = spec_from_file_location(name=module_name, location=source) # type: ignore
- if not spec:
- raise SPSDKError(
- f"Source '{source}' does not exist.Check if it is valid file path/module name"
- )
+class SingletonMeta(type):
+ """Singleton metaclass."""
- mod = module_from_spec(spec)
- try:
- sys.modules[spec.name] = mod
- spec.loader.exec_module(mod) # type: ignore
- logger.debug(f"A module {source} has been imported.")
- except Exception as e:
- raise SPSDKError(f"Failed to load source {source}: {e}") from e
+ _instance = None
+
+ def __call__(cls: Type[TS], *args: Any, **kwargs: Any) -> TS: # type: ignore
+ """Call dunder override."""
+ if cls._instance is None:
+ instance = super().__call__(*args, **kwargs)
+ cls._instance = instance
+ return cls._instance
diff --git a/spsdk/utils/nxpdevscan.py b/spsdk/utils/nxpdevscan.py
index e7cf314e..865b6ed8 100644
--- a/spsdk/utils/nxpdevscan.py
+++ b/spsdk/utils/nxpdevscan.py
@@ -15,12 +15,14 @@
from serial.tools.list_ports import comports
from spsdk import SPSDKError
+from spsdk.mboot.interfaces.sdio import scan_sdio as mb_scan_sdio
from spsdk.mboot.interfaces.uart import scan_uart as mb_scan_uart
from spsdk.sdp import SDP
from spsdk.sdp.exceptions import SdpConnectionError
from spsdk.sdp.interfaces.uart import Uart as SDP_Uart
from .devicedescription import (
+ SDIODeviceDescription,
SIODeviceDescription,
UartDeviceDescription,
USBDeviceDescription,
@@ -33,9 +35,34 @@
0x15A2,
]
+NXP_SDIO_DEVICE_PATHS = [
+ "/dev/mcu-sdio",
+]
+
logger = logging.getLogger(__name__)
+def search_nxp_sdio_devices() -> List[SDIODeviceDescription]:
+ """Searches all NXP SDIO devices based on their device path.
+
+ :return: list of SDIODeviceDescription corresponding to NXP devices
+ """
+ nxp_sdio_devices = []
+
+ search_path = NXP_SDIO_DEVICE_PATHS
+
+ for path in search_path:
+ sdio_device = mb_scan_sdio(device_path=path)
+ if len(sdio_device) > 0:
+ sdio_dev = SDIODeviceDescription(
+ vid=sdio_device[0].vid, pid=sdio_device[0].pid, path=sdio_device[0].path
+ )
+ nxp_sdio_devices.append(sdio_dev)
+ continue
+
+ return nxp_sdio_devices
+
+
def search_nxp_usb_devices(extend_vid_list: Optional[list] = None) -> List[USBDeviceDescription]:
"""Searches all NXP USB devices based on their Vendor ID.
diff --git a/spsdk/utils/plugins.py b/spsdk/utils/plugins.py
new file mode 100644
index 00000000..e42ac2c8
--- /dev/null
+++ b/spsdk/utils/plugins.py
@@ -0,0 +1,172 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+#
+# Copyright 2023 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+"""SPSDK plugins manager."""
+
+import logging
+import os
+import sys
+from importlib.machinery import ModuleSpec
+from importlib.util import find_spec, module_from_spec, spec_from_file_location
+from types import ModuleType
+from typing import Dict, List, Optional
+
+import importlib_metadata
+
+from spsdk.exceptions import SPSDKError, SPSDKTypeError
+from spsdk.utils.easy_enum import Enum
+from spsdk.utils.misc import SingletonMeta
+
+logger = logging.getLogger(__name__)
+
+
+class PluginType(Enum):
+ """Contains commands tags."""
+
+ SIGNATURE_PROVIDER = (0, "spsdk.sp", "Signature provider")
+
+
+class PluginsManager(metaclass=SingletonMeta):
+ """Plugin manager."""
+
+ def __init__(self) -> None:
+ """Plugin manager constructor."""
+ self.plugins: Dict[str, ModuleType] = {}
+
+ def load_from_entrypoints(self, group_name: Optional[str] = None) -> int:
+ """Load modules from given setuptools group.
+
+ :param group_name: Entry point group to load plugins
+
+ :return: The number of loaded plugins.
+ """
+ if group_name is not None and not isinstance(group_name, str):
+ raise SPSDKTypeError("Group name must be of string type.")
+ group_names = (
+ [group_name]
+ if group_name is not None
+ else [PluginType.name(tag) for tag in PluginType.tags()]
+ )
+
+ entry_points: List[importlib_metadata.EntryPoint] = []
+ for group_name in group_names:
+ eps = importlib_metadata.entry_points(group=group_name)
+ entry_points.extend(eps)
+
+ count = 0
+ for ep in entry_points:
+ try:
+ plugin = ep.load()
+ except ModuleNotFoundError:
+ logger.warning(f"Module {ep.module} could not be loaded")
+ continue
+ logger.info(f"Plugin {ep.name} has been loaded.")
+ self.register(plugin)
+ count += 1
+ return count
+
+ def load_from_source_file(self, source_file: str) -> None:
+ """Import Python source file directly.
+
+ :param source_file: Path to python source file: absolute or relative to cwd
+ :raises SPSDKError: If importing of source file failed
+ """
+ module_name = os.path.splitext(os.path.basename(source_file))[0]
+ spec = spec_from_file_location(name=module_name, location=source_file)
+ if not spec:
+ raise SPSDKError(
+ f"Source '{source_file}' does not exist. Check if it is valid file path name"
+ )
+
+ module = self._import_module_spec(spec)
+ self.register(module)
+
+ def load_from_module_name(self, module_name: str) -> None:
+ """Import Python module directly.
+
+ :param module_name: Module name to be imported
+ :raises SPSDKError: If importing of source file failed
+ """
+ spec = find_spec(name=module_name)
+ if not spec:
+ raise SPSDKError(
+ f"Source '{module_name}' does not exist.Check if it is valid file module name"
+ )
+ module = self._import_module_spec(spec)
+ self.register(module)
+
+ def _import_module_spec(self, spec: ModuleSpec) -> ModuleType:
+ """Import module from module specification.
+
+ :param spec: Module specification
+ :return: Imported module type
+ """
+ module = module_from_spec(spec)
+ try:
+ sys.modules[spec.name] = module
+ spec.loader.exec_module(module) # type: ignore
+ logger.debug(f"A module spec {spec.name} has been loaded.")
+ except Exception as e:
+ raise SPSDKError(f"Failed to load module spec {spec.name}: {e}") from e
+ return module
+
+ def register(self, plugin: ModuleType) -> None:
+ """Register a plugin with the given name.
+
+ :param plugin: Plugin as a module
+ """
+ plugin_name = self.get_plugin_name(plugin)
+ if plugin_name in self.plugins:
+ logger.debug(f"Plugin {plugin_name} has been aready registered.")
+ return
+ self.plugins[plugin_name] = plugin
+ logger.debug(f"A plugin {plugin_name} has been registered.")
+
+ def get_plugin(self, name: str) -> Optional[ModuleType]:
+ """Return a plugin for the given name.
+
+ :param name: Plugin name
+ :return: Plugin or None if plugin with name is not registered
+ """
+ return self.plugins.get(name)
+
+ def get_plugin_name(self, plugin: ModuleType) -> str:
+ """Get canonical name of plugin.
+
+ :param plugin: Plugin as a module
+ :return: String with plugin name
+ """
+ name = getattr(plugin, "__name__", None)
+ if name is None:
+ raise SPSDKError("Plugin name could not be determined.")
+ return name
+
+
+def load_plugin_from_source(source: str) -> None:
+ """Load plugin from source.
+
+ :param source: The source to be loaded
+ Accepted values:
+ - Path to source file
+ - Existing module name
+ - Existing entrypoint
+ """
+ manager = PluginsManager()
+ try:
+ return manager.load_from_source_file(source)
+ except SPSDKError:
+ pass
+ try:
+ manager.load_from_module_name(source)
+ return
+ except SPSDKError:
+ pass
+ try:
+ manager.load_from_entrypoints(source)
+ return
+ except SPSDKError:
+ pass
+ raise SPSDKError(f"Unable to load from source '{source}'.")
diff --git a/spsdk/utils/registers.py b/spsdk/utils/registers.py
index e9df638b..ea577f04 100644
--- a/spsdk/utils/registers.py
+++ b/spsdk/utils/registers.py
@@ -369,7 +369,7 @@ def set_enum_value(self, new_val: str, raw: bool = False) -> None:
"""
try:
val_int = self.get_enum_constant(new_val)
- except SPSDKRegsErrorEnumNotFound as exc:
+ except SPSDKRegsErrorEnumNotFound:
# Try to decode standard input
try:
val_int = value_to_int(new_val)
diff --git a/spsdk/utils/schema_validator.py b/spsdk/utils/schema_validator.py
index 90ebb141..4b898475 100644
--- a/spsdk/utils/schema_validator.py
+++ b/spsdk/utils/schema_validator.py
@@ -115,6 +115,7 @@ def process_nested_rule(
elif exc.rule == "format":
if exc.rule_definition == "file":
message += f"; Non-existing file: {exc.value}"
+ message += "; The file must exists even if the key is NOT used in configuration."
elif exc.rule == "anyOf":
message += process_nested_rule(exc, extra_formaters=extra_formaters)
elif exc.rule == "oneOf":
@@ -290,36 +291,43 @@ def _find_required_in_schema_kws(schema_node: Union[List, Dict[str, Any]]) -> Li
def _create_object_block(
self,
block: Dict[str, Dict[str, Any]],
- custom_value: Optional[Dict[str, Any]] = None,
- ) -> CMap:
+ custom_value: Optional[Union[Dict[str, Any], List[Any]]] = None,
+ ) -> Union[CMap, CSeq]:
"""Private function used to create object block with data.
:param block: Source block with data
:param custom_value:
- Optional dictionary of properties to be exported.
- It is recommeded to pass OrderedDict to preserve the key order.
+ Optional dictionary or List of properties to be exported.
+ It is recommended to pass OrderedDict to preserve the key order.
- key is property ID to be exported
- value is its value; or None if default value shall be used
- :return: CM base configuration object
+ :return: CMap or CSeq base configuration object
:raises SPSDKError: In case of invalid data pattern.
"""
assert block.get("type") == "object"
self.indent += 1
- cfg_m = CMap()
+
assert "properties" in block.keys()
- key_order = (
- self._get_schema_block_keys(block)
- if (custom_value is None)
- else list(custom_value.keys())
- )
- for key in key_order:
- assert key in block["properties"].keys()
+
+ if "oneOf" in block["properties"].keys():
+ cfg_s = self._create_one_of_block_array(block["properties"], custom_value) # type: ignore
+ self.indent -= 1
+ return cfg_s
+
+ cfg_m = CMap()
+ for key in self._get_schema_block_keys(block):
+ assert (
+ key in block["properties"].keys()
+ ), f"Missing key ({key}, in block properties. Block title: {block.get('title', 'Unknown')})"
+
+ # Skip the record in case that custom value key is defined,
+ # but it has None value as a mark to not use this record
+ value = custom_value.get(key, None) if custom_value else None # type: ignore
+ if not self.export_template and value is None:
+ continue
+
val_p: Dict = block["properties"][key]
- if (custom_value is not None) and (custom_value[key] is not None):
- value_to_add = custom_value[key]
- else:
- value_to_add = None
- value_to_add, comment, title = self._get_schema_value(val_p, value_to_add)
+ value_to_add, comment, title = self._get_schema_value(val_p, value)
cfg_m[key] = value_to_add
p_required = self.get_property_optional_required(key, block)
@@ -352,10 +360,13 @@ def _create_array_block(
cfg_s = CSeq()
if custom_value:
for cust_val in custom_value:
- value, comment, title = self._get_schema_value(val_i, cust_val)
- cfg_s.append(value)
- else:
- value, comment, title = self._get_schema_value(val_i, None)
+ value, _, _ = self._get_schema_value(val_i, cust_val)
+ if isinstance(value, list):
+ cfg_s.extend(value)
+ else:
+ cfg_s.append(value)
+ elif self.export_template:
+ value, _, _ = self._get_schema_value(val_i, None)
# the template_value can be the actual list(not only one element)
if isinstance(value, list):
cfg_s.extend(value)
@@ -386,7 +397,7 @@ def _find_matching_oneof_option(one_of: List[Dict[str, Any]], cust_val: Any) ->
def _create_one_of_block_array(
self, block: Dict[str, Dict[str, Any]], custom_value: Optional[List[Any]]
) -> CSeq:
- """Private function used to create oneOf block with data, and return as an array that contaisn all values.
+ """Private function used to create oneOf block with data, and return as an array that contains all values.
:param block: Source block with data
:param custom_value: custom value to fill the array
@@ -409,7 +420,7 @@ def _create_one_of_block_array(
before=self._get_title_block(loc_title),
indent=SPSDK_YML_INDENT * (self.indent - 1),
)
- else:
+ elif self.export_template:
option_types = ",".join([str(x.get("type")) for x in one_of])
title = f"List of possible {len(one_of)} options. Option types[{option_types}]"
for i, option in enumerate(one_of):
@@ -443,18 +454,23 @@ def _get_schema_value(
:raises SPSDKError: In case of invalid data pattern.
"""
title = None
- schema_type = block.get("type")
- assert schema_type, f"Type not available in block: {block}"
-
- if schema_type == "object":
- assert (custom_value is None) or isinstance(custom_value, dict)
- ret = self._create_object_block(block, custom_value) # type: ignore
- elif schema_type == "array":
- assert (custom_value is None) or isinstance(custom_value, list)
- ret = self._create_array_block(block, custom_value) # type: ignore
+ if "oneOf" in block.keys():
+ ret = self._create_one_of_block_array(block, custom_value)
else:
- assert "template_value" in block.keys()
- ret = custom_value if (custom_value is not None) else block.get("template_value")
+ schema_type = block.get("type")
+ if not schema_type:
+ raise SPSDKError(f"Type not available in block: {block}")
+ assert schema_type, f"Type not available in block: {block}"
+
+ if schema_type == "object":
+ assert (custom_value is None) or isinstance(custom_value, dict)
+ ret = self._create_object_block(block, custom_value) # type: ignore
+ elif schema_type == "array":
+ assert (custom_value is None) or isinstance(custom_value, list)
+ ret = self._create_array_block(block, custom_value) # type: ignore
+ else:
+ assert "template_value" in block.keys()
+ ret = custom_value if (custom_value is not None) else block.get("template_value")
assert isinstance(ret, (CMap, CSeq, str, int, float, list)) or (ret is None)
@@ -529,22 +545,21 @@ def export(self) -> CMap:
schemas_merger.merge(merged, copy.deepcopy(schema))
# 3. Create order of individual settings
- order_dict: Optional[Dict[str, Any]] = None
- if self.export_template and self.values:
- properties_for_template = self._get_schema_block_keys(merged)
- # create ordered dict with all properties and optionally override values
- order_dict = OrderedDict()
- for info in block_list.values():
- for p in info["properties"]:
- if p in properties_for_template:
- order_dict[p] = self.values.get(p, None)
- else:
- order_dict = self.values
+
+ order_dict: Dict[str, Any] = OrderedDict()
+ properties_for_template = self._get_schema_block_keys(merged)
+ for block in block_list.values():
+ block_properties: list = block["properties"]
+ # block_properties.sort()
+ for block_property in block_properties:
+ if block_property in properties_for_template:
+ order_dict[block_property] = merged["properties"][block_property]
+ merged["properties"] = order_dict
try:
self.indent = 0
# 4. Go through all individual logic blocks
- cfg = self._create_object_block(merged, order_dict)
+ cfg = self._create_object_block(merged, self.values)
assert isinstance(cfg, CMap)
# 5. Add main title of configuration
title = f"=========== {self.main_title} ===========\n"
@@ -611,5 +626,3 @@ def get_schema_file(sch_file: str) -> Dict[str, Any]:
class ConfigTemplate(CommentedConfig):
"""Deprecated, kept for backward compatibility only."""
-
- pass
diff --git a/tests/dat/data/elf2sb_config.json b/tests/dat/data/elf2sb_config.json
deleted file mode 100644
index 9bed3c69..00000000
--- a/tests/dat/data/elf2sb_config.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "family": "rt5xx",
- "inputImageFile": "input_images/rt500_hello_world_plain.bin",
- "imageLinkAddress": "0x08001000",
- "imageLinkAdressFromImage": false,
- "outputImageExecutionTarget": "External flash (XIP)",
- "outputImageAuthenticationType": "Signed",
- "deviceKeySource": "",
- "outputImageEncryptionKeyFile": "",
- "enableTrustZone": false,
- "trustZonePresetFile": "",
- "useKeyStore": false,
- "keyStoreFile": "",
- "rootCertificate0File": "p0_cert0_2048.pub",
- "rootCertificate1File": "p1_cert0_2048.pub",
- "rootCertificate2File": "p2_cert0_2048.pub",
- "rootCertificate3File": "p3_cert0_2048.pub",
- "mainCertChainId": 0,
- "mainCertPrivateKeyFile": "k0_cert0_2048.pem",
- "masterBootOutputFile": "output_images/application_signed.bin"
-}
\ No newline at end of file
diff --git a/tests/dat/data/elf2sb_config.yaml b/tests/dat/data/elf2sb_config.yaml
new file mode 100644
index 00000000..c8e90080
--- /dev/null
+++ b/tests/dat/data/elf2sb_config.yaml
@@ -0,0 +1,31 @@
+# Copyright 2023 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+# =========== Master Boot Image converted config. ===========
+# ----------------------------------------------------------------------------------------------------
+# == Basic Settings ==
+# ----------------------------------------------------------------------------------------------------
+family: rt5xx # [Required], MCU family name; Possible options:['lpc55s0x', 'lpc55s1x', 'rt5xx', 'rt6xx']
+outputImageExecutionTarget: External flash (XIP) # [Required], Application target; Definition if application is Execute in Place(XiP) or loaded to RAM during reset sequence; Possible options:['Internal flash (XIP)', 'External flash (XIP)', 'Internal Flash (XIP)', 'External Flash (XIP)', 'RAM', 'ram', 'xip']
+outputImageAuthenticationType: Signed # [Required], Type of boot image authentication; Specification of final master boot image authentication; Possible options:['Plain', 'CRC', 'Signed', 'Encrypted + Signed', 'NXP Signed', 'encrypted', 'signed', 'crc']
+masterBootOutputFile: output_images/application_signed.bin # [Required], Master Boot Image name; The file for Master Boot Image result file.
+inputImageFile: input_images/rt500_hello_world_plain.bin # [Required], Plain application image; The input application image to by modified to Master Boot Image.
+outputImageExecutionAddress: '0x00000000' # [Required], Loading address of application; Application loading address in RAM if not XiP, otherwise address of load in XiP.
+enableHwUserModeKeys: false # [Required], Enable User HW key sharing; Controlling secure hardware key bus. If enabled(1), then it is possible to access keys on hardware secure bus from non-secure application, else non-secure application will read zeros.
+# ----------------------------------------------------------------------------------------------------
+# == Trust Zone Settings ==
+# ----------------------------------------------------------------------------------------------------
+enableTrustZone: false # [Optional], TrustZone enable option; If not specified, the Trust zone is disabled.
+trustZonePresetFile: '' # [Optional], TrustZone Customization file; If not specified, but TrustZone is enabled(enableTrustZone) the default values are used.
+# ----------------------------------------------------------------------------------------------------
+# == Certificate V2 Settings ==
+# ----------------------------------------------------------------------------------------------------
+mainCertPrivateKeyFile: k0_cert0_2048.pem # [Conditionally required], Main Certificate private key used to sign certificate. It can be replaced by signProvider key.
+# ----------------------------------------------------------------------------------------------------
+# == Root Keys Settings ==
+# ----------------------------------------------------------------------------------------------------
+rootCertificate0File: p0_cert0_2048.pub # [Conditionally required], Root Certificate File 0; Root certificate file index 0.
+rootCertificate1File: p1_cert0_2048.pub # [Optional], Root Certificate File 1; Root certificate file index 1.
+rootCertificate2File: p2_cert0_2048.pub # [Optional], Root Certificate File 2; Root certificate file index 2.
+rootCertificate3File: p3_cert0_2048.pub # [Optional], Root Certificate File 3; Root certificate file index 3.
diff --git a/tests/dat/data/elf2sb_config_sp.yaml b/tests/dat/data/elf2sb_config_sp.yaml
new file mode 100644
index 00000000..6faf876c
--- /dev/null
+++ b/tests/dat/data/elf2sb_config_sp.yaml
@@ -0,0 +1,31 @@
+# Copyright 2023 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+# =========== Master Boot Image converted config. ===========
+# ----------------------------------------------------------------------------------------------------
+# == Basic Settings ==
+# ----------------------------------------------------------------------------------------------------
+family: rt5xx # [Required], MCU family name; Possible options:['lpc55s0x', 'lpc55s1x', 'rt5xx', 'rt6xx']
+outputImageExecutionTarget: External flash (XIP) # [Required], Application target; Definition if application is Execute in Place(XiP) or loaded to RAM during reset sequence; Possible options:['Internal flash (XIP)', 'External flash (XIP)', 'Internal Flash (XIP)', 'External Flash (XIP)', 'RAM', 'ram', 'xip']
+outputImageAuthenticationType: Signed # [Required], Type of boot image authentication; Specification of final master boot image authentication; Possible options:['Plain', 'CRC', 'Signed', 'Encrypted + Signed', 'NXP Signed', 'encrypted', 'signed', 'crc']
+masterBootOutputFile: output_images/application_signed.bin # [Required], Master Boot Image name; The file for Master Boot Image result file.
+inputImageFile: input_images/rt500_hello_world_plain.bin # [Required], Plain application image; The input application image to by modified to Master Boot Image.
+outputImageExecutionAddress: '0x00000000' # [Required], Loading address of application; Application loading address in RAM if not XiP, otherwise address of load in XiP.
+enableHwUserModeKeys: false # [Required], Enable User HW key sharing; Controlling secure hardware key bus. If enabled(1), then it is possible to access keys on hardware secure bus from non-secure application, else non-secure application will read zeros.
+# ----------------------------------------------------------------------------------------------------
+# == Trust Zone Settings ==
+# ----------------------------------------------------------------------------------------------------
+enableTrustZone: false # [Optional], TrustZone enable option; If not specified, the Trust zone is disabled.
+trustZonePresetFile: '' # [Optional], TrustZone Customization file; If not specified, but TrustZone is enabled(enableTrustZone) the default values are used.
+# ----------------------------------------------------------------------------------------------------
+# == Certificate V2 Settings ==
+# ----------------------------------------------------------------------------------------------------
+signProvider: type=file;file_path=k0_cert0_2048.pem # [Conditionally required], Signature provider configuration in format 'type=;=;=". It can be replaced by mainCertPrivateKeyFile key.
+# ----------------------------------------------------------------------------------------------------
+# == Root Keys Settings ==
+# ----------------------------------------------------------------------------------------------------
+rootCertificate0File: p0_cert0_2048.pub # [Conditionally required], Root Certificate File 0; Root certificate file index 0.
+rootCertificate1File: p1_cert0_2048.pub # [Optional], Root Certificate File 1; Root certificate file index 1.
+rootCertificate2File: p2_cert0_2048.pub # [Optional], Root Certificate File 2; Root certificate file index 2.
+rootCertificate3File: p3_cert0_2048.pub # [Optional], Root Certificate File 3; Root certificate file index 3.
diff --git a/tests/dat/test_debug_cred.py b/tests/dat/test_debug_cred.py
index 8888c656..faf9f7e9 100644
--- a/tests/dat/test_debug_cred.py
+++ b/tests/dat/test_debug_cred.py
@@ -39,6 +39,7 @@ def test_determine_protocol_version(protocol_version, rsa_detected, invalid):
if invalid:
with pytest.raises(SPSDKValueError):
protocol = DatProtocol(protocol_version)
+ protocol.validate()
else:
protocol = DatProtocol(protocol_version)
assert protocol.is_rsa() is rsa_detected
diff --git a/tests/dat/test_nxpdebugmbox.py b/tests/dat/test_nxpdebugmbox.py
index db835423..8b98f425 100644
--- a/tests/dat/test_nxpdebugmbox.py
+++ b/tests/dat/test_nxpdebugmbox.py
@@ -152,13 +152,17 @@ def test_generate_dc_file_lpc55s3x_384(tmpdir, data_dir):
assert os.path.isfile(out_file)
-def test_generate_rsa_with_elf2sb(tmpdir, data_dir):
+@pytest.mark.parametrize(
+ "config",
+ ["elf2sb_config.yaml", "elf2sb_config_sp.yaml"],
+)
+def test_generate_rsa_with_elf2sb(tmpdir, data_dir, config):
org_file = f"{tmpdir}/org.dc"
new_file = f"{tmpdir}/new.dc"
cmd1 = f"-p 1.0 gendc -c org_dck_rsa_2048.yml {org_file}"
# keys were removed from yaml and supplied by elf2sb config
- cmd2 = f"-p 1.0 gendc -c no_key_dck_rsa_2048.yml -e elf2sb_config.json {new_file}"
+ cmd2 = f"-p 1.0 gendc -c no_key_dck_rsa_2048.yml -e {config} {new_file}"
with use_working_directory(data_dir):
result = CliRunner().invoke(main, cmd1.split())
assert result.exit_code == 0, result.output
diff --git a/tests/dat/test_plugin.py b/tests/dat/test_plugin.py
index de71cad9..6b616947 100644
--- a/tests/dat/test_plugin.py
+++ b/tests/dat/test_plugin.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#
-# Copyright 2020-2021 NXP
+# Copyright 2020-2023 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
@@ -13,9 +13,18 @@
def test_nxpkeygen_plugin(tmpdir, data_dir):
out_dc = f"{tmpdir}/file.dc"
- cmd = f"gendc -c plugin_dck_rsa_2048.yml --plugin signature_provider.py {out_dc}"
+ cmd = [
+ "-p",
+ "1.0",
+ "gendc",
+ "-c",
+ "plugin_dck_rsa_2048.yml",
+ "--plugin",
+ "signature_provider.py",
+ out_dc,
+ ]
with use_working_directory(data_dir):
- result = CliRunner().invoke(nxpdebugmbox.main, cmd.split())
+ result = CliRunner().invoke(nxpdebugmbox.main, cmd)
assert result.exit_code == 0, result.output
with open(out_dc, "rb") as f:
dc_data = f.read()
diff --git a/tests/dk6/__init__.py b/tests/dk6/__init__.py
new file mode 100644
index 00000000..5db92522
--- /dev/null
+++ b/tests/dk6/__init__.py
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+#
+# Copyright 2022-2023 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+"""Unit test package for dk6_tools."""
diff --git a/tests/dk6/test_commands.py b/tests/dk6/test_commands.py
new file mode 100644
index 00000000..5d9a4ecb
--- /dev/null
+++ b/tests/dk6/test_commands.py
@@ -0,0 +1,155 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+#
+# Copyright 2022-2023 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+import pytest
+
+from spsdk.dk6.commands import *
+
+
+@pytest.mark.parametrize(
+ "type,raw_data",
+ [
+ (CommandTag.GET_CHIPID, b"\x21\x4a\x04\x94"),
+ (
+ CommandTag.UNLOCK_ISP,
+ b"\x01\x11\x22\x33\x44\x55\x66\x77\x88\x11\x22\x33\x44\x55\x66\x77\x88",
+ ),
+ ],
+)
+def test_cmd_response(type, raw_data):
+ cmd_response = CmdResponse(type, raw_data)
+ assert cmd_response.status == raw_data[0]
+ assert "Status" and "Type" in cmd_response.info()
+
+
+@pytest.mark.parametrize(
+ "type,raw_data",
+ [
+ (CommandTag.GET_CHIPID, b"\x21\x4a\x04\x94"),
+ (
+ CommandTag.UNLOCK_ISP,
+ b"\x01\x11\x22\x33\x44\x55\x66\x77\x88\x11\x22\x33\x44\x55\x66\x77\x88",
+ ),
+ ],
+)
+def test_generic_response(type, raw_data):
+ generic_response = GenericResponse(type, raw_data)
+ assert generic_response.status == raw_data[0]
+
+
+@pytest.mark.parametrize(
+ "type,raw_data",
+ [
+ (ResponseTag.UNLOCK_ISP, b"\x00"),
+ ],
+)
+def test_isp_unlock_response(type, raw_data):
+ isp_unlock = IspUnlockResponse(type, raw_data)
+ assert isp_unlock.authenticated == True
+ assert isp_unlock.status == StatusCode.OK
+
+
+@pytest.mark.parametrize(
+ "type,raw_data",
+ [
+ (ResponseTag.GET_CHIPID, b"\x00\x88\x88\x88\x88\xcc\x00\x00\x14"),
+ ],
+)
+def test_get_chip_id_response(type, raw_data):
+ chip_id = GetChipIdResponse(type, raw_data)
+ assert chip_id.status == StatusCode.OK
+ assert chip_id.chip_id == 0x88888888
+ assert chip_id.chip_version == 0x140000CC
+
+
+@pytest.mark.parametrize(
+ "type,raw_data",
+ [
+ (
+ ResponseTag.MEM_GET_INFO,
+ b"\x00\x00\x00\x00\x00\x00\x00\xde\x09\x00\x00\x02\x00\x00\x01\x0f\x46\x4c\x41\x53\x48",
+ )
+ ],
+)
+def test_mem_get_info_response(type, raw_data):
+ get_info = MemGetInfoResponse(type, raw_data)
+ assert get_info.status == StatusCode.OK
+ assert get_info.access == 15
+ assert get_info.base_addr == 0x0
+ assert get_info.length == 0x9DE00
+ assert "FLASH" in get_info.mem_name
+ assert get_info.mem_type == 0x1
+ assert get_info.memory_id == 0x0
+ assert get_info.sector_size == 0x200
+ assert get_info.mem_name == get_info.raw_data[15:].decode("ascii")
+
+
+@pytest.mark.parametrize(
+ "type,raw_data",
+ [
+ (ResponseTag.MEM_OPEN, b"\x00\x00"),
+ ],
+)
+def test_mem_open_response(type, raw_data):
+ mem_open = MemOpenResponse(type, raw_data)
+ assert mem_open.status == StatusCode.OK
+ assert mem_open.handle[0] == 0
+
+
+@pytest.mark.parametrize(
+ "type,raw_data",
+ [
+ (ResponseTag.MEM_READ, b"\x00\xff\xff\xff\xff\xff\xff\xff\xff"),
+ ],
+)
+def test_mem_read_response(type, raw_data):
+ mem_read = MemReadResponse(type, raw_data)
+ assert mem_read.status == StatusCode.OK
+ assert mem_read.data == raw_data[1:]
+
+
+@pytest.mark.parametrize(
+ "type,raw_data",
+ [
+ (ResponseTag.MEM_WRITE, b"\x00\x00\x00\x00\x00\x00\x00\x00\x00"),
+ ],
+)
+def test_mem_write_response(type, raw_data):
+ mem_write = MemWriteResponse(type, raw_data)
+ assert mem_write.status == StatusCode.OK
+
+
+@pytest.mark.parametrize(
+ "type,raw_data",
+ [
+ (ResponseTag.MEM_ERASE, b"\x00\x00\x09\x43\x00\x12\xa7\xd0\x54"),
+ ],
+)
+def test_mem_erase_response(type, raw_data):
+ mem_erase = MemEraseResponse(type, raw_data)
+ assert mem_erase.status == StatusCode.OK
+
+
+@pytest.mark.parametrize(
+ "type,raw_data",
+ [
+ (ResponseTag.MEM_BLANK_CHECK, b"\x00\x00\x09\x45\x00\x44\xfd\x77\xd2"),
+ ],
+)
+def test_mem_check_response(type, raw_data):
+ mem_check = MemBlankCheckResponse(type, raw_data)
+ assert mem_check.status == StatusCode.OK
+
+
+@pytest.mark.parametrize(
+ "type,raw_data",
+ [
+ (ResponseTag.MEM_CLOSE, b"\x00"),
+ ],
+)
+def test_mem_close_response(type, raw_data):
+ mem_close = MemCloseResponse(type, raw_data)
+ assert mem_close.status == StatusCode.OK
diff --git a/tests/dk6/test_dk6_tools.py b/tests/dk6/test_dk6_tools.py
new file mode 100644
index 00000000..9c933b67
--- /dev/null
+++ b/tests/dk6/test_dk6_tools.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+#
+# Copyright 2022-2023 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+"""Tests for `dk6_tools` package."""
+import platform
+
+from click.testing import CliRunner
+
+from spsdk.apps import dk6prog
+
+
+def test_cli():
+ """Test the CLI."""
+ runner = CliRunner()
+ result = runner.invoke(dk6prog.main)
+ assert result.exit_code == 0
+ assert "Usage: dk6prog [OPTIONS] COMMAND1" in result.output
+ help_result = runner.invoke(dk6prog.main, ["--help"])
+ assert help_result.exit_code == 0
+ assert "Usage: dk6prog [OPTIONS] COMMAND1" in help_result.output
+
+
+def test_cli_listdev():
+ """Test the CLI listdev command."""
+ if platform.system() == "Windows":
+ # Test needs FTD2xx.DLL
+ return
+ runner = CliRunner()
+ result = runner.invoke(dk6prog.main, "listdev")
+ assert result.exit_code == 0
+ assert "List of available devices:" in result.output
+
+
+def test_cli_erase():
+ """Test the CLI erase command."""
+ runner = CliRunner()
+ result = runner.invoke(dk6prog.main, "erase --help")
+ assert result.exit_code == 0
+ assert "Erase the content of memory at the given " in result.output
+
+
+def test_cli_read():
+ """Test the CLI read command."""
+ runner = CliRunner()
+ result = runner.invoke(dk6prog.main, "read --help")
+ assert result.exit_code == 0
+ assert "Reads the memory and writes it to the file or stdout." in result.output
+
+
+def test_cli_info():
+ """Test the CLI info command."""
+ runner = CliRunner()
+ result = runner.invoke(dk6prog.main, "info")
+ assert result.exit_code == 1
+ # assert "Issues ISP sequence as defined in Driver interface." in result.output
diff --git a/tests/dk6/test_protocol.py b/tests/dk6/test_protocol.py
new file mode 100644
index 00000000..9e1292ff
--- /dev/null
+++ b/tests/dk6/test_protocol.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+#
+# Copyright 2022-2023 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+import pytest
+
+from spsdk.dk6.commands import CommandTag
+from spsdk.dk6.interface import Uart, to_int
+
+
+@pytest.mark.parametrize(
+ "data,frame_type,expected_frame",
+ [
+ (None, CommandTag.GET_CHIPID, b"\x00\x00\x08\x32\x21\x4a\x04\x94"),
+ (b"\x00", CommandTag.UNLOCK_ISP, b"\x00\x00\x09\x4e\x00\xa7\x09\xae\x19"),
+ ],
+)
+def test_frame(data, frame_type, expected_frame):
+ frame = Uart.create_frame(data, frame_type)
+ assert frame == expected_frame
+
+
+def test_crc():
+ data = b"\x00"
+ frame_type = CommandTag.UNLOCK_ISP
+ expected_crc = to_int(b"\xa7\x09\xae\x19")
+ crc = Uart.calc_frame_crc(data, frame_type)
+ assert expected_crc == crc
diff --git a/tests/elftosb/data/workspace/cfgs/k32w1xx/mb_xip_256_none_sd.json b/tests/elftosb/data/workspace/cfgs/k32w1xx/mb_xip_256_none_sd.json
index 0e4e8918..36e7072c 100644
--- a/tests/elftosb/data/workspace/cfgs/k32w1xx/mb_xip_256_none_sd.json
+++ b/tests/elftosb/data/workspace/cfgs/k32w1xx/mb_xip_256_none_sd.json
@@ -5,7 +5,6 @@
"outputImageExecutionAddress": "0x08001000",
"outputImageAuthenticationType": "signed",
"enableTrustZone": true,
- "attachSignDigest": true,
"trustZonePresetFile": ".\\workspace\\trustzone\\kw45xx\\tztest.bin",
"firmwareVersion": "0x1",
"rootCertificate0File": ".\\workspace\\keys_certs\\ec_secp256r1_cert0.pem",
@@ -16,7 +15,7 @@
"useIsk": false,
"mainRootCertPrivateKeyFile": ".\\workspace\\keys_certs\\ec_pk_secp256r1_cert0.pem",
"rootCertificateEllipticCurve": "secp256r1",
- "masterBootOutputFile": ".\\workspace\\output_images\\kw45xx\\mb_xip_256_none_sd.bin",
+ "masterBootOutputFile": ".\\workspace\\output_images\\k32w1xx\\mb_xip_256_none_sd.bin",
"testCertBlockMagic": "",
"testCorruptRkhRecord": false,
"testCorruptRkhRecordId": 0,
@@ -24,4 +23,4 @@
"testImageManifestMagic": "",
"testImageType": false,
"testImageTypeValue": 255
-}
+}
\ No newline at end of file
diff --git a/tests/elftosb/data/workspace/cfgs/k32w1xx/mb_xip_384_256.json b/tests/elftosb/data/workspace/cfgs/k32w1xx/mb_xip_384_256.json
index c9091746..0f0ace49 100644
--- a/tests/elftosb/data/workspace/cfgs/k32w1xx/mb_xip_384_256.json
+++ b/tests/elftosb/data/workspace/cfgs/k32w1xx/mb_xip_384_256.json
@@ -4,7 +4,6 @@
"outputImageExecutionTarget": "xip",
"outputImageExecutionAddress": "0x08001000",
"outputImageAuthenticationType": "signed",
- "attachSignDigest": false,
"trustZonePresetFile": "",
"firmwareVersion": "0x1",
"outputImageSubtype": "default",
diff --git a/tests/elftosb/data/workspace/cfgs/k32w1xx/mb_xip_384_256_sd.json b/tests/elftosb/data/workspace/cfgs/k32w1xx/mb_xip_384_256_sd.json
index e7f03039..c68664f5 100644
--- a/tests/elftosb/data/workspace/cfgs/k32w1xx/mb_xip_384_256_sd.json
+++ b/tests/elftosb/data/workspace/cfgs/k32w1xx/mb_xip_384_256_sd.json
@@ -4,7 +4,7 @@
"outputImageExecutionTarget": "xip",
"outputImageExecutionAddress": "0x08001000",
"outputImageAuthenticationType": "signed",
- "attachSignDigest": true,
+ "manifestDigestHashAlgorithm": "sha256",
"trustZonePresetFile": "",
"firmwareVersion": "0x1",
"rootCertificate0File": ".\\workspace\\keys_certs\\ec_secp384r1_cert0.pem",
@@ -20,7 +20,7 @@
"signingCertificateConstraint": "0x25",
"iskCertificateEllipticCurve": "secp256r1",
"signCertData": "",
- "masterBootOutputFile": ".\\workspace\\output_images\\kw45xx\\mb_xip_384_256_sd.bin",
+ "masterBootOutputFile": ".\\workspace\\output_images\\k32w1xx\\mb_xip_384_256_sd.bin",
"testCertBlockMagic": "",
"testCorruptRkhRecord": false,
"testCorruptRkhRecordId": 0,
@@ -28,4 +28,4 @@
"testImageManifestMagic": "",
"testImageType": false,
"testImageTypeValue": 255
-}
+}
\ No newline at end of file
diff --git a/tests/elftosb/data/workspace/cfgs/k32w1xx/mb_xip_384_384.json b/tests/elftosb/data/workspace/cfgs/k32w1xx/mb_xip_384_384.json
index d0652175..372ab3fd 100644
--- a/tests/elftosb/data/workspace/cfgs/k32w1xx/mb_xip_384_384.json
+++ b/tests/elftosb/data/workspace/cfgs/k32w1xx/mb_xip_384_384.json
@@ -4,7 +4,6 @@
"outputImageExecutionTarget": "xip",
"outputImageExecutionAddress": "0x0",
"outputImageAuthenticationType": "signed",
- "attachSignDigest": false,
"trustZonePresetFile": "",
"firmwareVersion": "0x1",
"isNxpImage": false,
diff --git a/tests/elftosb/data/workspace/cfgs/k32w1xx/mb_xip_384_384_no_signature.json b/tests/elftosb/data/workspace/cfgs/k32w1xx/mb_xip_384_384_no_signature.json
index 99ff6ee0..fe53c26c 100644
--- a/tests/elftosb/data/workspace/cfgs/k32w1xx/mb_xip_384_384_no_signature.json
+++ b/tests/elftosb/data/workspace/cfgs/k32w1xx/mb_xip_384_384_no_signature.json
@@ -4,7 +4,6 @@
"outputImageExecutionTarget": "xip",
"outputImageExecutionAddress": "0x0",
"outputImageAuthenticationType": "signed",
- "attachSignDigest": false,
"trustZonePresetFile": "",
"firmwareVersion": "0x1",
"noSignature": true,
diff --git a/tests/elftosb/data/workspace/cfgs/k32w1xx/mb_xip_384_384_sd.json b/tests/elftosb/data/workspace/cfgs/k32w1xx/mb_xip_384_384_sd.json
index 63ad5701..788cf7a4 100644
--- a/tests/elftosb/data/workspace/cfgs/k32w1xx/mb_xip_384_384_sd.json
+++ b/tests/elftosb/data/workspace/cfgs/k32w1xx/mb_xip_384_384_sd.json
@@ -4,7 +4,7 @@
"outputImageExecutionTarget": "xip",
"outputImageExecutionAddress": "0x0",
"outputImageAuthenticationType": "signed",
- "attachSignDigest": true,
+ "manifestDigestHashAlgorithm": "sha384",
"trustZonePresetFile": "",
"firmwareVersion": "0x1",
"rootCertificate0File": ".\\workspace\\keys_certs\\ec_secp384r1_cert0.pem",
@@ -20,7 +20,7 @@
"signingCertificateConstraint": "0x25",
"iskCertificateEllipticCurve": "secp384r1",
"signCertData": ".\\workspace\\input_images\\testfffffff.bin",
- "masterBootOutputFile": ".\\workspace\\output_images\\kw45xx\\mb_xip_384_384_sd.bin",
+ "masterBootOutputFile": ".\\workspace\\output_images\\k32w1xx\\mb_xip_384_384_sd.bin",
"testCertBlockMagic": "",
"testCorruptRkhRecord": false,
"testCorruptRkhRecordId": 0,
@@ -28,4 +28,4 @@
"testImageManifestMagic": "",
"testImageType": false,
"testImageTypeValue": 255
-}
+}
\ No newline at end of file
diff --git a/tests/elftosb/data/workspace/cfgs/kw45xx/mb_xip_256_none_sd.json b/tests/elftosb/data/workspace/cfgs/kw45xx/mb_xip_256_none_sd.json
index 09ad21c6..dd25a77b 100644
--- a/tests/elftosb/data/workspace/cfgs/kw45xx/mb_xip_256_none_sd.json
+++ b/tests/elftosb/data/workspace/cfgs/kw45xx/mb_xip_256_none_sd.json
@@ -5,7 +5,6 @@
"outputImageExecutionAddress": "0x08001000",
"outputImageAuthenticationType": "signed",
"enableTrustZone": true,
- "attachSignDigest": true,
"trustZonePresetFile": ".\\workspace\\trustzone\\kw45xx\\tztest.bin",
"firmwareVersion": "0x1",
"rootCertificate0File": ".\\workspace\\keys_certs\\ec_secp256r1_cert0.pem",
diff --git a/tests/elftosb/data/workspace/cfgs/kw45xx/mb_xip_384_256.json b/tests/elftosb/data/workspace/cfgs/kw45xx/mb_xip_384_256.json
index 18e5e499..caeb7d97 100644
--- a/tests/elftosb/data/workspace/cfgs/kw45xx/mb_xip_384_256.json
+++ b/tests/elftosb/data/workspace/cfgs/kw45xx/mb_xip_384_256.json
@@ -4,7 +4,6 @@
"outputImageExecutionTarget": "xip",
"outputImageExecutionAddress": "0x08001000",
"outputImageAuthenticationType": "signed",
- "attachSignDigest": false,
"trustZonePresetFile": "",
"firmwareVersion": "0x1",
"outputImageSubtype": "default",
diff --git a/tests/elftosb/data/workspace/cfgs/kw45xx/mb_xip_384_256_sd.json b/tests/elftosb/data/workspace/cfgs/kw45xx/mb_xip_384_256_sd.json
index a097b9d7..0240ea03 100644
--- a/tests/elftosb/data/workspace/cfgs/kw45xx/mb_xip_384_256_sd.json
+++ b/tests/elftosb/data/workspace/cfgs/kw45xx/mb_xip_384_256_sd.json
@@ -4,7 +4,7 @@
"outputImageExecutionTarget": "xip",
"outputImageExecutionAddress": "0x08001000",
"outputImageAuthenticationType": "signed",
- "attachSignDigest": true,
+ "manifestDigestHashAlgorithm": "sha256",
"trustZonePresetFile": "",
"firmwareVersion": "0x1",
"rootCertificate0File": ".\\workspace\\keys_certs\\ec_secp384r1_cert0.pem",
diff --git a/tests/elftosb/data/workspace/cfgs/kw45xx/mb_xip_384_384.json b/tests/elftosb/data/workspace/cfgs/kw45xx/mb_xip_384_384.json
index 5e2956d3..5eb22a69 100644
--- a/tests/elftosb/data/workspace/cfgs/kw45xx/mb_xip_384_384.json
+++ b/tests/elftosb/data/workspace/cfgs/kw45xx/mb_xip_384_384.json
@@ -4,7 +4,6 @@
"outputImageExecutionTarget": "xip",
"outputImageExecutionAddress": "0x0",
"outputImageAuthenticationType": "signed",
- "attachSignDigest": false,
"trustZonePresetFile": "",
"firmwareVersion": "0x1",
"isNxpImage": false,
diff --git a/tests/elftosb/data/workspace/cfgs/kw45xx/mb_xip_384_384_no_signature.json b/tests/elftosb/data/workspace/cfgs/kw45xx/mb_xip_384_384_no_signature.json
index d911b68d..b42c8f28 100644
--- a/tests/elftosb/data/workspace/cfgs/kw45xx/mb_xip_384_384_no_signature.json
+++ b/tests/elftosb/data/workspace/cfgs/kw45xx/mb_xip_384_384_no_signature.json
@@ -4,7 +4,6 @@
"outputImageExecutionTarget": "xip",
"outputImageExecutionAddress": "0x0",
"outputImageAuthenticationType": "signed",
- "attachSignDigest": false,
"trustZonePresetFile": "",
"firmwareVersion": "0x1",
"noSignature": true,
diff --git a/tests/elftosb/data/workspace/cfgs/kw45xx/mb_xip_384_384_sd.json b/tests/elftosb/data/workspace/cfgs/kw45xx/mb_xip_384_384_sd.json
index 614cb0f2..155640bd 100644
--- a/tests/elftosb/data/workspace/cfgs/kw45xx/mb_xip_384_384_sd.json
+++ b/tests/elftosb/data/workspace/cfgs/kw45xx/mb_xip_384_384_sd.json
@@ -4,7 +4,7 @@
"outputImageExecutionTarget": "xip",
"outputImageExecutionAddress": "0x0",
"outputImageAuthenticationType": "signed",
- "attachSignDigest": true,
+ "manifestDigestHashAlgorithm": "sha384",
"trustZonePresetFile": "",
"firmwareVersion": "0x1",
"rootCertificate0File": ".\\workspace\\keys_certs\\ec_secp384r1_cert0.pem",
diff --git a/tests/elftosb/data/workspace/cfgs/lpc55s3x/mb_ext_xip_signed.json b/tests/elftosb/data/workspace/cfgs/lpc55s3x/mb_ext_xip_signed.json
index 79a0c7a9..5969862c 100644
--- a/tests/elftosb/data/workspace/cfgs/lpc55s3x/mb_ext_xip_signed.json
+++ b/tests/elftosb/data/workspace/cfgs/lpc55s3x/mb_ext_xip_signed.json
@@ -12,7 +12,6 @@
"signingCertificateFile": ".\\workspace\\keys_certs\\ec_secp384r1_sign_cert.pem",
"signingCertificateConstraint": "0x25",
"signCertData": ".\\workspace\\input_images\\testfffffff.bin",
- "manifestSigningHashLength": 32,
"rootCertificate0File": ".\\workspace\\keys_certs\\ec_secp384r1_cert0.pem",
"rootCertificate1File": ".\\workspace\\keys_certs\\ec_secp384r1_cert1.pem",
"rootCertificate2File": ".\\workspace\\keys_certs\\ec_secp384r1_cert2.pem",
@@ -20,4 +19,4 @@
"mainRootCertId": 0,
"enableTrustZone": false,
"trustZonePresetFile": ""
-}
+}
\ No newline at end of file
diff --git a/tests/elftosb/data/workspace/cfgs/mcxn9xx/mb_ram_crc.json b/tests/elftosb/data/workspace/cfgs/mcxn9xx/mb_ram_crc.json
new file mode 100644
index 00000000..ec596b0e
--- /dev/null
+++ b/tests/elftosb/data/workspace/cfgs/mcxn9xx/mb_ram_crc.json
@@ -0,0 +1,9 @@
+{
+ "family": "mcxn9xx",
+ "inputImageFile": ".\\workspace\\input_images\\normal_boot.bin",
+ "outputImageExecutionTarget": "ram",
+ "outputImageExecutionAddress": "0x1000",
+ "outputImageAuthenticationType": "crc",
+ "trustZonePresetFile": ".\\workspace\\trustzone\\mcxn9xx\\tz_mcxn9xx.bin",
+ "masterBootOutputFile": ".\\workspace\\output_images\\mcxn9xx\\mb_ram_crc.bin"
+}
diff --git a/tests/elftosb/data/workspace/cfgs/mcxn9xx/mb_xip_256_none.json b/tests/elftosb/data/workspace/cfgs/mcxn9xx/mb_xip_256_none.json
new file mode 100644
index 00000000..30606a9e
--- /dev/null
+++ b/tests/elftosb/data/workspace/cfgs/mcxn9xx/mb_xip_256_none.json
@@ -0,0 +1,25 @@
+{
+ "family": "mcxn9xx",
+ "inputImageFile": ".\\workspace\\input_images\\normal_boot.bin",
+ "outputImageExecutionTarget": "xip",
+ "outputImageExecutionAddress": "0x08001000",
+ "outputImageAuthenticationType": "signed",
+ "enableTrustZone": true,
+ "trustZonePresetFile": ".\\workspace\\trustzone\\mcxn9xx\\tz_mcxn9xx.bin",
+ "firmwareVersion": "0x0",
+ "rootCertificate0File": ".\\workspace\\keys_certs\\ec_secp256r1_cert0.pem",
+ "rootCertificate1File": ".\\workspace\\keys_certs\\ec_secp256r1_cert1.pem",
+ "rootCertificate2File": ".\\workspace\\keys_certs\\ec_secp256r1_cert2.pem",
+ "rootCertificate3File": ".\\workspace\\keys_certs\\ec_secp256r1_cert3.pem",
+ "mainRootCertId": 0,
+ "useIsk": false,
+ "mainRootCertPrivateKeyFile": ".\\workspace\\keys_certs\\ec_pk_secp256r1_cert0.pem",
+ "rootCertificateEllipticCurve": "secp256r1",
+ "masterBootOutputFile": ".\\workspace\\output_images\\mcxn9xx\\mb_xip_256_none.bin",
+ "testCorruptRkhRecord": false,
+ "testCorruptRkhRecordId": 0,
+ "testCorruptIskSignature": false,
+ "testImageManifestMagic": "",
+ "testImageType": false,
+ "testImageTypeValue": 255
+}
diff --git a/tests/elftosb/data/workspace/cfgs/mcxn9xx/mb_xip_384_256.json b/tests/elftosb/data/workspace/cfgs/mcxn9xx/mb_xip_384_256.json
new file mode 100644
index 00000000..1b50e41f
--- /dev/null
+++ b/tests/elftosb/data/workspace/cfgs/mcxn9xx/mb_xip_384_256.json
@@ -0,0 +1,31 @@
+{
+ "family": "mcxn9xx",
+ "inputImageFile": ".\\workspace\\input_images\\normal_boot.bin",
+ "outputImageExecutionTarget": "xip",
+ "outputImageExecutionAddress": "0x08001000",
+ "outputImageAuthenticationType": "signed",
+ "attachSignDigest": false,
+ "trustZonePresetFile": ".\\workspace\\trustzone\\mcxn9xx\\tz_mcxn9xx.bin",
+ "firmwareVersion": "0x0",
+ "rootCertificate0File": ".\\workspace\\keys_certs\\ec_secp384r1_cert0.pem",
+ "rootCertificate1File": ".\\workspace\\keys_certs\\ec_secp384r1_cert1.pem",
+ "rootCertificate2File": ".\\workspace\\keys_certs\\ec_secp384r1_cert2.pem",
+ "rootCertificate3File": ".\\workspace\\keys_certs\\ec_secp384r1_cert3.pem",
+ "mainRootCertId": 0,
+ "mainRootCertPrivateKeyFile": ".\\workspace\\keys_certs\\ec_pk_secp384r1_cert0.pem",
+ "rootCertificateEllipticCurve": "secp384r1",
+ "useIsk": true,
+ "signingCertificateFile": ".\\workspace\\keys_certs\\ec_secp256r1_sign_cert.pem",
+ "signingCertificatePrivateKeyFile": ".\\workspace\\keys_certs\\ec_pk_secp256r1_sign_cert.pem",
+ "signingCertificateConstraint": "0x25",
+ "iskCertificateEllipticCurve": "secp256r1",
+ "signCertData": "",
+ "masterBootOutputFile": ".\\workspace\\output_images\\mcxn9xx\\mb_xip_384_256.bin",
+ "testCertBlockMagic": "",
+ "testCorruptRkhRecord": false,
+ "testCorruptRkhRecordId": 0,
+ "testCorruptIskSignature": false,
+ "testImageManifestMagic": "",
+ "testImageType": false,
+ "testImageTypeValue": 255
+}
diff --git a/tests/elftosb/data/workspace/cfgs/mcxn9xx/mb_xip_384_384.json b/tests/elftosb/data/workspace/cfgs/mcxn9xx/mb_xip_384_384.json
new file mode 100644
index 00000000..0323774e
--- /dev/null
+++ b/tests/elftosb/data/workspace/cfgs/mcxn9xx/mb_xip_384_384.json
@@ -0,0 +1,31 @@
+{
+ "family": "mcxn9xx",
+ "inputImageFile": ".\\workspace\\input_images\\normal_boot.bin",
+ "outputImageExecutionTarget": "xip",
+ "outputImageExecutionAddress": "0x0",
+ "outputImageAuthenticationType": "signed",
+ "attachSignDigest": false,
+ "trustZonePresetFile": ".\\workspace\\trustzone\\mcxn9xx\\tz_mcxn9xx.bin",
+ "firmwareVersion": "0x0",
+ "rootCertificate0File": ".\\workspace\\keys_certs\\ec_secp384r1_cert0.pem",
+ "rootCertificate1File": ".\\workspace\\keys_certs\\ec_secp384r1_cert1.pem",
+ "rootCertificate2File": ".\\workspace\\keys_certs\\ec_secp384r1_cert2.pem",
+ "rootCertificate3File": ".\\workspace\\keys_certs\\ec_secp384r1_cert3.pem",
+ "mainRootCertId": 0,
+ "mainRootCertPrivateKeyFile": ".\\workspace\\keys_certs\\ec_pk_secp384r1_cert0.pem",
+ "rootCertificateEllipticCurve": "secp384r1",
+ "useIsk": true,
+ "signingCertificateFile": ".\\workspace\\keys_certs\\ec_secp384r1_sign_cert.pem",
+ "signingCertificatePrivateKeyFile": ".\\workspace\\keys_certs\\ec_pk_secp384r1_sign_cert.pem",
+ "signingCertificateConstraint": "0x25",
+ "iskCertificateEllipticCurve": "secp384r1",
+ "signCertData": ".\\workspace\\input_images\\testfffffff.bin",
+ "masterBootOutputFile": ".\\workspace\\output_images\\mcxn9xx\\mb_xip_384_384.bin",
+ "testCertBlockMagic": "",
+ "testCorruptRkhRecord": false,
+ "testCorruptRkhRecordId": 0,
+ "testCorruptIskSignature": false,
+ "testImageManifestMagic": "",
+ "testImageType": false,
+ "testImageTypeValue": 255
+}
diff --git a/tests/elftosb/data/workspace/cfgs/mcxn9xx/mb_xip_384_384_recovery.json b/tests/elftosb/data/workspace/cfgs/mcxn9xx/mb_xip_384_384_recovery.json
new file mode 100644
index 00000000..edca3202
--- /dev/null
+++ b/tests/elftosb/data/workspace/cfgs/mcxn9xx/mb_xip_384_384_recovery.json
@@ -0,0 +1,25 @@
+{
+ "family": "mcxn9xx",
+ "inputImageFile": ".\\workspace\\input_images\\normal_boot.bin",
+ "outputImageExecutionTarget": "xip",
+ "outputImageExecutionAddress": "0x0",
+ "outputImageAuthenticationType": "signed",
+ "outputImageSubtype": "recovery",
+ "attachSignDigest": false,
+ "trustZonePresetFile": ".\\workspace\\trustzone\\mcxn9xx\\tz_mcxn9xx.bin",
+ "firmwareVersion": "0x1",
+ "rootCertificate0File": ".\\workspace\\keys_certs\\ec_secp384r1_cert0.pem",
+ "rootCertificate1File": ".\\workspace\\keys_certs\\ec_secp384r1_cert1.pem",
+ "rootCertificate2File": ".\\workspace\\keys_certs\\ec_secp384r1_cert2.pem",
+ "rootCertificate3File": ".\\workspace\\keys_certs\\ec_secp384r1_cert3.pem",
+ "mainRootCertId": 0,
+ "mainRootCertPrivateKeyFile": ".\\workspace\\keys_certs\\ec_pk_secp384r1_cert0.pem",
+ "rootCertificateEllipticCurve": "secp384r1",
+ "useIsk": true,
+ "signingCertificateFile": ".\\workspace\\keys_certs\\ec_secp384r1_sign_cert.pem",
+ "signingCertificatePrivateKeyFile": ".\\workspace\\keys_certs\\ec_pk_secp384r1_sign_cert.pem",
+ "signingCertificateConstraint": "0x25",
+ "iskCertificateEllipticCurve": "secp384r1",
+ "signCertData": "",
+ "masterBootOutputFile": ".\\workspace\\output_images\\mcxn9xx\\mb_xip_384_384_recovery.bin"
+}
diff --git a/tests/elftosb/data/workspace/cfgs/mcxn9xx/mb_xip_384_384_recovery_crctest.json b/tests/elftosb/data/workspace/cfgs/mcxn9xx/mb_xip_384_384_recovery_crctest.json
new file mode 100644
index 00000000..d7b6629f
--- /dev/null
+++ b/tests/elftosb/data/workspace/cfgs/mcxn9xx/mb_xip_384_384_recovery_crctest.json
@@ -0,0 +1,25 @@
+{
+ "family": "mcxn9xx",
+ "inputImageFile": ".\\workspace\\input_images\\normal_boot.bin",
+ "outputImageExecutionTarget": "xip",
+ "outputImageExecutionAddress": "0x0",
+ "outputImageAuthenticationType": "signed",
+ "outputImageSubtype": "RECOVERY",
+ "attachSignDigest": false,
+ "trustZonePresetFile": ".\\workspace\\trustzone\\mcxn9xx\\tz_mcxn9xx.bin",
+ "firmwareVersion": "0x0",
+ "rootCertificate0File": ".\\workspace\\keys_certs\\ec_secp384r1_cert0.pem",
+ "rootCertificate1File": ".\\workspace\\keys_certs\\ec_secp384r1_cert1.pem",
+ "rootCertificate2File": ".\\workspace\\keys_certs\\ec_secp384r1_cert2.pem",
+ "rootCertificate3File": ".\\workspace\\keys_certs\\ec_secp384r1_cert3.pem",
+ "mainRootCertId": 0,
+ "mainRootCertPrivateKeyFile": ".\\workspace\\keys_certs\\ec_pk_secp384r1_cert0.pem",
+ "rootCertificateEllipticCurve": "secp384r1",
+ "useIsk": true,
+ "signingCertificateFile": ".\\workspace\\keys_certs\\ec_secp384r1_sign_cert.pem",
+ "signingCertificatePrivateKeyFile": ".\\workspace\\keys_certs\\ec_pk_secp384r1_sign_cert.pem",
+ "signingCertificateConstraint": "0x25",
+ "iskCertificateEllipticCurve": "secp384r1",
+ "signCertData": "",
+ "masterBootOutputFile": ".\\workspace\\output_images\\mcxn9xx\\mb_xip_384_384_recovery_crctest.bin"
+}
diff --git a/tests/elftosb/data/workspace/cfgs/mcxn9xx/mb_xip_crc.json b/tests/elftosb/data/workspace/cfgs/mcxn9xx/mb_xip_crc.json
new file mode 100644
index 00000000..19a021b0
--- /dev/null
+++ b/tests/elftosb/data/workspace/cfgs/mcxn9xx/mb_xip_crc.json
@@ -0,0 +1,9 @@
+{
+ "family": "mcxn9xx",
+ "inputImageFile": ".\\workspace\\input_images\\normal_boot.bin",
+ "outputImageExecutionTarget": "xip",
+ "outputImageExecutionAddress": "0x08001000",
+ "outputImageAuthenticationType": "crc",
+ "trustZonePresetFile": ".\\workspace\\trustzone\\mcxn9xx\\tz_mcxn9xx.bin",
+ "masterBootOutputFile": ".\\workspace\\output_images\\mcxn9xx\\mb_xip_crc.bin"
+}
diff --git a/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_256_256.json b/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_256_256.json
new file mode 100644
index 00000000..6355b4a6
--- /dev/null
+++ b/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_256_256.json
@@ -0,0 +1,38 @@
+{
+ "family": "mcxn9xx",
+ "containerKeyBlobEncryptionKey": ".\\workspace\\keys\\userkey.txt",
+ "isNxpContainer": false,
+ "description": "sb3_256_256.sb3",
+ "kdkAccessRights": 3,
+ "containerConfigurationWord": "0x0",
+ "firmwareVersion": "0x1",
+ "timestamp": "0x123456789abcdef",
+ "rootCertificate0File": ".\\workspace\\keys_certs\\ec_secp256r1_cert0.pem",
+ "rootCertificate1File": ".\\workspace\\keys_certs\\ec_secp256r1_cert1.pem",
+ "rootCertificate2File": ".\\workspace\\keys_certs\\ec_secp256r1_cert2.pem",
+ "rootCertificate3File": ".\\workspace\\keys_certs\\ec_secp256r1_cert3.pem",
+ "rootCertificateEllipticCurve": "secp256r1",
+ "mainRootCertId": 0,
+ "mainRootCertPrivateKeyFile": ".\\workspace\\keys_certs\\ec_pk_secp256r1_cert0.pem",
+ "useIsk": true,
+ "signingCertificateFile": ".\\workspace\\keys_certs\\ec_secp256r1_sign_cert.pem",
+ "signingCertificatePrivateKeyFile": ".\\workspace\\keys_certs\\ec_pk_secp256r1_sign_cert.pem",
+ "signingCertificateConstraint": "0x0000",
+ "iskCertificateEllipticCurve": "secp256r1",
+ "signCertData": ".\\workspace\\input_images\\testfffffff.bin",
+ "commands": [
+ {
+ "erase": {
+ "address": "0x0",
+ "size": "0x10000"
+ }
+ },
+ {
+ "load": {
+ "address": "0x0",
+ "file": ".\\workspace\\output_images\\mcxn9xx\\normal_boot_sign.bin"
+ }
+ }
+ ],
+ "containerOutputFile": ".\\workspace\\output_images\\mcxn9xx\\sb3_256_256.sb3"
+}
diff --git a/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_256_none.json b/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_256_none.json
new file mode 100644
index 00000000..97bd455b
--- /dev/null
+++ b/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_256_none.json
@@ -0,0 +1,40 @@
+{
+ "family": "mcxn9xx",
+ "containerKeyBlobEncryptionKey": ".\\workspace\\keys\\userkey.txt",
+ "isNxpContainer": false,
+ "description": "sb3_256_none.sb3",
+ "kdkAccessRights": 3,
+ "containerConfigurationWord": "0x0",
+ "firmwareVersion": "0x1",
+ "timestamp": "0x123456789abcdef",
+ "rootCertificate0File": ".\\workspace\\keys_certs\\ec_secp256r1_cert0.pem",
+ "rootCertificate1File": ".\\workspace\\keys_certs\\ec_secp256r1_cert1.pem",
+ "rootCertificate2File": ".\\workspace\\keys_certs\\ec_secp256r1_cert2.pem",
+ "rootCertificate3File": ".\\workspace\\keys_certs\\ec_secp256r1_cert3.pem",
+ "rootCertificateEllipticCurve": "secp256r1",
+ "mainRootCertId": 0,
+ "mainRootCertPrivateKeyFile": ".\\workspace\\keys_certs\\ec_pk_secp256r1_cert0.pem",
+ "useIsk": false,
+ "testSb3Magic": "",
+ "testSb3ImageType": false,
+ "testSb3ImageTypeValue": 255,
+ "testCertBlockMagic": "",
+ "testCorruptRkhRecord": false,
+ "testCorruptRkhRecordId": 0,
+ "testCorruptIskSignature": false,
+ "commands": [
+ {
+ "erase": {
+ "address": "0x0",
+ "size": "0x10000"
+ }
+ },
+ {
+ "load": {
+ "address": "0xABCD",
+ "file": ".\\workspace\\output_images\\mcxn9xx\\normal_boot_sign.bin"
+ }
+ }
+ ],
+ "containerOutputFile": ".\\workspace\\output_images\\mcxn9xx\\sb3_256_none.sb3"
+}
diff --git a/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_384_256.json b/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_384_256.json
new file mode 100644
index 00000000..94663ebe
--- /dev/null
+++ b/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_384_256.json
@@ -0,0 +1,45 @@
+{
+ "family": "mcxn9xx",
+ "containerKeyBlobEncryptionKey": ".\\workspace\\keys\\userkey.txt",
+ "isNxpContainer": false,
+ "description": "sb3_384_256.sb3",
+ "kdkAccessRights": 3,
+ "containerConfigurationWord": "0x0",
+ "firmwareVersion": "0x1",
+ "timestamp": "0x123456789abcdef",
+ "rootCertificate0File": ".\\workspace\\keys_certs\\ec_secp384r1_cert0.pem",
+ "rootCertificate1File": ".\\workspace\\keys_certs\\ec_secp384r1_cert1.pem",
+ "rootCertificate2File": ".\\workspace\\keys_certs\\ec_secp384r1_cert2.pem",
+ "rootCertificate3File": ".\\workspace\\keys_certs\\ec_secp384r1_cert3.pem",
+ "rootCertificateEllipticCurve": "secp384r1",
+ "mainRootCertId": 2,
+ "mainRootCertPrivateKeyFile": ".\\workspace\\keys_certs\\ec_pk_secp384r1_cert2.pem",
+ "useIsk": true,
+ "signingCertificateFile": ".\\workspace\\keys_certs\\ec_secp256r1_sign_cert.pem",
+ "signingCertificatePrivateKeyFile": ".\\workspace\\keys_certs\\ec_pk_secp256r1_sign_cert.pem",
+ "signingCertificateConstraint": "0x0000",
+ "iskCertificateEllipticCurve": "secp256r1",
+ "signCertData": ".\\workspace\\input_images\\testfffffff.bin",
+ "testSb3Magic": "",
+ "testSb3ImageType": false,
+ "testSb3ImageTypeValue": 255,
+ "testCertBlockMagic": "",
+ "testCorruptRkhRecord": false,
+ "testCorruptRkhRecordId": 0,
+ "testCorruptIskSignature": false,
+ "commands": [
+ {
+ "erase": {
+ "address": "0x0",
+ "size": "0x10000"
+ }
+ },
+ {
+ "load": {
+ "address": "0x0",
+ "file": ".\\workspace\\output_images\\mcxn9xx\\normal_boot_sign.bin"
+ }
+ }
+ ],
+ "containerOutputFile": ".\\workspace\\output_images\\mcxn9xx\\sb3_384_256.sb3"
+}
diff --git a/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_384_256_fixed_timestamp.json b/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_384_256_fixed_timestamp.json
new file mode 100644
index 00000000..316c612d
--- /dev/null
+++ b/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_384_256_fixed_timestamp.json
@@ -0,0 +1,45 @@
+{
+ "family": "mcxn9xx",
+ "containerKeyBlobEncryptionKey": ".\\workspace\\keys\\userkey.txt",
+ "isNxpContainer": false,
+ "description": "sb3_384_256.sb3",
+ "timestamp": "0x123456789abcdef",
+ "kdkAccessRights": 3,
+ "containerConfigurationWord": "0x0",
+ "firmwareVersion": "0x1",
+ "rootCertificate0File": ".\\workspace\\keys_certs\\ec_secp384r1_cert0.pem",
+ "rootCertificate1File": ".\\workspace\\keys_certs\\ec_secp384r1_cert1.pem",
+ "rootCertificate2File": ".\\workspace\\keys_certs\\ec_secp384r1_cert2.pem",
+ "rootCertificate3File": ".\\workspace\\keys_certs\\ec_secp384r1_cert3.pem",
+ "rootCertificateEllipticCurve": "secp384r1",
+ "mainRootCertId": 0,
+ "mainRootCertPrivateKeyFile": ".\\workspace\\keys_certs\\ec_pk_secp384r1_cert0.pem",
+ "useIsk": true,
+ "signingCertificateFile": ".\\workspace\\keys_certs\\ec_secp256r1_sign_cert.pem",
+ "signingCertificatePrivateKeyFile": ".\\workspace\\keys_certs\\ec_pk_secp256r1_sign_cert.pem",
+ "signingCertificateConstraint": "0x0000",
+ "iskCertificateEllipticCurve": "secp256r1",
+ "signCertData": ".\\workspace\\input_images\\testfffffff.bin",
+ "testSb3Magic": "",
+ "testSb3ImageType": false,
+ "testSb3ImageTypeValue": 255,
+ "testCertBlockMagic": "",
+ "testCorruptRkhRecord": false,
+ "testCorruptRkhRecordId": 0,
+ "testCorruptIskSignature": false,
+ "commands": [
+ {
+ "erase": {
+ "address": "0x0",
+ "size": "0x10000"
+ }
+ },
+ {
+ "load": {
+ "address": "0x0",
+ "file": ".\\workspace\\output_images\\mcxn9xx\\normal_boot_sign.bin"
+ }
+ }
+ ],
+ "containerOutputFile": ".\\workspace\\output_images\\mcxn9xx\\sb3_384_256_fixed_timestamp.sb3"
+}
diff --git a/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_384_256_unencrypted.json b/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_384_256_unencrypted.json
new file mode 100644
index 00000000..064f28b7
--- /dev/null
+++ b/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_384_256_unencrypted.json
@@ -0,0 +1,46 @@
+{
+ "family": "mcxn9xx",
+ "containerKeyBlobEncryptionKey": ".\\workspace\\keys\\userkey.txt",
+ "isNxpContainer": false,
+ "description": "sb3_384_256.sb3",
+ "kdkAccessRights": 3,
+ "containerConfigurationWord": "0x0",
+ "firmwareVersion": "0x1",
+ "timestamp": "0x123456789abcdef",
+ "rootCertificate0File": ".\\workspace\\keys_certs\\ec_secp384r1_cert0.pem",
+ "rootCertificate1File": ".\\workspace\\keys_certs\\ec_secp384r1_cert1.pem",
+ "rootCertificate2File": ".\\workspace\\keys_certs\\ec_secp384r1_cert2.pem",
+ "rootCertificate3File": ".\\workspace\\keys_certs\\ec_secp384r1_cert3.pem",
+ "rootCertificateEllipticCurve": "secp384r1",
+ "mainRootCertId": 0,
+ "mainRootCertPrivateKeyFile": ".\\workspace\\keys_certs\\ec_pk_secp384r1_cert0.pem",
+ "useIsk": true,
+ "signingCertificateFile": ".\\workspace\\keys_certs\\ec_secp256r1_sign_cert.pem",
+ "signingCertificatePrivateKeyFile": ".\\workspace\\keys_certs\\ec_pk_secp256r1_sign_cert.pem",
+ "signingCertificateConstraint": "0x0000",
+ "iskCertificateEllipticCurve": "secp256r1",
+ "signCertData": ".\\workspace\\input_images\\testfffffff.bin",
+ "testSb3Magic": "",
+ "testSb3ImageType": false,
+ "testSb3ImageTypeValue": 255,
+ "testCertBlockMagic": "",
+ "testCorruptRkhRecord": false,
+ "testCorruptRkhRecordId": 0,
+ "testCorruptIskSignature": false,
+ "isEncrypted": false,
+ "commands": [
+ {
+ "erase": {
+ "address": "0x0",
+ "size": "0x10000"
+ }
+ },
+ {
+ "load": {
+ "address": "0x0",
+ "file": ".\\workspace\\output_images\\mcxn9xx\\normal_boot_sign.bin"
+ }
+ }
+ ],
+ "containerOutputFile": ".\\workspace\\output_images\\mcxn9xx\\sb3_384_256_unencrypted.sb3"
+}
diff --git a/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_384_384.json b/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_384_384.json
new file mode 100644
index 00000000..727baf43
--- /dev/null
+++ b/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_384_384.json
@@ -0,0 +1,44 @@
+{
+ "family": "mcxn9xx",
+ "containerKeyBlobEncryptionKey": ".\\workspace\\keys\\userkey.txt",
+ "isNxpContainer": true,
+ "description": "sb3_384_384.sb3",
+ "kdkAccessRights": 3,
+ "containerConfigurationWord": "0x0",
+ "firmwareVersion": "0x1",
+ "timestamp": "0x123456789abcdef",
+ "rootCertificate0File": ".\\workspace\\keys_certs\\ec_secp384r1_cert0.pem",
+ "rootCertificate1File": ".\\workspace\\keys_certs\\ec_secp384r1_cert1.pem",
+ "rootCertificate2File": ".\\workspace\\keys_certs\\ec_secp384r1_cert2.pem",
+ "rootCertificate3File": ".\\workspace\\keys_certs\\ec_secp384r1_cert3.pem",
+ "rootCertificateEllipticCurve": "secp384r1",
+ "mainRootCertId": 0,
+ "mainRootCertPrivateKeyFile": ".\\workspace\\keys_certs\\ec_pk_secp384r1_cert0.pem",
+ "useIsk": true,
+ "signingCertificateFile": ".\\workspace\\keys_certs\\ec_secp384r1_sign_cert.pem",
+ "signingCertificatePrivateKeyFile": ".\\workspace\\keys_certs\\ec_pk_secp384r1_sign_cert.pem",
+ "signingCertificateConstraint": "0x0000",
+ "iskCertificateEllipticCurve": "secp384r1",
+ "testSb3Magic": "",
+ "testSb3ImageType": false,
+ "testSb3ImageTypeValue": 255,
+ "testCertBlockMagic": "",
+ "testCorruptRkhRecord": false,
+ "testCorruptRkhRecordId": 0,
+ "testCorruptIskSignature": false,
+ "commands": [
+ {
+ "erase": {
+ "address": "0x0",
+ "size": "0x10000"
+ }
+ },
+ {
+ "load": {
+ "address": "0x0",
+ "file": ".\\workspace\\output_images\\mcxn9xx\\normal_boot_sign.bin"
+ }
+ }
+ ],
+ "containerOutputFile": ".\\workspace\\output_images\\mcxn9xx\\sb3_384_384.sb3"
+}
diff --git a/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_384_none.json b/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_384_none.json
new file mode 100644
index 00000000..71d98acb
--- /dev/null
+++ b/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_384_none.json
@@ -0,0 +1,40 @@
+{
+ "family": "mcxn9xx",
+ "containerKeyBlobEncryptionKey": ".\\workspace\\keys\\userkey.txt",
+ "isNxpContainer": false,
+ "description": "sb3_384_none.sb3",
+ "kdkAccessRights": 3,
+ "containerConfigurationWord": "0x0",
+ "firmwareVersion": "0x1",
+ "timestamp": "0x123456789abcdef",
+ "rootCertificate0File": ".\\workspace\\keys_certs\\ec_secp384r1_cert0.pem",
+ "rootCertificate1File": ".\\workspace\\keys_certs\\ec_secp384r1_cert1.pem",
+ "rootCertificate2File": ".\\workspace\\keys_certs\\ec_secp384r1_cert2.pem",
+ "rootCertificate3File": ".\\workspace\\keys_certs\\ec_secp384r1_cert3.pem",
+ "rootCertificateEllipticCurve": "secp384r1",
+ "mainRootCertId": 0,
+ "mainRootCertPrivateKeyFile": ".\\workspace\\keys_certs\\ec_pk_secp384r1_cert0.pem",
+ "useIsk": false,
+ "testSb3Magic": "",
+ "testSb3ImageType": false,
+ "testSb3ImageTypeValue": 255,
+ "testCertBlockMagic": "",
+ "testCorruptRkhRecord": false,
+ "testCorruptRkhRecordId": 0,
+ "testCorruptIskSignature": false,
+ "commands": [
+ {
+ "erase": {
+ "address": "0x0",
+ "size": "0x10000"
+ }
+ },
+ {
+ "load": {
+ "address": "0x0",
+ "file": ".\\workspace\\output_images\\mcxn9xx\\normal_boot_sign.bin"
+ }
+ }
+ ],
+ "containerOutputFile": ".\\workspace\\output_images\\mcxn9xx\\sb3_384_none.sb3"
+}
diff --git a/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_384_none_keyblob.json b/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_384_none_keyblob.json
new file mode 100644
index 00000000..c54a624a
--- /dev/null
+++ b/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_384_none_keyblob.json
@@ -0,0 +1,35 @@
+{
+ "family": "mcxn9xx",
+ "containerKeyBlobEncryptionKey": ".\\workspace\\keys\\userkey.txt",
+ "isNxpContainer": false,
+ "description": "sb3_try.sb3",
+ "kdkAccessRights": 3,
+ "containerConfigurationWord": "0x0",
+ "timestamp": "0x123456789abcdef",
+ "firmwareVersion": "0x1",
+ "rootCertificate0File": ".\\workspace\\keys_certs\\ec_secp384r1_cert0.pem",
+ "rootCertificate1File": ".\\workspace\\keys_certs\\ec_secp384r1_cert1.pem",
+ "rootCertificate2File": ".\\workspace\\keys_certs\\ec_secp384r1_cert2.pem",
+ "rootCertificate3File": ".\\workspace\\keys_certs\\ec_secp384r1_cert3.pem",
+ "rootCertificateEllipticCurve": "secp384r1",
+ "mainRootCertId": 0,
+ "mainRootCertPrivateKeyFile": ".\\workspace\\keys_certs\\ec_pk_secp384r1_cert0.pem",
+ "useIsk": false,
+ "commands": [
+ {
+ "loadKeyBlob": {
+ "offset": "0x1256",
+ "file": ".\\workspace\\input_images\\test1.bin",
+ "wrappingKeyId": "NXP_CUST_KEK_INT_SK"
+ }
+ },
+ {
+ "loadKeyBlob": {
+ "offset": "0x2588",
+ "file": ".\\workspace\\input_images\\test2.bin",
+ "wrappingKeyId": "NXP_CUST_KEK_EXT_SK"
+ }
+ }
+ ],
+ "containerOutputFile": ".\\workspace\\output_images\\mcxn9xx\\sb3_384_none_keyblob.sb3"
+}
diff --git a/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_test_384_384_unencrypted.json b/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_test_384_384_unencrypted.json
new file mode 100644
index 00000000..e4e99fb5
--- /dev/null
+++ b/tests/elftosb/data/workspace/cfgs/mcxn9xx/sb3_test_384_384_unencrypted.json
@@ -0,0 +1,149 @@
+{
+ "family": "mcxn9xx",
+ "containerKeyBlobEncryptionKey": ".\\workspace\\keys\\userkey.txt",
+ "isNxpContainer": false,
+ "description": "sb3_test_384_384_unencrypted.sb3",
+ "kdkKeyAccesRights": 3,
+ "containerConfigurationWord": "0x0",
+ "timestamp": "0x123456789abcdef",
+ "firmwareVersion": "0x1",
+ "rootCertificate0File": ".\\workspace\\keys_certs\\ec_secp384r1_cert0.pem",
+ "rootCertificate1File": ".\\workspace\\keys_certs\\ec_secp384r1_cert1.pem",
+ "rootCertificate2File": ".\\workspace\\keys_certs\\ec_secp384r1_cert2.pem",
+ "rootCertificate3File": ".\\workspace\\keys_certs\\ec_secp384r1_cert3.pem",
+ "rootCertificateEllipticCurve": "secp384r1",
+ "mainRootCertId": 0,
+ "mainRootCertPrivateKeyFile": ".\\workspace\\keys_certs\\ec_pk_secp384r1_cert0.pem",
+ "useIsk": true,
+ "signingCertificateFile": ".\\workspace\\keys_certs\\ec_secp384r1_sign_cert.pem",
+ "signingCertificatePrivateKeyFile": ".\\workspace\\keys_certs\\ec_pk_secp384r1_sign_cert.pem",
+ "signingCertificateConstraint": "0x0000",
+ "iskCertificateEllipticCurve": "secp384r1",
+ "signCertData": ".\\workspace\\input_images\\testfffffff.bin",
+ "testSb3Magic": "",
+ "testSb3ImageType": false,
+ "testSb3ImageTypeValue": 255,
+ "testCertBlockMagic": "",
+ "testCorruptRkhRecord": false,
+ "testCorruptRkhRecordId": 0,
+ "testCorruptIskSignature": false,
+ "isEncrypted": false,
+ "commands": [
+ {
+ "erase": {
+ "address": "0x2588",
+ "size": "0xFFFF",
+ "memoryId": "0xA"
+ }
+ },
+ {
+ "load": {
+ "address": "0x1256",
+ "file": ".\\workspace\\input_images\\test1.bin"
+ }
+ },
+ {
+ "load": {
+ "address": "0x2588",
+ "file": ".\\workspace\\input_images\\test2.bin",
+ "authentication": "none",
+ "memoryId": "0xA"
+ }
+ },
+ {
+ "load": {
+ "address": "0x1256",
+ "file": ".\\workspace\\input_images\\test1.bin",
+ "authentication": "hashlocking"
+ }
+ },
+ {
+ "load": {
+ "address": "0x2588",
+ "file": ".\\workspace\\input_images\\test2.bin",
+ "authentication": "cmac"
+ }
+ },
+ {
+ "loadKeyBlob": {
+ "offset": "0x1256",
+ "file": ".\\workspace\\input_images\\test1.bin",
+ "wrappingKeyId": "NXP_CUST_KEK_INT_SK"
+ }
+ },
+ {
+ "loadKeyBlob": {
+ "offset": "0x2588",
+ "file": ".\\workspace\\input_images\\test2.bin",
+ "wrappingKeyId": "NXP_CUST_KEK_EXT_SK"
+ }
+ },
+ {
+ "programFuses": {
+ "address": "0x1384",
+ "values": "0x138498, 0x0, 0x5, 0x1ab, 0x1ab, 0xffffffff, 0xfffffff1"
+ }
+ },
+ {
+ "programFuses": {
+ "address": "0x2588",
+ "values": "0x138498, 0x0, 0x5, 0x1ab, 0x1ab, 0xffffffff, 0xfffffff1"
+ }
+ },
+ {
+ "programIFR": {
+ "address": "0x1384",
+ "file": ".\\workspace\\input_ifr\\ifr1.bin"
+ }
+ },
+ {
+ "programIFR": {
+ "address": "0x2588",
+ "file": ".\\workspace\\input_ifr\\ifr2.bin"
+ }
+ },
+ {
+ "fillMemory": {
+ "address": "0x25",
+ "pattern": "0xFFFFFFFF",
+ "size": "0xFF"
+ }
+ },
+ {
+ "checkFwVersion": {
+ "counterId": "nonsecure",
+ "value": "0x1"
+ }
+ },
+ {
+ "checkFwVersion": {
+ "counterId": "secure",
+ "value": "0x3"
+ }
+ },
+ {
+ "checkFwVersion": {
+ "counterId": "snt",
+ "value": "0x1"
+ }
+ },
+ {
+ "checkFwVersion": {
+ "counterId": "radio",
+ "value": "0x3"
+ }
+ },
+ {
+ "checkFwVersion": {
+ "counterId": "bootloader",
+ "value": "0x3"
+ }
+ },
+ {
+ "execute": {
+ "address": "0x1384"
+ }
+ }
+ ],
+ "containerOutputFile": ".\\workspace\\output_images\\mcxn9xx\\sb3_test_384_384_unencrypted.sb3"
+}
\ No newline at end of file
diff --git a/tests/elftosb/data/workspace/cfgs/rt5xx/mb_ram_encrypted_ks.json b/tests/elftosb/data/workspace/cfgs/rt5xx/mb_ram_encrypted_ks.json
index 29d2090b..0e8a4493 100644
--- a/tests/elftosb/data/workspace/cfgs/rt5xx/mb_ram_encrypted_ks.json
+++ b/tests/elftosb/data/workspace/cfgs/rt5xx/mb_ram_encrypted_ks.json
@@ -8,9 +8,7 @@
"outputImageAuthenticationType": "Encrypted + Signed",
"outputImageEncryptionKeyFile": ".\\workspace\\keys\\userkey.txt",
"enableTrustZone": false,
- "deviceKeySource": "Keystore",
- "useKeyStore": true,
- "useKeyStoreFile": "",
+ "keyStoreFile": ".\\workspace\\input_images\\keystore_empty.bin",
"enableHwUserModeKeys": false,
"imageBuildNumber": "0x0",
"rootCertificate0File": ".\\sb_sources\\keys_and_certs\\root_k0_signed_cert0_noca.der.cert",
diff --git a/tests/elftosb/data/workspace/cfgs/rt5xx/mb_ram_encrypted_ks_binkey.json b/tests/elftosb/data/workspace/cfgs/rt5xx/mb_ram_encrypted_ks_binkey.json
index 5d86451a..c011e996 100644
--- a/tests/elftosb/data/workspace/cfgs/rt5xx/mb_ram_encrypted_ks_binkey.json
+++ b/tests/elftosb/data/workspace/cfgs/rt5xx/mb_ram_encrypted_ks_binkey.json
@@ -8,9 +8,7 @@
"outputImageAuthenticationType": "Encrypted + Signed",
"outputImageEncryptionKeyFile": ".\\workspace\\keys\\userkey.bin",
"enableTrustZone": false,
- "deviceKeySource": "Keystore",
- "useKeyStore": true,
- "useKeyStoreFile": "",
+ "keyStoreFile": ".\\workspace\\input_images\\keystore_empty.bin",
"enableHwUserModeKeys": false,
"imageBuildNumber": "0x0",
"rootCertificate0File": ".\\sb_sources\\keys_and_certs\\root_k0_signed_cert0_noca.der.cert",
diff --git a/tests/elftosb/data/workspace/cfgs/rt5xx/mb_ram_signed_ks.json b/tests/elftosb/data/workspace/cfgs/rt5xx/mb_ram_signed_ks.json
index 465bb056..3211bc61 100644
--- a/tests/elftosb/data/workspace/cfgs/rt5xx/mb_ram_signed_ks.json
+++ b/tests/elftosb/data/workspace/cfgs/rt5xx/mb_ram_signed_ks.json
@@ -8,9 +8,7 @@
"outputImageAuthenticationType": "Signed",
"outputImageEncryptionKeyFile": ".\\workspace\\keys\\userkey.txt",
"enableTrustZone": false,
- "deviceKeySource": "Keystore",
- "useKeyStore": true,
- "useKeyStoreFile": "",
+ "keyStoreFile": ".\\workspace\\input_images\\keystore_empty.bin",
"enableHwUserModeKeys": false,
"imageBuildNumber": "0x0",
"rootCertificate0File": ".\\sb_sources\\keys_and_certs\\root_k0_signed_cert0_noca.der.cert",
diff --git a/tests/elftosb/data/workspace/input_images/keystore_empty.bin b/tests/elftosb/data/workspace/input_images/keystore_empty.bin
new file mode 100644
index 00000000..7c6e5d70
Binary files /dev/null and b/tests/elftosb/data/workspace/input_images/keystore_empty.bin differ
diff --git a/tests/elftosb/data/workspace/output_images/k32w1xx/mb_xip_256_none_sd.bin b/tests/elftosb/data/workspace/output_images/k32w1xx/mb_xip_256_none_sd.bin
index de617bca..57c38a70 100644
Binary files a/tests/elftosb/data/workspace/output_images/k32w1xx/mb_xip_256_none_sd.bin and b/tests/elftosb/data/workspace/output_images/k32w1xx/mb_xip_256_none_sd.bin differ
diff --git a/tests/elftosb/data/workspace/output_images/k32w1xx/mb_xip_384_256_sd.bin b/tests/elftosb/data/workspace/output_images/k32w1xx/mb_xip_384_256_sd.bin
index 1abc7e6c..62563ec2 100644
Binary files a/tests/elftosb/data/workspace/output_images/k32w1xx/mb_xip_384_256_sd.bin and b/tests/elftosb/data/workspace/output_images/k32w1xx/mb_xip_384_256_sd.bin differ
diff --git a/tests/elftosb/data/workspace/output_images/k32w1xx/mb_xip_384_384_sd.bin b/tests/elftosb/data/workspace/output_images/k32w1xx/mb_xip_384_384_sd.bin
index 1bf86448..9bf68029 100644
Binary files a/tests/elftosb/data/workspace/output_images/k32w1xx/mb_xip_384_384_sd.bin and b/tests/elftosb/data/workspace/output_images/k32w1xx/mb_xip_384_384_sd.bin differ
diff --git a/tests/elftosb/data/workspace/output_images/kw45xx/mb_xip_256_none_sd.bin b/tests/elftosb/data/workspace/output_images/kw45xx/mb_xip_256_none_sd.bin
index de617bca..57c38a70 100644
Binary files a/tests/elftosb/data/workspace/output_images/kw45xx/mb_xip_256_none_sd.bin and b/tests/elftosb/data/workspace/output_images/kw45xx/mb_xip_256_none_sd.bin differ
diff --git a/tests/elftosb/data/workspace/output_images/kw45xx/mb_xip_384_256_sd.bin b/tests/elftosb/data/workspace/output_images/kw45xx/mb_xip_384_256_sd.bin
index 1abc7e6c..62563ec2 100644
Binary files a/tests/elftosb/data/workspace/output_images/kw45xx/mb_xip_384_256_sd.bin and b/tests/elftosb/data/workspace/output_images/kw45xx/mb_xip_384_256_sd.bin differ
diff --git a/tests/elftosb/data/workspace/output_images/kw45xx/mb_xip_384_384_sd.bin b/tests/elftosb/data/workspace/output_images/kw45xx/mb_xip_384_384_sd.bin
index 1bf86448..9bf68029 100644
Binary files a/tests/elftosb/data/workspace/output_images/kw45xx/mb_xip_384_384_sd.bin and b/tests/elftosb/data/workspace/output_images/kw45xx/mb_xip_384_384_sd.bin differ
diff --git a/tests/elftosb/data/workspace/output_images/lpc55s3x/mb_xip_ext_signed.bin b/tests/elftosb/data/workspace/output_images/lpc55s3x/mb_xip_ext_signed.bin
index 7572c9de..dc5c88fb 100644
Binary files a/tests/elftosb/data/workspace/output_images/lpc55s3x/mb_xip_ext_signed.bin and b/tests/elftosb/data/workspace/output_images/lpc55s3x/mb_xip_ext_signed.bin differ
diff --git a/tests/elftosb/data/workspace/output_images/mcxn9xx/mb_ram_crc.bin b/tests/elftosb/data/workspace/output_images/mcxn9xx/mb_ram_crc.bin
new file mode 100644
index 00000000..265c3286
Binary files /dev/null and b/tests/elftosb/data/workspace/output_images/mcxn9xx/mb_ram_crc.bin differ
diff --git a/tests/elftosb/data/workspace/output_images/mcxn9xx/mb_xip_256_none.bin b/tests/elftosb/data/workspace/output_images/mcxn9xx/mb_xip_256_none.bin
new file mode 100644
index 00000000..61808b75
Binary files /dev/null and b/tests/elftosb/data/workspace/output_images/mcxn9xx/mb_xip_256_none.bin differ
diff --git a/tests/elftosb/data/workspace/output_images/mcxn9xx/mb_xip_384_256.bin b/tests/elftosb/data/workspace/output_images/mcxn9xx/mb_xip_384_256.bin
new file mode 100644
index 00000000..e6f86588
Binary files /dev/null and b/tests/elftosb/data/workspace/output_images/mcxn9xx/mb_xip_384_256.bin differ
diff --git a/tests/elftosb/data/workspace/output_images/mcxn9xx/mb_xip_384_384.bin b/tests/elftosb/data/workspace/output_images/mcxn9xx/mb_xip_384_384.bin
new file mode 100644
index 00000000..11af7bc8
Binary files /dev/null and b/tests/elftosb/data/workspace/output_images/mcxn9xx/mb_xip_384_384.bin differ
diff --git a/tests/elftosb/data/workspace/output_images/mcxn9xx/mb_xip_384_384_recovery.bin b/tests/elftosb/data/workspace/output_images/mcxn9xx/mb_xip_384_384_recovery.bin
new file mode 100644
index 00000000..f1281e3e
Binary files /dev/null and b/tests/elftosb/data/workspace/output_images/mcxn9xx/mb_xip_384_384_recovery.bin differ
diff --git a/tests/elftosb/data/workspace/output_images/mcxn9xx/mb_xip_384_384_recovery_crctest.bin b/tests/elftosb/data/workspace/output_images/mcxn9xx/mb_xip_384_384_recovery_crctest.bin
new file mode 100644
index 00000000..d6f39a6d
Binary files /dev/null and b/tests/elftosb/data/workspace/output_images/mcxn9xx/mb_xip_384_384_recovery_crctest.bin differ
diff --git a/tests/elftosb/data/workspace/output_images/mcxn9xx/mb_xip_crc.bin b/tests/elftosb/data/workspace/output_images/mcxn9xx/mb_xip_crc.bin
new file mode 100644
index 00000000..70efb539
Binary files /dev/null and b/tests/elftosb/data/workspace/output_images/mcxn9xx/mb_xip_crc.bin differ
diff --git a/tests/elftosb/data/workspace/output_images/mcxn9xx/normal_boot_sign.bin b/tests/elftosb/data/workspace/output_images/mcxn9xx/normal_boot_sign.bin
new file mode 100644
index 00000000..db19a899
Binary files /dev/null and b/tests/elftosb/data/workspace/output_images/mcxn9xx/normal_boot_sign.bin differ
diff --git a/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_256_256.sb3 b/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_256_256.sb3
new file mode 100644
index 00000000..2a73949c
Binary files /dev/null and b/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_256_256.sb3 differ
diff --git a/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_256_none.sb3 b/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_256_none.sb3
new file mode 100644
index 00000000..ed67cdd7
Binary files /dev/null and b/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_256_none.sb3 differ
diff --git a/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_384_256.sb3 b/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_384_256.sb3
new file mode 100644
index 00000000..df04b34e
Binary files /dev/null and b/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_384_256.sb3 differ
diff --git a/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_384_256_fixed_timestamp.sb3 b/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_384_256_fixed_timestamp.sb3
new file mode 100644
index 00000000..9b731270
Binary files /dev/null and b/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_384_256_fixed_timestamp.sb3 differ
diff --git a/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_384_256_unencrypted.sb3 b/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_384_256_unencrypted.sb3
new file mode 100644
index 00000000..ccca29ed
Binary files /dev/null and b/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_384_256_unencrypted.sb3 differ
diff --git a/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_384_384.sb3 b/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_384_384.sb3
new file mode 100644
index 00000000..8a16fb9a
Binary files /dev/null and b/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_384_384.sb3 differ
diff --git a/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_384_none.sb3 b/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_384_none.sb3
new file mode 100644
index 00000000..d4fc0145
Binary files /dev/null and b/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_384_none.sb3 differ
diff --git a/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_384_none_keyblob.sb3 b/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_384_none_keyblob.sb3
new file mode 100644
index 00000000..fbe0d16f
Binary files /dev/null and b/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_384_none_keyblob.sb3 differ
diff --git a/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_test_384_384_unencrypted.sb3 b/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_test_384_384_unencrypted.sb3
new file mode 100644
index 00000000..f1aebc40
Binary files /dev/null and b/tests/elftosb/data/workspace/output_images/mcxn9xx/sb3_test_384_384_unencrypted.sb3 differ
diff --git a/tests/elftosb/data/workspace/trustzone/mcxn9xx/tz_mcxn9xx.bin b/tests/elftosb/data/workspace/trustzone/mcxn9xx/tz_mcxn9xx.bin
new file mode 100644
index 00000000..296a2a33
Binary files /dev/null and b/tests/elftosb/data/workspace/trustzone/mcxn9xx/tz_mcxn9xx.bin differ
diff --git a/tests/elftosb/test_efltosb_sb21.py b/tests/elftosb/test_efltosb_sb21.py
index bb03d4d0..2a9b5891 100644
--- a/tests/elftosb/test_efltosb_sb21.py
+++ b/tests/elftosb/test_efltosb_sb21.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#
-# Copyright 2020-2022 NXP
+# Copyright 2020-2023 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
@@ -79,19 +79,31 @@ def test_elftosb_sb21(bd_file, legacy_sb, external, data_dir, tmpdir):
out_file_path_legacy = os.path.join(data_dir, legacy_sb)
- cmd = f"-c {bd_file_path} \
- -o {out_file_path_new}\
- -k {kek_key_path}\
- -s {priv_key_path}\
- -S {certificate_path}\
- -R {root_key_certificate0_path}\
- -R {root_key_certificate1_path}\
- -R {root_key_certificate2_path}\
- -R {root_key_certificate3_path}\
- -h {hash_of_hashes_output_path}"
+ cmd = [
+ "-c",
+ bd_file_path,
+ "-o",
+ out_file_path_new,
+ "-k",
+ kek_key_path,
+ "-s",
+ priv_key_path,
+ "-S",
+ certificate_path,
+ "-R",
+ root_key_certificate0_path,
+ "-R",
+ root_key_certificate1_path,
+ "-R",
+ root_key_certificate2_path,
+ "-R",
+ root_key_certificate3_path,
+ "-h",
+ hash_of_hashes_output_path,
+ ]
for entry in external:
- cmd += " " + entry
- result = runner.invoke(elftosb.main, cmd.split())
+ cmd.append(entry)
+ result = runner.invoke(elftosb.main, cmd)
assert result.exit_code == 0
assert os.path.isfile(out_file_path_new)
diff --git a/tests/elftosb/test_elftosb_cfg_template.py b/tests/elftosb/test_elftosb_cfg_template.py
index 36fcfc06..25757563 100644
--- a/tests/elftosb/test_elftosb_cfg_template.py
+++ b/tests/elftosb/test_elftosb_cfg_template.py
@@ -31,8 +31,8 @@
def test_elftosb_cfgtmp_create(tmpdir, device):
runner = CliRunner()
- cmd = f"-Y {tmpdir} -f {device}"
- result = runner.invoke(elftosb.main, cmd.split())
+ cmd = ["-Y", str(tmpdir), "-f", device]
+ result = runner.invoke(elftosb.main, cmd)
assert result.exit_code == 0
# Check at least common TrustZone Configuration file
assert os.path.isfile(os.path.join(tmpdir, f"{device}_tz.yaml"))
diff --git a/tests/elftosb/test_elftosb_mbi.py b/tests/elftosb/test_elftosb_mbi.py
index 23748444..c6fed121 100644
--- a/tests/elftosb/test_elftosb_mbi.py
+++ b/tests/elftosb/test_elftosb_mbi.py
@@ -92,6 +92,8 @@ def get_signing_key(config_file) -> ECC.EccKey:
("mb_xip_crc_version.json", "k32w1xx"),
("mb_xip_384_384_no_signature.json", "k32w1xx"),
("mb_ext_xip_crc_s19.json", "lpc55s3x"),
+ ("mb_ram_crc.json", "mcxn9xx"),
+ ("mb_xip_crc.json", "mcxn9xx"),
],
)
def test_elftosb_mbi_basic(data_dir, tmpdir, config_file, device):
@@ -100,8 +102,8 @@ def test_elftosb_mbi_basic(data_dir, tmpdir, config_file, device):
config_file = f"{data_dir}/workspace/cfgs/{device}/{config_file}"
ref_binary, new_binary, new_config = process_config_file(config_file, tmpdir, device)
- cmd = f"--image-conf {new_config}"
- result = runner.invoke(elftosb.main, cmd.split())
+ cmd = ["--image-conf", new_config]
+ result = runner.invoke(elftosb.main, cmd)
if result.exit_code != 0:
assert isinstance(result.exception, SPSDKUnsupportedImageType)
else:
@@ -116,16 +118,21 @@ def test_elftosb_mbi_basic(data_dir, tmpdir, config_file, device):
("mb_xip_384_256.json", "lpc55s3x", None),
("mb_xip_384_384.json", "lpc55s3x", None),
("mb_ext_xip_signed.json", "lpc55s3x", None),
+ ("mb_xip_256_none.json", "mcxn9xx", None),
+ ("mb_xip_384_256.json", "mcxn9xx", None),
+ ("mb_xip_384_384.json", "mcxn9xx", None),
+ ("mb_xip_384_384_recovery_crctest.json", "mcxn9xx", None),
+ ("mb_xip_384_384_recovery.json", "mcxn9xx", None),
("mb_xip_256_none.json", "k32w1xx", None),
("mb_xip_384_256.json", "k32w1xx", None),
("mb_xip_384_384.json", "k32w1xx", None),
- ("mb_xip_256_none_sd.json", "k32w1xx", "sha256"),
+ ("mb_xip_256_none_sd.json", "k32w1xx", None),
("mb_xip_384_256_sd.json", "k32w1xx", "sha256"),
("mb_xip_384_384_sd.json", "k32w1xx", "sha384"),
("mb_xip_256_none.json", "kw45xx", None),
("mb_xip_384_256.json", "kw45xx", None),
("mb_xip_384_384.json", "kw45xx", None),
- ("mb_xip_256_none_sd.json", "kw45xx", "sha256"),
+ ("mb_xip_256_none_sd.json", "kw45xx", None),
("mb_xip_384_256_sd.json", "kw45xx", "sha256"),
("mb_xip_384_384_sd.json", "kw45xx", "sha384"),
],
@@ -136,8 +143,8 @@ def test_elftosb_mbi_signed(data_dir, tmpdir, config_file, device, sign_digest):
config_file = f"{data_dir}/workspace/cfgs/{device}/{config_file}"
ref_binary, new_binary, new_config = process_config_file(config_file, tmpdir, device)
- cmd = f"--image-conf {new_config}"
- result = runner.invoke(elftosb.main, cmd.split())
+ cmd = ["--image-conf", new_config]
+ result = runner.invoke(elftosb.main, cmd)
assert result.exit_code == 0
assert os.path.isfile(new_binary)
@@ -210,8 +217,8 @@ def test_elftosb_mbi_legacy_signed(data_dir, tmpdir, config_file, device, skip_h
config_file = f"{data_dir}/workspace/cfgs/{device}/{config_file}"
ref_binary, new_binary, new_config = process_config_file(config_file, tmpdir, device)
- cmd = f"--image-conf {new_config}"
- result = runner.invoke(elftosb.main, cmd.split())
+ cmd = ["--image-conf", new_config]
+ result = runner.invoke(elftosb.main, cmd)
assert result.exit_code == 0
assert os.path.isfile(new_binary)
@@ -275,8 +282,8 @@ def test_elftosb_mbi_invalid_conf(data_dir, tmpdir, config_file, device):
config_file = f"{data_dir}/workspace/cfgs/{device}/{config_file}"
_, _, new_config = process_config_file(config_file, tmpdir, device)
- cmd = f"--image-conf {new_config}"
- result = runner.invoke(elftosb.main, cmd.split())
+ cmd = ["--image-conf", new_config]
+ result = runner.invoke(elftosb.main, cmd)
assert result.exit_code == 1
@@ -290,8 +297,9 @@ def test_elftosb_mbi_legacy_encrypted(data_dir, tmpdir, config_file, device, ski
config_file = f"{data_dir}/workspace/cfgs/{device}/{config_file}"
ref_binary, new_binary, new_config = process_config_file(config_file, tmpdir, device)
- cmd = f"--image-conf {new_config}"
- result = runner.invoke(elftosb.main, cmd.split())
+ cmd = ["--image-conf", new_config]
+ result = runner.invoke(elftosb.main, cmd)
+ assert result.exit_code == 0
assert os.path.isfile(new_binary)
# validate file lengths
diff --git a/tests/elftosb/test_elftosb_sb31.py b/tests/elftosb/test_elftosb_sb31.py
index 0fa217ac..302a9ab9 100644
--- a/tests/elftosb/test_elftosb_sb31.py
+++ b/tests/elftosb/test_elftosb_sb31.py
@@ -46,6 +46,15 @@ def process_config_file(
("sb3_384_384.json", "lpc55s3x"),
("sb3_384_none.json", "lpc55s3x"),
("sb3_test_384_384_unencrypted.json", "lpc55s3x"),
+ ("sb3_256_256.json", "mcxn9xx"),
+ ("sb3_256_none.json", "mcxn9xx"),
+ ("sb3_384_256.json", "mcxn9xx"),
+ ("sb3_384_256_fixed_timestamp.json", "mcxn9xx"),
+ ("sb3_384_256_unencrypted.json", "mcxn9xx"),
+ ("sb3_384_384.json", "mcxn9xx"),
+ ("sb3_384_none.json", "mcxn9xx"),
+ ("sb3_384_none_keyblob.json", "mcxn9xx"),
+ ("sb3_test_384_384_unencrypted.json", "mcxn9xx"),
("sb3_test_384_384_unencrypted.json", "kw45xx"),
("sb3_384_384.json", "kw45xx"),
("sb3_384_none.json", "kw45xx"),
@@ -61,8 +70,8 @@ def test_elftosb_sb31(data_dir, tmpdir, config_file, device):
ref_binary, new_binary, new_config = process_config_file(
config_file, tmpdir, "containerOutputFile"
)
- cmd = f"--container-conf {new_config}"
- result = runner.invoke(elftosb.main, cmd.split())
+ cmd = ["--container-conf", new_config]
+ result = runner.invoke(elftosb.main, cmd)
assert result.exit_code == 0
assert os.path.isfile(new_binary)
assert filecmp.cmp(ref_binary, new_binary, shallow=False)
@@ -77,8 +86,8 @@ def test_elftosb_sb31_notime(data_dir, tmpdir):
ref_binary, new_binary, new_config = process_config_file(
config_file, tmpdir, "containerOutputFile"
)
- cmd = f"--container-conf {new_config}"
- result = runner.invoke(elftosb.main, cmd.split())
+ cmd = ["--container-conf", new_config]
+ result = runner.invoke(elftosb.main, cmd)
assert result.exit_code == 0
assert os.path.isfile(new_binary)
diff --git a/tests/elftosb/test_elftosb_trustzone.py b/tests/elftosb/test_elftosb_trustzone.py
index aa4683cc..71cd9722 100644
--- a/tests/elftosb/test_elftosb_trustzone.py
+++ b/tests/elftosb/test_elftosb_trustzone.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#
-# Copyright 2020-2021 NXP
+# Copyright 2020-2023 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
@@ -18,7 +18,8 @@
def test_elftosb_trustzone_basic(data_dir, tmpdir):
runner = CliRunner()
with use_working_directory(tmpdir):
- cmd = f"--tzm-conf {data_dir}/lpc55xxA1.json"
- result = runner.invoke(elftosb.main, cmd.split())
+ cmd = ["--tzm-conf", f"{data_dir}/lpc55xxA1.json"]
+ result = runner.invoke(elftosb.main, cmd)
+ assert result.exit_code == 0
assert os.path.isfile(f"{tmpdir}/lpc55xxA1_tzFile.bin")
assert filecmp.cmp(f"{data_dir}/lpc55xxA1_tzFile.bin", f"{tmpdir}/lpc55xxA1_tzFile.bin")
diff --git a/tests/ifr/test_ifr.py b/tests/ifr/test_ifr.py
index 4de7e2e6..edc88665 100644
--- a/tests/ifr/test_ifr.py
+++ b/tests/ifr/test_ifr.py
@@ -17,23 +17,37 @@
def test_ifr_user_config(tmpdir):
"""Test IF CLI - Generation IF user config."""
- cmd = f"get-template -d kw45xx --output {tmpdir}/ifr.yml"
+ cmd = ["get-template", "-d", "kw45xx", "--output", f"{tmpdir}/ifr.yml"]
runner = CliRunner()
- result = runner.invoke(ifr.main, cmd.split())
+ result = runner.invoke(ifr.main, cmd)
assert result.exit_code == 0, result.output
assert os.path.isfile(f"{tmpdir}/ifr.yml")
def test_roundtrip(data_dir, tmpdir):
- parse_cmd = f"parse-binary -d kw45xx --binary {data_dir}/ref.bin --output {tmpdir}/ref.yaml"
+ parse_cmd = [
+ "parse-binary",
+ "-d",
+ "kw45xx",
+ "--binary",
+ f"{data_dir}/ref.bin",
+ "--output",
+ f"{tmpdir}/ref.yaml",
+ ]
runner = CliRunner()
- result = runner.invoke(ifr.main, parse_cmd.split())
+ result = runner.invoke(ifr.main, parse_cmd)
assert result.exit_code == 0
- generate_cmd = (
- f"generate-binary -d kw45xx --user-config {tmpdir}/ref.yaml --output {tmpdir}/new.bin"
- )
- result = runner.invoke(ifr.main, generate_cmd.split())
+ generate_cmd = [
+ "generate-binary",
+ "-d",
+ "kw45xx",
+ "--user-config",
+ f"{tmpdir}/ref.yaml",
+ "--output",
+ f"{tmpdir}/new.bin",
+ ]
+ result = runner.invoke(ifr.main, generate_cmd)
assert result.exit_code == 0
assert filecmp.cmp(f"{data_dir}/ref.bin", f"{tmpdir}/new.bin")
diff --git a/tests/image/images/test_hab_audit_log.py b/tests/image/images/test_hab_audit_log.py
index 94c57220..92f1a0eb 100644
--- a/tests/image/images/test_hab_audit_log.py
+++ b/tests/image/images/test_hab_audit_log.py
@@ -1,10 +1,11 @@
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#
-# Copyright 2020-2021 NXP
+# Copyright 2020-2023 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
+import os
from unittest.mock import patch
import pytest
@@ -26,6 +27,9 @@
# responses from rt1020 for mcu emulating
from spsdk.utils.serial_proxy import SimpleReadSerialProxy
+from tools.clr import ROOT_DIR
+
+HAB_AUDIT_PATH = os.path.join(ROOT_DIR, "examples", "data", "hab_audit")
class TestEnum(Enum):
@@ -80,13 +84,15 @@ def test_hab_audit_xip_app_simple(data_dir):
):
with McuBoot(Uart(port="totally-legit-port")) as mboot:
# test valid use case
- log = hab_audit_xip_app(CpuData.MIMXRT1020, mboot, read_log_only=True)
+ log = hab_audit_xip_app(CpuData.MIMXRT1020, mboot, True, HAB_AUDIT_PATH)
assert log[:4] != b"\xFF" * 4
def test_hab_audit_xip_app_invalid(data_dir):
with pytest.raises(SPSDKError, match="Flashloader is not running"):
- hab_audit_xip_app(CpuData.MIMXRT1020, mboot=None, read_log_only=True)
+ hab_audit_xip_app(
+ CpuData.MIMXRT1020, mboot=None, read_log_only=True, hab_audit_path=HAB_AUDIT_PATH
+ )
import os
import re
@@ -105,7 +111,7 @@ def test_hab_audit_xip_app_invalid(data_dir):
with pytest.raises(
SPSDKError, match="Can not read the log, because given cpu data were not provided."
):
- hab_audit_xip_app(None, mboot, read_log_only=True)
+ hab_audit_xip_app(None, mboot, read_log_only=True, hab_audit_path=HAB_AUDIT_PATH)
def test_get_hab_log_info():
diff --git a/tests/image/mbi/test_mbi.py b/tests/image/mbi/test_mbi.py
index b4281870..c51e6628 100644
--- a/tests/image/mbi/test_mbi.py
+++ b/tests/image/mbi/test_mbi.py
@@ -12,8 +12,6 @@
import pytest
from spsdk import SPSDKError
-from spsdk.apps.nxpimage import mbi_export
-from spsdk.crypto.signature_provider import SignatureProvider
from spsdk.image import (
MBIMG_SCH_FILE,
MasterBootImage,
@@ -22,7 +20,7 @@
TrustZone,
)
from spsdk.image.keystore import KeySourceType, KeyStore
-from spsdk.image.mbi_mixin import Mbi_MixinRelocTable
+from spsdk.image.mbi_mixin import Mbi_MixinRelocTable, SignatureProvider
from spsdk.image.mbimg import (
Mbi_CrcRamRtxxx,
Mbi_CrcXip,
diff --git a/tests/image/segments/test_bee.py b/tests/image/segments/test_bee.py
index 365ab3a6..d5f829b7 100644
--- a/tests/image/segments/test_bee.py
+++ b/tests/image/segments/test_bee.py
@@ -36,7 +36,7 @@ def verify_base_class_features(inst: BeeBaseClass, decrypt_key: Optional[bytes]
inst.validate()
# test size property and `_size()` class method returns the same number
expected_size = inst.size
- assert inst.__class__._size() == expected_size
+ assert inst.__class__.get_size() == expected_size
# check export
data = inst.export()
assert (data is not None) and (len(data) == expected_size)
diff --git a/tests/mboot/blhost/test_blhost_cli.py b/tests/mboot/blhost/test_blhost_cli.py
index 172e318b..a1ab2983 100644
--- a/tests/mboot/blhost/test_blhost_cli.py
+++ b/tests/mboot/blhost/test_blhost_cli.py
@@ -210,13 +210,13 @@ def run_blhost_proxy(caplog, cmd, expect_exit_code: int = 0, ignore_ack: bool =
"spsdk.mboot.interfaces.uart.Serial",
SerialProxy.init_proxy(data_responses, ignore_ack=ignore_ack),
):
- result = runner.invoke(blhost.main, cmd.split())
+ result = runner.invoke(blhost.main, cmd)
assert result.exit_code == expect_exit_code
return result
def test_get_property(caplog):
- cmd = "-p super-com get-property 1"
+ cmd = ["-p", "super-com", "get-property", "1"]
result = run_blhost_proxy(caplog, cmd)
assert "Current Version = K3.0.0" in result.output
@@ -224,12 +224,12 @@ def test_get_property(caplog):
def test_buspal_i2c_get_property(caplog):
caplog.set_level(100_000)
runner = CliRunner()
- cmd = "-b i2c -p super-com get-property 1"
+ cmd = ["-b", "i2c", "-p", "super-com", "get-property", "1"]
with patch(
"spsdk.mboot.interfaces.uart.Serial",
SerialBuspalProxy.init_buspal_proxy("i2c", data_responses_buspal_i2c),
):
- result = runner.invoke(blhost.main, cmd.split())
+ result = runner.invoke(blhost.main, cmd)
assert result.exit_code == 0
assert "Current Version = K3.0.0" in result.output
@@ -237,18 +237,18 @@ def test_buspal_i2c_get_property(caplog):
def test_buspal_spi_get_property(caplog):
caplog.set_level(100_000)
runner = CliRunner()
- cmd = "-b spi,5 -p super-com get-property 1"
+ cmd = ["-b", "spi,5", "-p", "super-com", "get-property", "1"]
with patch(
"spsdk.mboot.interfaces.uart.Serial",
SerialBuspalProxy.init_buspal_proxy("spi", data_responses_buspal_spi),
):
- result = runner.invoke(blhost.main, cmd.split())
+ result = runner.invoke(blhost.main, cmd)
assert result.exit_code == 0
assert "Current Version = K3.0.0" in result.output
def test_get_property_hex_input(caplog):
- cmd = "-p super-com get-property 0xA"
+ cmd = ["-p", "super-com", "get-property", "0xA"]
result = run_blhost_proxy(caplog, cmd)
assert "Response status = 0 (0x0) Success." in result.output
assert "Response word 1 = 1 (0x1)" in result.output
@@ -256,13 +256,13 @@ def test_get_property_hex_input(caplog):
def test_set_property(caplog):
- cmd = "-p super-com set-property 10 1"
+ cmd = ["-p", "super-com", "set-property", "10", "1"]
result = run_blhost_proxy(caplog, cmd)
assert "Response status = 0 (0x0) Success." in result.output
def test_efuse_read_once(caplog):
- cmd = "-p super-com efuse-read-once 100"
+ cmd = ["-p", "super-com", "efuse-read-once", "100"]
result = run_blhost_proxy(caplog, cmd)
assert "Response word 1 = 4 (0x4)" in result.output
assert "Response word 2 = 0 (0x0)" in result.output
@@ -270,7 +270,7 @@ def test_efuse_read_once(caplog):
def test_efuse_read_once_unknown_error(caplog):
- cmd = "-p super-com efuse-read-once 0x98"
+ cmd = ["-p", "super-com", "efuse-read-once", "0x98"]
result = run_blhost_proxy(caplog, cmd, expect_exit_code=1)
assert "Response word 1 = 4 (0x4)" not in result.output
assert "Unknown error code" in result.output
@@ -278,7 +278,7 @@ def test_efuse_read_once_unknown_error(caplog):
def test_no_response(caplog):
# use get-property 13 (reserved) as a vehicle to emulate no response from target
- cmd = "-p super-com get-property 13"
+ cmd = ["-p", "super-com", "get-property", "13"]
result = run_blhost_proxy(caplog, cmd, expect_exit_code=1)
assert (
"Response status = 10004 (0x2714) No response packet from target device." in result.output
@@ -287,13 +287,13 @@ def test_no_response(caplog):
def test_unknown_property(caplog):
# get-property 0xff
- cmd = "-p super-com get-property 0xff"
+ cmd = ["-p", "super-com", "get-property", "0xff"]
result = run_blhost_proxy(caplog, cmd, expect_exit_code=1)
assert "Response status = 10300 (0x283c) Unknown Property." in result.output
def test_flash_read_once(caplog):
- cmd = "-p super-com flash-read-once 1 4"
+ cmd = ["-p", "super-com", "flash-read-once", "1", "4"]
result = run_blhost_proxy(caplog, cmd)
assert "Response status = 0 (0x0) Success." in result.output
assert "Response word 1 = 4 (0x4)" in result.output
@@ -301,31 +301,31 @@ def test_flash_read_once(caplog):
def test_flash_program_once(caplog):
- cmd = "-p super-com flash-program-once 1 4 12345678"
+ cmd = ["-p", "super-com", "flash-program-once", "1", "4", "12345678"]
result = run_blhost_proxy(caplog, cmd)
assert "Response status = 0 (0x0) Success." in result.output
def test_flash_security_disable(caplog):
- cmd = "-p super-com flash-security-disable 0102030405060708"
+ cmd = ["-p", "super-com", "flash-security-disable", "0102030405060708"]
result = run_blhost_proxy(caplog, cmd, expect_exit_code=1)
assert "Response status = 10000 (0x2710) Unknown Command." in result.output
def test_flash_erase_all_unsecure(caplog):
- cmd = "-p super-com flash-erase-all-unsecure"
+ cmd = ["-p", "super-com", "flash-erase-all-unsecure"]
result = run_blhost_proxy(caplog, cmd, expect_exit_code=1)
assert "Response status = 10000 (0x2710) Unknown Command." in result.output
def test_flash_erase_all(caplog):
- cmd = "-p super-com flash-erase-all 0x0"
+ cmd = ["-p", "super-com", "flash-erase-all", "0x0"]
result = run_blhost_proxy(caplog, cmd)
assert "Response status = 0 (0x0) Success." in result.output
def test_flash_erase_region(caplog):
- cmd = "-p super-com flash-erase-region 0x8000000 0x0"
+ cmd = ["-p", "super-com", "flash-erase-region", "0x8000000", "0x0"]
result = run_blhost_proxy(caplog, cmd)
assert "Response status = 0 (0x0) Success." in result.output
@@ -339,45 +339,63 @@ def run_flash_read_resource(caplog, cmd):
def test_flash_read_resource(caplog):
- cmd = "-p super-com flash-read-resource 1 4 1"
+ cmd = ["-p", "super-com", "flash-read-resource", "1", "4", "1"]
result = run_flash_read_resource(caplog, cmd)
assert "00 00 00 00" in result.output
def test_flash_read_resource_to_file(caplog, tmpdir):
test_file = f"{tmpdir}/read.bin"
- cmd = f"-p super-com flash-read-resource 1 4 1 {test_file}"
+ cmd = ["-p", "super-com", "flash-read-resource", "1", "4", "1", test_file]
run_flash_read_resource(caplog, cmd)
assert os.path.isfile(test_file)
assert load_binary(test_file) == bytes(4)
def test_reliable_update(caplog):
- cmd = "-p super-com reliable-update 0xfe000"
+ cmd = ["-p", "super-com", "reliable-update", "0xfe000"]
result = run_blhost_proxy(caplog, cmd, expect_exit_code=1)
assert "Response status = 10000 (0x2710) Unknown Command." in result.output
def test_fuse_read(caplog):
- cmd = "-p super-com fuse-read 0x1 8"
+ cmd = ["-p", "super-com", "fuse-read", "0x1", "8"]
result = run_blhost_proxy(caplog, cmd, expect_exit_code=1)
assert "Response status = 10000 (0x2710) Unknown Command." in result.output
def test_fuse_program(caplog):
- cmd = "-p super-com fuse-program 3 {{12345678}} 0"
+ cmd = ["-p", "super-com", "fuse-program", "3", "{{12345678}}", "0"]
result = run_blhost_proxy(caplog, cmd, expect_exit_code=1)
assert "Response status = 10000 (0x2710) Unknown Command." in result.output
def test_flash_image_memory_not_configured(caplog, data_dir):
- cmd = f"-p super-com flash-image {os.path.join(data_dir, 'evkmimxrt685_led_blinky_ext_flash.srec')} erase 3"
+ cmd = [
+ "-p",
+ "super-com",
+ "flash-image",
+ os.path.join(data_dir, "evkmimxrt685_led_blinky_ext_flash.srec"),
+ "erase",
+ "3",
+ ]
result = run_blhost_proxy(caplog, cmd, expect_exit_code=1)
assert "Response status = 10205 (0x27dd) Memory Not Configured." in result.output
def test_tp_hsm_gen_key(caplog):
- cmd = "-p super-com trust-provisioning hsm_gen_key MFWISK 0 0x20008000 48 0x20009000 64"
+ cmd = [
+ "-p",
+ "super-com",
+ "trust-provisioning",
+ "hsm_gen_key",
+ "MFWISK",
+ "0",
+ "0x20008000",
+ "48",
+ "0x20009000",
+ "64",
+ ]
result = run_blhost_proxy(caplog, cmd)
assert "Response status = 0 (0x0) Success." in result.output
assert "Response word 1 = 48 (0x30)" in result.output
@@ -388,7 +406,18 @@ def test_tp_hsm_gen_key(caplog):
def test_tp_store_key(caplog):
- cmd = "-p super-com trust-provisioning hsm_store_key 5 1 0x2000B000 32 0x2000C000 48"
+ cmd = [
+ "-p",
+ "super-com",
+ "trust-provisioning",
+ "hsm_store_key",
+ "5",
+ "1",
+ "0x2000B000",
+ "32",
+ "0x2000C000",
+ "48",
+ ]
result = run_blhost_proxy(caplog, cmd)
assert "Response status = 0 (0x0) Success." in result.output
assert "Response word 1 = 269484129 (0x10100061)" in result.output
@@ -399,13 +428,37 @@ def test_tp_store_key(caplog):
def test_tp_hsm_enc_blk(caplog):
- cmd = "-p super-com trust-provisioning hsm_enc_blk 0x2000A000 48 16 0x2000C000 60 1 0x2000D000 256"
+ cmd = [
+ "-p",
+ "super-com",
+ "trust-provisioning",
+ "hsm_enc_blk",
+ "0x2000A000",
+ "48",
+ "16",
+ "0x2000C000",
+ "60",
+ "1",
+ "0x2000D000",
+ "256",
+ ]
result = run_blhost_proxy(caplog, cmd)
assert "Response status = 0 (0x0) Success." in result.output
def test_tp_hsm_enc_sign(caplog):
- cmd = "-p super-com trust-provisioning hsm_enc_sign 0x20008000 48 0x2000F000 220 0x20010000 64"
+ cmd = [
+ "-p",
+ "super-com",
+ "trust-provisioning",
+ "hsm_enc_sign",
+ "0x20008000",
+ "48",
+ "0x2000F000",
+ "220",
+ "0x20010000",
+ "64",
+ ]
result = run_blhost_proxy(caplog, cmd)
assert "Response status = 0 (0x0) Success." in result.output
assert "Response word 1 = 64 (0x40)" in result.output
@@ -414,7 +467,20 @@ def test_tp_hsm_enc_sign(caplog):
def test_tp_oem_gen_master_share(caplog):
- cmd = "-p super-com trust-provisioning oem_gen_master_share 0x20008000 0x10 0x20009000 0x1000 0x2000A000 0x1000 0x2000B000 0x1000"
+ cmd = [
+ "-p",
+ "super-com",
+ "trust-provisioning",
+ "oem_gen_master_share",
+ "0x20008000",
+ "0x10",
+ "0x20009000",
+ "0x1000",
+ "0x2000A000",
+ "0x1000",
+ "0x2000B000",
+ "0x1000",
+ ]
result = run_blhost_proxy(caplog, cmd)
assert "Response status = 0 (0x0) Success." in result.output
assert "Response word 1 = 48 (0x30)" in result.output
@@ -427,15 +493,31 @@ def test_tp_oem_gen_master_share(caplog):
def test_tp_oem_set_master_share(caplog):
- cmd = "-p super-com trust-provisioning oem_set_master_share 0x20008000 16 0x20009000 64"
+ cmd = [
+ "-p",
+ "super-com",
+ "trust-provisioning",
+ "oem_set_master_share",
+ "0x20008000",
+ "16",
+ "0x20009000",
+ "64",
+ ]
result = run_blhost_proxy(caplog, cmd)
assert "Response status = 0 (0x0) Success." in result.output
def test_oem_get_cust_cert_dice_puk(caplog):
- cmd = (
- "-p super-com trust-provisioning oem_get_cust_cert_dice_puk 0x30015000 0x20 0x30016000 0x40"
- )
+ cmd = [
+ "-p",
+ "super-com",
+ "trust-provisioning",
+ "oem_get_cust_cert_dice_puk",
+ "0x30015000",
+ "0x20",
+ "0x30016000",
+ "0x40",
+ ]
result = run_blhost_proxy(caplog, cmd)
assert "Response status = 0 (0x0) Success." in result.output
assert "Response word 1 = 64 (0x40)" in result.output
@@ -445,7 +527,7 @@ def test_oem_get_cust_cert_dice_puk(caplog):
def test_batch(caplog, data_dir):
command_file = os.path.join(data_dir, "blhost_commands.bcf")
- cmd = f"-p super-com batch {command_file}"
+ cmd = ["-p", "super-com", "batch", command_file]
result = run_blhost_proxy(caplog, cmd)
# we expect 3 successful command execution
assert result.output.count("Response status = 0 (0x0) Success.") == 3
@@ -453,6 +535,6 @@ def test_batch(caplog, data_dir):
def test_batch_error(caplog, data_dir):
command_file = os.path.join(data_dir, "bad_blhost_commands.bcf")
- cmd = f"-p super-com batch {command_file}"
+ cmd = ["-p", "super-com", "batch", command_file]
result = run_blhost_proxy(caplog, cmd, expect_exit_code=1)
assert "Unknown command" in str(result.exception)
diff --git a/tests/mcu_examples/test_rt5xx.py b/tests/mcu_examples/test_rt5xx.py
index c2bc014c..42b0e36c 100644
--- a/tests/mcu_examples/test_rt5xx.py
+++ b/tests/mcu_examples/test_rt5xx.py
@@ -14,7 +14,7 @@
import pytest
from bitstring import BitArray
-from spsdk.crypto.signature_provider import SignatureProvider
+from spsdk.crypto.signature_provider import get_signature_provider
from spsdk.image import KeySourceType, KeyStore, TrustZone
from spsdk.image.mbimg import (
Mbi_CrcRamRtxxx,
@@ -22,6 +22,7 @@
Mbi_EncryptedRamRtxxx,
Mbi_PlainSignedRamRtxxx,
Mbi_PlainSignedXipRtxxx,
+ SignatureProvider,
)
from spsdk.mboot import ExtMemId, KeyProvUserKeyType, McuBoot, PropertyTag, scan_usb
from spsdk.mboot.exceptions import McuBootConnectionError
@@ -667,10 +668,11 @@ def test_sb_unsigned_keystore(data_dir: str, subdir: str, image_name: str) -> No
# certificate + private key
cert_block = create_cert_block(data_dir)
- priv_key_pem_data = load_binary(os.path.join(data_dir, "keys_certs", "k0_cert0_2048.pem"))
+ priv_key = os.path.join(data_dir, "keys_certs", "k0_cert0_2048.pem")
+ signature_provider = get_signature_provider(local_file_key=priv_key)
boot_image.cert_block = cert_block
- boot_image.private_key_pem_data = priv_key_pem_data
+ boot_image.signature_provider = signature_provider
fcb_data = load_binary(os.path.join(data_dir, FCB_FILE_NAME))
plain_image_data = load_binary(os.path.join(data_dir, subdir, image_name + ".bin"))
@@ -752,10 +754,11 @@ def test_sb_unsigned_otp(data_dir: str, subdir: str, image_name: str) -> None:
# certificate + private key
cert_block = create_cert_block(data_dir)
- priv_key_pem_data = load_binary(os.path.join(data_dir, "keys_certs", "k0_cert0_2048.pem"))
+ priv_key = os.path.join(data_dir, "keys_certs", "k0_cert0_2048.pem")
+ signature_provider = get_signature_provider(local_file_key=priv_key)
boot_image.cert_block = cert_block
- boot_image.private_key_pem_data = priv_key_pem_data
+ boot_image.signature_provider = signature_provider
fcb_data = load_binary(os.path.join(data_dir, FCB_FILE_NAME))
plain_image_data = load_binary(os.path.join(data_dir, subdir, image_name + ".bin"))
@@ -834,10 +837,11 @@ def test_sb_signed_encr_keystore(data_dir: str, subdir: str, image_name: str) ->
# certificate + private key
cert_block = create_cert_block(data_dir)
- priv_key_pem_data = load_binary(os.path.join(data_dir, "keys_certs", "k0_cert0_2048.pem"))
+ priv_key = os.path.join(data_dir, "keys_certs", "k0_cert0_2048.pem")
+ signature_provider = get_signature_provider(local_file_key=priv_key)
boot_image.cert_block = cert_block
- boot_image.private_key_pem_data = priv_key_pem_data
+ boot_image.signature_provider = signature_provider
fcb_data = load_binary(os.path.join(data_dir, FCB_FILE_NAME))
plain_image_data = load_binary(os.path.join(data_dir, subdir, image_name + ".bin"))
@@ -917,10 +921,11 @@ def test_sb_otfad_keystore(data_dir: str, subdir: str, image_name: str, secure:
# certificate + private key
cert_block = create_cert_block(data_dir)
- priv_key_pem_data = load_binary(os.path.join(data_dir, "keys_certs", "k0_cert0_2048.pem"))
+ priv_key = os.path.join(data_dir, "keys_certs", "k0_cert0_2048.pem")
+ signature_provider = get_signature_provider(local_file_key=priv_key)
boot_image.cert_block = cert_block
- boot_image.private_key_pem_data = priv_key_pem_data
+ boot_image.signature_provider = signature_provider
fcb_data = load_binary(os.path.join(data_dir, FCB_FILE_NAME))
plain_image_data = load_binary(os.path.join(data_dir, subdir, image_name + ".bin"))
@@ -1051,10 +1056,11 @@ def test_sb_otfad_otp(data_dir: str, subdir: str, image_name: str, secure: bool)
# certificate + private key
cert_block = create_cert_block(data_dir)
- priv_key_pem_data = load_binary(os.path.join(data_dir, "keys_certs", "k0_cert0_2048.pem"))
+ priv_key = os.path.join(data_dir, "keys_certs", "k0_cert0_2048.pem")
+ signature_provider = get_signature_provider(local_file_key=priv_key)
boot_image.cert_block = cert_block
- boot_image.private_key_pem_data = priv_key_pem_data
+ boot_image.signature_provider = signature_provider
fcb_data = load_binary(os.path.join(data_dir, FCB_FILE_NAME))
plain_image_data = load_binary(os.path.join(data_dir, subdir, image_name + ".bin"))
diff --git a/tests/nxpcertgen/test_certgen.py b/tests/nxpcertgen/test_certgen.py
index 6798f9a4..b1f9b25a 100644
--- a/tests/nxpcertgen/test_certgen.py
+++ b/tests/nxpcertgen/test_certgen.py
@@ -241,11 +241,25 @@ def test_certificate_generation_cli(tmpdir, data_dir, json, encoding):
with use_working_directory(data_dir):
cert_path = os.path.join(tmpdir, "cert.crt")
if json:
- cmd = f'generate -j {os.path.join(data_dir, "certgen_config.json")} -o {cert_path}'
+ cmd = [
+ "generate",
+ "-j",
+ f'{os.path.join(data_dir, "certgen_config.json")}',
+ "-o",
+ f"{cert_path}",
+ ]
else:
- cmd = f'generate -c {os.path.join(data_dir, "certgen_config.yaml")} -o {cert_path} -e {encoding}'
+ cmd = [
+ "generate",
+ "-c",
+ f'{os.path.join(data_dir, "certgen_config.yaml")}',
+ "-o",
+ cert_path,
+ "-e",
+ encoding,
+ ]
runner = CliRunner()
- result = runner.invoke(main, cmd.split())
+ result = runner.invoke(main, cmd)
assert result.exit_code == 0
assert os.path.isfile(cert_path)
diff --git a/tests/nxpimage/data/ahab/cntr_fspi1_xip_cm33_img.bin b/tests/nxpimage/data/ahab/cntr_fspi1_xip_cm33_img.bin
deleted file mode 100644
index 956002b5..00000000
Binary files a/tests/nxpimage/data/ahab/cntr_fspi1_xip_cm33_img.bin and /dev/null differ
diff --git a/tests/nxpimage/data/ahab/cntr_fspi2_xip_cm33_img.bin b/tests/nxpimage/data/ahab/cntr_fspi2_xip_cm33_img.bin
deleted file mode 100644
index 34c4613c..00000000
Binary files a/tests/nxpimage/data/ahab/cntr_fspi2_xip_cm33_img.bin and /dev/null differ
diff --git a/tests/nxpimage/data/ahab/cntr_signed_ctcm_cm33_cert.bin b/tests/nxpimage/data/ahab/cntr_signed_ctcm_cm33_cert.bin
index e3f7b8af..02bb128b 100644
Binary files a/tests/nxpimage/data/ahab/cntr_signed_ctcm_cm33_cert.bin and b/tests/nxpimage/data/ahab/cntr_signed_ctcm_cm33_cert.bin differ
diff --git a/tests/nxpimage/data/ahab/cntr_signed_ctcm_cm33_cert_nand.bin b/tests/nxpimage/data/ahab/cntr_signed_ctcm_cm33_cert_nand.bin
new file mode 100644
index 00000000..1700f110
Binary files /dev/null and b/tests/nxpimage/data/ahab/cntr_signed_ctcm_cm33_cert_nand.bin differ
diff --git a/tests/nxpimage/data/ahab/cntr_signed_ctcm_cm33_cert_nx.bin b/tests/nxpimage/data/ahab/cntr_signed_ctcm_cm33_cert_nx.bin
index c93c3536..cd154518 100644
Binary files a/tests/nxpimage/data/ahab/cntr_signed_ctcm_cm33_cert_nx.bin and b/tests/nxpimage/data/ahab/cntr_signed_ctcm_cm33_cert_nx.bin differ
diff --git a/tests/nxpimage/data/ahab/cntr_signed_ctcm_cm33_cert_sb.bin b/tests/nxpimage/data/ahab/cntr_signed_ctcm_cm33_cert_sb.bin
index abcdc9c9..d75575f1 100644
Binary files a/tests/nxpimage/data/ahab/cntr_signed_ctcm_cm33_cert_sb.bin and b/tests/nxpimage/data/ahab/cntr_signed_ctcm_cm33_cert_sb.bin differ
diff --git a/tests/nxpimage/data/ahab/config_fspi1.json b/tests/nxpimage/data/ahab/config_fspi1.json
deleted file mode 100644
index e50a5255..00000000
--- a/tests/nxpimage/data/ahab/config_fspi1.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "family": "rt118x",
- "revision": "a0",
- "output": "./cntr_fspi1_xip_cm33_img.bin",
- "containers": [
- {
- "srk_set": "none",
- "fuse_version": 0,
- "sw_version": 0,
- "image_array_entries": [
- {
- "image_path": "./bin/fspi1_xip_cm33_img.bin",
- "image_offset": "0x2000",
- "load_address": "0x38003000",
- "entry_point": "0x38003000",
- "image_type": "executable",
- "core_id": "cortex-m33",
- "hash_type": "sha512",
- "is_encrypted": false
- }
- ]
- }
- ]
-}
diff --git a/tests/nxpimage/data/ahab/config_fspi2.json b/tests/nxpimage/data/ahab/config_fspi2.json
deleted file mode 100644
index 03336aad..00000000
--- a/tests/nxpimage/data/ahab/config_fspi2.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "family": "rt118x",
- "revision": "a0",
- "output": "./cntr_ele_fw_fspi2_xip_cm33_img.bin",
- "containers": [
- {
- "srk_set": "none",
- "fuse_version": 0,
- "sw_version": 0,
- "image_array_entries": [
- {
- "image_path": "./bin/fspi2_xip_cm33_img.bin",
- "image_offset": "0x2000",
- "load_address": "0x14003000",
- "entry_point": "0x14003000",
- "image_type": "executable",
- "core_id": "cortex-m33",
- "hash_type": "sha512",
- "is_encrypted": false
- }
- ]
- }
- ]
-}
diff --git a/tests/nxpimage/data/ahab/config_fspi2eleFw.json b/tests/nxpimage/data/ahab/config_fspi2eleFw.json
deleted file mode 100644
index c52d36f4..00000000
--- a/tests/nxpimage/data/ahab/config_fspi2eleFw.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "family": "rt118x",
- "revision": "a0",
- "output": "./cntr_ele_fw_fspi2_xip_cm33_img.bin",
- "containers": [
- {
- "path": "./bin/mxrt1180a0-ahab-container.img"
- },
- {
- "srk_set": "none",
- "fuse_version": 0,
- "sw_version": 0,
- "image_array_entries": [
- {
- "image_path": "./bin/fspi2_xip_cm33_img.bin",
- "image_offset": "0x3000",
- "load_address": "0x14004000",
- "entry_point": "0x14004000",
- "image_type": "executable",
- "core_id": "cortex-m33",
- "hash_type": "sha512",
- "is_encrypted": false
- }
- ]
- }
- ]
-}
diff --git a/tests/nxpimage/data/ahab/ctcm_cm33_signed_cert_nand.yaml b/tests/nxpimage/data/ahab/ctcm_cm33_signed_cert_nand.yaml
new file mode 100644
index 00000000..028daadf
--- /dev/null
+++ b/tests/nxpimage/data/ahab/ctcm_cm33_signed_cert_nand.yaml
@@ -0,0 +1,76 @@
+# Copyright 2023 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+# ----------------------------------------------------------------------------------------------------
+# =========== Advanced High-Assurance Boot Configuration template for rt118x. ===========
+# ----------------------------------------------------------------------------------------------------
+# == General Options ==
+family: rt118x # [Required], MCU family, Family identifier including the chip revision. If revision is not present, latest revision is used as default., Possible options:['rt118x']
+revision: a0 # [Optional], MCU revision, Revision of silicon, Possible options:['a0']
+image_type: nand # [Required], Type of image, The final use of image, this setting is changing the style of offsets in final container., Possible options:['xip', 'non_xip', 'serial_downloader']
+output: ahab/cntr_signed_ctcm_cm33_cert_nand.bin # [Required], Output AHAB file name, Revision of silicon
+containers: # [Required], List of containers present in AHAB., The order of containers in the list defines the order in AHAB.
+ # ----------------------------------------------------------------------------------------------------
+ # == List of possible 2 options. Option types[object,object] ==
+ # ----------------------------------------------------------------------------------------------------
+ - # [Example of possible configuration #0]
+ # ----------------------------------------------------------------------------------------------------
+ # == Optional Binary Container format to add to AHAB image ==
+ # ----------------------------------------------------------------------------------------------------
+ binary_container: # [Required], Binary AHAB container
+ path: ahab/mxrt1180a0-ahab-container.bin # [Required], The AHAB container binary file, The binary file that contains AHAB "my_binary_container.bin
+ - # [Example of possible configuration #1]
+ # ----------------------------------------------------------------------------------------------------
+ # == Optional Configuration Container format to add to AHAB image ==
+ # ----------------------------------------------------------------------------------------------------
+ container: # [Required], AHAB Container
+ srk_set: oem # [Required], Super Root Key (SRK) set, Defines which set is used to authenticate the container., Possible options:['none', 'oem', 'nxp']
+ used_srk_id: 0 # [Conditionally required], Used SRK, Which key from SRK set is being used.
+ srk_revoke_mask: 0 # [Optional], SRK revoke mask, Bitmask to indicate which SRKs to revoke. Bit set to 1 means revoke key. Bit 0 = revoke SRK_0, bit 1 = revoke SRK_1 etc.
+ fuse_version: 0 # [Required], Fuse version, The value must be equal or greater than the version stored in fuses to allow loading this container.
+ sw_version: 0 # [Required], Software version, Number used by Privileged Host Boot Companion (PHBC) to select between multiple images with same Fuse version field.
+ signing_key:
+ ahab/keys/cert1_key_ecc_prime256v1.pem # [Conditionally required], AHAB container signing key, Private key used for sign the container header. Header can be signed by SRK or by image key that was signed by SRK. If an image key is used, it must be the same algorithm and key size as the SRK. In both cases, the referenced SRK must not have been revoked.
+ # ----------------------------------------------------------------------------------------------------
+ # == Configuration of AHAB Container images (array of multiple images) ==
+ # ----------------------------------------------------------------------------------------------------
+ images: # [Required], Image array, Array of image entries.
+ - image_path: ahab/ctcm_cm33_img.bin # [Required], Image path, Path to image binary (absolute/relative).
+ image_offset: "0xb000" # [Required], Image offset in AHAB container, Relative address for start of AHAB image (can contain multiple AHAB containers). In case of XiP type of AHAB image, the load_address and entry_point must correspond to this values. Example of setting of load_address - AHAB_IMAGE_ADDRESS+IMAGE_OFFSET=LOAD_ADDRESS
+ load_address: "0x1FFE0000" # [Required], Image destination address, Address the image is written to in memory (absolute address in system memory).
+ entry_point: "0x1FFE0000" # [Required], Image entry point, Image entry point (absolute address). Valid only for executable image types.
+ image_type: executable # [Required], Image type, Kind of image., Possible options:['executable', 'data', 'dcd_image', 'seco', 'provisioning_image', 'provisioning_data']
+ core_id: cortex-m33 # [Required], Core ID, Defines the core the image is dedicated for., Possible options:['cortex-m33', 'cortex-m7']
+ is_encrypted: false # [Required], Image encryption, Determines, whether image is encrypted or not.
+ boot_flags: 0 # [Optional], Boot flags, Boot flags controlling SCFW boot.
+ meta_data_start_cpu_id: 0 # [Optional], Start CPU ID, Resource ID of CPU to be started
+ meta_data_mu_cpu_id: 0 # [Optional], CPU memory unit start ID, Resource ID of the MU associated with the CPU
+ meta_data_start_partition_id: 0 # [Optional], Start partition ID, Partition ID of the partition to start
+ hash_type: sha512 # [Optional], Images HASH type, HASH type of image. All images in the container must have the same HASH type., Possible options:['sha256', 'sha384', 'sha512']
+ #iv_path: my_IV.bin # [Optional], IV file path, Used only for encrypted images (zero otherwise): SHA256 of the plain text image. Fixed size at 256 bits. The lower 128-bit part of the SHA256 value will be retained as IV in the encryption/decryption process.
+ # ----------------------------------------------------------------------------------------------------
+ # == Configuration of AHAB SRK table ==
+ # ----------------------------------------------------------------------------------------------------
+ srk_table: # [Conditionally required], SRK Table, SRK (Super Root key) table definition.
+ hash_type: sha256 # [Required], SRK HASH type, HASH type of image. All images in the container must have the same HASH type., Possible options:['sha256', 'sha384', 'sha512']
+ srk_array: # [Required], Super Root Key (SRK) table, Table containing the used SRK records. All SRKs must be of the same type. Supported signing algorithms are: RSASSA-PSS or ECDSA. Supported hash algorithms: sha256, sha384, sha512. Supported key sizes/curves: prime256v1, sec384r1, sec512r1, rsa2048, rsa4096. Certificate may be of Certificate Authority.
+ - ahab/certs/cert1_ecc_prime256v1.pem # SRK key, Path to SRK Key file.
+ - ahab/certs/cert2_ecc_prime256v1.pem
+ - ahab/certs/cert3_ecc_prime256v1.pem
+ - ahab/certs/cert4_ecc_prime256v1.pem
+ # ----------------------------------------------------------------------------------------------------
+ # == Optional configuration of AHAB Container Certificate (if not used, erase the section) ==
+ # ----------------------------------------------------------------------------------------------------
+ certificate: # [Optional], Certificate container, Optional certificate container definition."
+ permissions: # [Optional], Certificate permissions, Permissions used to indicate what a certificate can be used for
+ - container # , Possible options:['container', 'secure_enclave_debug', 'phbc_debug', 'hdmi_debug', 'soc_debug_domain_1', 'soc_debug_domain_2', 'life_cycle', 'hdcp_fuses', 'monotonic_counter'] uuid: 00001111aaaabbbb22223333ccccdddd # [Optional], UUID, (Optional) 128-bit unique identifier
+ uuid: 0x00001111aaaabbbb22223333ccccdddd # [Optional], UUID, (Optional) 128-bit unique identifier
+ public_key: ahab/certs/cert1_ecc_prime256v1.pem # [Required], Certificate public key, Path to Public key file (RSA and ECDSA).
+ hash_type: sha256 # [Required], Certificate HASH type, HASH type of public key. The hash type should correspond to SRK keys., Possible options:['sha256', 'sha384', 'sha512']
+ signing_key: ahab/keys/cert1_key_ecc_prime256v1.pem # [Required], Certificate container signing key, Private key used for sign the certificate container.
+ # ----------------------------------------------------------------------------------------------------
+ # == Optional configuration of AHAB Container Encryption blob (if not used, erase the section) ==
+ # ----------------------------------------------------------------------------------------------------
+# blob: # [Optional], Encryption blob, Encryption blob container definition
+# wrapped_key_path: my_wrapped_key.pem # [Required], KEK blob wrapped key, Wrapped Data Encryption key. Used for AES CBC-MAC (128/192/256 size).
diff --git a/tests/nxpimage/data/ahab/ctcm_cm33_signed_img.bin b/tests/nxpimage/data/ahab/ctcm_cm33_signed_img.bin
new file mode 100644
index 00000000..592e7ff1
Binary files /dev/null and b/tests/nxpimage/data/ahab/ctcm_cm33_signed_img.bin differ
diff --git a/tests/nxpimage/data/ahab/ctcm_cm33_signed_img.json b/tests/nxpimage/data/ahab/ctcm_cm33_signed_img.json
index 24db388f..82d305ae 100644
--- a/tests/nxpimage/data/ahab/ctcm_cm33_signed_img.json
+++ b/tests/nxpimage/data/ahab/ctcm_cm33_signed_img.json
@@ -1,7 +1,7 @@
{
"family": "rt118x",
"revision": "a0",
- "output": "ahab/cntr_signed_ctcm_cm33_img.bin",
+ "output": "ahab/ctcm_cm33_signed_img.bin",
"image_type": "non_xip",
"containers": [
{
@@ -45,4 +45,4 @@
}
}
]
-}
+}
\ No newline at end of file
diff --git a/tests/nxpimage/data/bootable_image/rt104x/flexspi_nor/bee_header_0.bin b/tests/nxpimage/data/bootable_image/rt104x/flexspi_nor/bee_header_0.bin
new file mode 100644
index 00000000..70890f71
Binary files /dev/null and b/tests/nxpimage/data/bootable_image/rt104x/flexspi_nor/bee_header_0.bin differ
diff --git a/tests/nxpimage/data/bootable_image/rt104x/flexspi_nor/bee_header_1.bin b/tests/nxpimage/data/bootable_image/rt104x/flexspi_nor/bee_header_1.bin
new file mode 100644
index 00000000..501ff904
Binary files /dev/null and b/tests/nxpimage/data/bootable_image/rt104x/flexspi_nor/bee_header_1.bin differ
diff --git a/tests/nxpimage/data/bootable_image/rt104x/flexspi_nor/config.yaml b/tests/nxpimage/data/bootable_image/rt104x/flexspi_nor/config.yaml
new file mode 100644
index 00000000..84bc572b
--- /dev/null
+++ b/tests/nxpimage/data/bootable_image/rt104x/flexspi_nor/config.yaml
@@ -0,0 +1,14 @@
+# Copyright 2023 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+# =========== Bootable Image Configuration template for rt104x. ===========
+# ----------------------------------------------------------------------------------------------------
+# == General Options ==
+# ----------------------------------------------------------------------------------------------------
+family: rt104x # [Required], MCU family name; Possible options:['rt102x', 'rt104x', 'rt105x', 'rt106x']
+revision: latest # [Optional], Chip silicon revision; If needed this could be used to specify silicon revision of device; Possible options:['latest']
+memory_type: flexspi_nor # [Required], Memory type; Specify type of memory used by bootable image description; Possible options:['flexspi_nor']
+fcb: fcb.bin # [Optional], FCB block path; Flash Configuration block path
+bee_header_0: bee_header_0.bin # [Optional], BEE encryption header 0 path
+bee_header_1: bee_header_1.bin # [Optional], BEE encryption header 1 path
+hab_container: hab_container.bin # [Required], HAB container path
diff --git a/tests/nxpimage/data/bootable_image/rt104x/flexspi_nor/fcb.bin b/tests/nxpimage/data/bootable_image/rt104x/flexspi_nor/fcb.bin
new file mode 100644
index 00000000..616b6d5a
Binary files /dev/null and b/tests/nxpimage/data/bootable_image/rt104x/flexspi_nor/fcb.bin differ
diff --git a/tests/nxpimage/data/bootable_image/rt104x/flexspi_nor/hab_container.bin b/tests/nxpimage/data/bootable_image/rt104x/flexspi_nor/hab_container.bin
new file mode 100644
index 00000000..f462d007
Binary files /dev/null and b/tests/nxpimage/data/bootable_image/rt104x/flexspi_nor/hab_container.bin differ
diff --git a/tests/nxpimage/data/bootable_image/rt104x/flexspi_nor/merged_image.bin b/tests/nxpimage/data/bootable_image/rt104x/flexspi_nor/merged_image.bin
new file mode 100644
index 00000000..2e46fb4a
Binary files /dev/null and b/tests/nxpimage/data/bootable_image/rt104x/flexspi_nor/merged_image.bin differ
diff --git a/tests/nxpimage/data/iee/aes_xts512_multiple/encrypted_blobs.bin b/tests/nxpimage/data/iee/aes_xts512_multiple/encrypted_blobs.bin
index c916dc67..709b2fd7 100644
Binary files a/tests/nxpimage/data/iee/aes_xts512_multiple/encrypted_blobs.bin and b/tests/nxpimage/data/iee/aes_xts512_multiple/encrypted_blobs.bin differ
diff --git a/tests/nxpimage/data/iee/aes_xts512_multiple/iee_config.yaml b/tests/nxpimage/data/iee/aes_xts512_multiple/iee_config.yaml
index 9d971a39..4de85f8d 100644
--- a/tests/nxpimage/data/iee/aes_xts512_multiple/iee_config.yaml
+++ b/tests/nxpimage/data/iee/aes_xts512_multiple/iee_config.yaml
@@ -44,4 +44,4 @@ key_blobs: # [Required], List of Key Blobs used by IEE, The list of definition o
key1: "0x000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F" # [Required], AES-XTS key1 / AES-CTR key, AES key for the key blob, size depends on key_size
key2: "0x202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F" # [Required], AES-CTR Counter value or AES-XTS key2, AES key for the key blob, size depends on key_size
start_address: "0x30008000" # [Required], Start address of key blob data, Start address of key blob data, it should be aligned to 1 KB (1024 B)
- end_address: "0x30026000" # [Required], End address of key blob data, End address of key blob data, it should be aligned to 1 KB (1024 B)
+ end_address: "0x30019000" # [Required], End address of key blob data, End address of key blob data, it should be aligned to 1 KB (1024 B)
diff --git a/tests/nxpimage/data/iee/aes_xts512_multiple/iee_keyblob.bin b/tests/nxpimage/data/iee/aes_xts512_multiple/iee_keyblob.bin
index c926d9af..7f1d06fe 100644
Binary files a/tests/nxpimage/data/iee/aes_xts512_multiple/iee_keyblob.bin and b/tests/nxpimage/data/iee/aes_xts512_multiple/iee_keyblob.bin differ
diff --git a/tests/nxpimage/data/mbi/ext_xip_signed_lpc55s3x.yml b/tests/nxpimage/data/mbi/ext_xip_signed_lpc55s3x.yml
index 18d1ca3d..93e5d8c1 100644
--- a/tests/nxpimage/data/mbi/ext_xip_signed_lpc55s3x.yml
+++ b/tests/nxpimage/data/mbi/ext_xip_signed_lpc55s3x.yml
@@ -1,7 +1,6 @@
# Copyright 2023 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
----
family: rt5xx
outputImageExecutionTarget: External flash (XIP)
outputImageAuthenticationType: Signed
diff --git a/tests/nxpimage/data/mbi/ext_xip_signed_lpc55s3x_invalid.yml b/tests/nxpimage/data/mbi/ext_xip_signed_lpc55s3x_invalid.yml
index 0182187a..f16939da 100644
--- a/tests/nxpimage/data/mbi/ext_xip_signed_lpc55s3x_invalid.yml
+++ b/tests/nxpimage/data/mbi/ext_xip_signed_lpc55s3x_invalid.yml
@@ -1,7 +1,6 @@
# Copyright 2023 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
----
family: rt5xx
outputImageExecutionTarget: External flash (XIP)
outputImageAuthenticationType: Signed
diff --git a/tests/nxpimage/data/mbi/ext_xip_signed_rtxxxx.yml b/tests/nxpimage/data/mbi/ext_xip_signed_rtxxxx.yml
index 17626f80..43680887 100644
--- a/tests/nxpimage/data/mbi/ext_xip_signed_rtxxxx.yml
+++ b/tests/nxpimage/data/mbi/ext_xip_signed_rtxxxx.yml
@@ -1,7 +1,6 @@
# Copyright 2023 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
----
family: rt5xx
outputImageExecutionTarget: External flash (XIP)
outputImageAuthenticationType: Signed
diff --git a/tests/nxpimage/data/mbi/ext_xip_signed_rtxxxx_invalid.yml b/tests/nxpimage/data/mbi/ext_xip_signed_rtxxxx_invalid.yml
index d1c6698a..99a4df7e 100644
--- a/tests/nxpimage/data/mbi/ext_xip_signed_rtxxxx_invalid.yml
+++ b/tests/nxpimage/data/mbi/ext_xip_signed_rtxxxx_invalid.yml
@@ -1,7 +1,6 @@
# Copyright 2023 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
----
family: rt5xx
outputImageExecutionTarget: External flash (XIP)
outputImageAuthenticationType: Signed
diff --git a/tests/nxpimage/data/mbi/int_xip_signed_kw45xx.yml b/tests/nxpimage/data/mbi/int_xip_signed_kw45xx.yml
index c9335f31..94ebef7a 100644
--- a/tests/nxpimage/data/mbi/int_xip_signed_kw45xx.yml
+++ b/tests/nxpimage/data/mbi/int_xip_signed_kw45xx.yml
@@ -1,7 +1,6 @@
# Copyright 2023 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
----
family: kw45xx
outputImageExecutionTarget: Internal flash (XIP)
outputImageAuthenticationType: Signed
diff --git a/tests/nxpimage/data/mbi/int_xip_signed_kw45xx_invalid.yml b/tests/nxpimage/data/mbi/int_xip_signed_kw45xx_invalid.yml
index ed401791..f6eefc58 100644
--- a/tests/nxpimage/data/mbi/int_xip_signed_kw45xx_invalid.yml
+++ b/tests/nxpimage/data/mbi/int_xip_signed_kw45xx_invalid.yml
@@ -1,7 +1,6 @@
# Copyright 2023 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
----
family: kw45xx
outputImageExecutionTarget: Internal flash (XIP)
outputImageAuthenticationType: Signed
diff --git a/tests/nxpimage/data/mbi/int_xip_signed_xip.yml b/tests/nxpimage/data/mbi/int_xip_signed_xip.yml
index 8764bfc8..bfefe4b6 100644
--- a/tests/nxpimage/data/mbi/int_xip_signed_xip.yml
+++ b/tests/nxpimage/data/mbi/int_xip_signed_xip.yml
@@ -1,7 +1,6 @@
# Copyright 2023 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
----
family: lpc551x
outputImageExecutionTarget: Internal flash (XIP)
outputImageAuthenticationType: Signed
diff --git a/tests/nxpimage/data/mbi/int_xip_signed_xip_invalid.yml b/tests/nxpimage/data/mbi/int_xip_signed_xip_invalid.yml
index 5392d036..647eaf4b 100644
--- a/tests/nxpimage/data/mbi/int_xip_signed_xip_invalid.yml
+++ b/tests/nxpimage/data/mbi/int_xip_signed_xip_invalid.yml
@@ -1,7 +1,6 @@
# Copyright 2023 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
----
family: lpc551x
outputImageExecutionTarget: Internal flash (XIP)
outputImageAuthenticationType: Signed
diff --git a/tests/nxpimage/data/otfad/otfad_rt1160_out.bin b/tests/nxpimage/data/otfad/otfad_rt1160_out.bin
index 703490e4..03888b65 100644
Binary files a/tests/nxpimage/data/otfad/otfad_rt1160_out.bin and b/tests/nxpimage/data/otfad/otfad_rt1160_out.bin differ
diff --git a/tests/nxpimage/data/otfad/otfad_rt1170_out.bin b/tests/nxpimage/data/otfad/otfad_rt1170_out.bin
index 703490e4..03888b65 100644
Binary files a/tests/nxpimage/data/otfad/otfad_rt1170_out.bin and b/tests/nxpimage/data/otfad/otfad_rt1170_out.bin differ
diff --git a/tests/nxpimage/data/xmcd/rt116x/templates/xmcd_rt116x_semc_sdram_simplified.yaml b/tests/nxpimage/data/xmcd/rt116x/templates/xmcd_rt116x_semc_sdram_simplified.yaml
index e4e49dde..f80c8ed5 100644
--- a/tests/nxpimage/data/xmcd/rt116x/templates/xmcd_rt116x_semc_sdram_simplified.yaml
+++ b/tests/nxpimage/data/xmcd/rt116x/templates/xmcd_rt116x_semc_sdram_simplified.yaml
@@ -3,7 +3,7 @@
# SPDX-License-Identifier: BSD-3-Clause
# =========== External Memory Configuration Data template for rt116x. ===========
# ----------------------------------------------------------------------------------------------------
-# == General Options ==
+# == General Options ==
# ----------------------------------------------------------------------------------------------------
family: rt116x # [Required], MCU family name; Possible options:['rt116x', 'rt117x', 'rt118x']
revision: latest # [Optional], Chip silicon revision; If needed this could be used to specify silicon revision of device; Possible options:['latest']
diff --git a/tests/nxpimage/data/xmcd/rt117x/flexspi_ram_simplified.bin b/tests/nxpimage/data/xmcd/rt117x/flexspi_ram_simplified.bin
deleted file mode 100644
index 86484988..00000000
Binary files a/tests/nxpimage/data/xmcd/rt117x/flexspi_ram_simplified.bin and /dev/null differ
diff --git a/tests/nxpimage/data/xmcd/rt117x/flexspi_ram_simplified.yaml b/tests/nxpimage/data/xmcd/rt117x/flexspi_ram_simplified.yaml
deleted file mode 100644
index fbc8003f..00000000
--- a/tests/nxpimage/data/xmcd/rt117x/flexspi_ram_simplified.yaml
+++ /dev/null
@@ -1,30 +0,0 @@
---- # ----------------------------------------------------------------------------------------------------
-# Copyright 2023 NXP
-#
-# SPDX-License-Identifier: BSD-3-Clause
-
-# =========== External Memory Configuration Data template for rt117x. ===========
-# ----------------------------------------------------------------------------------------------------
-# == General Options ==
-family: rt117x # [Required], MCU family, MCU family name., Possible options:['rt117x']
-revision: latest # [Optional], Chip silicon revision, If needed this could be used to specify silicon revision of device., Possible options:['latest']
-mem_type: flexspi_ram # [Optional], Memory type, Specify type of memory used by XMCD description., Possible options:['flexspi_ram', 'semc_sdram']
-config_type: simplified # [Optional], Configuration type, Specify type of configuration used by XMCD description., Possible options:['simplified', 'full']
-xmcd_settings: # [Required], rt117x
- header: # [Optional], header, XMCD Header
- bitfields: # [Required]
- configurationBlockSize: 8 # [Optional], configurationBlockSize, Configuration block size including XMCD header itself
- configurationBlockType: 0 # [Optional], configurationBlockType, Configuration block type - 0 - Simplified, 1 - Full
- instance: 0 # [Optional], instance, SoC defined instances
- memoryInterface: 0 # [Optional], memoryInterface, Memory interface 0 - FlexSPI, 1 - SEMC
- version: 0 # [Optional], version, Version, fixed value 0x0
- tag: 12 # [Optional], tag, Tag, fixed value 0xc
- configBlock: # [Optional], configBlock, XMCD Configuration Block
- bitfields: # [Required]
- sizeInMB: 0 # [Optional], sizeInMB, Size in MB. 0 - Auto detection, Others - Size in MB
- maximumFrequency: 7 # [Optional], maximumFrequency, Maximum frequency. SoC specific definitions
- misc: 0 # [Optional], misc, Misc. For HyperRAM 0 - 1.8V, 1 - 3V
- reserved: 0 # [Optional], reserved, Reserved for future use
- deviceType: 0 # [Optional], deviceType, Device type 0 - Hyper RAM, 1 - APMemory
- optionSize: 0 # [Optional], optionSize, Option Size
- tag: 12 # [Optional], tag, Tag, fixed value 0xc
diff --git a/tests/nxpimage/data/xmcd/rt117x/templates/xmcd_rt117x_semc_sdram_simplified.yaml b/tests/nxpimage/data/xmcd/rt117x/templates/xmcd_rt117x_semc_sdram_simplified.yaml
index 61480b8a..f85e1326 100644
--- a/tests/nxpimage/data/xmcd/rt117x/templates/xmcd_rt117x_semc_sdram_simplified.yaml
+++ b/tests/nxpimage/data/xmcd/rt117x/templates/xmcd_rt117x_semc_sdram_simplified.yaml
@@ -3,7 +3,7 @@
# SPDX-License-Identifier: BSD-3-Clause
# =========== External Memory Configuration Data template for rt117x. ===========
# ----------------------------------------------------------------------------------------------------
-# == General Options ==
+# == General Options ==
# ----------------------------------------------------------------------------------------------------
family: rt117x # [Required], MCU family name; Possible options:['rt116x', 'rt117x', 'rt118x']
revision: latest # [Optional], Chip silicon revision; If needed this could be used to specify silicon revision of device; Possible options:['latest']
diff --git a/tests/nxpimage/test_nxpimage_ahab.py b/tests/nxpimage/test_nxpimage_ahab.py
index 1854373d..f5eab5e5 100644
--- a/tests/nxpimage/test_nxpimage_ahab.py
+++ b/tests/nxpimage/test_nxpimage_ahab.py
@@ -15,7 +15,7 @@
from spsdk.apps import nxpimage
from spsdk.image.ahab.ahab_container import AHABImage
from spsdk.image.ahab.signed_msg import SignedMessage
-from spsdk.utils.misc import load_binary, use_working_directory
+from spsdk.utils.misc import load_binary, use_working_directory, write_file
from tests.elftosb.test_elftosb_sb31 import process_config_file
@@ -44,6 +44,7 @@ def test_nxpimage_ahab_export(tmpdir, data_dir, config_file):
("ctcm_cm33_signed_cert.yaml"),
("ctcm_cm33_signed_cert_nx.yaml"),
("ctcm_cm33_signed_cert_sb.yaml"),
+ ("ctcm_cm33_signed_cert_nand.yaml"),
("ctcm_cm33_encrypted_img.yaml"),
],
)
@@ -68,15 +69,27 @@ def test_nxpimage_ahab_parse_cli(tmpdir, data_dir):
assert os.path.isfile(os.path.join(tmpdir, "parsed_config.yaml"))
-def test_nxpimage_ahab_parse(data_dir):
+@pytest.mark.parametrize(
+ "binary,image_type",
+ [
+ ("cntr_signed_ctcm_cm33_cert.bin", "xip"),
+ ("cntr_signed_ctcm_cm33_cert_nx.bin", "non_xip"),
+ ("cntr_signed_ctcm_cm33_cert_sb.bin", "serial_downloader"),
+ ("cntr_signed_ctcm_cm33_cert_nand.bin", "nand"),
+ ("cntr_encrypted_ctcm_cm33.bin", "non_xip"),
+ ("ctcm_cm33_signed_img.bin", "non_xip"),
+ ],
+)
+def test_nxpimage_ahab_parse(data_dir, binary, image_type):
with use_working_directory(data_dir):
- original_file = load_binary(f"{data_dir}/ahab/mxrt1180a0-ahab-container.bin")
- ahab = AHABImage("rt118x", "a0")
+ original_file = load_binary(f"{data_dir}/ahab/{binary}")
+ ahab = AHABImage("rt118x", "a0", image_type)
ahab.parse(original_file)
ahab.update_fields()
ahab.validate()
exported_ahab = ahab.export()
assert original_file == exported_ahab
+ assert ahab.image_type == image_type
@pytest.mark.parametrize(
diff --git a/tests/nxpimage/test_nxpimage_bimg.py b/tests/nxpimage/test_nxpimage_bimg.py
index 65438304..fcdb8c09 100644
--- a/tests/nxpimage/test_nxpimage_bimg.py
+++ b/tests/nxpimage/test_nxpimage_bimg.py
@@ -24,6 +24,7 @@
("flexspi_nor", "lpc55s3x"),
("flexspi_nor", "rt101x"),
("flexspi_nor", "rt102x"),
+ ("flexspi_nor", "rt104x"),
("flexspi_nor", "rt105x"),
("flexspi_nor", "rt106x"),
("flexspi_nor", "rt116x"),
@@ -40,8 +41,8 @@ def test_nxpimage_bimg_merge(tmpdir, data_dir, mem_type, family):
with use_working_directory(data_dir):
config_file = os.path.join(data_dir, "bootable_image", family, mem_type, "config.yaml")
out_file = os.path.join(tmpdir, f"bimg_{family}_merged.bin")
- cmd = f"bootable-image merge -c {config_file} {out_file}"
- result = runner.invoke(nxpimage.main, cmd.split())
+ cmd = [f"bootable-image", "merge", "-c", config_file, out_file]
+ result = runner.invoke(nxpimage.main, cmd)
assert result.exit_code == 0
assert os.path.isfile(out_file)
assert filecmp.cmp(
@@ -59,6 +60,7 @@ def test_nxpimage_bimg_merge(tmpdir, data_dir, mem_type, family):
("lpc55s3x", "flexspi_nor", ["fcb", "application"]),
("rt101x", "flexspi_nor", ["fcb", "keyblob", "hab_container"]),
("rt102x", "flexspi_nor", ["fcb", "bee_header_0", "bee_header_1", "hab_container"]),
+ ("rt104x", "flexspi_nor", ["fcb", "bee_header_0", "bee_header_1", "hab_container"]),
("rt105x", "flexspi_nor", ["fcb", "bee_header_0", "bee_header_1", "hab_container"]),
("rt106x", "flexspi_nor", ["fcb", "bee_header_0", "bee_header_1", "hab_container"]),
("rt116x", "flexspi_nor", ["keyblob", "fcb", "keystore", "hab_container"]),
@@ -74,8 +76,19 @@ def test_nxpimage_bimg_parse_cli(tmpdir, data_dir, family, mem_type, blocks):
runner = CliRunner()
with use_working_directory(data_dir):
data_folder = os.path.join(data_dir, "bootable_image", family, mem_type)
- cmd = f"bootable-image parse -f {family} -m {mem_type} -b {data_folder}/merged_image.bin {tmpdir}"
- result = runner.invoke(nxpimage.main, cmd.split())
+ input_binary = os.path.join(data_folder, "merged_image.bin")
+ cmd = [
+ "bootable-image",
+ "parse",
+ "-f",
+ family,
+ "-m",
+ mem_type,
+ "-b",
+ input_binary,
+ str(tmpdir),
+ ]
+ result = runner.invoke(nxpimage.main, cmd)
assert result.exit_code == 0
assert os.path.isfile(os.path.join(tmpdir, f"bootable_image_{family}_{mem_type}.yaml"))
@@ -97,6 +110,7 @@ def test_nxpimage_bimg_parse_cli(tmpdir, data_dir, family, mem_type, blocks):
("lpc55s3x", ["flexspi_nor"]),
("rt101x", ["flexspi_nor"]),
("rt102x", ["flexspi_nor"]),
+ ("rt104x", ["flexspi_nor"]),
("rt105x", ["flexspi_nor"]),
("rt106x", ["flexspi_nor"]),
("rt116x", ["flexspi_nor", "semc_nand", "flexspi_nand"]),
diff --git a/tests/nxpimage/test_nxpimage_cert_block.py b/tests/nxpimage/test_nxpimage_cert_block.py
index edc96631..6da4104c 100644
--- a/tests/nxpimage/test_nxpimage_cert_block.py
+++ b/tests/nxpimage/test_nxpimage_cert_block.py
@@ -35,20 +35,20 @@ def process_config_file(
def test_nxpimage_cert_block_get_template(tmpdir):
out_file = f"{tmpdir}/cert_block_template.yaml"
runner = CliRunner()
- cmd = f"cert-block get-template {out_file}"
- result = runner.invoke(nxpimage.main, cmd.split())
+ cmd = ["cert-block", "get-template", out_file]
+ result = runner.invoke(nxpimage.main, cmd)
assert result.exit_code == 0
assert os.path.isfile(out_file)
def test_nxpimage_cert_block_parse(elftosb_data_dir, tmpdir):
- out_folder = tmpdir
+ out_folder = str(tmpdir)
input_file = os.path.join(
elftosb_data_dir, "workspace", "output_images", "lpc55s3x", "cert_384_256.bin"
)
runner = CliRunner()
- cmd = f"cert-block parse -b {input_file} {out_folder}"
- result = runner.invoke(nxpimage.main, cmd.split())
+ cmd = ["cert-block", "parse", "-b", input_file, out_folder]
+ result = runner.invoke(nxpimage.main, cmd)
assert result.exit_code == 0
assert os.path.isfile(os.path.join(out_folder, "cert_block_config.yaml"))
assert os.path.isfile(os.path.join(out_folder, "rootCertificate0File.pub"))
diff --git a/tests/nxpimage/test_nxpimage_fcb.py b/tests/nxpimage/test_nxpimage_fcb.py
index 3e7f0637..e898b136 100644
--- a/tests/nxpimage/test_nxpimage_fcb.py
+++ b/tests/nxpimage/test_nxpimage_fcb.py
@@ -32,8 +32,8 @@ def test_nxpimage_fcb_export(tmpdir, data_dir, family, mem_type):
with use_working_directory(data_dir):
config_file = os.path.join(data_dir, "fcb", family, f"fcb_{family}_{mem_type}.yaml")
out_file = os.path.join(tmpdir, f"fcb_{family}_exported.bin")
- cmd = f"bootable-image fcb export -c {config_file} {out_file}"
- result = runner.invoke(nxpimage.main, cmd.split())
+ cmd = ["bootable-image", "fcb", "export", "-c", config_file, out_file]
+ result = runner.invoke(nxpimage.main, cmd)
assert result.exit_code == 0
assert os.path.isfile(out_file)
assert filecmp.cmp(
@@ -58,11 +58,24 @@ def test_nxpimage_fcb_parse_cli(tmpdir, data_dir, family, mem_type, binary):
runner = CliRunner()
with use_working_directory(data_dir):
data_folder = os.path.join(data_dir, "fcb", family)
- cmd = f"bootable-image fcb parse -f {family} -m {mem_type} -b {data_folder}/{binary} {tmpdir}/fcb_{family}_{mem_type}.yaml"
- result = runner.invoke(nxpimage.main, cmd.split())
+ binary_path = os.path.join(data_folder, binary)
+ out_config = os.path.join(tmpdir, f"fcb_{family}_{mem_type}.yaml")
+ cmd = [
+ "bootable-image",
+ "fcb",
+ "parse",
+ "-f",
+ family,
+ "-m",
+ mem_type,
+ "-b",
+ binary_path,
+ out_config,
+ ]
+ result = runner.invoke(nxpimage.main, cmd)
assert result.exit_code == 0
- assert os.path.isfile(os.path.join(tmpdir, f"fcb_{family}_{mem_type}.yaml"))
+ assert os.path.isfile(out_config)
@pytest.mark.parametrize(
@@ -74,6 +87,7 @@ def test_nxpimage_fcb_parse_cli(tmpdir, data_dir, family, mem_type, binary):
("rt106x", ["flexspi_nor"]),
("rt117x", ["flexspi_nor"]),
("lpc55s3x", ["flexspi_nor"]),
+ ("rw61x", ["flexspi_nor"]),
],
)
def test_nxpimage_fcb_template_cli(tmpdir, family, mem_types):
diff --git a/tests/nxpimage/test_nxpimage_hab.py b/tests/nxpimage/test_nxpimage_hab.py
index 1f6b378e..ee305a8d 100644
--- a/tests/nxpimage/test_nxpimage_hab.py
+++ b/tests/nxpimage/test_nxpimage_hab.py
@@ -50,10 +50,16 @@ def test_nxpimage_hab_export(tmpdir, hab_data_dir, configuration, app_name):
runner = CliRunner()
with use_working_directory(tmpdir):
output_file_path = os.path.join(tmpdir, "image_output.bin")
- cmd = (
- f"hab export --command {command_file_path} --output {output_file_path} {app_file_path}"
- )
- result = runner.invoke(nxpimage.main, cmd.split())
+ cmd = [
+ "hab",
+ "export",
+ "--command",
+ command_file_path,
+ "--output",
+ output_file_path,
+ app_file_path,
+ ]
+ result = runner.invoke(nxpimage.main, cmd)
assert result.exit_code == 0
assert os.path.isfile(output_file_path)
assert load_file(ref_file_path, mode="rb") == load_file(output_file_path, mode="rb")
@@ -74,8 +80,8 @@ def test_nxpimage_hab_parse(tmpdir, hab_data_dir, configuration, source_bin, seg
source_bin_path = os.path.join(config_dir, source_bin)
runner = CliRunner()
with use_working_directory(tmpdir):
- cmd = f"hab parse --binary {source_bin_path} {tmpdir}"
- result = runner.invoke(nxpimage.main, cmd.split())
+ cmd = ["hab", "parse", "--binary", source_bin_path, str(tmpdir)]
+ result = runner.invoke(nxpimage.main, cmd)
assert result.exit_code == 0
for segment in segments:
segment_file_name = f"{segment}.bin"
diff --git a/tests/nxpimage/test_nxpimage_mbi.py b/tests/nxpimage/test_nxpimage_mbi.py
index 4fe0d737..318cb46e 100644
--- a/tests/nxpimage/test_nxpimage_mbi.py
+++ b/tests/nxpimage/test_nxpimage_mbi.py
@@ -25,8 +25,69 @@
from spsdk.utils.crypto.backend_internal import ECC, RSA, internal_backend
from spsdk.utils.misc import load_configuration, use_working_directory
+mbi_basic_tests = [
+ ("mb_ram_crc.json", "lpc55xx"),
+ ("mb_ram_crc_s19.json", "lpc55xx"),
+ ("mb_ram_crc_hex.json", "lpc55xx"),
+ ("mb_xip_crc.json", "lpc55xx"),
+ ("mb_xip_crc_tz.json", "lpc55xx"),
+ ("mb_xip_crc_tz_no_preset.json", "lpc55xx"),
+ ("mb_xip_crc_hwk.json", "lpc55xx"),
+ ("mb_xip_crc_hwk_tz.json", "lpc55xx"),
+ ("mb_ram_crc.json", "lpc55s1x"),
+ ("mb_xip_crc_tz.json", "lpc55s1x"),
+ ("mb_xip_crc_tz_no_preset.json", "lpc55s1x"),
+ ("mb_xip_crc_hwk.json", "lpc55s1x"),
+ ("mb_xip_crc_hwk_tz.json", "lpc55s1x"),
+ ("mb_ram_plain.json", "rt5xx"),
+ ("mb_ram_crc.json", "rt5xx"),
+ ("mb_ram_crc_tz.json", "rt5xx"),
+ ("mb_ram_crc_tz_no_preset.json", "rt5xx"),
+ ("mb_ram_crc_hwk.json", "rt5xx"),
+ ("mb_ram_crc_hwk_tz.json", "rt5xx"),
+ ("mb_xip_crc.json", "rt5xx"),
+ ("mb_xip_crc_tz.json", "rt5xx"),
+ ("mb_xip_crc_tz_no_preset.json", "rt5xx"),
+ ("mb_xip_crc_hwk.json", "rt5xx"),
+ ("mb_xip_crc_hwk_tz.json", "rt5xx"),
+ ("mb_ram_crc.json", "lpc55s3x"),
+ ("mb_ram_crc_version.json", "lpc55s3x"),
+ ("mb_xip_crc.json", "lpc55s3x"),
+ ("mb_ext_xip_crc.json", "lpc55s3x"),
+ ("mb_ext_xip_crc_s19.json", "lpc55s3x"),
+ ("mb_ram_crc.json", "mcxn9xx"),
+ ("mb_xip_crc.json", "mcxn9xx"),
+]
+
+mbi_signed_tests = [
+ ("mb_xip_256_none.json", "lpc55s3x", None),
+ ("mb_xip_384_256.json", "lpc55s3x", None),
+ ("mb_xip_384_384.json", "lpc55s3x", None),
+ ("mb_ext_xip_signed.json", "lpc55s3x", None),
+ ("mb_xip_256_none.json", "mcxn9xx", None),
+ ("mb_xip_384_256.json", "mcxn9xx", None),
+ ("mb_xip_384_384.json", "mcxn9xx", None),
+ ("mb_xip_384_384_recovery_crctest.json", "mcxn9xx", None),
+ ("mb_xip_384_384_recovery.json", "mcxn9xx", None),
+]
+
+mbi_legacy_signed_tests = [
+ ("mb_xip_signed.json", "lpc55xx", 0),
+ ("mb_xip_signed.json", "lpc55s1x", 0),
+ ("mb_xip_signed_chain.json", "lpc55xx", 0),
+ ("mb_xip_signed_no_ks.json", "rt5xx", 0),
+ ("mb_ram_signed_no_ks.json", "rt5xx", 1),
+ ("mb_ram_signed_ks.json", "rt5xx", 2),
+]
+
+mbi_legacy_encrypted_tests = [
+ ("mb_ram_encrypted_ks.json", "rt5xx", 2),
+ ("mb_ram_encrypted_ks_binkey.json", "rt5xx", 2),
+]
+
def process_config_file(config_path: str, destination: str):
+ config_path.replace("\\", "/")
with open(config_path) as f:
config_data = json.load(f)
for key in config_data:
@@ -56,44 +117,11 @@ def get_signing_key(config_file) -> ECC.EccKey:
return siging_key
-@pytest.mark.parametrize(
- "config_file,device",
- [
- ("mb_ram_crc.json", "lpc55xx"),
- ("mb_ram_crc_s19.json", "lpc55xx"),
- ("mb_ram_crc_hex.json", "lpc55xx"),
- ("mb_xip_crc.json", "lpc55xx"),
- ("mb_xip_crc_tz.json", "lpc55xx"),
- ("mb_xip_crc_tz_no_preset.json", "lpc55xx"),
- ("mb_xip_crc_hwk.json", "lpc55xx"),
- ("mb_xip_crc_hwk_tz.json", "lpc55xx"),
- ("mb_ram_crc.json", "lpc55s1x"),
- ("mb_xip_crc_tz.json", "lpc55s1x"),
- ("mb_xip_crc_tz_no_preset.json", "lpc55s1x"),
- ("mb_xip_crc_hwk.json", "lpc55s1x"),
- ("mb_xip_crc_hwk_tz.json", "lpc55s1x"),
- ("mb_ram_plain.json", "rt5xx"),
- ("mb_ram_crc.json", "rt5xx"),
- ("mb_ram_crc_tz.json", "rt5xx"),
- ("mb_ram_crc_tz_no_preset.json", "rt5xx"),
- ("mb_ram_crc_hwk.json", "rt5xx"),
- ("mb_ram_crc_hwk_tz.json", "rt5xx"),
- ("mb_xip_crc.json", "rt5xx"),
- ("mb_xip_crc_tz.json", "rt5xx"),
- ("mb_xip_crc_tz_no_preset.json", "rt5xx"),
- ("mb_xip_crc_hwk.json", "rt5xx"),
- ("mb_xip_crc_hwk_tz.json", "rt5xx"),
- ("mb_ram_crc.json", "lpc55s3x"),
- ("mb_ram_crc_version.json", "lpc55s3x"),
- ("mb_xip_crc.json", "lpc55s3x"),
- ("mb_ext_xip_crc.json", "lpc55s3x"),
- ("mb_ext_xip_crc_s19.json", "lpc55s3x"),
- ],
-)
-def test_nxpimage_mbi_basic(elftosb_data_dir, tmpdir, config_file, device):
+@pytest.mark.parametrize("config_file,family", mbi_basic_tests)
+def test_nxpimage_mbi_basic(elftosb_data_dir, tmpdir, config_file, family):
runner = CliRunner()
with use_working_directory(elftosb_data_dir):
- config_file = f"{elftosb_data_dir}/workspace/cfgs/{device}/{config_file}"
+ config_file = f"{elftosb_data_dir}/workspace/cfgs/{family}/{config_file}"
ref_binary, new_binary, new_config = process_config_file(config_file, tmpdir)
cmd = f"mbi export {new_config}"
@@ -105,15 +133,32 @@ def test_nxpimage_mbi_basic(elftosb_data_dir, tmpdir, config_file, device):
assert filecmp.cmp(new_binary, ref_binary)
-@pytest.mark.parametrize(
- "config_file,device,sign_digest",
- [
- ("mb_xip_256_none.json", "lpc55s3x", None),
- ("mb_xip_384_256.json", "lpc55s3x", None),
- ("mb_xip_384_384.json", "lpc55s3x", None),
- ("mb_ext_xip_signed.json", "lpc55s3x", None),
- ],
-)
+@pytest.mark.parametrize("config_file,family", mbi_basic_tests)
+def test_mbi_parser_basic(tmpdir, elftosb_data_dir, family, config_file):
+ # Create new MBI file
+ mbi_data_dir = os.path.join(elftosb_data_dir, "workspace")
+ config_file = os.path.join(mbi_data_dir, "cfgs", family, config_file)
+
+ ref_binary, new_binary, new_config = process_config_file(config_file, tmpdir)
+
+ cmd = f"mbi export {new_config}"
+ runner = CliRunner()
+ with use_working_directory(elftosb_data_dir):
+ result = runner.invoke(nxpimage.main, cmd.split())
+ assert result.exit_code == 0
+
+ cmd = f"mbi parse -b {new_binary} -f {family} {tmpdir}/parsed"
+ result = runner.invoke(nxpimage.main, cmd.split())
+
+ assert result.exit_code == 0
+ input_image = os.path.join(elftosb_data_dir, load_configuration(config_file)["inputImageFile"])
+ parsed_app = os.path.join(tmpdir, "parsed", "application.bin")
+ assert os.path.isfile(parsed_app)
+ if os.path.split(input_image)[1] == "bin":
+ assert filecmp.cmp(input_image, parsed_app)
+
+
+@pytest.mark.parametrize("config_file,device,sign_digest", mbi_signed_tests)
def test_nxpimage_mbi_signed(elftosb_data_dir, tmpdir, config_file, device, sign_digest):
runner = CliRunner()
with use_working_directory(elftosb_data_dir):
@@ -173,6 +218,31 @@ def test_nxpimage_mbi_signed(elftosb_data_dir, tmpdir, config_file, device, sign
assert ref_data[:-signature_length] == new_data[:-signature_length]
+@pytest.mark.parametrize("config_file,family,sign_digest", mbi_signed_tests)
+def test_mbi_parser_signed(tmpdir, elftosb_data_dir, family, config_file, sign_digest):
+ # Create new MBI file
+ mbi_data_dir = os.path.join(elftosb_data_dir, "workspace")
+ config_file = os.path.join(mbi_data_dir, "cfgs", family, config_file)
+
+ ref_binary, new_binary, new_config = process_config_file(config_file, tmpdir)
+
+ cmd = f"mbi export {new_config}"
+ runner = CliRunner()
+ with use_working_directory(elftosb_data_dir):
+ result = runner.invoke(nxpimage.main, cmd.split())
+ assert result.exit_code == 0
+
+ cmd = f"mbi parse -b {new_binary} -f {family} {tmpdir}/parsed"
+ result = runner.invoke(nxpimage.main, cmd.split())
+
+ assert result.exit_code == 0
+ input_image = os.path.join(elftosb_data_dir, load_configuration(config_file)["inputImageFile"])
+ parsed_app = os.path.join(tmpdir, "parsed", "application.bin")
+ assert os.path.isfile(parsed_app)
+ if os.path.split(input_image)[1] == "bin":
+ assert filecmp.cmp(input_image, parsed_app)
+
+
@pytest.mark.parametrize(
"mbi_config_file,cert_block_config_file,device",
[
@@ -276,17 +346,7 @@ def test_nxpimage_mbi_cert_block_signed_invalid(
# 0 indicates no hmac and no keystore present in output image
# 1 indicates hmac present but no keystore
# 2 indicates both hmac/keystore present in output image
-@pytest.mark.parametrize(
- "config_file,device,skip_hmac_keystore",
- [
- ("mb_xip_signed.json", "lpc55xx", 0),
- ("mb_xip_signed.json", "lpc55s1x", 0),
- ("mb_xip_signed_chain.json", "lpc55xx", 0),
- ("mb_xip_signed_no_ks.json", "rt5xx", 0),
- ("mb_ram_signed_no_ks.json", "rt5xx", 1),
- ("mb_ram_signed_ks.json", "rt5xx", 2),
- ],
-)
+@pytest.mark.parametrize("config_file,device,skip_hmac_keystore", mbi_legacy_signed_tests)
def test_nxpimage_mbi_legacy_signed(
elftosb_data_dir, tmpdir, config_file, device, skip_hmac_keystore
):
@@ -348,6 +408,33 @@ def test_nxpimage_mbi_legacy_signed(
assert ref_data[:-signature_length] == new_data[:-signature_length]
+@pytest.mark.parametrize("config_file,family,skip_hmac_keystore", mbi_legacy_signed_tests)
+def test_mbi_parser_legacy_signed(
+ tmpdir, elftosb_data_dir, family, config_file, skip_hmac_keystore
+):
+ # Create new MBI file
+ mbi_data_dir = os.path.join(elftosb_data_dir, "workspace")
+ config_file = os.path.join(mbi_data_dir, "cfgs", family, config_file)
+
+ ref_binary, new_binary, new_config = process_config_file(config_file, tmpdir)
+
+ cmd = f"mbi export {new_config}"
+ runner = CliRunner()
+ with use_working_directory(elftosb_data_dir):
+ result = runner.invoke(nxpimage.main, cmd.split())
+ assert result.exit_code == 0
+
+ cmd = f"mbi parse -b {new_binary} -f {family} {tmpdir}/parsed"
+ result = runner.invoke(nxpimage.main, cmd.split())
+
+ assert result.exit_code == 0
+ input_image = os.path.join(elftosb_data_dir, load_configuration(config_file)["inputImageFile"])
+ parsed_app = os.path.join(tmpdir, "parsed", "application.bin")
+ assert os.path.isfile(parsed_app)
+ if os.path.split(input_image)[1] == "bin":
+ assert filecmp.cmp(input_image, parsed_app)
+
+
@pytest.mark.parametrize(
"config_file,device",
[
@@ -365,10 +452,7 @@ def test_nxpimage_mbi_invalid_conf(elftosb_data_dir, tmpdir, config_file, device
assert result.exit_code == 1
-@pytest.mark.parametrize(
- "config_file,device,skip_hmac_keystore",
- [("mb_ram_encrypted_ks.json", "rt5xx", 2), ("mb_ram_encrypted_ks_binkey.json", "rt5xx", 2)],
-)
+@pytest.mark.parametrize("config_file,device,skip_hmac_keystore", mbi_legacy_encrypted_tests)
def test_nxpimage_mbi_legacy_encrypted(
elftosb_data_dir, tmpdir, config_file, device, skip_hmac_keystore
):
@@ -430,28 +514,51 @@ def test_nxpimage_mbi_legacy_encrypted(
assert ref_data[:-signature_length] == new_data[:-signature_length]
-def test_nxpimage_mbi_lower():
- mbi = Mbi_PlainRamLpc55s3x(app=bytes(100), load_addr=0, firmware_version=0)
- assert mbi.app
+@pytest.mark.parametrize("config_file,family,skip_hmac_keystore", mbi_legacy_encrypted_tests)
+def test_mbi_parser_legacy_encrypted(
+ tmpdir, elftosb_data_dir, family, config_file, skip_hmac_keystore
+):
+ # Create new MBI file
+ mbi_data_dir = os.path.join(elftosb_data_dir, "workspace")
+ config_file = os.path.join(mbi_data_dir, "cfgs", family, config_file)
+
+ ref_binary, new_binary, new_config = process_config_file(config_file, tmpdir)
+
+ cmd = ["mbi", "export", new_config]
+ runner = CliRunner()
+ with use_working_directory(elftosb_data_dir):
+ result = runner.invoke(nxpimage.main, cmd)
+ assert result.exit_code == 0
+
+ cmd = [
+ "mbi",
+ "parse",
+ "-b",
+ new_binary,
+ "-f",
+ family,
+ "-k",
+ f"{mbi_data_dir}/keys/userkey.txt",
+ f"{tmpdir}/parsed",
+ ]
+ result = runner.invoke(nxpimage.main, cmd)
+
+ assert result.exit_code == 0
+ input_image = os.path.join(elftosb_data_dir, load_configuration(config_file)["inputImageFile"])
+ parsed_app = os.path.join(tmpdir, "parsed", "application.bin")
+ assert os.path.isfile(parsed_app)
+ if os.path.split(input_image)[1] == "bin":
+ assert filecmp.cmp(input_image, parsed_app)
+
+def test_nxpimage_mbi_lower():
mbi = Mbi_PlainRamLpc55s3x(app=bytes(100), load_addr=0, firmware_version=0)
assert mbi.app
assert mbi.export()
def test_mbi_lpc55s3x_invalid():
- mbi = Mbi_PlainXipSignedLpc55s3x(
- app=bytes(100),
- firmware_version=0,
- )
- with pytest.raises(SPSDKError):
- mbi.validate()
-
- mbi = Mbi_PlainXipSignedLpc55s3x(
- app=bytes(100),
- firmware_version=0,
- )
-
+ mbi = Mbi_PlainXipSignedLpc55s3x(app=bytes(100), firmware_version=0)
with pytest.raises(SPSDKError):
mbi.validate()
diff --git a/tests/nxpimage/test_nxpimage_sb21.py b/tests/nxpimage/test_nxpimage_sb21.py
index c0300c05..1614ecfb 100644
--- a/tests/nxpimage/test_nxpimage_sb21.py
+++ b/tests/nxpimage/test_nxpimage_sb21.py
@@ -18,6 +18,7 @@
from spsdk.utils.misc import use_working_directory
+@pytest.mark.parametrize("use_signature_provider", [True, False])
@pytest.mark.parametrize(
"bd_file,legacy_sb,external",
[
@@ -48,15 +49,17 @@
),
],
)
-def test_nxpimage_sb21(bd_file, legacy_sb, external, elftosb_data_dir, tmpdir):
+def test_nxpimage_sb21(
+ use_signature_provider, bd_file, legacy_sb, external, elftosb_data_dir, tmpdir
+):
runner = CliRunner()
with use_working_directory(elftosb_data_dir):
bd_file_path = os.path.join(elftosb_data_dir, bd_file)
out_file_path_new = os.path.join(tmpdir, "new_elf2sb.bin")
kek_key_path = os.path.join(elftosb_data_dir, "sb_sources/keys/SBkek_PUF.txt")
- priv_key_path = os.path.join(
- elftosb_data_dir, "sb_sources/keys_and_certs/k0_cert0_2048.pem"
- )
+ pkey = os.path.join(elftosb_data_dir, "sb_sources/keys_and_certs/k0_cert0_2048.pem")
+ if use_signature_provider:
+ pkey = f"type=file;file_path={pkey}"
certificate_path = os.path.join(
elftosb_data_dir, "sb_sources/keys_and_certs/root_k0_signed_cert0_noca.der.cert"
)
@@ -76,20 +79,33 @@ def test_nxpimage_sb21(bd_file, legacy_sb, external, elftosb_data_dir, tmpdir):
out_file_path_legacy = os.path.join(elftosb_data_dir, legacy_sb)
- cmd = f"sb21 export \
- -c {bd_file_path} \
- -o {out_file_path_new}\
- -k {kek_key_path}\
- -s {priv_key_path}\
- -S {certificate_path}\
- -R {root_key_certificate0_path}\
- -R {root_key_certificate1_path}\
- -R {root_key_certificate2_path}\
- -R {root_key_certificate3_path}\
- -h {hash_of_hashes_output_path}"
+ cmd = [
+ "sb21",
+ "export",
+ "-c",
+ bd_file_path,
+ "-o",
+ out_file_path_new,
+ "-k",
+ kek_key_path,
+ "-s",
+ pkey,
+ "-S",
+ certificate_path,
+ "-R",
+ root_key_certificate0_path,
+ "-R",
+ root_key_certificate1_path,
+ "-R",
+ root_key_certificate2_path,
+ "-R",
+ root_key_certificate3_path,
+ "-h",
+ hash_of_hashes_output_path,
+ ]
for entry in external:
- cmd += " " + entry
- result = runner.invoke(nxpimage.main, cmd.split())
+ cmd.append(entry)
+ result = runner.invoke(nxpimage.main, cmd)
assert result.exit_code == 0
assert os.path.isfile(out_file_path_new)
@@ -140,6 +156,63 @@ def test_nxpimage_sb21(bd_file, legacy_sb, external, elftosb_data_dir, tmpdir):
assert i[0] == i[1]
+def test_sb_21_invalid_signature_provider(tmpdir, elftosb_data_dir):
+ runner = CliRunner()
+ with use_working_directory(elftosb_data_dir):
+ cmd = [
+ "sb21",
+ "export",
+ "-c",
+ os.path.join(elftosb_data_dir, "sb_sources", "BD_files", "real_example1.bd"),
+ "-o",
+ os.path.join(tmpdir, "new_elf2sb.bin"),
+ "-k",
+ os.path.join(elftosb_data_dir, "sb_sources", "keys", "SBkek_PUF.txt"),
+ "-s",
+ "type=invalid_sp",
+ "-S",
+ os.path.join(
+ elftosb_data_dir,
+ "sb_sources",
+ "keys_and_certs",
+ "root_k0_signed_cert0_noca.der.cert",
+ ),
+ "-R",
+ os.path.join(
+ elftosb_data_dir,
+ "sb_sources",
+ "keys_and_certs",
+ "root_k0_signed_cert0_noca.der.cert",
+ ),
+ "-R",
+ os.path.join(
+ elftosb_data_dir,
+ "sb_sources",
+ "keys_and_certs",
+ "root_k1_signed_cert0_noca.der.cert",
+ ),
+ "-R",
+ os.path.join(
+ elftosb_data_dir,
+ "sb_sources",
+ "keys_and_certs",
+ "root_k2_signed_cert0_noca.der.cert",
+ ),
+ "-R",
+ os.path.join(
+ elftosb_data_dir,
+ "sb_sources",
+ "keys_and_certs",
+ "root_k3_signed_cert0_noca.der.cert",
+ ),
+ "-h",
+ os.path.join(tmpdir, "hash.bin"),
+ ]
+ result = runner.invoke(nxpimage.main, cmd)
+ assert result.exit_code == 1
+ assert issubclass(result.exc_info[0], SPSDKError)
+
+
def test_sb_21_invalid_parse():
with pytest.raises(SPSDKError, match="kek cannot be empty"):
BootImageV21.parse(data=bytes(232), kek=None)
diff --git a/tests/nxpimage/test_nxpimage_utils_convert.py b/tests/nxpimage/test_nxpimage_utils_convert.py
index e8564b4a..615a1785 100644
--- a/tests/nxpimage/test_nxpimage_utils_convert.py
+++ b/tests/nxpimage/test_nxpimage_utils_convert.py
@@ -33,8 +33,11 @@ def test_nxpimage_convert_hexbin(tmpdir, data_dir, in_file, out_file, command, r
input_file = f"{data_dir}/utils/convert/hexbin/{in_file}"
correct_ouput = f"{data_dir}/utils/convert/hexbin/{out_file}"
output = f"{tmpdir}/{out_file}"
- cmd = f"utils convert {command} -i {input_file} {'-r' if reverse else ''} {output}"
- result = runner.invoke(nxpimage.main, cmd.split())
+ cmd = ["utils", "convert", command, "-i", input_file]
+ if reverse:
+ cmd.append("-r")
+ cmd.append(output)
+ result = runner.invoke(nxpimage.main, cmd)
assert result.exit_code == 0
assert os.path.isfile(output)
assert filecmp.cmp(output, correct_ouput, shallow=False)
@@ -46,8 +49,8 @@ def test_nxpimage_convert_hexbin_invalid(tmpdir, data_dir, in_file):
with use_working_directory(data_dir):
input_file = f"{data_dir}/utils/convert/hexbin/{in_file}"
output = f"{tmpdir}/test.bin"
- cmd = f"utils convert hex2bin -i {input_file} {output}"
- result = runner.invoke(nxpimage.main, cmd.split())
+ cmd = ["utils", "convert", "hex2bin", "-i", input_file, output]
+ result = runner.invoke(nxpimage.main, cmd)
assert result.exit_code != 0
@@ -133,14 +136,14 @@ def test_nxpimage_convert_bin2carr(data_dir, in_file, out_str, type, padding, en
runner = CliRunner()
with use_working_directory(data_dir):
input_file = f"{data_dir}/utils/convert/bin2carr/{in_file}"
- cmd = f"utils convert bin2carr -i {input_file}"
+ cmd = ["utils", "convert", "bin2carr", "-i", f"{input_file}"]
if type:
- cmd += f" -t {type}"
+ cmd.extend(["-t", type])
if padding:
- cmd += f" -p {padding}"
+ cmd.extend(["-p", padding])
if endian:
- cmd += f" -e {endian}"
- result = runner.invoke(nxpimage.main, cmd.split())
+ cmd.extend(["-e", endian])
+ result = runner.invoke(nxpimage.main, cmd)
if error:
assert result.exit_code != 0
else:
@@ -153,10 +156,22 @@ def test_nxpimage_convert_bin2carr_file(tmpdir, data_dir):
input_file = f"{data_dir}/utils/convert/bin2carr/inc9.bin"
correct_ouput = f"{data_dir}/utils/convert/bin2carr/inc9_uint32_t.txt"
output = f"{tmpdir}/inc9_uint32_t.txt"
- cmd = (
- f"utils convert bin2carr -i {input_file} -t uint32_t -p 0xAABBCC -e little -o {output}"
- )
- result = runner.invoke(nxpimage.main, cmd.split())
+ cmd = [
+ "utils",
+ "convert",
+ "bin2carr",
+ "-i",
+ f"{input_file}",
+ "-t",
+ "uint32_t",
+ "-p",
+ "0xAABBCC",
+ "-e",
+ "little",
+ "-o",
+ f"{output}",
+ ]
+ result = runner.invoke(nxpimage.main, cmd)
assert result.exit_code == 0
assert os.path.isfile(output)
assert filecmp.cmp(output, correct_ouput, shallow=False)
diff --git a/tests/nxpimage/test_nxpimage_xmcd.py b/tests/nxpimage/test_nxpimage_xmcd.py
index 476829d2..35ec1c4a 100644
--- a/tests/nxpimage/test_nxpimage_xmcd.py
+++ b/tests/nxpimage/test_nxpimage_xmcd.py
@@ -42,8 +42,8 @@ def test_nxpimage_xmcd_export(tmpdir, data_dir, family, mem_type, config_type, o
file_base_name += f"_{option}"
config_file_path = os.path.join(data_dir, "xmcd", family, f"{file_base_name}.yaml")
out_file = os.path.join(tmpdir, f"xmcd_{family}_{mem_type}_{config_type}_exported.bin")
- cmd = f"bootable-image xmcd export -c {config_file_path} {out_file}"
- result = runner.invoke(nxpimage.main, cmd.split())
+ cmd = ["bootable-image", "xmcd", "export", "-c", config_file_path, out_file]
+ result = runner.invoke(nxpimage.main, cmd)
assert result.exit_code == 0
assert os.path.isfile(out_file)
assert filecmp.cmp(
@@ -78,8 +78,17 @@ def test_nxpimage_xmcd_parse_cli(tmpdir, data_dir, family, mem_type, config_type
file_base_name += f"_{option}"
bin_path = os.path.join(data_folder, f"{file_base_name}.bin")
- cmd = f"bootable-image xmcd parse -f {family} -b {bin_path} {output_file}"
- result = runner.invoke(nxpimage.main, cmd.split())
+ cmd = [
+ "bootable-image",
+ "xmcd",
+ "parse",
+ "-f",
+ family,
+ "-b",
+ bin_path,
+ output_file,
+ ]
+ result = runner.invoke(nxpimage.main, cmd)
assert result.exit_code == 0
assert os.path.isfile(output_file)
diff --git a/tests/pfr/test_pfr_cli.py b/tests/pfr/test_pfr_cli.py
index 638f5243..3dfa4df9 100644
--- a/tests/pfr/test_pfr_cli.py
+++ b/tests/pfr/test_pfr_cli.py
@@ -47,12 +47,19 @@ def test_cli_devices_global():
def test_generate_cmpa(data_dir, tmpdir):
"""Test PFR CLI - Generation CMPA binary."""
- cmd = f"generate-binary --output {tmpdir}/pnd.bin "
- cmd += f"--user-config {data_dir}/cmpa_96mhz.json --calc-inverse "
- cmd += f"--secret-file {data_dir}/selfsign_privatekey_rsa2048.pem "
+ cmd = [
+ "generate-binary",
+ "--output",
+ f"{tmpdir}/pnd.bin",
+ "--user-config",
+ f"{data_dir}/cmpa_96mhz.json",
+ "--calc-inverse",
+ "--secret-file",
+ f"{data_dir}/selfsign_privatekey_rsa2048.pem",
+ ]
logging.debug(cmd)
runner = CliRunner()
- result = runner.invoke(cli.main, cmd.split())
+ result = runner.invoke(cli.main, cmd)
assert result.exit_code == 0, result.output
new_data = open(f"{tmpdir}/pnd.bin", "rb").read()
expected = open(f"{data_dir}/CMPA_96MHz.bin", "rb").read()
@@ -99,13 +106,22 @@ def test_generate_cmpa_with_elf2sb_lpc55s3x(data_dir, tmpdir):
def test_parse(data_dir, tmpdir):
"""Test PFR CLI - Parsing CMPA binary to get config."""
- cmd = "parse-binary --device lpc55s6x --type cmpa "
- cmd += f"--binary {data_dir}/CMPA_96MHz.bin "
- cmd += f"--show-diff "
- cmd += f"--output {tmpdir}/config.yml"
+ cmd = [
+ "parse-binary",
+ "--device",
+ "lpc55s6x",
+ "--type",
+ "cmpa",
+ "--binary",
+ f"{data_dir}/CMPA_96MHz.bin",
+ "--show-diff",
+ "--output",
+ f"{tmpdir}/config.yml",
+ ]
+
logging.debug(cmd)
runner = CliRunner()
- result = runner.invoke(cli.main, cmd.split())
+ result = runner.invoke(cli.main, cmd)
assert result.exit_code == 0, result.output
new_cfg = PfrConfiguration(f"{tmpdir}/config.yml")
expected_cfg = PfrConfiguration(f"{data_dir}/cmpa_96mhz_rotkh.yml")
@@ -114,10 +130,18 @@ def test_parse(data_dir, tmpdir):
def test_user_config(tmpdir):
"""Test PFR CLI - Generation CMPA user config."""
- cmd = f"get-template --device lpc55s6x --type cmpa --output {tmpdir}/cmpa.yml"
+ cmd = [
+ "get-template",
+ "--device",
+ "lpc55s6x",
+ "--type",
+ "cmpa",
+ "--output",
+ f"{tmpdir}/cmpa.yml",
+ ]
logging.debug(cmd)
runner = CliRunner()
- result = runner.invoke(cli.main, cmd.split())
+ result = runner.invoke(cli.main, cmd)
assert result.exit_code == 0, result.output
# verify that the output is a valid json object
pfr_config = PfrConfiguration(f"{tmpdir}/cmpa.yml")
diff --git a/tests/sbfile/sb31/test_commands_api.py b/tests/sbfile/sb31/test_commands_api.py
index e44681fc..6d3f8444 100644
--- a/tests/sbfile/sb31/test_commands_api.py
+++ b/tests/sbfile/sb31/test_commands_api.py
@@ -258,14 +258,14 @@ def test_cmd_loadkeyblob():
assert cmd.data == cmd_parsed.data == 10 * b"x"
-def test_cmd_loadkeyblob():
- """Test offset, length, key_wrap, data info value, size after export and parsing of CmdLoadKeyBlob command."""
+def test_cmd_loadkeyblob_v2():
+ """Test offset, length, key_wrap, data info value, size after export and parsing of CmdLoadKeyBlob V2 command."""
cmd = CmdLoadKeyBlob(
- offset=100, key_wrap_id=CmdLoadKeyBlob._KeyWraps.NXP_CUST_KEK_EXT_SK.value, data=10 * b"x"
+ offset=100, key_wrap_id=CmdLoadKeyBlob._KeyWrapsV2.NXP_CUST_KEK_EXT_SK.value, data=10 * b"x"
)
assert cmd.address == 100
assert cmd.length == 10
- assert cmd.key_wrap_id == 17
+ assert cmd.key_wrap_id == 19
assert cmd.info()
data = cmd.export()
diff --git a/tests/sbfile/test_sbfile_image.py b/tests/sbfile/test_sbfile_image.py
index 3ebf5ffc..404ce406 100644
--- a/tests/sbfile/test_sbfile_image.py
+++ b/tests/sbfile/test_sbfile_image.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#
-# Copyright 2019-2022 NXP
+# Copyright 2019-2023 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
@@ -13,6 +13,7 @@
import pytest
from spsdk import SPSDKError
+from spsdk.crypto.signature_provider import get_signature_provider
from spsdk.sbfile.sb2.commands import (
CmdCall,
CmdErase,
@@ -267,12 +268,12 @@ def test_sb2x_builder(
if signed:
boot_image.cert_block = gen_cert_block(data_dir, sign_bits)
- with open(
- os.path.join(data_dir, "sb2_x", "selfsign_privatekey_rsa" + str(sign_bits) + ".pem"),
- "rb",
- ) as keyf:
- key_data = keyf.read()
- boot_image.private_key_pem_data = key_data
+ private_key = os.path.join(
+ data_dir, "sb2_x", "selfsign_privatekey_rsa" + str(sign_bits) + ".pem"
+ )
+ signature_provider = get_signature_provider(local_file_key=private_key)
+
+ boot_image.signature_provider = signature_provider
for sect in get_boot_sections(data_dir, otfad, sect_cont, load_addr):
boot_image.add_boot_section(sect)
diff --git a/tests/shadowregs/data/test_database.yaml b/tests/shadowregs/data/test_database.yaml
index f816adab..88961aa2 100644
--- a/tests/shadowregs/data/test_database.yaml
+++ b/tests/shadowregs/data/test_database.yaml
@@ -12,6 +12,7 @@ devices:
address: 0x4000_0000
inverted_regs:
REG1: REG_INVERTED_AP
+ flush_func: rw61x_update_scratch_reg
computed_fields:
REG1:
DEV_TEST_EN: comalg_dcfg_cc_socu_test_en
diff --git a/tests/shadowregs/data/test_database_invalid_flush_func.yaml b/tests/shadowregs/data/test_database_invalid_flush_func.yaml
new file mode 100644
index 00000000..4c47040e
--- /dev/null
+++ b/tests/shadowregs/data/test_database_invalid_flush_func.yaml
@@ -0,0 +1,30 @@
+# Copyright 2023 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+devices:
+ sh_test_dev:
+ revisions:
+ x0:
+ data_file: sh_test_dev_x0.xml
+ latest: x0
+ attributes:
+ address: 0x4000_0000
+ inverted_regs:
+ REG1: REG_INVERTED_AP
+ flush_func: flush_func_invalid
+ computed_fields:
+ REG1:
+ CMP1: comalg_dcfg_cc_socu_invalid
+ CRC8: comalg_dcfg_cc_socu_crc8
+ REG2:
+ RESERVED: comalg_do_nothing
+attributes:
+ grouped_registers:
+ - name: REG_BIG
+ width: 256
+ description: Just Big register
+ - name: REG_BIG_REV
+ width: 256
+ reversed: 1
+ description: Just Big register in reversed order
diff --git a/tests/shadowregs/test_shadowregs.py b/tests/shadowregs/test_shadowregs.py
index 11ae40aa..c6e15b75 100644
--- a/tests/shadowregs/test_shadowregs.py
+++ b/tests/shadowregs/test_shadowregs.py
@@ -21,6 +21,7 @@
TEST_DEV_NAME = "sh_test_dev"
TEST_DATABASE = "test_database.yaml"
TEST_DATABASE_BAD_COMPUTED_FUNC = "test_database_invalid_computed.yaml"
+TEST_DATABASE_INVALID_FLUSH_FUNC = "test_database_invalid_flush_func.yaml"
def get_probe():
@@ -281,6 +282,16 @@ def test_shadow_register_crc8_hook(data_dir):
assert shadowregs.comalg_dcfg_cc_socu_crc8(0x80FFFF00) == 0x80FFFF20
+def test_shadow_register_invalid_flush_hook(data_dir):
+ """Test Shadow Registers - invalid flush hook test."""
+ config = get_config(os.path.join(data_dir, TEST_DATABASE_INVALID_FLUSH_FUNC))
+ probe = get_probe()
+ shadowregs1 = SR.ShadowRegisters(probe, config, TEST_DEV_NAME)
+
+ with pytest.raises(SPSDKError):
+ shadowregs1.set_register("REG1", 0x12345678)
+
+
def test_shadow_register_enable_debug_invalid_probe():
"""Test Shadow Registers - Enable debug algorithm check with invalid probe."""
probe = None
diff --git a/tests/shadowregs/test_shadowregs_app.py b/tests/shadowregs/test_shadowregs_app.py
index 3b01118e..0db2c234 100644
--- a/tests/shadowregs/test_shadowregs_app.py
+++ b/tests/shadowregs/test_shadowregs_app.py
@@ -197,8 +197,19 @@ def test_command_line_interface_loadconfig_exe_fail(data_dir):
'-o subs_ap={"12":["Exception",12345678],"33554432":[2,0,2,0],"33554440":[0]} '
'-o subs_mem={"1074987040":["Exception"]}'
)
- cmd = f"-dev rt5xx -i virtual -s {DebugProbeVirtual.UNIQUE_SERIAL} {enable_debug} loadconfig -f {filename}"
- result = runner.invoke(main, cmd.split())
+ cmd = [
+ "-dev",
+ "rt5xx",
+ "-i",
+ "virtual",
+ "-s",
+ DebugProbeVirtual.UNIQUE_SERIAL,
+ enable_debug,
+ "loadconfig",
+ "-f",
+ filename,
+ ]
+ result = runner.invoke(main, cmd)
assert result.exit_code == 1
diff --git a/tests/tp/audit_log/test_audit_log_cli.py b/tests/tp/audit_log/test_audit_log_cli.py
index 1d15e0f6..7f93c2a0 100644
--- a/tests/tp/audit_log/test_audit_log_cli.py
+++ b/tests/tp/audit_log/test_audit_log_cli.py
@@ -14,13 +14,16 @@
def test_cli_run(data_dir):
- cmd = (
- f"verify --audit-log {data_dir}/tp_audit_log.db "
- f"--audit-log-key {data_dir}/oem_log_puk.pub"
- )
+ cmd = [
+ "verify",
+ "--audit-log",
+ f"{data_dir}/tp_audit_log.db",
+ "--audit-log-key",
+ f"{data_dir}/oem_log_puk.pub",
+ ]
runner = CliRunner()
- result = runner.invoke(tphost.main, cmd.split())
+ result = runner.invoke(tphost.main, cmd)
assert result.exit_code == 0
@@ -37,18 +40,23 @@ def test_cli_run(data_dir):
],
)
def test_tphost_extract(data_dir, tmpdir, skip_nxp, skip_oem, cert_index, expected_count):
- cmd = (
- f"verify --audit-log {data_dir}/tp_audit_log.db "
- f"--audit-log-key {data_dir}/oem_log_puk.pub --destination {tmpdir}"
- )
+ cmd = [
+ "verify",
+ "--audit-log",
+ f"{data_dir}/tp_audit_log.db",
+ "--audit-log-key",
+ f"{data_dir}/oem_log_puk.pub",
+ "--destination",
+ str(tmpdir),
+ ]
if skip_nxp:
- cmd += " --skip-nxp"
+ cmd.append("--skip-nxp")
if skip_oem:
- cmd += " --skip-oem"
+ cmd.append("--skip-oem")
if cert_index:
- cmd += f" --cert-index {cert_index}"
+ cmd.extend(["--cert-index", cert_index])
runner = CliRunner()
- result = runner.invoke(tphost.main, cmd.split())
+ result = runner.invoke(tphost.main, cmd)
assert result.exit_code == 0
assert len(os.listdir(tmpdir)) == expected_count
diff --git a/tests/tp/data/lpc55_devattest.bin b/tests/tp/data/lpc55_devattest.bin
new file mode 100644
index 00000000..d26593ef
--- /dev/null
+++ b/tests/tp/data/lpc55_devattest.bin
@@ -0,0 +1 @@
+f�Q�MRk�0߆g� � CtV}�wy�Jܘ�8]�7��-��@���V�V���������F�
\ No newline at end of file
diff --git a/tests/tp/data/tp_response.bin b/tests/tp/data/tp_response.bin
new file mode 100644
index 00000000..8abcfded
Binary files /dev/null and b/tests/tp/data/tp_response.bin differ
diff --git a/tests/tp/data/wrong_tp_response.bin b/tests/tp/data/wrong_tp_response.bin
deleted file mode 100644
index 337d8470..00000000
Binary files a/tests/tp/data/wrong_tp_response.bin and /dev/null differ
diff --git a/tests/tp/test_tp_host.py b/tests/tp/test_tp_host.py
index 7af310b1..c580fe42 100644
--- a/tests/tp/test_tp_host.py
+++ b/tests/tp/test_tp_host.py
@@ -14,15 +14,44 @@
def test_tphost_check_cot(data_dir):
- cmd = (
- f"check-cot "
- f"--root-cer {data_dir}/nxp_glob_devattest.crt "
- f"--intermediate-cert {data_dir}/lpc55_devattest.crt "
- f"--tp-response {data_dir}/wrong_tp_response.bin "
- )
+ cmd = [
+ "--root-cert",
+ f"{data_dir}/nxp_glob_devattest.crt",
+ "--intermediate-cert",
+ f"{data_dir}/lpc55_devattest.crt",
+ "--tp-response",
+ f"{data_dir}/tp_response.bin",
+ ]
runner = CliRunner()
- result = runner.invoke(tphost.check_cot, cmd.split())
- assert result != 0
+ result = runner.invoke(tphost.check_cot, cmd)
+ assert "OK" in result.output
+ assert "FAILED" in result.output
+
+
+def test_tphost_check_cot_no_glob(data_dir):
+ cmd = [
+ "--intermediate-cert",
+ f"{data_dir}/lpc55_devattest.crt",
+ "--tp-response",
+ f"{data_dir}/tp_response.bin",
+ ]
+ runner = CliRunner()
+ result = runner.invoke(tphost.check_cot, cmd)
+ assert "OK" in result.output
+ assert "FAILED" in result.output
+
+
+def test_tphost_check_cot_no_glob_bin(data_dir):
+ cmd = [
+ "--intermediate-cert",
+ f"{data_dir}/lpc55_devattest.bin",
+ "--tp-response",
+ f"{data_dir}/tp_response.bin",
+ ]
+ runner = CliRunner()
+ result = runner.invoke(tphost.check_cot, cmd)
+ assert "OK" in result.output
+ assert "FAILED" in result.output
def test_tphost_with_unsupported_family():
diff --git a/tests/utils/crypto/test_common.py b/tests/utils/crypto/test_common.py
index 83650132..47ea816a 100644
--- a/tests/utils/crypto/test_common.py
+++ b/tests/utils/crypto/test_common.py
@@ -7,6 +7,8 @@
""" Test of common crypto utilities module."""
+import os
+
import pytest
from cryptography.hazmat.primitives.asymmetric.ec import SECP256R1
@@ -17,7 +19,10 @@
generate_ecc_public_key,
generate_rsa_private_key,
generate_rsa_public_key,
+ save_ecc_private_key,
+ save_rsa_private_key,
)
+from spsdk.crypto.signature_provider import PlainFileSP
from spsdk.exceptions import SPSDKValueError
from spsdk.utils.crypto import Counter
from spsdk.utils.crypto.common import (
@@ -73,35 +78,50 @@ def test_ecc_public_numbers_to_bytes():
@pytest.mark.parametrize("length", [(2048), (4096)])
-def test_matching_keys_rsa(length):
- prv_keys = []
+def test_matching_keys_rsa(tmpdir, length):
+ signature_providers = []
pub_keys = []
for i in range(4):
- prv_keys.append(generate_rsa_private_key(key_size=length))
- pub_keys.append(generate_rsa_public_key(prv_keys[i]))
+ prv_key = generate_rsa_private_key(key_size=length)
+ save_rsa_private_key(prv_key, os.path.join(tmpdir, f"key{i}.pem"))
+ signature_providers.append(PlainFileSP(os.path.join(tmpdir, f"key{i}.pem")))
+ pub_keys.append(generate_rsa_public_key(prv_key))
for i in range(4):
- assert i == get_matching_key_id(public_keys=pub_keys, private_key=prv_keys[i])
+ assert i == get_matching_key_id(
+ public_keys=pub_keys, signature_provider=signature_providers[i]
+ )
@pytest.mark.parametrize("curve", [(curve_name) for curve_name in CurveName])
-def test_matching_keys_ecc(curve):
- prv_keys = []
+def test_matching_keys_ecc(tmpdir, curve):
+ signature_providers = []
pub_keys = []
for i in range(4):
- prv_keys.append(generate_ecc_private_key(curve_name=curve))
- pub_keys.append(generate_ecc_public_key(prv_keys[i]))
+ prv_key = generate_ecc_private_key(curve_name=curve)
+ save_ecc_private_key(prv_key, os.path.join(tmpdir, f"key{i}.pem"))
+ signature_providers.append(PlainFileSP(os.path.join(tmpdir, f"key{i}.pem")))
+ pub_keys.append(generate_ecc_public_key(prv_key))
for i in range(4):
- assert i == get_matching_key_id(public_keys=pub_keys, private_key=prv_keys[i])
+ assert i == get_matching_key_id(
+ public_keys=pub_keys, signature_provider=signature_providers[i]
+ )
-def test_matching_keys_unmatch():
- prv_keys = []
+def test_matching_keys_unmatch(tmpdir):
+ signature_providers = []
pub_keys = []
for i in range(4):
- prv_keys.append(generate_rsa_private_key())
- pub_keys.append(generate_rsa_public_key(prv_keys[i]))
+ prv_key = generate_rsa_private_key()
+ save_rsa_private_key(prv_key, os.path.join(tmpdir, f"key{i}.pem"))
+ signature_providers.append(PlainFileSP(os.path.join(tmpdir, f"key{i}.pem")))
+ pub_keys.append(generate_rsa_public_key(prv_key))
+ prv_key = generate_rsa_private_key()
+ save_rsa_private_key(prv_key, os.path.join(tmpdir, f"diff_key.pem"))
with pytest.raises(SPSDKValueError):
- get_matching_key_id(public_keys=pub_keys, private_key=generate_rsa_private_key())
+ get_matching_key_id(
+ public_keys=pub_keys,
+ signature_provider=PlainFileSP(os.path.join(tmpdir, f"diff_key.pem")),
+ )
diff --git a/tests/utils/data/plugins/custom_plugin.py b/tests/utils/data/plugins/custom_plugin.py
new file mode 100644
index 00000000..3f9cc8ab
--- /dev/null
+++ b/tests/utils/data/plugins/custom_plugin.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+#
+# Copyright 2023 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+"""Custom plugin."""
+
+
+class CustomPlugin:
+ """Custom plugin to be imported."""
+
+ def __init__(self) -> None:
+ """Initialize the Custom Plugin."""
+ pass
diff --git a/tests/utils/test_devicedescription.py b/tests/utils/test_devicedescription.py
index a9f3b1af..3c553ddf 100644
--- a/tests/utils/test_devicedescription.py
+++ b/tests/utils/test_devicedescription.py
@@ -43,6 +43,17 @@ def test_usb_device_description():
assert dev.info() == formatted_output
+def test_sdio_device_description():
+ formatted_output = "Vendor ID: 0x000a\n" "Product ID: 0x0014\n" "Path: some_path\n"
+ dev = devicedescription.SDIODeviceDescription(
+ vid=10,
+ pid=20,
+ path="some_path",
+ )
+
+ assert dev.info() == formatted_output
+
+
# Test SIO device description is done by NXPDEVSCAN tests :-)
diff --git a/tests/utils/test_nxpdevscan.py b/tests/utils/test_nxpdevscan.py
index 679f2e9c..7180b0e4 100644
--- a/tests/utils/test_nxpdevscan.py
+++ b/tests/utils/test_nxpdevscan.py
@@ -184,6 +184,53 @@ def test_uart_device_search():
assert dev.info() == res.info()
+# following mock functions are only for `test_sdio_device_search usage`
+class mockSdio:
+ def __init__(self, path: str = None) -> None:
+ """Initialize the SDIO interface object.
+
+ :raises McuBootConnectionError: when the path is empty
+ """
+ super().__init__()
+
+ self._opened = False
+ # Temporarily use hard code until there is a way to retrive VID/PID
+ self.vid = 0x0471
+ self.pid = 0x0209
+ self.timeout = 2000
+ if path is None:
+ raise McuBootConnectionError("No SDIO device path")
+ self.path = path
+ self.is_blocking = False
+
+
+def test_sdio_device_search():
+ """Test, that search method returns all NXP SDIO devices."""
+
+ test = mockSdio("/dev/mcu-sdio")
+ result = [
+ devicedescription.SDIODeviceDescription(0x0471, 0x0209, "/dev/mcu-sdio"),
+ ]
+ with patch("spsdk.utils.nxpdevscan.mb_scan_sdio", MagicMock(return_value=[test])):
+ devices = nds.search_nxp_sdio_devices()
+
+ assert len(devices) == len(result)
+
+ for dev, res in zip(devices, result):
+ assert dev.info() == res.info()
+
+
+def test_sdio_device_search_no_device_found():
+ """Test, that search method returns all NXP SDIO devices."""
+
+ result = [
+ devicedescription.SDIODeviceDescription(0x0471, 0x0209, ""),
+ ]
+ with patch("spsdk.utils.nxpdevscan.mb_scan_sdio", MagicMock(return_value=[])):
+ devices = nds.search_nxp_sdio_devices()
+ assert len(devices) != len(result)
+
+
@pytest.mark.parametrize(
"vid, pid, expected_result",
[
diff --git a/tests/utils/test_plugins.py b/tests/utils/test_plugins.py
new file mode 100644
index 00000000..977bafe9
--- /dev/null
+++ b/tests/utils/test_plugins.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+#
+# Copyright 2023 NXP
+#
+# SPDX-License-Identifier: BSD-3-Clause
+import os
+import sys
+
+import pytest
+
+from spsdk.exceptions import SPSDKError
+from spsdk.utils.plugins import PluginsManager
+
+
+@pytest.fixture
+def plugin_cleanup() -> None:
+ PluginsManager().plugins = {}
+
+
+def test_plugin_manager_init(plugin_cleanup):
+ pm = PluginsManager()
+ assert pm.plugins == {}
+
+
+def test_plugin_from_file_path(data_dir, plugin_cleanup):
+ plugin_path = os.path.join(data_dir, "plugins", "custom_plugin.py")
+ pm = PluginsManager()
+ pm.load_from_source_file(plugin_path)
+ assert len(pm.plugins) == 1
+ assert list(pm.plugins.keys())[0] == "custom_plugin"
+ klass = getattr(sys.modules["custom_plugin"], "CustomPlugin")
+ assert klass is not None
+ instance = klass()
+ assert instance is not None
+
+
+def test_plugin_from_file_path_non_existing(data_dir, plugin_cleanup):
+ plugin_path = os.path.join(data_dir, "plugins", "non_existing.py")
+ pm = PluginsManager()
+ with pytest.raises(SPSDKError):
+ pm.load_from_source_file(plugin_path)
+
+
+def test_plugins_is_singleton(data_dir, plugin_cleanup):
+ plugin_path = os.path.join(data_dir, "plugins", "custom_plugin.py")
+ pm = PluginsManager()
+ pm.load_from_source_file(plugin_path)
+ assert len(pm.plugins) == 1
+ same_instance = PluginsManager()
+ assert len(same_instance.plugins) == 1
diff --git a/tools/approved_packages.json b/tools/approved_packages.json
index d4ef4c85..33d4972d 100644
--- a/tools/approved_packages.json
+++ b/tools/approved_packages.json
@@ -3,12 +3,12 @@
"Apache 2.0",
"Apache-2.0",
"Apache-2.0 license",
+ "Apache-2.0 OR BSD-3-Clause",
"Apache License 2.0",
"Apache License, Version 2.0",
"Apache Software License",
"BSD",
"BSD (3 clause)",
- "BSD or Apache License, Version 2.0",
"BSD, Public Domain",
"BSD, Public Domain, Apache",
"BSD-3-Clause",
@@ -146,7 +146,7 @@
},
{
"name": "cryptography",
- "license": "BSD or Apache License, Version 2.0",
+ "license": "Apache-2.0 OR BSD-3-Clause",
"home_page": "https://github.com/pyca/cryptography",
"is_manual": false
},
@@ -407,6 +407,24 @@
"license": "MIT",
"home_page": "https://github.com/whwright/click-command-tree",
"is_manual": false
+ },
+ {
+ "name": "importlib-resources",
+ "license": "Apache 2.0",
+ "home_page": "https://pypi.org/project/importlib-resources/",
+ "is_manual": true
+ },
+ {
+ "name": "lark",
+ "license": "MIT",
+ "home_page": "https://github.com/lark-parser/lark",
+ "is_manual": false
+ },
+ {
+ "name": "pyreadline3",
+ "license": "BSD",
+ "home_page": "https://pypi.org/project/pyreadline3",
+ "is_manual": false
}
]
}
\ No newline at end of file
diff --git a/tools/fcb_header_to_xml.py b/tools/fcb_header_to_xml.py
index 4bb21959..7902b6b2 100644
--- a/tools/fcb_header_to_xml.py
+++ b/tools/fcb_header_to_xml.py
@@ -25,7 +25,7 @@
def get_struct(text: str, name: str) -> str:
"""Get sub list with structure content.
- :param text_lines: Input lines with header file.
+ :param text: Input lines with header file.
:param name: name of structure
:raises SPSDKError: When there is invalid structure name to find
:return: Subset of lines with structure content.
@@ -98,7 +98,7 @@ def __next__(self) -> StructMember:
)
match = re.match(re_type_name, self.text[self.last_ix :])
if not match:
- raise SPSDKError()
+ raise StopIteration
self.last_ix += match.end()
mem_type = match.group("mem_type")
mem_name = match.group("mem_name")
diff --git a/tools/gitcov.py b/tools/gitcov.py
index 8ddbfc7d..f10a6ef2 100644
--- a/tools/gitcov.py
+++ b/tools/gitcov.py
@@ -159,15 +159,18 @@ def get_changed_files(
repo_path: str,
include_merges: bool,
parent_branch: Optional[str] = None,
- file_extensions: Iterable[str] = ["py"],
+ file_extensions: Optional[Iterable[str]] = None,
) -> Sequence[str]:
"""Get a list of changed files.
:param repo_path: Path to the root of the repository
- :param parent_branch: Git branch to compare to
:param include_merges: Include changes done via merge-commits
+ :param parent_branch: Git branch to compare to
+ :param file_extensions: File extensions to be searched
:return: List of changed files
"""
+ if file_extensions is None:
+ file_extensions = ["py"]
file_extension_regex = "(" + "|".join(file_extensions) + ")"
file_regex_str = rf"^(?P[AM])\s+(?P[a-zA-Z0-9_/\\]+\.{file_extension_regex})$"
file_regex = re.compile(file_regex_str)
diff --git a/tools/release_notes.py b/tools/release_notes.py
index e3b04494..573769b0 100644
--- a/tools/release_notes.py
+++ b/tools/release_notes.py
@@ -23,8 +23,8 @@
from spsdk.exceptions import SPSDKError
-JIRA_SERVER = "https://jira.sw.nxp.com"
TICKET_REGEX = re.compile(r"(SPSDK-\d+)")
+JIRA_SERVER = "https://jira.sw.nxp.com"
class RNParams(NamedTuple):
diff --git a/tox.ini b/tox.ini
index 4eab2c8e..5bc17bda 100644
--- a/tox.ini
+++ b/tox.ini
@@ -5,13 +5,13 @@ envlist = py38,py39,py310,py311
[testenv]
# install testing framework
# ... or install anything else you might need here
-extras = tp
+extras = all
deps = -rrequirements-develop.txt
install_command = python -m pip install --upgrade pip {opts} {packages}
# run the tests
# ... or run any other command line tool you need to run here
-commands = python {toxinidir}{/}codecheck.py -s -o .{/}reports_{envname} {posargs}
+commands = python "{toxinidir}{/}codecheck.py" -s -o .{/}reports_{envname} {posargs}
setenv =
PYTHONDONTWRITEBYTECODE = 1