hw/riscv: sifive_u: Sort the SoC memmap table entries
[qemu/ar7.git] / python / qemu / machine.py
blob041c615052e4d7e2577cdc071be647f59bc76ffa
1 """
2 QEMU machine module:
4 The machine module primarily provides the QEMUMachine class,
5 which provides facilities for managing the lifetime of a QEMU VM.
6 """
8 # Copyright (C) 2015-2016 Red Hat Inc.
9 # Copyright (C) 2012 IBM Corp.
11 # Authors:
12 # Fam Zheng <famz@redhat.com>
14 # This work is licensed under the terms of the GNU GPL, version 2. See
15 # the COPYING file in the top-level directory.
17 # Based on qmp.py.
20 import errno
21 import logging
22 import os
23 import subprocess
24 import shutil
25 import socket
26 import tempfile
27 from typing import Optional, Type
28 from types import TracebackType
30 from . import qmp
32 LOG = logging.getLogger(__name__)
35 class QEMUMachineError(Exception):
36 """
37 Exception called when an error in QEMUMachine happens.
38 """
41 class QEMUMachineAddDeviceError(QEMUMachineError):
42 """
43 Exception raised when a request to add a device can not be fulfilled
45 The failures are caused by limitations, lack of information or conflicting
46 requests on the QEMUMachine methods. This exception does not represent
47 failures reported by the QEMU binary itself.
48 """
51 class MonitorResponseError(qmp.QMPError):
52 """
53 Represents erroneous QMP monitor reply
54 """
55 def __init__(self, reply):
56 try:
57 desc = reply["error"]["desc"]
58 except KeyError:
59 desc = reply
60 super().__init__(desc)
61 self.reply = reply
64 class QEMUMachine:
65 """
66 A QEMU VM
68 Use this object as a context manager to ensure
69 the QEMU process terminates::
71 with VM(binary) as vm:
72 ...
73 # vm is guaranteed to be shut down here
74 """
76 def __init__(self, binary, args=None, wrapper=None, name=None,
77 test_dir="/var/tmp", monitor_address=None,
78 socket_scm_helper=None, sock_dir=None):
79 '''
80 Initialize a QEMUMachine
82 @param binary: path to the qemu binary
83 @param args: list of extra arguments
84 @param wrapper: list of arguments used as prefix to qemu binary
85 @param name: prefix for socket and log file names (default: qemu-PID)
86 @param test_dir: where to create socket and log file
87 @param monitor_address: address for QMP monitor
88 @param socket_scm_helper: helper program, required for send_fd_scm()
89 @note: Qemu process is not started until launch() is used.
90 '''
91 if args is None:
92 args = []
93 if wrapper is None:
94 wrapper = []
95 if name is None:
96 name = "qemu-%d" % os.getpid()
97 if sock_dir is None:
98 sock_dir = test_dir
99 self._name = name
100 self._monitor_address = monitor_address
101 self._vm_monitor = None
102 self._qemu_log_path = None
103 self._qemu_log_file = None
104 self._popen = None
105 self._binary = binary
106 self._args = list(args) # Force copy args in case we modify them
107 self._wrapper = wrapper
108 self._events = []
109 self._iolog = None
110 self._socket_scm_helper = socket_scm_helper
111 self._qmp_set = True # Enable QMP monitor by default.
112 self._qmp = None
113 self._qemu_full_args = None
114 self._test_dir = test_dir
115 self._temp_dir = None
116 self._sock_dir = sock_dir
117 self._launched = False
118 self._machine = None
119 self._console_index = 0
120 self._console_set = False
121 self._console_device_type = None
122 self._console_address = None
123 self._console_socket = None
124 self._remove_files = []
126 def __enter__(self):
127 return self
129 def __exit__(self,
130 exc_type: Optional[Type[BaseException]],
131 exc_val: Optional[BaseException],
132 exc_tb: Optional[TracebackType]) -> None:
133 self.shutdown()
135 def add_monitor_null(self):
137 This can be used to add an unused monitor instance.
139 self._args.append('-monitor')
140 self._args.append('null')
142 def add_fd(self, fd, fdset, opaque, opts=''):
144 Pass a file descriptor to the VM
146 options = ['fd=%d' % fd,
147 'set=%d' % fdset,
148 'opaque=%s' % opaque]
149 if opts:
150 options.append(opts)
152 # This did not exist before 3.4, but since then it is
153 # mandatory for our purpose
154 if hasattr(os, 'set_inheritable'):
155 os.set_inheritable(fd, True)
157 self._args.append('-add-fd')
158 self._args.append(','.join(options))
159 return self
161 def send_fd_scm(self, fd=None, file_path=None):
163 Send an fd or file_path to socket_scm_helper.
165 Exactly one of fd and file_path must be given.
166 If it is file_path, the helper will open that file and pass its own fd.
168 # In iotest.py, the qmp should always use unix socket.
169 assert self._qmp.is_scm_available()
170 if self._socket_scm_helper is None:
171 raise QEMUMachineError("No path to socket_scm_helper set")
172 if not os.path.exists(self._socket_scm_helper):
173 raise QEMUMachineError("%s does not exist" %
174 self._socket_scm_helper)
176 # This did not exist before 3.4, but since then it is
177 # mandatory for our purpose
178 if hasattr(os, 'set_inheritable'):
179 os.set_inheritable(self._qmp.get_sock_fd(), True)
180 if fd is not None:
181 os.set_inheritable(fd, True)
183 fd_param = ["%s" % self._socket_scm_helper,
184 "%d" % self._qmp.get_sock_fd()]
186 if file_path is not None:
187 assert fd is None
188 fd_param.append(file_path)
189 else:
190 assert fd is not None
191 fd_param.append(str(fd))
193 devnull = open(os.path.devnull, 'rb')
194 proc = subprocess.Popen(
195 fd_param, stdin=devnull, stdout=subprocess.PIPE,
196 stderr=subprocess.STDOUT, close_fds=False
198 output = proc.communicate()[0]
199 if output:
200 LOG.debug(output)
202 return proc.returncode
204 @staticmethod
205 def _remove_if_exists(path):
207 Remove file object at path if it exists
209 try:
210 os.remove(path)
211 except OSError as exception:
212 if exception.errno == errno.ENOENT:
213 return
214 raise
216 def is_running(self):
217 """Returns true if the VM is running."""
218 return self._popen is not None and self._popen.poll() is None
220 def exitcode(self):
221 """Returns the exit code if possible, or None."""
222 if self._popen is None:
223 return None
224 return self._popen.poll()
226 def get_pid(self):
227 """Returns the PID of the running process, or None."""
228 if not self.is_running():
229 return None
230 return self._popen.pid
232 def _load_io_log(self):
233 if self._qemu_log_path is not None:
234 with open(self._qemu_log_path, "r") as iolog:
235 self._iolog = iolog.read()
237 def _base_args(self):
238 args = ['-display', 'none', '-vga', 'none']
239 if self._qmp_set:
240 if isinstance(self._monitor_address, tuple):
241 moncdev = "socket,id=mon,host=%s,port=%s" % (
242 self._monitor_address[0],
243 self._monitor_address[1])
244 else:
245 moncdev = 'socket,id=mon,path=%s' % self._vm_monitor
246 args.extend(['-chardev', moncdev, '-mon',
247 'chardev=mon,mode=control'])
248 if self._machine is not None:
249 args.extend(['-machine', self._machine])
250 for _ in range(self._console_index):
251 args.extend(['-serial', 'null'])
252 if self._console_set:
253 self._console_address = os.path.join(self._sock_dir,
254 self._name + "-console.sock")
255 self._remove_files.append(self._console_address)
256 chardev = ('socket,id=console,path=%s,server,nowait' %
257 self._console_address)
258 args.extend(['-chardev', chardev])
259 if self._console_device_type is None:
260 args.extend(['-serial', 'chardev:console'])
261 else:
262 device = '%s,chardev=console' % self._console_device_type
263 args.extend(['-device', device])
264 return args
266 def _pre_launch(self):
267 self._temp_dir = tempfile.mkdtemp(dir=self._test_dir)
268 self._qemu_log_path = os.path.join(self._temp_dir, self._name + ".log")
269 self._qemu_log_file = open(self._qemu_log_path, 'wb')
271 if self._qmp_set:
272 if self._monitor_address is not None:
273 self._vm_monitor = self._monitor_address
274 else:
275 self._vm_monitor = os.path.join(self._sock_dir,
276 self._name + "-monitor.sock")
277 self._remove_files.append(self._vm_monitor)
278 self._qmp = qmp.QEMUMonitorProtocol(self._vm_monitor, server=True,
279 nickname=self._name)
281 def _post_launch(self):
282 if self._qmp:
283 self._qmp.accept()
285 def _post_shutdown(self):
286 if self._qemu_log_file is not None:
287 self._qemu_log_file.close()
288 self._qemu_log_file = None
290 self._qemu_log_path = None
292 if self._temp_dir is not None:
293 shutil.rmtree(self._temp_dir)
294 self._temp_dir = None
296 while len(self._remove_files) > 0:
297 self._remove_if_exists(self._remove_files.pop())
299 def launch(self):
301 Launch the VM and make sure we cleanup and expose the
302 command line/output in case of exception
305 if self._launched:
306 raise QEMUMachineError('VM already launched')
308 self._iolog = None
309 self._qemu_full_args = None
310 try:
311 self._launch()
312 self._launched = True
313 except:
314 self.shutdown()
316 LOG.debug('Error launching VM')
317 if self._qemu_full_args:
318 LOG.debug('Command: %r', ' '.join(self._qemu_full_args))
319 if self._iolog:
320 LOG.debug('Output: %r', self._iolog)
321 raise
323 def _launch(self):
325 Launch the VM and establish a QMP connection
327 devnull = open(os.path.devnull, 'rb')
328 self._pre_launch()
329 self._qemu_full_args = (self._wrapper + [self._binary] +
330 self._base_args() + self._args)
331 LOG.debug('VM launch command: %r', ' '.join(self._qemu_full_args))
332 self._popen = subprocess.Popen(self._qemu_full_args,
333 stdin=devnull,
334 stdout=self._qemu_log_file,
335 stderr=subprocess.STDOUT,
336 shell=False,
337 close_fds=False)
338 self._post_launch()
340 def wait(self):
342 Wait for the VM to power off
344 self._popen.wait()
345 if self._qmp:
346 self._qmp.close()
347 self._load_io_log()
348 self._post_shutdown()
350 def shutdown(self, has_quit=False, hard=False):
352 Terminate the VM and clean up
354 # If we keep the console socket open, we may deadlock waiting
355 # for QEMU to exit, while QEMU is waiting for the socket to
356 # become writeable.
357 if self._console_socket is not None:
358 self._console_socket.close()
359 self._console_socket = None
361 if self.is_running():
362 if hard:
363 self._popen.kill()
364 elif self._qmp:
365 try:
366 if not has_quit:
367 self._qmp.cmd('quit')
368 self._qmp.close()
369 self._popen.wait(timeout=3)
370 except:
371 self._popen.kill()
372 self._popen.wait()
374 self._load_io_log()
375 self._post_shutdown()
377 exitcode = self.exitcode()
378 if exitcode is not None and exitcode < 0 and \
379 not (exitcode == -9 and hard):
380 msg = 'qemu received signal %i: %s'
381 if self._qemu_full_args:
382 command = ' '.join(self._qemu_full_args)
383 else:
384 command = ''
385 LOG.warning(msg, -int(exitcode), command)
387 self._launched = False
389 def kill(self):
390 self.shutdown(hard=True)
392 def set_qmp_monitor(self, enabled=True):
394 Set the QMP monitor.
396 @param enabled: if False, qmp monitor options will be removed from
397 the base arguments of the resulting QEMU command
398 line. Default is True.
399 @note: call this function before launch().
401 if enabled:
402 self._qmp_set = True
403 else:
404 self._qmp_set = False
405 self._qmp = None
407 def qmp(self, cmd, conv_keys=True, **args):
409 Invoke a QMP command and return the response dict
411 qmp_args = dict()
412 for key, value in args.items():
413 if conv_keys:
414 qmp_args[key.replace('_', '-')] = value
415 else:
416 qmp_args[key] = value
418 return self._qmp.cmd(cmd, args=qmp_args)
420 def command(self, cmd, conv_keys=True, **args):
422 Invoke a QMP command.
423 On success return the response dict.
424 On failure raise an exception.
426 reply = self.qmp(cmd, conv_keys, **args)
427 if reply is None:
428 raise qmp.QMPError("Monitor is closed")
429 if "error" in reply:
430 raise MonitorResponseError(reply)
431 return reply["return"]
433 def get_qmp_event(self, wait=False):
435 Poll for one queued QMP events and return it
437 if self._events:
438 return self._events.pop(0)
439 return self._qmp.pull_event(wait=wait)
441 def get_qmp_events(self, wait=False):
443 Poll for queued QMP events and return a list of dicts
445 events = self._qmp.get_events(wait=wait)
446 events.extend(self._events)
447 del self._events[:]
448 self._qmp.clear_events()
449 return events
451 @staticmethod
452 def event_match(event, match=None):
454 Check if an event matches optional match criteria.
456 The match criteria takes the form of a matching subdict. The event is
457 checked to be a superset of the subdict, recursively, with matching
458 values whenever the subdict values are not None.
460 This has a limitation that you cannot explicitly check for None values.
462 Examples, with the subdict queries on the left:
463 - None matches any object.
464 - {"foo": None} matches {"foo": {"bar": 1}}
465 - {"foo": None} matches {"foo": 5}
466 - {"foo": {"abc": None}} does not match {"foo": {"bar": 1}}
467 - {"foo": {"rab": 2}} matches {"foo": {"bar": 1, "rab": 2}}
469 if match is None:
470 return True
472 try:
473 for key in match:
474 if key in event:
475 if not QEMUMachine.event_match(event[key], match[key]):
476 return False
477 else:
478 return False
479 return True
480 except TypeError:
481 # either match or event wasn't iterable (not a dict)
482 return match == event
484 def event_wait(self, name, timeout=60.0, match=None):
486 event_wait waits for and returns a named event from QMP with a timeout.
488 name: The event to wait for.
489 timeout: QEMUMonitorProtocol.pull_event timeout parameter.
490 match: Optional match criteria. See event_match for details.
492 return self.events_wait([(name, match)], timeout)
494 def events_wait(self, events, timeout=60.0):
496 events_wait waits for and returns a named event
497 from QMP with a timeout.
499 events: a sequence of (name, match_criteria) tuples.
500 The match criteria are optional and may be None.
501 See event_match for details.
502 timeout: QEMUMonitorProtocol.pull_event timeout parameter.
504 def _match(event):
505 for name, match in events:
506 if event['event'] == name and self.event_match(event, match):
507 return True
508 return False
510 # Search cached events
511 for event in self._events:
512 if _match(event):
513 self._events.remove(event)
514 return event
516 # Poll for new events
517 while True:
518 event = self._qmp.pull_event(wait=timeout)
519 if _match(event):
520 return event
521 self._events.append(event)
523 return None
525 def get_log(self):
527 After self.shutdown or failed qemu execution, this returns the output
528 of the qemu process.
530 return self._iolog
532 def add_args(self, *args):
534 Adds to the list of extra arguments to be given to the QEMU binary
536 self._args.extend(args)
538 def set_machine(self, machine_type):
540 Sets the machine type
542 If set, the machine type will be added to the base arguments
543 of the resulting QEMU command line.
545 self._machine = machine_type
547 def set_console(self, device_type=None, console_index=0):
549 Sets the device type for a console device
551 If set, the console device and a backing character device will
552 be added to the base arguments of the resulting QEMU command
553 line.
555 This is a convenience method that will either use the provided
556 device type, or default to a "-serial chardev:console" command
557 line argument.
559 The actual setting of command line arguments will be be done at
560 machine launch time, as it depends on the temporary directory
561 to be created.
563 @param device_type: the device type, such as "isa-serial". If
564 None is given (the default value) a "-serial
565 chardev:console" command line argument will
566 be used instead, resorting to the machine's
567 default device type.
568 @param console_index: the index of the console device to use.
569 If not zero, the command line will create
570 'index - 1' consoles and connect them to
571 the 'null' backing character device.
573 self._console_set = True
574 self._console_device_type = device_type
575 self._console_index = console_index
577 @property
578 def console_socket(self):
580 Returns a socket connected to the console
582 if self._console_socket is None:
583 self._console_socket = socket.socket(socket.AF_UNIX,
584 socket.SOCK_STREAM)
585 self._console_socket.connect(self._console_address)
586 return self._console_socket