From ac94257a314ad8b7e1377341c7a7747ed9c786e8 Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Sat, 27 Jul 2024 10:17:36 -0600
Subject: [PATCH 1/4] driver/qemudriver: Make extra_args, cpu and machine
 optional

At least for x86 devices it is not necessary to provide these arguments.
Make them optional.

Add an x86 example to the documentation too.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 doc/configuration.rst        | 13 ++++++++++--
 labgrid/driver/qemudriver.py | 39 +++++++++++++++++++++---------------
 2 files changed, 34 insertions(+), 18 deletions(-)

diff --git a/doc/configuration.rst b/doc/configuration.rst
index c293ba6c9..0c64a51fb 100644
--- a/doc/configuration.rst
+++ b/doc/configuration.rst
@@ -2693,6 +2693,15 @@ Binds to:
      dtb: 'dtb'
      nic: 'user'
 
+   QEMUDriver:
+     qemu_bin: qemu-i386
+     machine: pc
+     cpu: core2duo
+     memory: 2G
+     extra_args: "-accel kvm"
+     nic: user,model=virtio-net-pci
+     disk: disk-image
+
 .. code-block:: yaml
 
    tools:
@@ -2709,8 +2718,8 @@ Implements:
 
 Arguments:
   - qemu_bin (str): reference to the tools key for the QEMU binary
-  - machine (str): QEMU machine type
-  - cpu (str): QEMU cpu type
+  - machine (str): optional, QEMU machine type
+  - cpu (str): optional, QEMU cpu type
   - memory (str): QEMU memory size (ends with M or G)
   - extra_args (str): optional, extra QEMU arguments, they are passed directly to the QEMU binary
   - boot_args (str): optional, additional kernel boot argument
diff --git a/labgrid/driver/qemudriver.py b/labgrid/driver/qemudriver.py
index a9dc0829d..9ae7188b3 100644
--- a/labgrid/driver/qemudriver.py
+++ b/labgrid/driver/qemudriver.py
@@ -32,10 +32,11 @@ class QEMUDriver(ConsoleExpectMixin, Driver, PowerProtocol, ConsoleProtocol):
 
     Args:
         qemu_bin (str): reference to the tools key for the QEMU binary
-        machine (str): QEMU machine type
-        cpu (str): QEMU cpu type
         memory (str): QEMU memory size (ends with M or G)
-        extra_args (str): optional, extra QEMU arguments passed directly to the QEMU binary
+        extra_args (str): optional, extra QEMU arguments passed directly to the
+            QEMU binary
+        cpu (str): optional, QEMU cpu type
+        machine (str): optional, QEMU machine type
         boot_args (str): optional, additional kernel boot argument
         kernel (str): optional, reference to the images key for the kernel
         disk (str): optional, reference to the images key for the disk image
@@ -52,11 +53,15 @@ class QEMUDriver(ConsoleExpectMixin, Driver, PowerProtocol, ConsoleProtocol):
         nic (str): optional, configuration string to pass to QEMU to create a network interface
     """
     qemu_bin = attr.ib(validator=attr.validators.instance_of(str))
-    machine = attr.ib(validator=attr.validators.instance_of(str))
-    cpu = attr.ib(validator=attr.validators.instance_of(str))
     memory = attr.ib(validator=attr.validators.instance_of(str))
     extra_args = attr.ib(
-        default='',
+        default=None,
+        validator=attr.validators.optional(attr.validators.instance_of(str)))
+    cpu = attr.ib(
+        default=None,
+        validator=attr.validators.optional(attr.validators.instance_of(str)))
+    machine = attr.ib(
+        default=None,
         validator=attr.validators.optional(attr.validators.instance_of(str)))
     boot_args = attr.ib(
         default=None,
@@ -161,7 +166,7 @@ def get_qemu_base_args(self):
                 cmd.append(
                     f"if=sd,format={disk_format},file={disk_path},id=mmc0{disk_opts}")
                 boot_args.append("root=/dev/mmcblk0p1 rootfstype=ext4 rootwait")
-            elif self.machine in ["pc", "q35", "virt"]:
+            elif self.machine in ["pc", "q35", "virt", None]:
                 cmd.append("-drive")
                 cmd.append(
                     f"if=virtio,format={disk_format},file={disk_path}{disk_opts}")
@@ -189,15 +194,17 @@ def get_qemu_base_args(self):
             cmd.append("-bios")
             cmd.append(
                 self.target.env.config.get_image_path(self.bios))
-
-        if "-append" in shlex.split(self.extra_args):
-            raise ExecutionError("-append in extra_args not allowed, use boot_args instead")
-
-        cmd.extend(shlex.split(self.extra_args))
-        cmd.append("-machine")
-        cmd.append(self.machine)
-        cmd.append("-cpu")
-        cmd.append(self.cpu)
+        if self.extra_args:
+            if "-append" in shlex.split(self.extra_args):
+                raise ExecutionError("-append in extra_args not allowed, use boot_args instead")
+
+            cmd.extend(shlex.split(self.extra_args))
+        if self.machine:
+            cmd.append("-machine")
+            cmd.append(self.machine)
+        if self.cpu:
+            cmd.append("-cpu")
+            cmd.append(self.cpu)
         cmd.append("-m")
         cmd.append(self.memory)
         if self.display == "none":

From ec0af701044c2bc522282ac32fcd12e109593347 Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Sat, 27 Jul 2024 10:17:36 -0600
Subject: [PATCH 2/4] driver/qemudriver: Delay setting of the QEMU arguments

These arguments are currently set on activation. Where the driver is
being used by a strategy, it may need to set the arguments after that.
There is no need to have everything set in stone until the on() method
is called, so move it there.

For existing users, no functional change is intended.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 labgrid/driver/qemudriver.py | 28 +++++++++++++++-------------
 1 file changed, 15 insertions(+), 13 deletions(-)

diff --git a/labgrid/driver/qemudriver.py b/labgrid/driver/qemudriver.py
index 9ae7188b3..68813708b 100644
--- a/labgrid/driver/qemudriver.py
+++ b/labgrid/driver/qemudriver.py
@@ -108,6 +108,7 @@ def __attrs_post_init__(self):
         self._tempdir = None
         self._socket = None
         self._clientsocket = None
+        self._sockpath = None
         self._forwarded_ports = {}
         atexit.register(self._atexit)
 
@@ -238,22 +239,11 @@ def get_qemu_base_args(self):
 
     def on_activate(self):
         self._tempdir = tempfile.mkdtemp(prefix="labgrid-qemu-tmp-")
-        sockpath = f"{self._tempdir}/serialrw"
+        self._sockpath = f"{self._tempdir}/serialrw"
         self._socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-        self._socket.bind(sockpath)
+        self._socket.bind(self._sockpath)
         self._socket.listen(0)
 
-        self._cmd = self.get_qemu_base_args()
-
-        self._cmd.append("-S")
-        self._cmd.append("-qmp")
-        self._cmd.append("stdio")
-
-        self._cmd.append("-chardev")
-        self._cmd.append(f"socket,id=serialsocket,path={sockpath}")
-        self._cmd.append("-serial")
-        self._cmd.append("chardev:serialsocket")
-
     def on_deactivate(self):
         if self.status:
             self.off()
@@ -262,6 +252,7 @@ def on_deactivate(self):
             self._clientsocket = None
         self._socket.close()
         self._socket = None
+        self._sockpath = None
         shutil.rmtree(self._tempdir)
 
     @step()
@@ -270,6 +261,17 @@ def on(self):
         afterwards start the emulator using a QMP Command"""
         if self.status:
             return
+        self._cmd = self.get_qemu_base_args()
+
+        self._cmd.append("-S")
+        self._cmd.append("-qmp")
+        self._cmd.append("stdio")
+
+        self._cmd.append("-chardev")
+        self._cmd.append(f"socket,id=serialsocket,path={self._sockpath}")
+        self._cmd.append("-serial")
+        self._cmd.append("chardev:serialsocket")
+
         self.logger.debug("Starting with: %s", self._cmd)
         self._child = subprocess.Popen(
             self._cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)

From 7305d57445a50c64b03eef7e9d54899c681f6859 Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Sat, 27 Jul 2024 10:17:36 -0600
Subject: [PATCH 3/4] driver/qemudriver: Allow the BIOS filename to be changed

The U-Boot strategy will need to provide the filename of the BIOS
directly when booting U-Boot on QEMU. Add a method to support this.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 labgrid/driver/qemudriver.py | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/labgrid/driver/qemudriver.py b/labgrid/driver/qemudriver.py
index 68813708b..baf863539 100644
--- a/labgrid/driver/qemudriver.py
+++ b/labgrid/driver/qemudriver.py
@@ -1,5 +1,6 @@
 """The QEMUDriver implements a driver to use a QEMU target"""
 import atexit
+import os
 import select
 import shlex
 import shutil
@@ -133,6 +134,17 @@ def get_qemu_version(self, qemu_bin):
 
         return (int(m.group('major')), int(m.group('minor')), int(m.group('micro')))
 
+    def set_bios(self, bios):
+        """Set the filename of the bios
+
+        This can be used by strategies to set the bios filename, overriding the
+        value provided in the environment.
+
+        Args:
+            bios (str): New bios filename
+        """
+        self.bios = bios
+
     def get_qemu_base_args(self):
         """Returns the base command line used for Qemu without the options
         related to QMP. These options can be used to start an interactive
@@ -193,8 +205,10 @@ def get_qemu_base_args(self):
                 f"if=pflash,format=raw,file={self.target.env.config.get_image_path(self.flash)},id=nor0")  # pylint: disable=line-too-long
         if self.bios is not None:
             cmd.append("-bios")
-            cmd.append(
-                self.target.env.config.get_image_path(self.bios))
+            if os.path.exists(self.bios):
+                cmd.append(self.bios)
+            else:
+                cmd.append(self.target.env.config.get_image_path(self.bios))
         if self.extra_args:
             if "-append" in shlex.split(self.extra_args):
                 raise ExecutionError("-append in extra_args not allowed, use boot_args instead")

From 70cf4b21c37f7d756102ae937f22f9fb80ea5cdc Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Wed, 28 Aug 2024 10:56:13 -0600
Subject: [PATCH 4/4] driver/qemudriver: Report an error if QEMU is not turned
 on

Rather than provide a strange exception, complain when a strategy does
not use the QEMU driver properly, perhaps due to user settings.

Series-changes: 6
- Add new patch to report an error if QEMU is not turned on

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 labgrid/driver/qemudriver.py | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/labgrid/driver/qemudriver.py b/labgrid/driver/qemudriver.py
index baf863539..652833f66 100644
--- a/labgrid/driver/qemudriver.py
+++ b/labgrid/driver/qemudriver.py
@@ -356,6 +356,8 @@ def remove_port_forward(self, proto, local_address, local_port):
         )
 
     def _read(self, size=1, timeout=10, max_size=None):
+        if not self._clientsocket:
+            raise ExecutionError('QEMU has not been started')
         ready, _, _ = select.select([self._clientsocket], [], [], timeout)
         if ready:
             # Collect some more data