11import asyncio
2+ import binascii
23import logging
34import os
45import shlex
56import socket
67import typing as t
8+ from dataclasses import dataclass
79
810from pytest_embedded .log import DuplicateStdoutPopen
911from qemu .qmp import QMPClient
1416 from .app import QemuApp
1517
1618
19+ @dataclass
20+ class QemuTarget :
21+ strap_mode : str
22+ default_efuse : bytes
23+
24+
25+ QEMU_TARGETS : dict [str , QemuTarget ] = {
26+ 'esp32' : QemuTarget (
27+ strap_mode = '0x0F' ,
28+ default_efuse = binascii .unhexlify (
29+ '00000000000000000000000000800000000000000000100000000000000000000000000000000000'
30+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
31+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
32+ '00000000'
33+ ),
34+ ),
35+ 'esp32c3' : QemuTarget (
36+ strap_mode = '0x02' ,
37+ default_efuse = binascii .unhexlify (
38+ '00000000000000000000000000000000000000000000000000000000000000000000000000000c00'
39+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
40+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
41+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
42+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
43+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
44+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
45+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
46+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
47+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
48+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
49+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
50+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
51+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
52+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
53+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
54+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
55+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
56+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
57+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
58+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
59+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
60+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
61+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
62+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
63+ '000000000000000000000000000000000000000000000000'
64+ ),
65+ ),
66+ 'esp32s3' : QemuTarget (
67+ strap_mode = '0x07' ,
68+ default_efuse = binascii .unhexlify (
69+ '00000000000000000000000000000000000000000000000000000000000000000000000000000c00'
70+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
71+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
72+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
73+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
74+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
75+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
76+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
77+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
78+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
79+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
80+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
81+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
82+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
83+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
84+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
85+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
86+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
87+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
88+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
89+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
90+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
91+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
92+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
93+ '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
94+ '000000000000000000000000000000000000000000000000'
95+ ),
96+ ),
97+ }
98+
99+
17100class Qemu (DuplicateStdoutPopen ):
18101 """
19102 QEMU class
@@ -26,9 +109,7 @@ class Qemu(DuplicateStdoutPopen):
26109 QEMU_DEFAULT_ARGS = '-nographic -machine esp32'
27110 QEMU_DEFAULT_FMT = '-nographic -machine {}'
28111
29- QEMU_STRAP_MODE_FMT = '-global driver=esp32.gpio,property=strap_mode,value={}'
30- QEMU_SERIAL_TCP_FMT = '-serial tcp::{},server,nowait'
31-
112+ QEMU_STRAP_MODE_FMT = 'driver={}.gpio,property=strap_mode,value={}'
32113 QEMU_DEFAULT_QMP_FMT = '-qmp tcp:127.0.0.1:{},server,wait=off'
33114
34115 def __init__ (
@@ -37,6 +118,7 @@ def __init__(
37118 qemu_prog_path : str | None = None ,
38119 qemu_cli_args : str | None = None ,
39120 qemu_extra_args : str | None = None ,
121+ qemu_efuse_path : str | None = None ,
40122 app : t .Optional ['QemuApp' ] = None ,
41123 ** kwargs ,
42124 ):
@@ -55,11 +137,28 @@ def __init__(
55137
56138 qemu_prog_path = qemu_prog_path or self .qemu_prog_name
57139
140+ self .current_qemu_executable_path = qemu_prog_path
141+ self .image_path = image_path
142+ self .efuse_path = qemu_efuse_path
143+
58144 if qemu_cli_args :
59145 qemu_cli_args = qemu_cli_args .strip ('"' ).strip ("'" )
60146 qemu_cli_args = shlex .split (qemu_cli_args or self .qemu_default_args )
61147 qemu_extra_args = shlex .split (qemu_extra_args or '' )
62148
149+ if self .efuse_path :
150+ logging .debug ('The eFuse file will be saved to: %s' , self .efuse_path )
151+ with open (self .efuse_path , 'wb' ) as f :
152+ f .write (QEMU_TARGETS [self .app .target ].default_efuse )
153+ qemu_extra_args += [
154+ '-global' ,
155+ self .QEMU_STRAP_MODE_FMT .format (self .app .target , QEMU_TARGETS [self .app .target ].strap_mode ),
156+ '-drive' ,
157+ f'file={ self .efuse_path } ,if=none,format=raw,id=efuse' ,
158+ '-global' ,
159+ f'driver=nvram.{ self .app .target } .efuse,property=drive,value=efuse' ,
160+ ]
161+
63162 self .qmp_addr = None
64163 self .qmp_port = None
65164
@@ -87,6 +186,49 @@ def __init__(
87186 ** kwargs ,
88187 )
89188
189+ def execute_efuse_command (self , command : str ):
190+ import espefuse
191+ import pexpect
192+
193+ with socket .socket (socket .AF_INET , socket .SOCK_STREAM ) as s :
194+ s .bind (('127.0.0.1' , 0 ))
195+ _ , available_port = s .getsockname ()
196+
197+ run_qemu_command = [
198+ '-nographic' ,
199+ '-machine' ,
200+ self .app .target ,
201+ '-drive' ,
202+ f'file={ self .image_path } ,if=mtd,format=raw' ,
203+ '-global' ,
204+ self .QEMU_STRAP_MODE_FMT .format (self .app .target , QEMU_TARGETS [self .app .target ].strap_mode ),
205+ '-drive' ,
206+ f'file={ self .efuse_path } ,if=none,format=raw,id=efuse' ,
207+ '-global' ,
208+ f'driver=nvram.{ self .app .target } .efuse,property=drive,value=efuse' ,
209+ '-serial' ,
210+ f'tcp::{ available_port } ,server,nowait' ,
211+ ]
212+ try :
213+ child = pexpect .spawn (self .current_qemu_executable_path , run_qemu_command )
214+ res = shlex .split (command )
215+ child .expect ('qemu' )
216+
217+ res = [r for r in res if r != '--do-not-confirm' ]
218+ espefuse .main (
219+ [
220+ '--port' ,
221+ f'socket://localhost:{ available_port } ' ,
222+ '--before' ,
223+ 'no_reset' ,
224+ '--do-not-confirm' ,
225+ * res ,
226+ ]
227+ )
228+ self ._hard_reset ()
229+ finally :
230+ child .terminate ()
231+
90232 @property
91233 def qemu_prog_name (self ):
92234 if self .app :
0 commit comments