qemu/scripts/qmp/fault_injection.py
<<
>>
Prefs
   1# Fault injection helper script based on top of QMP.
   2#
   3# Developed by KONRAD Frederic <fred.konrad@greensocs.com>
   4#
   5# This work is licensed under the terms of the GNU GPL, version 2 or later.
   6# See the COPYING file in the top-level directory.
   7#
   8
   9import qmp
  10import json
  11import ast
  12import readline
  13import sys
  14
  15def die(cause):
  16    sys.stderr.write('error: %s\n' % cause)
  17    sys.exit(1)
  18
  19class FaultInjectionFramework(qmp.QEMUMonitorProtocol):
  20    qemu_time = 0
  21    verbose = 0
  22    callback = {}
  23
  24    def print_v(self, msg, level):
  25        if level <= self.verbose:
  26            print msg
  27
  28    def print_qemu_version(self):
  29        version = self._greeting['QMP']['version']['qemu']
  30        print 'Connected to QEMU %d.%d.%d\n' % (version['major'],
  31                                                version['minor'],
  32                                                version['micro'])
  33
  34    def __init__(self, address, verbose = 0):
  35        self.verbose = verbose
  36        qmp.QEMUMonitorProtocol.__init__(self, self.__get_address(address))
  37
  38        try:
  39            self._greeting = qmp.QEMUMonitorProtocol.connect(self)
  40        except qmp.QMPConnectError:
  41            die('Didn\'t get QMP greeting message')
  42        except qmp.QMPCapabilitiesError:
  43            die('Could not negotiate capabilities')
  44        except self.error:
  45            die('Could not connect to %s' % address)
  46
  47        self.print_qemu_version()
  48        self._completer = None
  49        self._pretty = False
  50        self._transmode = False
  51        self._actions = list()
  52
  53    def time_print(self, arg):
  54        self.print_v('%sns: %s' % (self.qemu_time, arg), 1)
  55
  56    def send(self, qmpcmd):
  57        self.print_v(qmpcmd, 2)
  58        resp = self.cmd_obj(qmpcmd)
  59        if resp is None:
  60            die('Disconnected')
  61        self.print_v(resp, 2)
  62        return resp
  63
  64    def cont(self):
  65        qmpcmd = {'execute': 'cont', 'arguments': {}}
  66        self.send(qmpcmd)
  67
  68    def run(self):
  69        # RUN the simulation.
  70        self.time_print('Simulation is now running')
  71        self.cont()
  72        # Wait for an event to appear
  73        shutdown_evt = False
  74        while shutdown_evt == False:
  75            for ev in self.get_events(True):
  76                self.print_v(ev, 2)
  77                if ev['event'] == 'FAULT_EVENT':
  78                    data = ev['data']
  79                    self.qemu_time = data['time_ns'];
  80                    self.callback[data['event_id']]()
  81                    self.cont()
  82                elif ev['event'] == 'SHUTDOWN':
  83                    shutdown_evt = True
  84            self.clear_events()
  85        self.close()
  86
  87    def notify(self, time_ns, cb):
  88        # Notify a callback at qemu time time_ns
  89        next_index = len(self.callback)
  90        elt = 0
  91        for elt in range(0, next_index + 1):
  92            if elt == next_index:
  93                break
  94            if self.callback[elt] == cb:
  95                break
  96
  97        self.callback[elt] = cb
  98        self.time_print('Notify %s in %sns' % (cb, time_ns))
  99        qmpcmd = {'execute': 'trigger_event',
 100                  'arguments': {'event_id': elt,
 101                                'time_ns': time_ns}}
 102        self.send(qmpcmd)
 103
 104    def write(self, address, value, size, cpu):
 105        # write a value
 106        self.time_print('write: 0x%08x @0x%08x size %s from cpu %s' \
 107                        %(value, address, size, cpu))
 108        if type(cpu) is int:
 109                qmpcmd = {'execute': 'write_mem',
 110                          'arguments': {'size': size,
 111                                        'addr': address,
 112                                        'val': value,
 113                                        'cpu': cpu}}
 114        else:
 115                qmpcmd = {'execute': 'write_mem',
 116                          'arguments': {'size': size,
 117                                        'addr': address,
 118                                        'val': value,
 119                                        'qom': cpu}}
 120        self.send(qmpcmd)
 121
 122    def read(self, address, size, cpu):
 123        # Read a value
 124        self.time_print('read value: @0x%8.8X size %s from cpu %s' \
 125                        %(address, size, cpu))
 126        if type(cpu) is int:
 127            qmpcmd = {'execute': 'read_mem',
 128                      'arguments': {'size': size,
 129                                   'addr': address,
 130                                   'cpu': cpu}}
 131        else:
 132            qmpcmd = {'execute': 'read_mem',
 133                      'arguments': {'size': size,
 134                                   'addr': address,
 135                                   'qom': cpu}}
 136        value = self.send(qmpcmd)['return']
 137        return value
 138
 139    def get_qom_property(self, path, property):
 140        # Get a QOM property
 141        qmpcmd = {'execute': 'qom-get',
 142                  'arguments': {'path': path,
 143                                'property': property}}
 144        value = self.send(qmpcmd)['return']
 145        return value
 146
 147    def set_qom_property(self, path, property, value):
 148        # Set a QOM property
 149        qmpcmd = {'execute': 'qom-set',
 150                  'arguments': {'path': path,
 151                                'property': property,
 152                                'value': value}}
 153        self.send(qmpcmd)
 154
 155    def set_gpio(self, device_name, gpio, num, value):
 156        # Set a GPIO
 157        if gpio != "":
 158            qmpcmd = {'execute': 'inject_gpio',
 159                      'arguments': {'device_name': device_name,
 160                                    'gpio': gpio,
 161                                    'num': num,
 162                                    'val': value}}
 163        else:
 164            qmpcmd = {'execute': 'inject_gpio',
 165                      'arguments': {'device_name': device_name,
 166                                    'num': num,
 167                                    'val': value}}
 168        self.send(qmpcmd)
 169
 170    def help(self):
 171        print "\nFault Injection Framework Commands"
 172        print "==================================\n"
 173        print "cont()"
 174        print " * Resume the simulation when the Virtual Machine is stopped.\n"
 175        print "run()"
 176        print " * Start the simulation when the notify are set.\n"
 177        print "notify(time_ns, cb)"
 178        print " * Notify the callback cb in guest time time_ns.\n"
 179        print "write(address, value, size, cpu)"
 180        print " * Write @value of size @size at @address from @cpu."
 181        print " * @cpu can be either a qom path or the cpu id.\n"
 182        print "read(address, size, cpu)"
 183        print " * Read a value of size @size at @address from @cpu."
 184        print " * @cpu can be either a qom path or the cpu id."
 185        print " * Returns the value.\n"
 186        print "get_qom_property(path, property)"
 187        print " * Get a qom property."
 188        print " * Returns the qom property named @property in @path.\n"
 189        print "set_qom_property(path, property, value)"
 190        print " * Set the property named @property in @path with @value.\n"
 191        print "set_gpio(path, gpio, num, value)"
 192        print " * Set the gpio named @gpio number @num in @path with the @val."
 193        print " * @val is a boolean.\n"
 194
 195    def __get_address(self, arg):
 196        """
 197        Figure out if the argument is in the port:host form, if it's not it's
 198        probably a file path.
 199        """
 200        addr = arg.split(':')
 201        if len(addr) == 2:
 202            try:
 203                port = int(addr[1])
 204            except ValueError:
 205                raise QMPShellBadPort
 206            return ( addr[0], port )
 207        # socket path
 208        return arg
 209
 210