1# HOST_TEST for espefuse.py using the pytest framework
2#
3# Supports esp32, esp32s2, esp32s3beta2, esp32s3,
4#          esp32c3, esp32h2beta1, esp32c2, esp32c6, esp32p4,
5#          esp32c61, esp32c5, esp32c5beta3.
6#
7# How to use:
8#
9# Run as HOST_TEST (without a physical connection to a chip):
10#  - `pytest test_espefuse.py --chip esp32`
11#  - `pytest test_espefuse.py --chip esp32s2`
12#
13# OR
14#
15# Run as TEST on FPGA (connection to FPGA with a flashed image):
16# required two COM ports
17#  - `pytest test_espefuse.py \
18#     --chip esp32 --port /dev/ttyUSB0 --reset-port /dev/ttyUSB1`
19#
20# where  - --port       - a port for espefuse.py operation
21#        - --reset-port - a port to clear efuses (connect RTS or DTR ->- J14 pin 39)
22#
23# Note: For FPGA with ESP32 image, you need to set an env variable ESPTOOL_ENV_FPGA to 1
24#       to slow down the connection sequence
25#       because of a long delay (~6 seconds) after resetting the FPGA.
26#       This is not necessary when using other images than ESP32
27
28import os
29import subprocess
30import sys
31import tempfile
32import time
33
34from bitstring import BitStream
35
36# Make command line options --port, --reset-port and --chip available
37from conftest import arg_chip, arg_port, arg_reset_port, need_to_install_package_err
38
39TEST_DIR = os.path.abspath(os.path.dirname(__file__))
40IMAGES_DIR = os.path.join(TEST_DIR, "images", "efuse")
41S_IMAGES_DIR = os.path.join(TEST_DIR, "secure_images")
42EFUSE_S_DIR = os.path.join(TEST_DIR, "efuse_scripts")
43
44import pytest
45
46try:
47    from espefuse import SUPPORTED_CHIPS
48except ImportError:
49    need_to_install_package_err()
50
51SUPPORTED_CHIPS = list(SUPPORTED_CHIPS.keys())
52
53import serial
54
55# Set reset_port if --reset-port cmdline option is specified
56# This activates testing with real hardware (FPGA)
57reset_port = (
58    serial.Serial(arg_reset_port, 115200) if arg_reset_port is not None else None
59)
60
61if arg_chip not in SUPPORTED_CHIPS:
62    pytest.exit(f"{arg_chip} is not a supported target, choose from {SUPPORTED_CHIPS}")
63print(f"\nHost tests of espefuse.py for {arg_chip}:")
64print("Running espefuse.py tests...")
65
66
67@pytest.mark.host_test
68class EfuseTestCase:
69    def setup_method(self):
70        if reset_port is None:
71            self.efuse_file = tempfile.NamedTemporaryFile(delete=False)
72            self.base_cmd = (
73                f"{sys.executable} -m espefuse --chip {arg_chip} "
74                f"--virt --path-efuse-file {self.efuse_file.name} -d"
75            )
76            self._set_target_wafer_version()
77        else:
78            self.base_cmd = (
79                f"{sys.executable} -m espefuse --chip {arg_chip} "
80                f"--port {arg_port} -d"
81            )
82            self.reset_efuses()
83
84    def teardown_method(self):
85        if reset_port is None:
86            self.efuse_file.close()
87            os.unlink(self.efuse_file.name)
88
89    def reset_efuses(self):
90        # reset and zero efuses
91        reset_port.dtr = False
92        reset_port.rts = False
93        time.sleep(0.05)
94        reset_port.dtr = True
95        reset_port.rts = True
96        time.sleep(0.05)
97        reset_port.dtr = False
98        reset_port.rts = False
99
100    def get_esptool(self):
101        if reset_port is not None:
102            import esptool
103
104            esp = esptool.cmds.detect_chip(port=arg_port)
105            del esptool
106        else:
107            import espefuse
108
109            efuse = espefuse.SUPPORTED_CHIPS[arg_chip].efuse_lib
110            esp = efuse.EmulateEfuseController(self.efuse_file.name)
111            del espefuse
112            del efuse
113        return esp
114
115    def _set_34_coding_scheme(self):
116        self.espefuse_py("burn_efuse CODING_SCHEME 1")
117
118    def _set_none_recovery_coding_scheme(self):
119        self.espefuse_py("burn_efuse CODING_SCHEME 3")
120
121    def _set_target_wafer_version(self):
122        # ESP32 has to be ECO3 (v3.0) for tests
123        if arg_chip == "esp32":
124            self.espefuse_py("burn_efuse CHIP_VER_REV1 1 CHIP_VER_REV2 1")
125
126    def check_data_block_in_log(
127        self, log, file_path, repeat=1, reverse_order=False, offset=0
128    ):
129        with open(file_path, "rb") as f:
130            data = BitStream("0x00") * offset + BitStream(f)
131            blk = data.readlist(f"{data.len // 8}*uint:8")
132            blk = blk[::-1] if reverse_order else blk
133            hex_blk = " ".join(f"{num:02x}" for num in blk)
134            assert repeat == log.count(hex_blk)
135
136    def espefuse_not_virt_py(self, cmd, check_msg=None, ret_code=0):
137        full_cmd = " ".join((f"{sys.executable} -m espefuse", cmd))
138        return self._run_command(full_cmd, check_msg, ret_code)
139
140    def espefuse_py(self, cmd, do_not_confirm=True, check_msg=None, ret_code=0):
141        full_cmd = " ".join(
142            [self.base_cmd, "--do-not-confirm" if do_not_confirm else "", cmd]
143        )
144        output = self._run_command(full_cmd, check_msg, ret_code)
145        self._run_command(
146            " ".join([self.base_cmd, "check_error"]), "No errors detected", 0
147        )
148        print(output)
149        return output
150
151    def _run_command(self, cmd, check_msg, ret_code):
152        try:
153            p = subprocess.Popen(
154                cmd.split(),
155                shell=False,
156                stdin=subprocess.PIPE,
157                stdout=subprocess.PIPE,
158                universal_newlines=True,
159            )
160            output, _ = p.communicate()
161            returncode = p.returncode
162            if check_msg:
163                assert check_msg in output
164            if returncode:
165                print(output)
166                print(cmd)
167            assert ret_code == returncode
168            return output
169        except subprocess.CalledProcessError as error:
170            print(error)
171            raise
172
173
174class TestReadCommands(EfuseTestCase):
175    def test_help(self):
176        self.espefuse_not_virt_py("--help", check_msg="usage: __main__.py [-h]")
177        self.espefuse_not_virt_py(f"--chip {arg_chip} --help")
178
179    def test_help2(self):
180        self.espefuse_not_virt_py("", check_msg="usage: __main__.py [-h]", ret_code=1)
181
182    def test_dump(self):
183        self.espefuse_py("dump -h")
184        self.espefuse_py("dump")
185
186    def test_dump_format_joint(self):
187        tmp_file = tempfile.NamedTemporaryFile(delete=False)
188        self.espefuse_py(f"dump --format joint --file_name {tmp_file.name}")
189
190    def test_dump_split_default(self):
191        tmp_file = tempfile.NamedTemporaryFile(delete=False)
192        self.espefuse_py(f"dump --file_name {tmp_file.name}")
193
194    def test_dump_split(self):
195        tmp_file = tempfile.NamedTemporaryFile(delete=False)
196        self.espefuse_py(f"dump --format split --file_name {tmp_file.name}")
197
198    def test_summary(self):
199        self.espefuse_py("summary -h")
200        self.espefuse_py("summary")
201
202    def test_summary_json(self):
203        self.espefuse_py("summary --format json")
204
205    def test_summary_filter(self):
206        self.espefuse_py("summary MAC")
207        self.espefuse_py("summary --format value_only MAC")
208        self.espefuse_py(
209            "summary --format value_only MAC WR_DIS",
210            check_msg="The 'value_only' format can be used exactly for one efuse.",
211            ret_code=2,
212        )
213
214    @pytest.mark.skipif(
215        arg_chip == "esp32p4", reason="No Custom MAC Address defined yet"
216    )
217    def test_get_custom_mac(self):
218        self.espefuse_py("get_custom_mac -h")
219        if arg_chip == "esp32":
220            right_msg = "Custom MAC Address is not set in the device."
221        else:
222            right_msg = "Custom MAC Address: 00:00:00:00:00:00 (OK)"
223        self.espefuse_py("get_custom_mac", check_msg=right_msg)
224
225    def test_adc_info(self):
226        self.espefuse_py("adc_info -h")
227        self.espefuse_py("adc_info")
228
229    def test_adc_info_2(self):
230        if arg_chip == "esp32":
231            self.espefuse_py("burn_efuse BLK3_PART_RESERVE 1")
232        elif arg_chip in ["esp32c3", "esp32s3", "esp32s3beta2"]:
233            self.espefuse_py("burn_efuse BLK_VERSION_MAJOR 1")
234        elif arg_chip in ["esp32c2", "esp32s2", "esp32c6"]:
235            self.espefuse_py("burn_efuse BLK_VERSION_MINOR 1")
236        elif arg_chip in ["esp32h2", "esp32h2beta1"]:
237            self.espefuse_py("burn_efuse BLK_VERSION_MINOR 2")
238        self.espefuse_py("adc_info")
239
240    def test_check_error(self):
241        self.espefuse_py("check_error -h")
242        self.espefuse_py("check_error")
243        self.espefuse_py("check_error --recovery")
244
245
246class TestReadProtectionCommands(EfuseTestCase):
247    def test_read_protect_efuse(self):
248        self.espefuse_py("read_protect_efuse -h")
249        if arg_chip == "esp32":
250            cmd = "read_protect_efuse \
251                   CODING_SCHEME \
252                   MAC_VERSION \
253                   BLOCK1 \
254                   BLOCK2 \
255                   BLOCK3"
256            count_protects = 5
257        elif arg_chip == "esp32c2":
258            cmd = "read_protect_efuse \
259                   BLOCK_KEY0_LOW_128"
260            count_protects = 1
261        else:
262            self.espefuse_py(
263                "burn_efuse \
264                KEY_PURPOSE_0 HMAC_UP \
265                KEY_PURPOSE_1 XTS_AES_128_KEY \
266                KEY_PURPOSE_2 XTS_AES_128_KEY \
267                KEY_PURPOSE_3 HMAC_DOWN_ALL \
268                KEY_PURPOSE_4 HMAC_DOWN_JTAG \
269                KEY_PURPOSE_5 HMAC_DOWN_DIGITAL_SIGNATURE"
270            )
271            cmd = "read_protect_efuse \
272                   BLOCK_KEY0 \
273                   BLOCK_KEY1 \
274                   BLOCK_KEY2 \
275                   BLOCK_KEY3 \
276                   BLOCK_KEY4 \
277                   BLOCK_KEY5"
278            count_protects = 6
279        self.espefuse_py(cmd)
280        output = self.espefuse_py(cmd)
281        assert count_protects == output.count("is already read protected")
282
283    def test_read_protect_efuse2(self):
284        self.espefuse_py("write_protect_efuse RD_DIS")
285        if arg_chip == "esp32":
286            efuse_name = "CODING_SCHEME"
287        elif arg_chip == "esp32c2":
288            efuse_name = "BLOCK_KEY0_HI_128"
289        else:
290            efuse_name = "BLOCK_SYS_DATA2"
291        self.espefuse_py(
292            f"read_protect_efuse {efuse_name}",
293            check_msg="A fatal error occurred: This efuse cannot be read-disabled "
294            "due the to RD_DIS field is already write-disabled",
295            ret_code=2,
296        )
297
298    @pytest.mark.skipif(arg_chip != "esp32", reason="when the purpose of BLOCK2 is set")
299    def test_read_protect_efuse3(self):
300        self.espefuse_py("burn_efuse ABS_DONE_1 1")
301        self.espefuse_py(f"burn_key BLOCK2 {IMAGES_DIR}/256bit")
302        self.espefuse_py(
303            "read_protect_efuse BLOCK2",
304            check_msg="Secure Boot V2 is on (ABS_DONE_1 = True), "
305            "BLOCK2 must be readable, stop this operation!",
306            ret_code=2,
307        )
308
309    def test_read_protect_efuse4(self):
310        if arg_chip == "esp32":
311            self.espefuse_py(f"burn_key BLOCK2 {IMAGES_DIR}/256bit")
312            msg = "must be readable, please stop this operation!"
313            self.espefuse_py("read_protect_efuse BLOCK2", check_msg=msg)
314        elif arg_chip == "esp32c2":
315            self.espefuse_py(
316                f"burn_key BLOCK_KEY0 {IMAGES_DIR}/128bit_key SECURE_BOOT_DIGEST"
317            )
318            self.espefuse_py(
319                "read_protect_efuse BLOCK_KEY0",
320                check_msg="A fatal error occurred: "
321                "BLOCK_KEY0 must be readable, stop this operation!",
322                ret_code=2,
323            )
324        else:
325            key1_purpose = (
326                "USER"
327                if arg_chip in ["esp32p4", "esp32c61", "esp32c5", "esp32c5beta3"]
328                else "RESERVED"
329            )
330            self.espefuse_py(
331                f"burn_key BLOCK_KEY0 {IMAGES_DIR}/256bit USER \
332                BLOCK_KEY1 {IMAGES_DIR}/256bit {key1_purpose} \
333                BLOCK_KEY2 {IMAGES_DIR}/256bit SECURE_BOOT_DIGEST0 \
334                BLOCK_KEY3 {IMAGES_DIR}/256bit SECURE_BOOT_DIGEST1 \
335                BLOCK_KEY4 {IMAGES_DIR}/256bit SECURE_BOOT_DIGEST2 \
336                BLOCK_KEY5 {IMAGES_DIR}/256bit HMAC_UP"
337            )
338            self.espefuse_py(
339                "read_protect_efuse BLOCK_KEY0",
340                check_msg="A fatal error occurred: "
341                "BLOCK_KEY0 must be readable, stop this operation!",
342                ret_code=2,
343            )
344            self.espefuse_py(
345                "read_protect_efuse BLOCK_KEY1",
346                check_msg="A fatal error occurred: "
347                "BLOCK_KEY1 must be readable, stop this operation!",
348                ret_code=2,
349            )
350            self.espefuse_py(
351                "read_protect_efuse BLOCK_KEY2",
352                check_msg="A fatal error occurred: "
353                "BLOCK_KEY2 must be readable, stop this operation!",
354                ret_code=2,
355            )
356            self.espefuse_py(
357                "read_protect_efuse BLOCK_KEY3",
358                check_msg="A fatal error occurred: "
359                "BLOCK_KEY3 must be readable, stop this operation!",
360                ret_code=2,
361            )
362            self.espefuse_py(
363                "read_protect_efuse BLOCK_KEY4",
364                check_msg="A fatal error occurred: "
365                "BLOCK_KEY4 must be readable, stop this operation!",
366                ret_code=2,
367            )
368            self.espefuse_py("read_protect_efuse BLOCK_KEY5")
369
370    @pytest.mark.skipif(
371        arg_chip != "esp32",
372        reason="system parameters efuse read-protection is supported only by esp32, "
373        "other chips protect whole blocks",
374    )
375    def test_burn_and_read_protect_efuse(self):
376        self.espefuse_py(
377            "burn_efuse FLASH_CRYPT_CONFIG 15 RD_DIS 8",
378            check_msg="Efuse FLASH_CRYPT_CONFIG is read-protected. "
379            "Read back the burn value is not possible.",
380        )
381
382
383class TestWriteProtectionCommands(EfuseTestCase):
384    def test_write_protect_efuse(self):
385        self.espefuse_py("write_protect_efuse -h")
386        if arg_chip == "esp32":
387            efuse_lists = """WR_DIS RD_DIS CODING_SCHEME
388                           XPD_SDIO_FORCE XPD_SDIO_REG XPD_SDIO_TIEH SPI_PAD_CONFIG_CLK
389                           FLASH_CRYPT_CNT UART_DOWNLOAD_DIS FLASH_CRYPT_CONFIG
390                           ADC_VREF BLOCK1 BLOCK2 BLOCK3"""
391            efuse_lists2 = "WR_DIS RD_DIS"
392        elif arg_chip == "esp32c2":
393            efuse_lists = """RD_DIS DIS_DOWNLOAD_ICACHE
394                           XTS_KEY_LENGTH_256 UART_PRINT_CONTROL"""
395            efuse_lists2 = "RD_DIS DIS_DOWNLOAD_ICACHE"
396        elif arg_chip == "esp32p4":
397            efuse_lists = """RD_DIS KEY_PURPOSE_0 SECURE_BOOT_KEY_REVOKE0
398                           SPI_BOOT_CRYPT_CNT"""
399            efuse_lists2 = "RD_DIS KEY_PURPOSE_0 KEY_PURPOSE_2"
400        else:
401            efuse_lists = """RD_DIS DIS_ICACHE DIS_FORCE_DOWNLOAD
402                           DIS_DOWNLOAD_MANUAL_ENCRYPT
403                           USB_EXCHG_PINS WDT_DELAY_SEL SPI_BOOT_CRYPT_CNT
404                           SECURE_BOOT_KEY_REVOKE0 SECURE_BOOT_KEY_REVOKE1
405                           SECURE_BOOT_KEY_REVOKE2 KEY_PURPOSE_0 KEY_PURPOSE_1
406                           KEY_PURPOSE_2 KEY_PURPOSE_3 KEY_PURPOSE_4 KEY_PURPOSE_5
407                           SECURE_BOOT_EN SECURE_BOOT_AGGRESSIVE_REVOKE FLASH_TPUW
408                           DIS_DOWNLOAD_MODE
409                           ENABLE_SECURITY_DOWNLOAD UART_PRINT_CONTROL
410                           MAC
411                           BLOCK_USR_DATA BLOCK_KEY0 BLOCK_KEY1
412                           BLOCK_KEY2 BLOCK_KEY3 BLOCK_KEY4 BLOCK_KEY5"""
413            if arg_chip not in [
414                "esp32h2",
415                "esp32h2beta1",
416                "esp32c6",
417                "esp32c61",
418                "esp32c5",
419                "esp32c5beta3",
420            ]:
421                efuse_lists += """ DIS_DOWNLOAD_ICACHE
422                            SPI_PAD_CONFIG_CLK SPI_PAD_CONFIG_Q
423                            SPI_PAD_CONFIG_D SPI_PAD_CONFIG_CS SPI_PAD_CONFIG_HD
424                            SPI_PAD_CONFIG_WP SPI_PAD_CONFIG_DQS SPI_PAD_CONFIG_D4
425                            SPI_PAD_CONFIG_D5 SPI_PAD_CONFIG_D6 SPI_PAD_CONFIG_D7"""
426            efuse_lists2 = "RD_DIS DIS_ICACHE"
427        self.espefuse_py(f"write_protect_efuse {efuse_lists}")
428        output = self.espefuse_py(f"write_protect_efuse {efuse_lists2}")
429        assert output.count("is already write protected") == 2
430
431    def test_write_protect_efuse2(self):
432        if arg_chip == "esp32":
433            self.espefuse_py("write_protect_efuse WR_DIS")
434            self.espefuse_py(
435                "write_protect_efuse CODING_SCHEME",
436                check_msg="A fatal error occurred: This efuse cannot be write-disabled "
437                "due to the WR_DIS field is already write-disabled",
438                ret_code=2,
439            )
440
441
442@pytest.mark.skipif(arg_chip == "esp32p4", reason="No Custom MAC Address defined yet")
443class TestBurnCustomMacCommands(EfuseTestCase):
444    def test_burn_custom_mac(self):
445        self.espefuse_py("burn_custom_mac -h")
446        cmd = "burn_custom_mac AA:CD:EF:11:22:33"
447        mac = "aa:cd:ef:11:22:33"
448        if arg_chip == "esp32":
449            self.espefuse_py(
450                cmd, check_msg=f"Custom MAC Address version 1: {mac} (CRC 0x63 OK)"
451            )
452        else:
453            self.espefuse_py(cmd, check_msg=f"Custom MAC Address: {mac} (OK)")
454
455    def test_burn_custom_mac2(self):
456        self.espefuse_py(
457            "burn_custom_mac AA:CD:EF:11:22:33:44",
458            check_msg="A fatal error occurred: MAC Address needs to be a 6-byte "
459            "hexadecimal format separated by colons (:)!",
460            ret_code=2,
461        )
462
463    def test_burn_custom_mac3(self):
464        self.espefuse_py(
465            "burn_custom_mac AB:CD:EF:11:22:33",
466            check_msg="A fatal error occurred: Custom MAC must be a unicast MAC!",
467            ret_code=2,
468        )
469
470    @pytest.mark.skipif(
471        arg_chip != "esp32", reason="3/4 coding scheme is only in esp32"
472    )
473    def test_burn_custom_mac_with_34_coding_scheme(self):
474        self._set_34_coding_scheme()
475        self.espefuse_py("burn_custom_mac -h")
476        self.espefuse_py(
477            "burn_custom_mac AA:CD:EF:01:02:03",
478            check_msg="Custom MAC Address version 1: aa:cd:ef:01:02:03 (CRC 0x56 OK)",
479        )
480        self.espefuse_py(
481            "get_custom_mac",
482            check_msg="Custom MAC Address version 1: aa:cd:ef:01:02:03 (CRC 0x56 OK)",
483        )
484
485        self.espefuse_py(
486            "burn_custom_mac FE:22:33:44:55:66",
487            check_msg="New value contains some bits that cannot be cleared "
488            "(value will be 0x675745ffeffe)",
489            ret_code=2,
490        )
491
492
493@pytest.mark.skipif(
494    arg_chip
495    not in [
496        "esp32",
497        "esp32s2",
498        "esp32s3",
499    ],
500    reason=f"{arg_chip} does not support set_flash_voltage",
501)
502class TestSetFlashVoltageCommands(EfuseTestCase):
503    def test_set_flash_voltage_1_8v(self):
504        self.espefuse_py("set_flash_voltage -h")
505        vdd = "VDD_SDIO" if arg_chip == "esp32" else "VDD_SPI"
506        self.espefuse_py(
507            "set_flash_voltage 1.8V",
508            check_msg=f"Set internal flash voltage regulator ({vdd}) to 1.8V.",
509        )
510        if arg_chip == "esp32":
511            error_msg = "A fatal error occurred: "
512            "Can't set flash regulator to OFF as XPD_SDIO_REG efuse is already burned"
513        else:
514            error_msg = "A fatal error occurred: "
515            "Can't set flash regulator to OFF as VDD_SPI_XPD efuse is already burned"
516        self.espefuse_py(
517            "set_flash_voltage 3.3V",
518            check_msg=f"Enable internal flash voltage regulator ({vdd}) to 3.3V.",
519        )
520        self.espefuse_py("set_flash_voltage OFF", check_msg=error_msg, ret_code=2)
521
522    def test_set_flash_voltage_3_3v(self):
523        vdd = "VDD_SDIO" if arg_chip == "esp32" else "VDD_SPI"
524        self.espefuse_py(
525            "set_flash_voltage 3.3V",
526            check_msg=f"Enable internal flash voltage regulator ({vdd}) to 3.3V.",
527        )
528        if arg_chip == "esp32":
529            error_msg = "A fatal error occurred: "
530            "Can't set regulator to 1.8V is XPD_SDIO_TIEH efuse is already burned"
531        else:
532            error_msg = "A fatal error occurred: "
533            "Can't set regulator to 1.8V is VDD_SPI_TIEH efuse is already burned"
534        self.espefuse_py("set_flash_voltage 1.8V", check_msg=error_msg, ret_code=2)
535
536        if arg_chip == "esp32":
537            error_msg = "A fatal error occurred: "
538            "Can't set flash regulator to OFF as XPD_SDIO_REG efuse is already burned"
539        else:
540            error_msg = "A fatal error occurred: "
541            "Can't set flash regulator to OFF as VDD_SPI_XPD efuse is already burned"
542        self.espefuse_py("set_flash_voltage OFF", check_msg=error_msg, ret_code=2)
543
544    def test_set_flash_voltage_off(self):
545        vdd = "VDD_SDIO" if arg_chip == "esp32" else "VDD_SPI"
546        self.espefuse_py(
547            "set_flash_voltage OFF",
548            check_msg=f"Disable internal flash voltage regulator ({vdd})",
549        )
550        self.espefuse_py(
551            "set_flash_voltage 3.3V",
552            check_msg=f"Enable internal flash voltage regulator ({vdd}) to 3.3V.",
553        )
554
555    def test_set_flash_voltage_off2(self):
556        vdd = "VDD_SDIO" if arg_chip == "esp32" else "VDD_SPI"
557        self.espefuse_py(
558            "set_flash_voltage OFF",
559            check_msg=f"Disable internal flash voltage regulator ({vdd})",
560        )
561        self.espefuse_py(
562            "set_flash_voltage 1.8V",
563            check_msg=f"Set internal flash voltage regulator ({vdd}) to 1.8V.",
564        )
565
566
567@pytest.mark.skipif(arg_chip != "esp32c3", reason="Not necessary for all chips")
568class TestValueArgForBurnEfuseCommands(EfuseTestCase):
569    def test_efuse_is_bool_given_none(self):
570        self.espefuse_py("burn_efuse SECURE_BOOT_KEY_REVOKE0")
571
572    def test_efuse_is_bool_given_0(self):
573        self.espefuse_py(
574            "burn_efuse SECURE_BOOT_KEY_REVOKE0 0",
575            check_msg="A fatal error occurred: "
576            "New value is not accepted for efuse 'SECURE_BOOT_KEY_REVOKE0' "
577            "(will always burn 0->1), given value=0",
578            ret_code=2,
579        )
580
581    def test_efuse_is_bool_given_2(self):
582        self.espefuse_py(
583            "burn_efuse SECURE_BOOT_KEY_REVOKE0 2",
584            check_msg="A fatal error occurred: "
585            "New value is not accepted for efuse 'SECURE_BOOT_KEY_REVOKE0' "
586            "(will always burn 0->1), given value=2",
587            ret_code=2,
588        )
589
590    def test_efuse_is_bytes_ok(self):
591        self.espefuse_py(
592            "burn_efuse OPTIONAL_UNIQUE_ID 0x12345678123456781234567812345678"
593        )
594
595    def test_efuse_is_bytes_given_short_val(self):
596        self.espefuse_py(
597            "burn_efuse OPTIONAL_UNIQUE_ID 0x1234567812345678",
598            check_msg="A fatal error occurred: "
599            "The length of efuse 'OPTIONAL_UNIQUE_ID' (128 bits) "
600            "(given len of the new value= 64 bits)",
601            ret_code=2,
602        )
603
604    def test_efuse_is_bytes_given_none(self):
605        self.espefuse_py(
606            "burn_efuse OPTIONAL_UNIQUE_ID",
607            check_msg="A fatal error occurred: "
608            "New value required for efuse 'OPTIONAL_UNIQUE_ID' (given None)",
609            ret_code=2,
610        )
611
612    def test_efuse_is_int_ok(self):
613        self.espefuse_py("burn_efuse SPI_PAD_CONFIG_D 7")
614
615    def test_efuse_is_int_given_out_of_range_val(self):
616        self.espefuse_py(
617            "burn_efuse SPI_PAD_CONFIG_D 200",
618            check_msg="A fatal error occurred: "
619            "200 is too large an unsigned integer for a bitstring "
620            "of length 6. The allowed range is [0, 63].",
621            ret_code=2,
622        )
623
624    def test_efuse_is_int_given_none(self):
625        self.espefuse_py(
626            "burn_efuse SPI_PAD_CONFIG_D",
627            check_msg="A fatal error occurred: "
628            "New value required for efuse 'SPI_PAD_CONFIG_D' (given None)",
629            ret_code=2,
630        )
631
632    def test_efuse_is_int_given_0(self):
633        self.espefuse_py(
634            "burn_efuse SPI_PAD_CONFIG_D 0",
635            check_msg="A fatal error occurred: "
636            "New value should not be 0 for 'SPI_PAD_CONFIG_D' "
637            "(given value= 0)",
638            ret_code=2,
639        )
640
641    def test_efuse_is_bitcount_given_out_of_range_val(self):
642        self.espefuse_py(
643            "burn_efuse SPI_BOOT_CRYPT_CNT 9",
644            check_msg="A fatal error occurred: "
645            "9 is too large an unsigned integer for a bitstring "
646            "of length 3. The allowed range is [0, 7].",
647            ret_code=2,
648        )
649
650    def test_efuse_is_bitcount_given_increase_over_max(self):
651        self.espefuse_py("burn_efuse SPI_BOOT_CRYPT_CNT")
652        self.espefuse_py("burn_efuse SPI_BOOT_CRYPT_CNT")
653        self.espefuse_py("burn_efuse SPI_BOOT_CRYPT_CNT")
654        self.espefuse_py(
655            "burn_efuse SPI_BOOT_CRYPT_CNT",
656            check_msg="A fatal error occurred: "
657            "15 is too large an unsigned integer for a bitstring "
658            "of length 3. The allowed range is [0, 7].",
659            ret_code=2,
660        )
661
662
663class TestBurnEfuseCommands(EfuseTestCase):
664    @pytest.mark.skipif(
665        arg_chip != "esp32",
666        reason="IO pins 30 & 31 cannot be set for SPI flash only on esp32",
667    )
668    def test_set_spi_flash_pin_efuses(self):
669        self.espefuse_py(
670            "burn_efuse SPI_PAD_CONFIG_HD 30",
671            check_msg="A fatal error occurred: "
672            "IO pins 30 & 31 cannot be set for SPI flash. 0-29, 32 & 33 only.",
673            ret_code=2,
674        )
675        self.espefuse_py(
676            "burn_efuse SPI_PAD_CONFIG_Q 0x23",
677            check_msg="A fatal error occurred: "
678            "IO pin 35 cannot be set for SPI flash. 0-29, 32 & 33 only.",
679            ret_code=2,
680        )
681        output = self.espefuse_py("burn_efuse SPI_PAD_CONFIG_CS0 33")
682        assert "(Override SD_CMD pad (GPIO11/SPICS0)) 0b00000 -> 0b11111" in output
683        assert "BURN BLOCK0  - OK (all write block bits are set)" in output
684
685    @pytest.mark.skipif(
686        arg_chip == "esp32p4", reason="No Custom MAC Address defined yet"
687    )
688    def test_burn_mac_custom_efuse(self):
689        crc_msg = "(OK)"
690        self.espefuse_py("burn_efuse -h")
691        if arg_chip == "esp32":
692            self.espefuse_py(
693                "burn_efuse MAC AA:CD:EF:01:02:03",
694                check_msg="Writing Factory MAC address is not supported",
695                ret_code=2,
696            )
697            self.espefuse_py("burn_efuse MAC_VERSION 1")
698            crc_msg = "(CRC 0x56 OK)"
699        if arg_chip == "esp32c2":
700            self.espefuse_py("burn_efuse CUSTOM_MAC_USED 1")
701        self.espefuse_py("burn_efuse -h")
702        self.espefuse_py(
703            "burn_efuse CUSTOM_MAC AB:CD:EF:01:02:03",
704            check_msg="A fatal error occurred: Custom MAC must be a unicast MAC!",
705            ret_code=2,
706        )
707        self.espefuse_py("burn_efuse CUSTOM_MAC AA:CD:EF:01:02:03")
708        self.espefuse_py("get_custom_mac", check_msg=f"aa:cd:ef:01:02:03 {crc_msg}")
709
710    def test_burn_efuse(self):
711        self.espefuse_py("burn_efuse -h")
712        if arg_chip == "esp32":
713            self.espefuse_py(
714                "burn_efuse \
715                CHIP_VER_REV2 1 \
716                DISABLE_DL_ENCRYPT 1 \
717                CONSOLE_DEBUG_DISABLE 1"
718            )
719            blk1 = "BLOCK1"
720            blk2 = "BLOCK2"
721        elif arg_chip == "esp32c2":
722            self.espefuse_py(
723                "burn_efuse \
724                XTS_KEY_LENGTH_256 1 \
725                UART_PRINT_CONTROL 1 \
726                FORCE_SEND_RESUME 1"
727            )
728            blk1 = "BLOCK_KEY0"
729            blk2 = None
730        else:
731            self.espefuse_py(
732                "burn_efuse \
733                SECURE_BOOT_EN 1 \
734                UART_PRINT_CONTROL 1"
735            )
736            if arg_chip not in ["esp32c5", "esp32c5beta3", "esp32c61"]:
737                # chips having the OPTIONAL_UNIQUE_ID field
738                self.espefuse_py(
739                    "burn_efuse \
740                    OPTIONAL_UNIQUE_ID 0x2328ad5ac9145f698f843a26d6eae168",
741                    check_msg="-> 0x2328ad5ac9145f698f843a26d6eae168",
742                )
743                output = self.espefuse_py("summary -d")
744                assert (
745                    "read_regs: d6eae168 8f843a26 c9145f69 2328ad5a "
746                    "00000000 00000000 00000000 00000000"
747                ) in output
748                assert "= 68 e1 ea d6 26 3a 84 8f 69 5f 14 c9 5a ad 28 23 R/W" in output
749                self.espefuse_py(
750                    "burn_bit BLOCK_SYS_DATA 1",
751                    check_msg="Burn into BLOCK_SYS_DATA is forbidden "
752                    "(RS coding scheme does not allow this).",
753                    ret_code=2,
754                )
755            blk1 = "BLOCK_KEY1"
756            blk2 = "BLOCK_KEY2"
757        output = self.espefuse_py(
758            f"burn_efuse {blk1}"
759            + " 0x00010203040506070809111111111111111111111111111111110000112233FF"
760        )
761        assert (
762            "-> 0x00010203040506070809111111111111111111111111111111110000112233ff"
763            in output
764        )
765        output = self.espefuse_py("summary -d")
766        assert (
767            "read_regs: 112233ff 11110000 11111111 11111111 "
768            "11111111 08091111 04050607 00010203"
769        ) in output
770        assert (
771            "= ff 33 22 11 00 00 11 11 11 11 11 11 11 11 11 11 "
772            "11 11 11 11 11 11 09 08 07 06 05 04 03 02 01 00 R/W"
773        ) in output
774
775        if blk2 is not None:
776            output = self.espefuse_py(
777                f"burn_efuse {blk2}"
778                + " 00010203040506070809111111111111111111111111111111110000112233FF"
779            )
780            assert (
781                "-> 0xff33221100001111111111111111111111111111111109080706050403020100"
782                in output
783            )
784            output = self.espefuse_py("summary -d")
785            assert (
786                "read_regs: 03020100 07060504 11110908 11111111 "
787                "11111111 11111111 00001111 ff332211"
788            ) in output
789            assert (
790                "= 00 01 02 03 04 05 06 07 08 09 11 11 11 11 11 11 "
791                "11 11 11 11 11 11 11 11 11 11 00 00 11 22 33 ff R/W"
792            ) in output
793
794    @pytest.mark.skipif(
795        arg_chip != "esp32", reason="3/4 coding scheme is only in esp32"
796    )
797    def test_burn_efuse_with_34_coding_scheme(self):
798        self._set_34_coding_scheme()
799        self.espefuse_py("burn_efuse BLK3_PART_RESERVE 1")
800        self.espefuse_py("burn_efuse ADC1_TP_LOW 50")
801        self.espefuse_py(
802            "burn_efuse ADC1_TP_HIGH 55",
803            check_msg="Burn into BLOCK3 is forbidden "
804            "(3/4 coding scheme does not allow this)",
805            ret_code=2,
806        )
807
808    @pytest.mark.skipif(
809        arg_chip != "esp32", reason="3/4 coding scheme is only in esp32"
810    )
811    def test_burn_efuse_with_34_coding_scheme2(self):
812        self._set_34_coding_scheme()
813        self.espefuse_py("burn_efuse BLK3_PART_RESERVE 1")
814        self.espefuse_py(
815            "burn_efuse \
816            ADC1_TP_LOW 50 \
817            ADC1_TP_HIGH 55 \
818            ADC2_TP_LOW 40 \
819            ADC2_TP_HIGH 45"
820        )
821
822    @pytest.mark.skipif(
823        arg_chip != "esp32s3",
824        reason="Currently S3 only has this efuse incompatibility check",
825    )
826    def test_burn_efuse_incompatibility_check(self):
827        self.espefuse_py(
828            "burn_efuse DIS_USB_JTAG 1 DIS_USB_SERIAL_JTAG 1",
829            check_msg="Incompatible eFuse settings detected, abort",
830            ret_code=2,
831        )
832        self.espefuse_py("burn_efuse DIS_USB_JTAG 1")
833        self.espefuse_py(
834            "burn_efuse DIS_USB_SERIAL_JTAG 1",
835            check_msg="Incompatible eFuse settings detected, abort",
836            ret_code=2,
837        )
838        self.espefuse_py("burn_efuse DIS_USB_SERIAL_JTAG 1 --force")
839
840
841class TestBurnKeyCommands(EfuseTestCase):
842    @pytest.mark.skipif(arg_chip != "esp32", reason="ESP32-only")
843    def test_burn_key_3_key_blocks(self):
844        self.espefuse_py("burn_key -h")
845        self.espefuse_py(
846            f"burn_key BLOCK1 {IMAGES_DIR}/192bit",
847            check_msg="A fatal error occurred: Incorrect key file size 24. "
848            "Key file must be 32 bytes (256 bits) of raw binary key data.",
849            ret_code=2,
850        )
851        self.espefuse_py(
852            f"burn_key \
853            BLOCK1 {IMAGES_DIR}/256bit \
854            BLOCK2 {IMAGES_DIR}/256bit_1 \
855            BLOCK3 {IMAGES_DIR}/256bit_2 --no-protect-key"
856        )
857        output = self.espefuse_py("summary -d")
858        self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit")
859        self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit_1")
860        self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit_2")
861
862        self.espefuse_py(
863            f"burn_key \
864            BLOCK1 {IMAGES_DIR}/256bit \
865            BLOCK2 {IMAGES_DIR}/256bit_1 \
866            BLOCK3 {IMAGES_DIR}/256bit_2"
867        )
868        output = self.espefuse_py("summary -d")
869        self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit")
870        self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit_1")
871        self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit_2")
872
873    @pytest.mark.skipif(arg_chip != "esp32c2", reason="ESP32-C2-only")
874    def test_burn_key_1_key_block(self):
875        self.espefuse_py("burn_key -h")
876        self.espefuse_py(
877            f"burn_key BLOCK_KEY0 {IMAGES_DIR}/128bit XTS_AES_128_KEY",
878            check_msg="A fatal error occurred: Incorrect key file size 16. "
879            "Key file must be 32 bytes (256 bits) of raw binary key data.",
880            ret_code=2,
881        )
882        self.espefuse_py(
883            f"burn_key BLOCK_KEY0 {IMAGES_DIR}/256bit XTS_AES_128_KEY --no-read-protect"
884        )
885        output = self.espefuse_py("summary -d")
886        self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit", reverse_order=True)
887
888        self.espefuse_py(f"burn_key BLOCK_KEY0 {IMAGES_DIR}/256bit XTS_AES_128_KEY")
889        output = self.espefuse_py("summary -d")
890        assert (
891            "[3 ] read_regs: 00000000 00000000 00000000 00000000 "
892            "00000000 00000000 00000000 00000000"
893        ) in output
894
895        assert (
896            "= ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? "
897            "?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? -/-"
898        ) in output
899
900    @pytest.mark.skipif(arg_chip != "esp32c2", reason="ESP32-C2-only")
901    def test_burn_key_one_key_block_with_fe_and_sb_keys(self):
902        self.espefuse_py("burn_key -h")
903        self.espefuse_py(
904            f"burn_key BLOCK_KEY0 {IMAGES_DIR}/256bit XTS_AES_128_KEY \
905            BLOCK_KEY0 {IMAGES_DIR}/128bit_key SECURE_BOOT_DIGEST",
906            check_msg="A fatal error occurred: These keypurposes are incompatible "
907            "['XTS_AES_128_KEY', 'SECURE_BOOT_DIGEST']",
908            ret_code=2,
909        )
910        self.espefuse_py(
911            f"burn_key BLOCK_KEY0 {IMAGES_DIR}/128bit_key "
912            f"XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS "
913            f"BLOCK_KEY0 {IMAGES_DIR}/128bit_key SECURE_BOOT_DIGEST --no-read-protect"
914        )
915        output = self.espefuse_py("summary -d")
916        assert (
917            "[3 ] read_regs: 0c0d0e0f 08090a0b 04050607 00010203 "
918            "03020100 07060504 0b0a0908 0f0e0d0c"
919        ) in output
920
921        self.espefuse_py(
922            f"burn_key BLOCK_KEY0 {IMAGES_DIR}/128bit_key "
923            "XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS "
924            f"BLOCK_KEY0 {IMAGES_DIR}/128bit_key SECURE_BOOT_DIGEST"
925        )
926        output = self.espefuse_py("summary -d")
927        assert (
928            "[3 ] read_regs: 00000000 00000000 00000000 00000000 "
929            "03020100 07060504 0b0a0908 0f0e0d0c"
930        ) in output
931
932        assert (
933            "= ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? "
934            "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f -/-"
935        ) in output
936        assert "= ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? -/-" in output
937        assert "= 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f R/-" in output
938
939    @pytest.mark.skipif(
940        arg_chip
941        not in [
942            "esp32s2",
943            "esp32s3",
944            "esp32s3beta1",
945            "esp32c3",
946            "esp32h2beta1",
947            "esp32c6",
948            "esp32h2",
949            "esp32p4",
950            "esp32c5",
951            "esp32c5beta3",
952            "esp32c61",
953        ],
954        reason="Only chips with 6 keys",
955    )
956    def test_burn_key_with_6_keys(self):
957        cmd = f"burn_key \
958               BLOCK_KEY0 {IMAGES_DIR}/256bit   XTS_AES_256_KEY_1 \
959               BLOCK_KEY1 {IMAGES_DIR}/256bit_1 XTS_AES_256_KEY_2 \
960               BLOCK_KEY2 {IMAGES_DIR}/256bit_2 XTS_AES_128_KEY"
961        if arg_chip in [
962            "esp32c3",
963            "esp32c6",
964            "esp32h2",
965            "esp32h2beta1",
966            "esp32c5",
967            "esp32c5beta3",
968        ]:
969            cmd = cmd.replace("XTS_AES_256_KEY_1", "XTS_AES_128_KEY")
970            cmd = cmd.replace("XTS_AES_256_KEY_2", "XTS_AES_128_KEY")
971        self.espefuse_py(cmd + " --no-read-protect --no-write-protect")
972        output = self.espefuse_py("summary -d")
973        self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit", reverse_order=True)
974        self.check_data_block_in_log(
975            output, f"{IMAGES_DIR}/256bit_1", reverse_order=True
976        )
977        self.check_data_block_in_log(
978            output, f"{IMAGES_DIR}/256bit_2", reverse_order=True
979        )
980
981        self.espefuse_py(cmd)
982        output = self.espefuse_py("summary -d")
983        assert (
984            "[4 ] read_regs: 00000000 00000000 00000000 00000000 "
985            "00000000 00000000 00000000 00000000"
986        ) in output
987        assert (
988            "[5 ] read_regs: 00000000 00000000 00000000 00000000 "
989            "00000000 00000000 00000000 00000000"
990        ) in output
991        assert (
992            "[6 ] read_regs: 00000000 00000000 00000000 00000000 "
993            "00000000 00000000 00000000 00000000"
994        ) in output
995
996        self.espefuse_py(
997            f"burn_key \
998            BLOCK_KEY3 {IMAGES_DIR}/256bit   SECURE_BOOT_DIGEST0 \
999            BLOCK_KEY4 {IMAGES_DIR}/256bit_1 SECURE_BOOT_DIGEST1 \
1000            BLOCK_KEY5 {IMAGES_DIR}/256bit_2 SECURE_BOOT_DIGEST2"
1001        )
1002        output = self.espefuse_py("summary -d")
1003        self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit")
1004        self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit_1")
1005        self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit_2")
1006
1007    @pytest.mark.skipif(
1008        arg_chip != "esp32", reason="3/4 coding scheme is only in esp32"
1009    )
1010    def test_burn_key_with_34_coding_scheme(self):
1011        self._set_34_coding_scheme()
1012        self.espefuse_py(
1013            f"burn_key BLOCK1 {IMAGES_DIR}/256bit",
1014            check_msg="A fatal error occurred: Incorrect key file size 32. "
1015            "Key file must be 24 bytes (192 bits) of raw binary key data.",
1016            ret_code=2,
1017        )
1018        self.espefuse_py(
1019            f"burn_key \
1020            BLOCK1 {IMAGES_DIR}/192bit \
1021            BLOCK2 {IMAGES_DIR}/192bit_1 \
1022            BLOCK3 {IMAGES_DIR}/192bit_2 --no-protect-key"
1023        )
1024        output = self.espefuse_py("summary -d")
1025        self.check_data_block_in_log(output, f"{IMAGES_DIR}/192bit")
1026        self.check_data_block_in_log(output, f"{IMAGES_DIR}/192bit_1")
1027        self.check_data_block_in_log(output, f"{IMAGES_DIR}/192bit_2")
1028
1029        self.espefuse_py(
1030            f"burn_key \
1031            BLOCK1 {IMAGES_DIR}/192bit \
1032            BLOCK2 {IMAGES_DIR}/192bit_1 \
1033            BLOCK3 {IMAGES_DIR}/192bit_2"
1034        )
1035        output = self.espefuse_py("summary -d")
1036        self.check_data_block_in_log(output, f"{IMAGES_DIR}/192bit")
1037        self.check_data_block_in_log(output, f"{IMAGES_DIR}/192bit_1")
1038        self.check_data_block_in_log(output, f"{IMAGES_DIR}/192bit_2")
1039
1040    @pytest.mark.skipif(
1041        arg_chip not in ["esp32s2", "esp32s3", "esp32p4", "esp32c61"],
1042        reason="512 bit keys are only supported on ESP32-S2, S3, P4, C61",
1043    )
1044    def test_burn_key_512bit(self):
1045        self.espefuse_py(
1046            f"burn_key \
1047            BLOCK_KEY0 {IMAGES_DIR}/256bit_1_256bit_2_combined \
1048            XTS_AES_256_KEY --no-read-protect --no-write-protect"
1049        )
1050        output = self.espefuse_py("summary -d")
1051        self.check_data_block_in_log(
1052            output, f"{IMAGES_DIR}/256bit_1", reverse_order=True
1053        )
1054        self.check_data_block_in_log(
1055            output, f"{IMAGES_DIR}/256bit_2", reverse_order=True
1056        )
1057
1058    @pytest.mark.skipif(
1059        arg_chip not in ["esp32s2", "esp32s3", "esp32p4", "esp32c61"],
1060        reason="512 bit keys are only supported on ESP32-S2, S3, P4, C61",
1061    )
1062    def test_burn_key_512bit_non_consecutive_blocks(self):
1063        # Burn efuses separately to test different kinds
1064        # of "key used" detection criteria
1065        self.espefuse_py(
1066            f"burn_key \
1067            BLOCK_KEY2 {IMAGES_DIR}/256bit XTS_AES_128_KEY"
1068        )
1069        self.espefuse_py(
1070            f"burn_key \
1071            BLOCK_KEY4 {IMAGES_DIR}/256bit SECURE_BOOT_DIGEST0"
1072        )
1073        self.espefuse_py(
1074            f"burn_key \
1075            BLOCK_KEY1 {IMAGES_DIR}/256bit_1_256bit_2_combined \
1076            XTS_AES_256_KEY --no-read-protect --no-write-protect"
1077        )
1078        self.espefuse_py(
1079            f"burn_key \
1080            BLOCK_KEY5 {IMAGES_DIR}/256bit USER --no-read-protect --no-write-protect"
1081        )
1082
1083        # Second half of key should burn to first available key block (BLOCK_KEY5)
1084        output = self.espefuse_py("summary -d")
1085        self.check_data_block_in_log(
1086            output, f"{IMAGES_DIR}/256bit_1", reverse_order=True
1087        )
1088        self.check_data_block_in_log(
1089            output, f"{IMAGES_DIR}/256bit_2", reverse_order=True
1090        )
1091
1092        assert (
1093            "[5 ] read_regs: bcbd11bf b8b9babb b4b5b6b7 "
1094            "b0b1b2b3 acadaeaf a8a9aaab a4a5a6a7 11a1a2a3"
1095        ) in output
1096        assert (
1097            "[7 ] read_regs: bcbd22bf b8b9babb b4b5b6b7 "
1098            "b0b1b2b3 acadaeaf a8a9aaab a4a5a6a7 22a1a2a3"
1099        ) in output
1100
1101    @pytest.mark.skipif(
1102        arg_chip not in ["esp32s2", "esp32s3", "esp32p4", "esp32c61"],
1103        reason="512 bit keys are only supported on ESP32-S2, S3, P4, C61",
1104    )
1105    def test_burn_key_512bit_non_consecutive_blocks_loop_around(self):
1106        self.espefuse_py(
1107            f"burn_key \
1108            BLOCK_KEY2 {IMAGES_DIR}/256bit XTS_AES_128_KEY \
1109            BLOCK_KEY3 {IMAGES_DIR}/256bit USER \
1110            BLOCK_KEY4 {IMAGES_DIR}/256bit SECURE_BOOT_DIGEST0 \
1111            BLOCK_KEY5 {IMAGES_DIR}/256bit SECURE_BOOT_DIGEST1 \
1112            BLOCK_KEY1 {IMAGES_DIR}/256bit_1_256bit_2_combined \
1113            XTS_AES_256_KEY --no-read-protect --no-write-protect"
1114        )
1115
1116        # Second half of key should burn to first available key block (BLOCK_KEY0)
1117        output = self.espefuse_py("summary -d")
1118        self.check_data_block_in_log(
1119            output, f"{IMAGES_DIR}/256bit_1", reverse_order=True
1120        )
1121        self.check_data_block_in_log(
1122            output, f"{IMAGES_DIR}/256bit_2", reverse_order=True
1123        )
1124
1125        assert (
1126            "[5 ] read_regs: bcbd11bf b8b9babb b4b5b6b7 b0b1b2b3 "
1127            "acadaeaf a8a9aaab a4a5a6a7 11a1a2a3"
1128        ) in output
1129        assert (
1130            "[4 ] read_regs: bcbd22bf b8b9babb b4b5b6b7 b0b1b2b3 "
1131            "acadaeaf a8a9aaab a4a5a6a7 22a1a2a3"
1132        ) in output
1133
1134    @pytest.mark.skipif(
1135        arg_chip not in ["esp32h2", "esp32c5", "esp32c5beta3", "esp32c61", "esp32p4"],
1136        reason="These chips support ECDSA_KEY",
1137    )
1138    def test_burn_key_ecdsa_key(self):
1139        self.espefuse_py(
1140            f"burn_key \
1141            BLOCK_KEY0 {S_IMAGES_DIR}/ecdsa192_secure_boot_signing_key_v2.pem \
1142            ECDSA_KEY \
1143            BLOCK_KEY1 {S_IMAGES_DIR}/ecdsa256_secure_boot_signing_key_v2.pem \
1144            ECDSA_KEY"
1145        )
1146        output = self.espefuse_py("summary -d")
1147        assert 2 == output.count(
1148            "= ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? "
1149            "?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? -/-"
1150        )
1151        assert (
1152            "[4 ] read_regs: 00000000 00000000 00000000 00000000 "
1153            "00000000 00000000 00000000 00000000"
1154        ) in output
1155        assert (
1156            "[5 ] read_regs: 00000000 00000000 00000000 00000000 "
1157            "00000000 00000000 00000000 00000000"
1158        ) in output
1159
1160    @pytest.mark.skipif(
1161        arg_chip not in ["esp32h2", "esp32c5", "esp32c5beta3", "esp32c61", "esp32p4"],
1162        reason="These chips support ECDSA_KEY",
1163    )
1164    def test_burn_key_ecdsa_key_check_byte_order(self):
1165        self.espefuse_py(
1166            f"burn_key \
1167            BLOCK_KEY0 {S_IMAGES_DIR}/ecdsa192_secure_boot_signing_key_v2.pem \
1168            ECDSA_KEY \
1169            BLOCK_KEY1 {S_IMAGES_DIR}/ecdsa256_secure_boot_signing_key_v2.pem \
1170            ECDSA_KEY \
1171            --no-read-protect"
1172        )
1173        output = self.espefuse_py("summary -d")
1174        assert (
1175            "= c8 c4 5d 62 9e 05 05 bd cb 04 a4 7c 06 f5 86 14 "
1176            "cb 23 81 23 95 b7 71 4f 00 00 00 00 00 00 00 00 R/-"
1177        ) in output
1178        assert (
1179            "= fc 6b ec 75 64 37 7d 3b 88 8d 34 05 ed 91 06 1b "
1180            "38 c2 50 84 7a 08 9d c3 66 6a 06 90 23 8b 54 b4 R/-"
1181        ) in output
1182        assert (
1183            "[4 ] read_regs: 625dc4c8 bd05059e 7ca404cb 1486f506 "
1184            "238123cb 4f71b795 00000000 00000000"
1185        ) in output
1186        assert (
1187            "[5 ] read_regs: 75ec6bfc 3b7d3764 05348d88 1b0691ed "
1188            "8450c238 c39d087a 90066a66 b4548b23"
1189        ) in output
1190
1191
1192class TestBurnBlockDataCommands(EfuseTestCase):
1193    def test_burn_block_data_check_args(self):
1194        self.espefuse_py("burn_block_data -h")
1195        blk0 = "BLOCK0"
1196        blk1 = "BLOCK1"
1197        self.espefuse_py(
1198            f"burn_block_data {blk0} {IMAGES_DIR}/224bit {blk1}",
1199            check_msg="A fatal error occurred: "
1200            "The number of block_name (2) and datafile (1) should be the same.",
1201            ret_code=2,
1202        )
1203
1204    @pytest.mark.skipif(arg_chip != "esp32", reason="ESP32-only")
1205    def test_burn_block_data_with_3_key_blocks(self):
1206        self.espefuse_py(
1207            f"burn_block_data \
1208            BLOCK0 {IMAGES_DIR}/224bit \
1209            BLOCK3 {IMAGES_DIR}/256bit"
1210        )
1211        output = self.espefuse_py("summary -d")
1212        assert (
1213            "[3 ] read_regs: a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac "
1214            "b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc"
1215        ) in output
1216        self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit")
1217
1218        self.espefuse_py(
1219            f"burn_block_data \
1220            BLOCK2 {IMAGES_DIR}/256bit_1"
1221        )
1222        self.check_data_block_in_log(
1223            self.espefuse_py("summary -d"), f"{IMAGES_DIR}/256bit_1"
1224        )
1225
1226        self.espefuse_py(
1227            f"burn_block_data \
1228            BLOCK1 {IMAGES_DIR}/256bit_2"
1229        )
1230        self.check_data_block_in_log(
1231            self.espefuse_py("summary -d"), f"{IMAGES_DIR}/256bit_2"
1232        )
1233
1234    @pytest.mark.skipif(arg_chip != "esp32c2", reason="ESP32-C2-only")
1235    def test_burn_block_data_with_1_key_block(self):
1236        self.espefuse_py(
1237            f"burn_block_data \
1238            BLOCK0 {IMAGES_DIR}/64bit \
1239            BLOCK1 {IMAGES_DIR}/96bit \
1240            BLOCK2 {IMAGES_DIR}/256bit \
1241            BLOCK3 {IMAGES_DIR}/256bit"
1242        )
1243        output = self.espefuse_py("summary -d")
1244        assert "[0 ] read_regs: 00000001 0000000c" in output
1245        assert "[1 ] read_regs: 03020100 07060504 000a0908" in output
1246        assert (
1247            "[2 ] read_regs: a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac "
1248            "b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc"
1249        ) in output
1250        assert (
1251            "[3 ] read_regs: a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac "
1252            "b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc"
1253        ) in output
1254
1255    @pytest.mark.skipif(
1256        arg_chip
1257        not in [
1258            "esp32s2",
1259            "esp32s3",
1260            "esp32s3beta1",
1261            "esp32c3",
1262            "esp32h2beta1",
1263            "esp32c6",
1264            "esp32h2",
1265            "esp32p4",
1266            "esp32c5",
1267            "esp32c5beta3",
1268            "esp32c61",
1269        ],
1270        reason="Only chip with 6 keys",
1271    )
1272    def test_burn_block_data_with_6_keys(self):
1273        self.espefuse_py(
1274            f"burn_block_data \
1275            BLOCK0 {IMAGES_DIR}/192bit \
1276            BLOCK3 {IMAGES_DIR}/256bit"
1277        )
1278        output = self.espefuse_py("summary -d")
1279        assert (
1280            "[0 ] read_regs: 00000000 07060500 00000908 00000000 13000000 00161514"
1281            in output
1282        )
1283        assert (
1284            "[3 ] read_regs: a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac "
1285            "b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc"
1286        ) in output
1287        self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit")
1288
1289        self.espefuse_py(
1290            f"burn_block_data \
1291            BLOCK10 {IMAGES_DIR}/256bit_1"
1292        )
1293        self.check_data_block_in_log(
1294            self.espefuse_py("summary -d"), f"{IMAGES_DIR}/256bit_1"
1295        )
1296
1297        self.espefuse_py(
1298            f"burn_block_data \
1299            BLOCK1 {IMAGES_DIR}/192bit \
1300            BLOCK5 {IMAGES_DIR}/256bit_1 \
1301            BLOCK6 {IMAGES_DIR}/256bit_2"
1302        )
1303        output = self.espefuse_py("summary -d")
1304        assert (
1305            "[1 ] read_regs: 00000000 07060500 00000908 00000000 13000000 00161514"
1306            in output
1307        )
1308        self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit")
1309        self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit_1", 2)
1310        self.check_data_block_in_log(output, f"{IMAGES_DIR}/256bit_2")
1311
1312    def test_burn_block_data_check_errors(self):
1313        self.espefuse_py(
1314            f"burn_block_data \
1315            BLOCK2 {IMAGES_DIR}/192bit \
1316            BLOCK2 {IMAGES_DIR}/192bit_1",
1317            check_msg="A fatal error occurred: Found repeated",
1318            ret_code=2,
1319        )
1320        self.espefuse_py(
1321            f"burn_block_data \
1322            BLOCK2 {IMAGES_DIR}/192bit \
1323            BLOCK3 {IMAGES_DIR}/192bit_1 \
1324            --offset 4",
1325            check_msg="A fatal error occurred: "
1326            "The 'offset' option is not applicable when a few blocks are passed.",
1327            ret_code=2,
1328        )
1329        self.espefuse_py(
1330            f"burn_block_data BLOCK0 {IMAGES_DIR}/192bit --offset 33",
1331            check_msg="A fatal error occurred: Invalid offset: the block0 only holds",
1332            ret_code=2,
1333        )
1334        self.espefuse_py(
1335            f"burn_block_data BLOCK0 {IMAGES_DIR}/256bit --offset 4",
1336            check_msg="A fatal error occurred: Data does not fit:",
1337            ret_code=2,
1338        )
1339
1340    @pytest.mark.skipif(arg_chip != "esp32", reason="ESP32-only")
1341    def test_burn_block_data_with_offset_for_3_key_blocks(self):
1342        offset = 1
1343        self.espefuse_py(
1344            f"burn_block_data --offset {offset} BLOCK0 {IMAGES_DIR}/192bit"
1345        )
1346
1347        offset = 4
1348        self.espefuse_py(
1349            f"burn_block_data --offset {offset} BLOCK1 {IMAGES_DIR}/192bit_1"
1350        )
1351        self.check_data_block_in_log(
1352            self.espefuse_py("summary -d"), f"{IMAGES_DIR}/192bit_1", offset=offset
1353        )
1354
1355        offset = 6
1356        self.espefuse_py(
1357            f"burn_block_data --offset {offset} BLOCK2 {IMAGES_DIR}/192bit_2"
1358        )
1359        self.check_data_block_in_log(
1360            self.espefuse_py("summary -d"), f"{IMAGES_DIR}/192bit_2", offset=offset
1361        )
1362
1363        offset = 8
1364        self.espefuse_py(
1365            f"burn_block_data --offset {offset} BLOCK3 {IMAGES_DIR}/192bit_2"
1366        )
1367        self.check_data_block_in_log(
1368            self.espefuse_py("summary -d"), f"{IMAGES_DIR}/192bit_2", offset=offset
1369        )
1370
1371    @pytest.mark.skipif(arg_chip != "esp32c2", reason="ESP32-C2-only")
1372    def test_burn_block_data_with_offset_1_key_block(self):
1373        offset = 4
1374        self.espefuse_py(f"burn_block_data --offset {offset} BLOCK1 {IMAGES_DIR}/92bit")
1375        output = self.espefuse_py("summary -d")
1376        assert "[1 ] read_regs: 00000000 03020100 00060504" in output
1377
1378        offset = 6
1379        self.espefuse_py(
1380            f"burn_block_data --offset {offset} BLOCK2 {IMAGES_DIR}/192bit_1"
1381        )
1382        output = self.espefuse_py("summary -d")
1383        assert (
1384            "[2 ] read_regs: 00000000 00110000 05000000 09080706 "
1385            "0d0c0b0a 11100f0e 15141312 00002116"
1386        ) in output
1387
1388        offset = 8
1389        self.espefuse_py(
1390            f"burn_block_data --offset {offset} BLOCK3 {IMAGES_DIR}/192bit_2"
1391        )
1392        self.check_data_block_in_log(
1393            self.espefuse_py("summary -d"), f"{IMAGES_DIR}/192bit_2", offset=offset
1394        )
1395
1396    @pytest.mark.skipif(
1397        arg_chip
1398        not in [
1399            "esp32s2",
1400            "esp32s3",
1401            "esp32s3beta1",
1402            "esp32c3",
1403            "esp32h2beta1",
1404            "esp32c6",
1405            "esp32h2",
1406            "esp32p4",
1407            "esp32c5",
1408            "esp32c5beta3",
1409            "esp32c61",
1410        ],
1411        reason="Only chips with 6 keys",
1412    )
1413    def test_burn_block_data_with_offset_6_keys(self):
1414        offset = 4
1415        self.espefuse_py(
1416            f"burn_block_data --offset {offset} BLOCK_KEY0 {IMAGES_DIR}/192bit_1"
1417        )
1418        self.check_data_block_in_log(
1419            self.espefuse_py("summary -d"), f"{IMAGES_DIR}/192bit_1", offset=offset
1420        )
1421
1422        offset = 6
1423        self.espefuse_py(
1424            f"burn_block_data --offset {offset} BLOCK_KEY1 {IMAGES_DIR}/192bit_2"
1425        )
1426        self.check_data_block_in_log(
1427            self.espefuse_py("summary -d"), f"{IMAGES_DIR}/192bit_2", offset=offset
1428        )
1429
1430        offset = 8
1431        self.espefuse_py(
1432            f"burn_block_data --offset {offset} BLOCK_KEY2 {IMAGES_DIR}/192bit_2"
1433        )
1434        self.check_data_block_in_log(
1435            self.espefuse_py("summary -d"), f"{IMAGES_DIR}/192bit_2", offset=offset
1436        )
1437
1438    @pytest.mark.skipif(
1439        arg_chip != "esp32", reason="3/4 coding scheme is only in esp32"
1440    )
1441    def test_burn_block_data_with_34_coding_scheme(self):
1442        self._set_34_coding_scheme()
1443        self.espefuse_py(
1444            f"burn_block_data BLOCK1 {IMAGES_DIR}/256bit",
1445            check_msg="A fatal error occurred: Data does not fit: "
1446            "the block1 size is 24 bytes, data file is 32 bytes, offset 0",
1447            ret_code=2,
1448        )
1449
1450        self.espefuse_py(
1451            f"burn_block_data \
1452            BLOCK1 {IMAGES_DIR}/192bit \
1453            BLOCK2 {IMAGES_DIR}/192bit_1 \
1454            BLOCK3 {IMAGES_DIR}/192bit_2"
1455        )
1456        output = self.espefuse_py("summary -d")
1457        self.check_data_block_in_log(output, f"{IMAGES_DIR}/192bit")
1458        self.check_data_block_in_log(output, f"{IMAGES_DIR}/192bit_1")
1459        self.check_data_block_in_log(output, f"{IMAGES_DIR}/192bit_2")
1460
1461    @pytest.mark.skipif(
1462        arg_chip != "esp32", reason="3/4 coding scheme is only in esp32"
1463    )
1464    def test_burn_block_data_with_34_coding_scheme_and_offset(self):
1465        self._set_34_coding_scheme()
1466
1467        offset = 4
1468        self.espefuse_py(
1469            f"burn_block_data --offset {offset} BLOCK1 {IMAGES_DIR}/128bit"
1470        )
1471        self.check_data_block_in_log(
1472            self.espefuse_py("summary -d"), f"{IMAGES_DIR}/128bit", offset=offset
1473        )
1474
1475        offset = 6
1476        self.espefuse_py(
1477            f"burn_block_data --offset {offset} BLOCK2 {IMAGES_DIR}/128bit"
1478        )
1479        self.check_data_block_in_log(
1480            self.espefuse_py("summary -d"), f"{IMAGES_DIR}/128bit", offset=offset
1481        )
1482
1483        offset = 8
1484        self.espefuse_py(
1485            f"burn_block_data --offset {offset} BLOCK3 {IMAGES_DIR}/128bit"
1486        )
1487        self.check_data_block_in_log(
1488            self.espefuse_py("summary -d"), f"{IMAGES_DIR}/128bit", offset=offset
1489        )
1490
1491
1492@pytest.mark.skipif(arg_chip != "esp32", reason="ESP32-only, supports 2 key blocks")
1493class TestBurnKeyDigestCommandsEsp32(EfuseTestCase):
1494    def test_burn_key_digest(self):
1495        self.espefuse_py("burn_key_digest -h")
1496        esp = self.get_esptool()
1497        if esp.get_chip_revision() >= 300:
1498            self.espefuse_py(
1499                f"burn_key_digest {S_IMAGES_DIR}/rsa_secure_boot_signing_key.pem"
1500            )
1501            output = self.espefuse_py("summary -d")
1502            assert (
1503                " = cb 27 91 a3 71 b0 c0 32 2b f7 37 04 78 ba 09 62 "
1504                "22 4c ab 1c f2 28 78 79 e4 29 67 3e 7d a8 44 63 R/-"
1505            ) in output
1506        else:
1507            self.espefuse_py(
1508                f"burn_key_digest {S_IMAGES_DIR}/rsa_secure_boot_signing_key.pem",
1509                check_msg="Incorrect chip revision for Secure boot v2.",
1510                ret_code=2,
1511            )
1512
1513    def test_burn_key_from_digest(self):
1514        # python espsecure.py digest_rsa_public_key
1515        # --keyfile test/{S_IMAGES_DIR}/rsa_secure_boot_signing_key.pem
1516        # -o {S_IMAGES_DIR}/rsa_public_key_digest.bin
1517        self.espefuse_py(
1518            f"burn_key \
1519            BLOCK2 {S_IMAGES_DIR}/rsa_public_key_digest.bin --no-protect-key"
1520        )
1521        output = self.espefuse_py("summary -d")
1522        assert 1 == output.count(
1523            " = cb 27 91 a3 71 b0 c0 32 2b f7 37 04 78 ba 09 62 "
1524            "22 4c ab 1c f2 28 78 79 e4 29 67 3e 7d a8 44 63 R/W"
1525        )
1526
1527    def test_burn_key_digest_with_34_coding_scheme(self):
1528        self._set_34_coding_scheme()
1529        self.espefuse_py(
1530            f"burn_key_digest {S_IMAGES_DIR}/rsa_secure_boot_signing_key.pem",
1531            check_msg="burn_key_digest only works with 'None' coding scheme",
1532            ret_code=2,
1533        )
1534
1535
1536@pytest.mark.skipif(arg_chip != "esp32c2", reason="ESP32-C2-only, supports 1 key block")
1537class TestBurnKeyDigestCommandsEsp32C2(EfuseTestCase):
1538    def test_burn_key_digest1(self):
1539        # python espsecure.py generate_signing_key --version 2
1540        # secure_images/ecdsa192_secure_boot_signing_key_v2.pem --scheme ecdsa192
1541        self.espefuse_py("burn_key_digest -h")
1542        self.espefuse_py(
1543            f"burn_key_digest {S_IMAGES_DIR}/ecdsa192_secure_boot_signing_key_v2.pem"
1544        )
1545        output = self.espefuse_py("summary -d")
1546        assert " = 1e 3d 15 16 96 ca 7f 22 a6 e8 8b d5 27 a0 3b 3b R/-" in output
1547        assert (
1548            " = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 "
1549            "1e 3d 15 16 96 ca 7f 22 a6 e8 8b d5 27 a0 3b 3b R/-"
1550        ) in output
1551
1552    def test_burn_key_digest2(self):
1553        # python espsecure.py generate_signing_key --version 2
1554        # secure_images/ecdsa256_secure_boot_signing_key_v2.pem   --scheme ecdsa256
1555        self.espefuse_py("burn_key_digest -h")
1556        self.espefuse_py(
1557            f"burn_key_digest {S_IMAGES_DIR}/ecdsa256_secure_boot_signing_key_v2.pem"
1558        )
1559        output = self.espefuse_py("summary -d")
1560        assert " = bf 0f 6a f6 8b d3 6d 8b 53 b3 da a9 33 f6 0a 04 R/-" in output
1561        assert (
1562            " = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 "
1563            "bf 0f 6a f6 8b d3 6d 8b 53 b3 da a9 33 f6 0a 04 R/-"
1564        ) in output
1565
1566    def test_burn_key_from_digest1(self):
1567        # python espsecure.py digest_sbv2_public_key --keyfile
1568        # secure_images/ecdsa192_secure_boot_signing_key_v2.pem
1569        # -o secure_images/ecdsa192_public_key_digest_v2.bin
1570        self.espefuse_py(
1571            "burn_key BLOCK_KEY0 "
1572            f"{S_IMAGES_DIR}/ecdsa192_public_key_digest_v2.bin SECURE_BOOT_DIGEST"
1573        )
1574        output = self.espefuse_py("summary -d")
1575        assert (
1576            " = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 "
1577            "1e 3d 15 16 96 ca 7f 22 a6 e8 8b d5 27 a0 3b 3b R/-"
1578        ) in output
1579
1580    def test_burn_key_from_digest2(self):
1581        # python espsecure.py digest_sbv2_public_key --keyfile
1582        # secure_images/ecdsa256_secure_boot_signing_key_v2.pem
1583        # -o secure_images/ecdsa256_public_key_digest_v2.bin
1584        self.espefuse_py(
1585            "burn_key BLOCK_KEY0 "
1586            f"{S_IMAGES_DIR}/ecdsa256_public_key_digest_v2.bin SECURE_BOOT_DIGEST"
1587        )
1588        output = self.espefuse_py("summary -d")
1589        assert (
1590            " = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 "
1591            "bf 0f 6a f6 8b d3 6d 8b 53 b3 da a9 33 f6 0a 04 R/-"
1592        ) in output
1593
1594
1595@pytest.mark.skipif(
1596    arg_chip
1597    not in [
1598        "esp32s2",
1599        "esp32s3",
1600        "esp32s3beta1",
1601        "esp32c3",
1602        "esp32h2beta1",
1603        "esp32c6",
1604        "esp32h2",
1605        "esp32p4",
1606        "esp32c5",
1607        "esp32c5beta3",
1608        "esp32c61",
1609    ],
1610    reason="Supports 6 key blocks",
1611)
1612class TestBurnKeyDigestCommands(EfuseTestCase):
1613    def test_burn_key_digest(self):
1614        self.espefuse_py("burn_key_digest -h")
1615        self.espefuse_py(
1616            f"burn_key_digest \
1617            BLOCK_KEY0 \
1618            {S_IMAGES_DIR}/rsa_secure_boot_signing_key.pem SECURE_BOOT_DIGEST0 \
1619            BLOCK_KEY1 \
1620            {S_IMAGES_DIR}/rsa_secure_boot_signing_key2.pem SECURE_BOOT_DIGEST1 \
1621            BLOCK_KEY2 ",
1622            check_msg="A fatal error occurred: The number of blocks (3), "
1623            "datafile (2) and keypurpose (2) should be the same.",
1624            ret_code=2,
1625        )
1626        self.espefuse_py(
1627            f"burn_key_digest \
1628            BLOCK_KEY0 \
1629            {S_IMAGES_DIR}/rsa_secure_boot_signing_key.pem SECURE_BOOT_DIGEST0 \
1630            BLOCK_KEY1 \
1631            {S_IMAGES_DIR}/rsa_secure_boot_signing_key2.pem SECURE_BOOT_DIGEST1 \
1632            BLOCK_KEY2 \
1633            {S_IMAGES_DIR}/rsa_secure_boot_signing_key2.pem SECURE_BOOT_DIGEST2"
1634        )
1635        output = self.espefuse_py("summary -d")
1636        assert 1 == output.count(
1637            " = cb 27 91 a3 71 b0 c0 32 2b f7 37 04 78 ba 09 62 "
1638            "22 4c ab 1c f2 28 78 79 e4 29 67 3e 7d a8 44 63 R/-"
1639        )
1640        assert 2 == output.count(
1641            " = 90 1a 74 09 23 8d 52 d4 cb f9 6f 56 3f b3 f4 29 "
1642            "6d ab d6 6a 33 f5 3b 15 ee cd 8c b3 e7 ec 45 d3 R/-"
1643        )
1644
1645    def test_burn_key_from_digest(self):
1646        #  python espsecure.py digest_rsa_public_key
1647        # --keyfile test/secure_images/rsa_secure_boot_signing_key.pem
1648        # -o secure_images/rsa_public_key_digest.bin
1649        self.espefuse_py(
1650            f"burn_key \
1651            BLOCK_KEY0 {S_IMAGES_DIR}/rsa_public_key_digest.bin SECURE_BOOT_DIGEST0"
1652        )
1653        output = self.espefuse_py("summary -d")
1654        assert 1 == output.count(
1655            " = cb 27 91 a3 71 b0 c0 32 2b f7 37 04 78 ba 09 62 "
1656            "22 4c ab 1c f2 28 78 79 e4 29 67 3e 7d a8 44 63 R/-"
1657        )
1658
1659        self.espefuse_py(
1660            f"burn_key_digest \
1661            BLOCK_KEY1 \
1662            {S_IMAGES_DIR}/rsa_secure_boot_signing_key.pem SECURE_BOOT_DIGEST1"
1663        )
1664        output = self.espefuse_py("summary -d")
1665        assert 2 == output.count(
1666            " = cb 27 91 a3 71 b0 c0 32 2b f7 37 04 78 ba 09 62 "
1667            "22 4c ab 1c f2 28 78 79 e4 29 67 3e 7d a8 44 63 R/-"
1668        )
1669
1670
1671class TestBurnBitCommands(EfuseTestCase):
1672    @pytest.mark.skipif(arg_chip != "esp32", reason="ESP32-only")
1673    def test_burn_bit_for_chips_with_3_key_blocks(self):
1674        self.espefuse_py("burn_bit -h")
1675        self.espefuse_py("burn_bit BLOCK3 0 1 2 4 8 16 32 64 96 128 160 192 224 255")
1676        self.espefuse_py(
1677            "summary",
1678            check_msg="17 01 01 00 01 00 00 00 01 00 00 00 01 00 00 "
1679            "00 01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 80",
1680        )
1681
1682        self.espefuse_py(
1683            "burn_bit BLOCK3 3 5 6 7 9 10 11 12 13 14 15 31 63 95 127 159 191 223 254"
1684        )
1685        self.espefuse_py(
1686            "summary",
1687            check_msg="ff ff 01 80 01 00 00 80 01 00 00 80 01 "
1688            "00 00 80 01 00 00 80 01 00 00 80 01 00 00 80 01 00 00 c0",
1689        )
1690
1691    @pytest.mark.skipif(arg_chip != "esp32c2", reason="ESP32-C2-only")
1692    def test_burn_bit_for_chips_with_1_key_block(self):
1693        self.espefuse_py("burn_bit -h")
1694        self.espefuse_py("burn_bit BLOCK3 0 1 2 4 8 16 32 64 96 128 160 192 224 255")
1695        self.espefuse_py(
1696            "summary",
1697            check_msg="17 01 01 00 01 00 00 00 01 00 00 00 01 00 "
1698            "00 00 01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 80",
1699        )
1700        self.espefuse_py(
1701            "burn_bit BLOCK3 100",
1702            check_msg="Burn into BLOCK_KEY0 is forbidden "
1703            "(RS coding scheme does not allow this)",
1704            ret_code=2,
1705        )
1706
1707        self.espefuse_py("burn_bit BLOCK0 0 1 2")
1708        self.espefuse_py("summary", check_msg="[0 ] read_regs: 00000007 00000000")
1709
1710    @pytest.mark.skipif(
1711        arg_chip
1712        not in [
1713            "esp32s2",
1714            "esp32s3",
1715            "esp32s3beta1",
1716            "esp32c3",
1717            "esp32h2beta1",
1718            "esp32c6",
1719            "esp32h2",
1720            "esp32p4",
1721            "esp32c5",
1722            "esp32c5beta3",
1723            "esp32c61",
1724        ],
1725        reason="Only chip with 6 keys",
1726    )
1727    def test_burn_bit_for_chips_with_6_key_blocks(self):
1728        self.espefuse_py("burn_bit -h")
1729        self.espefuse_py("burn_bit BLOCK3 0 1 2 4 8 16 32 64 96 128 160 192 224 255")
1730        self.espefuse_py(
1731            "summary",
1732            check_msg="17 01 01 00 01 00 00 00 01 00 00 00 01 00 "
1733            "00 00 01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 80",
1734        )
1735        self.espefuse_py(
1736            "burn_bit BLOCK3 100",
1737            check_msg="Burn into BLOCK_USR_DATA is forbidden "
1738            "(RS coding scheme does not allow this)",
1739            ret_code=2,
1740        )
1741
1742        self.espefuse_py("burn_bit BLOCK0 13")
1743        self.espefuse_py(
1744            "summary",
1745            check_msg="[0 ] read_regs: 00002000 00000000 00000000 "
1746            "00000000 00000000 00000000",
1747        )
1748
1749        self.espefuse_py("burn_bit BLOCK0 24")
1750        self.espefuse_py(
1751            "summary",
1752            check_msg="[0 ] read_regs: 01002000 00000000 00000000 "
1753            "00000000 00000000 00000000",
1754        )
1755
1756    @pytest.mark.skipif(
1757        arg_chip != "esp32", reason="3/4 coding scheme is only in esp32"
1758    )
1759    def test_burn_bit_with_34_coding_scheme(self):
1760        self._set_34_coding_scheme()
1761        self.espefuse_py("burn_bit BLOCK3 0 1 2 4 8 16 32 64 96 128 160 191")
1762        self.espefuse_py(
1763            "summary",
1764            check_msg="17 01 01 00 01 00 00 00 01 00 00 00 01 00 "
1765            "00 00 01 00 00 00 01 00 00 80",
1766        )
1767        self.espefuse_py(
1768            "burn_bit BLOCK3 17",
1769            check_msg="Burn into BLOCK3 is forbidden "
1770            "(3/4 coding scheme does not allow this).",
1771            ret_code=2,
1772        )
1773
1774    @pytest.mark.skipif(arg_chip != "esp32", reason="ESP32-only")
1775    def test_burn_bit_with_none_recovery_coding_scheme(self):
1776        self._set_none_recovery_coding_scheme()
1777        self.espefuse_py("burn_bit BLOCK3 0 1 2 4 8 16 32 64 96 128 160 192 224 255")
1778        self.espefuse_py(
1779            "summary",
1780            check_msg="17 01 01 00 01 00 00 00 01 00 00 00 01 00 00 "
1781            "00 01 00 00 00 01 00 00 00 01 00 00 00 01 00 00 80",
1782        )
1783
1784
1785@pytest.mark.skipif(
1786    arg_chip != "esp32", reason="Tests are only for esp32. (TODO: add for all chips)"
1787)
1788class TestByteOrderBurnKeyCommand(EfuseTestCase):
1789    def test_1_secure_boot_v1(self):
1790        if arg_chip == "esp32":
1791            self.espefuse_py(
1792                f"burn_key \
1793                flash_encryption {IMAGES_DIR}/256bit \
1794                secure_boot_v1 {IMAGES_DIR}/256bit_1 --no-protect-key"
1795            )
1796            output = self.espefuse_py("summary -d")
1797            self.check_data_block_in_log(
1798                output, f"{IMAGES_DIR}/256bit", reverse_order=True
1799            )
1800            self.check_data_block_in_log(
1801                output, f"{IMAGES_DIR}/256bit_1", reverse_order=True
1802            )
1803
1804            self.espefuse_py(
1805                f"burn_key \
1806                flash_encryption  {IMAGES_DIR}/256bit \
1807                secure_boot_v1    {IMAGES_DIR}/256bit_1"
1808            )
1809            output = self.espefuse_py("summary -d")
1810            assert (
1811                "[1 ] read_regs: 00000000 00000000 00000000 00000000 "
1812                "00000000 00000000 00000000 00000000"
1813            ) in output
1814            assert (
1815                "[2 ] read_regs: 00000000 00000000 00000000 00000000 "
1816                "00000000 00000000 00000000 00000000"
1817            ) in output
1818            assert (
1819                "[3 ] read_regs: 00000000 00000000 00000000 00000000 "
1820                "00000000 00000000 00000000 00000000"
1821            ) in output
1822
1823    def test_2_secure_boot_v1(self):
1824        if arg_chip == "esp32":
1825            self.espefuse_py(
1826                f"burn_key \
1827                flash_encryption {IMAGES_DIR}/256bit \
1828                secure_boot_v2 {IMAGES_DIR}/256bit_1 --no-protect-key"
1829            )
1830            output = self.espefuse_py("summary -d")
1831            self.check_data_block_in_log(
1832                output, f"{IMAGES_DIR}/256bit", reverse_order=True
1833            )
1834            self.check_data_block_in_log(
1835                output, f"{IMAGES_DIR}/256bit_1", reverse_order=False
1836            )
1837
1838            self.espefuse_py(
1839                f"burn_key \
1840                flash_encryption {IMAGES_DIR}/256bit \
1841                secure_boot_v2 {IMAGES_DIR}/256bit_1"
1842            )
1843            output = self.espefuse_py("summary -d")
1844            assert (
1845                "[1 ] read_regs: 00000000 00000000 00000000 00000000 "
1846                "00000000 00000000 00000000 00000000"
1847            ) in output
1848            self.check_data_block_in_log(
1849                output, f"{IMAGES_DIR}/256bit_1", reverse_order=False
1850            )
1851
1852
1853class TestExecuteScriptsCommands(EfuseTestCase):
1854    @classmethod
1855    def setup_class(self):
1856        # Save the current working directory to be restored later
1857        self.stored_dir = os.getcwd()
1858
1859    @classmethod
1860    def teardown_class(self):
1861        # Restore the stored working directory
1862        os.chdir(self.stored_dir)
1863
1864    @pytest.mark.skipif(
1865        arg_chip in ["esp32c2", "esp32p4"],
1866        reason="These chips do not have eFuses used in this test",
1867    )
1868    def test_execute_scripts_with_check_that_only_one_burn(self):
1869        self.espefuse_py("execute_scripts -h")
1870        name = arg_chip if arg_chip in ["esp32", "esp32c2"] else "esp32xx"
1871        os.chdir(os.path.join(TEST_DIR, "efuse_scripts", name))
1872        self.espefuse_py("execute_scripts execute_efuse_script2.py")
1873
1874    @pytest.mark.skipif(
1875        arg_chip in ["esp32c2", "esp32p4"],
1876        reason="These chips do not have eFuses used in this test",
1877    )
1878    def test_execute_scripts_with_check(self):
1879        self.espefuse_py("execute_scripts -h")
1880        name = arg_chip if arg_chip in ["esp32", "esp32c2"] else "esp32xx"
1881        os.chdir(os.path.join(TEST_DIR, "efuse_scripts", name))
1882        self.espefuse_py("execute_scripts execute_efuse_script.py")
1883
1884    def test_execute_scripts_with_index_and_config(self):
1885        os.chdir(TEST_DIR)
1886        if arg_chip in ["esp32", "esp32c2"]:
1887            cmd = f"execute_scripts {EFUSE_S_DIR}/efuse_burn1.py --index 10 \
1888            --configfiles {EFUSE_S_DIR}/esp32/config1.json"
1889        else:
1890            cmd = f"execute_scripts {EFUSE_S_DIR}/efuse_burn1.py --index 10 \
1891            --configfiles {EFUSE_S_DIR}/esp32xx/config1.json"
1892        self.espefuse_py(cmd)
1893        output = self.espefuse_py("summary -d")
1894        if arg_chip in ["esp32", "esp32c2"]:
1895            assert (
1896                "[3 ] read_regs: e00007ff 00000000 00000000 00000000 "
1897                "00000000 00000000 00000000 00000000"
1898            ) in output
1899        else:
1900            assert (
1901                "[8 ] read_regs: e00007ff 00000000 00000000 00000000 "
1902                "00000000 00000000 00000000 00000000"
1903            ) in output
1904
1905    def test_execute_scripts_nesting(self):
1906        os.chdir(TEST_DIR)
1907        if arg_chip in ["esp32", "esp32c2"]:
1908            cmd = f"execute_scripts {EFUSE_S_DIR}/efuse_burn2.py --index 28 \
1909            --configfiles {EFUSE_S_DIR}/esp32/config2.json"
1910        else:
1911            cmd = f"execute_scripts {EFUSE_S_DIR}/efuse_burn2.py --index 28 \
1912            --configfiles {EFUSE_S_DIR}/esp32xx/config2.json"
1913        self.espefuse_py(cmd)
1914        output = self.espefuse_py("summary -d")
1915        if arg_chip in ["esp32", "esp32c2"]:
1916            assert (
1917                "[2 ] read_regs: 10000000 00000000 00000000 00000000 "
1918                "00000000 00000000 00000000 00000000"
1919            ) in output
1920            assert (
1921                "[3 ] read_regs: ffffffff 00000000 00000000 00000000 "
1922                "00000000 00000000 00000000 00000000"
1923            ) in output
1924        else:
1925            assert (
1926                "[7 ] read_regs: 10000000 00000000 00000000 00000000 "
1927                "00000000 00000000 00000000 00000000"
1928            ) in output
1929            assert (
1930                "[8 ] read_regs: ffffffff 00000000 00000000 00000000 "
1931                "00000000 00000000 00000000 00000000"
1932            ) in output
1933
1934
1935class TestMultipleCommands(EfuseTestCase):
1936    def test_multiple_cmds_help(self):
1937        if arg_chip == "esp32c2":
1938            command1 = (
1939                f"burn_key_digest {S_IMAGES_DIR}"
1940                "/ecdsa256_secure_boot_signing_key_v2.pem"
1941            )
1942            command2 = (
1943                f"burn_key BLOCK_KEY0 {IMAGES_DIR}/128bit_key "
1944                "XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS"
1945            )
1946        elif arg_chip == "esp32":
1947            command1 = f"burn_key_digest {S_IMAGES_DIR}/rsa_secure_boot_signing_key.pem"
1948            command2 = f"burn_key flash_encryption {IMAGES_DIR}/256bit"
1949        else:
1950            command1 = f"burn_key_digest BLOCK_KEY0 \
1951            {S_IMAGES_DIR}/rsa_secure_boot_signing_key.pem SECURE_BOOT_DIGEST0"
1952            command2 = f"burn_key BLOCK_KEY0 \
1953            {S_IMAGES_DIR}/rsa_public_key_digest.bin SECURE_BOOT_DIGEST0"
1954
1955        self.espefuse_py(
1956            f"-h {command1} {command2}",
1957            check_msg="usage: __main__.py [-h]",
1958        )
1959
1960        self.espefuse_py(
1961            f"{command1} -h {command2}",
1962            check_msg="usage: __main__.py burn_key_digest [-h]",
1963        )
1964
1965        self.espefuse_py(
1966            f"{command1} {command2} -h",
1967            check_msg="usage: __main__.py burn_key [-h]",
1968        )
1969
1970    @pytest.mark.skipif(
1971        arg_chip != "esp32c2", reason="For this chip, FE and SB keys go into one BLOCK"
1972    )
1973    def test_1_esp32c2(self):
1974        self.espefuse_py(
1975            f"burn_key_digest {S_IMAGES_DIR}/ecdsa256_secure_boot_signing_key_v2.pem \
1976            burn_key BLOCK_KEY0 {IMAGES_DIR}/128bit_key \
1977            XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS --no-read-protect \
1978            summary"
1979        )
1980        output = self.espefuse_py("summary -d")
1981        assert (
1982            "[3 ] read_regs: 0c0d0e0f 08090a0b 04050607 00010203 "
1983            "f66a0fbf 8b6dd38b a9dab353 040af633"
1984        ) in output
1985        assert " = 0f 0e 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00 R/-" in output
1986        assert " = bf 0f 6a f6 8b d3 6d 8b 53 b3 da a9 33 f6 0a 04 R/-" in output
1987
1988    @pytest.mark.skipif(
1989        arg_chip != "esp32c2", reason="For this chip, FE and SB keys go into one BLOCK"
1990    )
1991    def test_2_esp32c2(self):
1992        self.espefuse_py(
1993            f"burn_key_digest {S_IMAGES_DIR}/ecdsa256_secure_boot_signing_key_v2.pem \
1994            burn_key BLOCK_KEY0 \
1995            {IMAGES_DIR}/128bit_key XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS \
1996            summary"
1997        )
1998        output = self.espefuse_py("summary -d")
1999        assert (
2000            "[3 ] read_regs: 00000000 00000000 00000000 00000000 "
2001            "f66a0fbf 8b6dd38b a9dab353 040af633"
2002        ) in output
2003        assert " = ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? -/-" in output
2004        assert " = bf 0f 6a f6 8b d3 6d 8b 53 b3 da a9 33 f6 0a 04 R/-" in output
2005
2006    def test_burn_bit(self):
2007        if arg_chip == "esp32":
2008            self._set_34_coding_scheme()
2009        self.espefuse_py(
2010            "burn_bit BLOCK2 0 1 2 3 \
2011            burn_bit BLOCK2 4 5 6 7 \
2012            burn_bit BLOCK2 8 9 10 11 \
2013            burn_bit BLOCK2 12 13 14 15 \
2014            summary"
2015        )
2016        output = self.espefuse_py("summary -d")
2017        assert "[2 ] read_regs: 0000ffff 00000000" in output
2018
2019    def test_not_burn_cmds(self):
2020        self.espefuse_py(
2021            "summary \
2022            dump \
2023            get_custom_mac \
2024            adc_info \
2025            check_error"
2026        )
2027
2028
2029@pytest.mark.skipif(
2030    arg_chip not in ["esp32c3", "esp32c6", "esp32h2", "esp32s3"],
2031    reason="These chips have a hardware bug that limits the use of the KEY5",
2032)
2033class TestKeyPurposes(EfuseTestCase):
2034    def test_burn_xts_aes_key_purpose(self):
2035        self.espefuse_py(
2036            "burn_efuse KEY_PURPOSE_5 XTS_AES_128_KEY",
2037            check_msg="A fatal error occurred: "
2038            "KEY_PURPOSE_5 can not have XTS_AES_128_KEY "
2039            "key due to a hardware bug (please see TRM for more details)",
2040            ret_code=2,
2041        )
2042
2043    @pytest.mark.skipif(
2044        arg_chip != "esp32h2", reason="esp32h2 can not have ECDSA key in KEY5"
2045    )
2046    def test_burn_ecdsa_key_purpose(self):
2047        self.espefuse_py(
2048            "burn_efuse KEY_PURPOSE_5 ECDSA_KEY",
2049            check_msg="A fatal error occurred: "
2050            "KEY_PURPOSE_5 can not have ECDSA_KEY "
2051            "key due to a hardware bug (please see TRM for more details)",
2052            ret_code=2,
2053        )
2054
2055    def test_burn_xts_aes_key(self):
2056        self.espefuse_py(
2057            f"burn_key \
2058            BLOCK_KEY5 {IMAGES_DIR}/256bit XTS_AES_128_KEY",
2059            check_msg="A fatal error occurred: "
2060            "KEY_PURPOSE_5 can not have XTS_AES_128_KEY "
2061            "key due to a hardware bug (please see TRM for more details)",
2062            ret_code=2,
2063        )
2064
2065    @pytest.mark.skipif(
2066        arg_chip != "esp32h2", reason="esp32h2 can not have ECDSA key in KEY5"
2067    )
2068    def test_burn_ecdsa_key(self):
2069        self.espefuse_py(
2070            f"burn_key \
2071            BLOCK_KEY5 {S_IMAGES_DIR}/ecdsa192_secure_boot_signing_key_v2.pem \
2072            ECDSA_KEY",
2073            check_msg="A fatal error occurred: "
2074            "KEY_PURPOSE_5 can not have ECDSA_KEY "
2075            "key due to a hardware bug (please see TRM for more details)",
2076            ret_code=2,
2077        )
2078
2079
2080class TestPostponedEfuses(EfuseTestCase):
2081    def test_postpone_efuses(self):
2082        if arg_chip == "esp32":
2083            cmd = f"--postpone \
2084                    burn_efuse UART_DOWNLOAD_DIS 1 \
2085                    burn_key BLOCK1 {IMAGES_DIR}/256bit \
2086                    burn_efuse ABS_DONE_1 1 FLASH_CRYPT_CNT 1"
2087            num = 1
2088        else:
2089            sb_digest_name = (
2090                "SECURE_BOOT_DIGEST" if arg_chip == "esp32c2" else "SECURE_BOOT_DIGEST0"
2091            )
2092            cmd = f"--postpone \
2093                burn_efuse ENABLE_SECURITY_DOWNLOAD 1 DIS_DOWNLOAD_MODE 1 \
2094                SECURE_VERSION 1 \
2095                burn_key BLOCK_KEY0 {IMAGES_DIR}/256bit {sb_digest_name} \
2096                burn_efuse SPI_BOOT_CRYPT_CNT 1 SECURE_BOOT_EN 1"
2097            num = 3 if arg_chip == "esp32c2" else 4
2098        output = self.espefuse_py(cmd)
2099        assert f"BURN BLOCK{num}  - OK" in output
2100        assert "BURN BLOCK0  - OK" in output
2101        assert "Burn postponed efuses from BLOCK0" in output
2102        assert "BURN BLOCK0  - OK" in output
2103        assert "Successful" in output
2104
2105
2106class TestCSVEfuseTable(EfuseTestCase):
2107    def test_extend_efuse_table_with_csv_file(self):
2108        csv_file = f"{IMAGES_DIR}/esp_efuse_custom_table.csv"
2109        output = self.espefuse_py(f" --extend-efuse-table {csv_file} summary")
2110        assert "MODULE_VERSION (BLOCK3)" in output
2111        assert "DEVICE_ROLE (BLOCK3)" in output
2112        assert "SETTING_2 (BLOCK3)" in output
2113        assert "ID_NUM_0 (BLOCK3)" in output
2114        assert "ID_NUM_1 (BLOCK3)" in output
2115        assert "ID_NUM_2 (BLOCK3)" in output
2116        assert "CUSTOM_SECURE_VERSION (BLOCK3)" in output
2117        assert "ID_NUMK_0 (BLOCK3)" in output
2118        assert "ID_NUMK_1 (BLOCK3)" in output
2119
2120        self.espefuse_py(
2121            f"--extend-efuse-table {csv_file} burn_efuse \
2122                         MODULE_VERSION 1 \
2123                         CUSTOM_SECURE_VERSION 4 \
2124                         SETTING_1_ALT_NAME 7 \
2125                         SETTING_2 1 \
2126                         ID_NUM_0 1 \
2127                         ID_NUM_1 1 \
2128                         ID_NUM_2 1 \
2129                         MY_ID_NUMK_0 1 \
2130                         MY_ID_NUMK_1 1 \
2131                         MY_DATA_FIELD1 1"
2132        )
2133