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,8 @@ 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={}'
112+ QEMU_STRAP_MODE_FMT = 'driver={} .gpio,property=strap_mode,value={}'
30113 QEMU_SERIAL_TCP_FMT = '-serial tcp::{},server,nowait'
31-
32114 QEMU_DEFAULT_QMP_FMT = '-qmp tcp:127.0.0.1:{},server,wait=off'
33115
34116 def __init__ (
@@ -37,6 +119,7 @@ def __init__(
37119 qemu_prog_path : str | None = None ,
38120 qemu_cli_args : str | None = None ,
39121 qemu_extra_args : str | None = None ,
122+ qemu_efuse_path : str | None = None ,
40123 app : t .Optional ['QemuApp' ] = None ,
41124 ** kwargs ,
42125 ):
@@ -53,13 +136,28 @@ def __init__(
53136 if not os .path .exists (image_path ):
54137 raise ValueError (f"QEMU image path doesn't exist: { image_path } " )
55138
56- qemu_prog_path = qemu_prog_path or self .qemu_prog_name
139+ self .qemu_prog_path = qemu_prog_path or self .qemu_prog_name
140+ self .image_path = image_path
141+ self .efuse_path = qemu_efuse_path
57142
58143 if qemu_cli_args :
59144 qemu_cli_args = qemu_cli_args .strip ('"' ).strip ("'" )
60145 qemu_cli_args = shlex .split (qemu_cli_args or self .qemu_default_args )
61146 qemu_extra_args = shlex .split (qemu_extra_args or '' )
62147
148+ if self .efuse_path :
149+ logging .debug ('The eFuse file will be saved to: %s' , self .efuse_path )
150+ with open (self .efuse_path , 'wb' ) as f :
151+ f .write (QEMU_TARGETS [self .app .target ].default_efuse )
152+ qemu_extra_args += [
153+ '-global' ,
154+ self .QEMU_STRAP_MODE_FMT .format (self .app .target , QEMU_TARGETS [self .app .target ].strap_mode ),
155+ '-drive' ,
156+ f'file={ self .efuse_path } ,if=none,format=raw,id=efuse' ,
157+ '-global' ,
158+ f'driver=nvram.{ self .app .target } .efuse,property=drive,value=efuse' ,
159+ ]
160+
63161 self .qmp_addr = None
64162 self .qmp_port = None
65163
@@ -83,10 +181,59 @@ def __init__(
83181 qemu_cli_args += shlex .split (self .QEMU_DEFAULT_QMP_FMT .format (self .qmp_port ))
84182
85183 super ().__init__ (
86- cmd = [qemu_prog_path , * qemu_cli_args , * qemu_extra_args , '-drive' , f'file={ image_path } ,if=mtd,format=raw' ],
184+ cmd = [
185+ self .qemu_prog_path ,
186+ * qemu_cli_args ,
187+ * qemu_extra_args ,
188+ '-drive' ,
189+ f'file={ image_path } ,if=mtd,format=raw' ,
190+ ],
87191 ** kwargs ,
88192 )
89193
194+ def execute_efuse_command (self , command : str ):
195+ import espefuse
196+ import pexpect
197+
198+ with socket .socket (socket .AF_INET , socket .SOCK_STREAM ) as s :
199+ s .bind (('127.0.0.1' , 0 ))
200+ _ , available_port = s .getsockname ()
201+
202+ run_qemu_command = [
203+ '-nographic' ,
204+ '-machine' ,
205+ self .app .target ,
206+ '-drive' ,
207+ f'file={ self .image_path } ,if=mtd,format=raw' ,
208+ '-global' ,
209+ self .QEMU_STRAP_MODE_FMT .format (self .app .target , QEMU_TARGETS [self .app .target ].strap_mode ),
210+ '-drive' ,
211+ f'file={ self .efuse_path } ,if=none,format=raw,id=efuse' ,
212+ '-global' ,
213+ f'driver=nvram.{ self .app .target } .efuse,property=drive,value=efuse' ,
214+ '-serial' ,
215+ f'tcp::{ available_port } ,server,nowait' ,
216+ ]
217+ try :
218+ child = pexpect .spawn (self .qemu_prog_path , run_qemu_command )
219+ res = shlex .split (command )
220+ child .expect ('qemu' )
221+
222+ res = [r for r in res if r != '--do-not-confirm' ]
223+ espefuse .main (
224+ [
225+ '--port' ,
226+ f'socket://localhost:{ available_port } ' ,
227+ '--before' ,
228+ 'no-reset' ,
229+ '--do-not-confirm' ,
230+ * res ,
231+ ]
232+ )
233+ self ._hard_reset ()
234+ finally :
235+ child .terminate ()
236+
90237 @property
91238 def qemu_prog_name (self ):
92239 if self .app :
0 commit comments