xref: /aosp_15_r20/external/pigweed/pw_emu/design.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker.. _module-pw_emu-design:
2*61c4878aSAndroid Build Coastguard Worker
3*61c4878aSAndroid Build Coastguard Worker======
4*61c4878aSAndroid Build Coastguard WorkerDesign
5*61c4878aSAndroid Build Coastguard Worker======
6*61c4878aSAndroid Build Coastguard Worker.. pigweed-module-subpage::
7*61c4878aSAndroid Build Coastguard Worker   :name: pw_emu
8*61c4878aSAndroid Build Coastguard Worker
9*61c4878aSAndroid Build Coastguard Worker-----------
10*61c4878aSAndroid Build Coastguard WorkerParallelism
11*61c4878aSAndroid Build Coastguard Worker-----------
12*61c4878aSAndroid Build Coastguard Worker
13*61c4878aSAndroid Build Coastguard Worker``pw_emu`` supports running multiple instances simultaneously. This is helpful
14*61c4878aSAndroid Build Coastguard Workerfor developers who work on multiple downstream Pigweed projects or who want
15*61c4878aSAndroid Build Coastguard Workerto run multiple tests in parallel on the same machine.
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard WorkerEach instance is identified by a system absolute path that is also used to store
18*61c4878aSAndroid Build Coastguard Workerstate about the running instance such as ``pid`` files for running processes,
19*61c4878aSAndroid Build Coastguard Workercurrent emulator and target, etc. This directory also contains information about
20*61c4878aSAndroid Build Coastguard Workerhow to access the emulator channels, e.g. socket ports, PTY paths, etc.
21*61c4878aSAndroid Build Coastguard Worker
22*61c4878aSAndroid Build Coastguard Worker.. mermaid::
23*61c4878aSAndroid Build Coastguard Worker
24*61c4878aSAndroid Build Coastguard Worker   graph TD;
25*61c4878aSAndroid Build Coastguard Worker       TemporaryEmulator & pw_emu_cli[pw emu cli] <--> Emulator
26*61c4878aSAndroid Build Coastguard Worker       Emulator <--> Launcher & Connector
27*61c4878aSAndroid Build Coastguard Worker       Launcher  <--> Handles
28*61c4878aSAndroid Build Coastguard Worker       Connector <--> Handles
29*61c4878aSAndroid Build Coastguard Worker       Launcher <--> Config
30*61c4878aSAndroid Build Coastguard Worker       Handles --Save--> WD --Load--> Handles
31*61c4878aSAndroid Build Coastguard Worker       WD[Working Directory]
32*61c4878aSAndroid Build Coastguard Worker
33*61c4878aSAndroid Build Coastguard Worker-----------
34*61c4878aSAndroid Build Coastguard WorkerAPI surface
35*61c4878aSAndroid Build Coastguard Worker-----------
36*61c4878aSAndroid Build Coastguard Worker
37*61c4878aSAndroid Build Coastguard WorkerThe implementation uses the following classes:
38*61c4878aSAndroid Build Coastguard Worker
39*61c4878aSAndroid Build Coastguard Worker* :py:class:`pw_emu.frontend.Emulator` - The user-visible API.
40*61c4878aSAndroid Build Coastguard Worker* :py:class:`pw_emu.core.Launcher` - An abstract class that starts an
41*61c4878aSAndroid Build Coastguard Worker  emulator instance for a given configuration and target.
42*61c4878aSAndroid Build Coastguard Worker* :py:class:`pw_emu.core.Connector` - An abstract class that is the
43*61c4878aSAndroid Build Coastguard Worker  interface between a running emulator and the user-visible APIs.
44*61c4878aSAndroid Build Coastguard Worker* :py:class:`pw_emu.core.Handles` - A class that stores specific
45*61c4878aSAndroid Build Coastguard Worker  information about a running emulator instance such as ports to reach emulator
46*61c4878aSAndroid Build Coastguard Worker  channels; it is populated by :py:class:`pw_emu.core.Launcher` and
47*61c4878aSAndroid Build Coastguard Worker  saved in the working directory and used by
48*61c4878aSAndroid Build Coastguard Worker  :py:class:`pw_emu.core.Connector` to access the emulator channels,
49*61c4878aSAndroid Build Coastguard Worker  process PIDs, etc.
50*61c4878aSAndroid Build Coastguard Worker* :py:class:`pw_emu.core.Config` - Loads the ``pw_emu`` configuration and
51*61c4878aSAndroid Build Coastguard Worker  provides helper methods to get and validate configuration options.
52*61c4878aSAndroid Build Coastguard Worker
53*61c4878aSAndroid Build Coastguard Worker-------------------
54*61c4878aSAndroid Build Coastguard WorkerEmulator properties
55*61c4878aSAndroid Build Coastguard Worker-------------------
56*61c4878aSAndroid Build Coastguard WorkerThe implementation exposes the ability to list, read, and write emulator
57*61c4878aSAndroid Build Coastguard Workerproperties. The frontend does not abstract properties in a way that is
58*61c4878aSAndroid Build Coastguard Workeremulator-independent or even emulator-target-independent, other than mandating
59*61c4878aSAndroid Build Coastguard Workerthat each property is identified by a path. Note that the format of the path is
60*61c4878aSAndroid Build Coastguard Workeralso emulator-specific and not standardized.
61*61c4878aSAndroid Build Coastguard Worker
62*61c4878aSAndroid Build Coastguard Worker----
63*61c4878aSAndroid Build Coastguard WorkerQEMU
64*61c4878aSAndroid Build Coastguard Worker----
65*61c4878aSAndroid Build Coastguard WorkerThe QEMU frontend is using `QMP <https://wiki.qemu.org/Documentation/QMP>`_ to
66*61c4878aSAndroid Build Coastguard Workercommunicate with the running QEMU process and implement emulator-specific
67*61c4878aSAndroid Build Coastguard Workerfunctionality like reset, list properties, reading properties, etc.
68*61c4878aSAndroid Build Coastguard Worker
69*61c4878aSAndroid Build Coastguard WorkerQMP is exposed to the host through two channels: a temporary one to establish
70*61c4878aSAndroid Build Coastguard Workerthe initial connection that is used to read the dynamic configuration (e.g. TCP
71*61c4878aSAndroid Build Coastguard Workerports, PTY paths) and a permanent one that can be used throughout the life of
72*61c4878aSAndroid Build Coastguard Workerthe QEMU processes. The frontend is configuring QEMU to expose QMP to a
73*61c4878aSAndroid Build Coastguard Worker``localhost`` TCP port reserved by the frontend and then waiting for QEMU to
74*61c4878aSAndroid Build Coastguard Workerestablish the connection on that port. Once the connection is established the
75*61c4878aSAndroid Build Coastguard Workerfrontend reads the configuration of the permanent QMP channel (which can be
76*61c4878aSAndroid Build Coastguard Workereither a TCP port or a PTY path) and save it as a channel named ``qmp`` in the
77*61c4878aSAndroid Build Coastguard Worker:py:class:`pw_emu.core.Handles` object.
78*61c4878aSAndroid Build Coastguard Worker
79*61c4878aSAndroid Build Coastguard Worker------
80*61c4878aSAndroid Build Coastguard WorkerRenode
81*61c4878aSAndroid Build Coastguard Worker------
82*61c4878aSAndroid Build Coastguard WorkerThe Renode frontend uses `robot port
83*61c4878aSAndroid Build Coastguard Worker<https://renode.readthedocs.io/en/latest/introduction/testing.html>`_ to
84*61c4878aSAndroid Build Coastguard Workerinteract with the Renode process. Although the robot interface is designed for
85*61c4878aSAndroid Build Coastguard Workertesting and not as a control interface, it is more robust and better suited to
86*61c4878aSAndroid Build Coastguard Workerbe used as a machine interface than the alternative ``monitor`` interface which
87*61c4878aSAndroid Build Coastguard Workeris a user-oriented, ANSI-colored, echoed, log-mixed, telnet interface.
88*61c4878aSAndroid Build Coastguard Worker
89*61c4878aSAndroid Build Coastguard WorkerBugs
90*61c4878aSAndroid Build Coastguard Worker====
91*61c4878aSAndroid Build Coastguard WorkerWhile Renode allows passing ``0`` for ports to allocate a dynamic port, it does
92*61c4878aSAndroid Build Coastguard Workernot have APIs to retrieve the allocated port. Until support for such a feature
93*61c4878aSAndroid Build Coastguard Workeris added upstream, the implementation is using the following technique to
94*61c4878aSAndroid Build Coastguard Workerallocate a port dynamically:
95*61c4878aSAndroid Build Coastguard Worker
96*61c4878aSAndroid Build Coastguard Worker.. code-block:: py
97*61c4878aSAndroid Build Coastguard Worker
98*61c4878aSAndroid Build Coastguard Worker   sock = socket.socket(socket.SOCK_INET, socket.SOCK_STREAM)
99*61c4878aSAndroid Build Coastguard Worker   sock.bind(('', 0))
100*61c4878aSAndroid Build Coastguard Worker   _, port = socket.getsockname()
101*61c4878aSAndroid Build Coastguard Worker   sock.close()
102*61c4878aSAndroid Build Coastguard Worker
103*61c4878aSAndroid Build Coastguard WorkerThere is a race condition that allows another program to fetch the same port,
104*61c4878aSAndroid Build Coastguard Workerbut it should work in most light use cases until the issue is properly resolved
105*61c4878aSAndroid Build Coastguard Workerupstream.
106*61c4878aSAndroid Build Coastguard Worker
107*61c4878aSAndroid Build Coastguard Worker----------------
108*61c4878aSAndroid Build Coastguard WorkerMore pw_emu docs
109*61c4878aSAndroid Build Coastguard Worker----------------
110*61c4878aSAndroid Build Coastguard Worker.. include:: docs.rst
111*61c4878aSAndroid Build Coastguard Worker   :start-after: .. pw_emu-nav-start
112*61c4878aSAndroid Build Coastguard Worker   :end-before: .. pw_emu-nav-end
113