                           Fault Injection Framework
                           =========================

Introduction
------------

The fault injection framework allows users to write python scripts to inject
faults through the QMP (QEMU Machine Protocol) during execution.

Basically it's composed of a Python API which makes some QMP commands easy to
send to the machine:
  * read/write a memory location from a CPU view.
  * set a GPIO line.
  * get/set a QOM property.

In addition it allows the Python script to be notified back by QEMU so it can
do any of the previous commands at a given time.

Today the available function in the API are the following:
  * notify(time_ns, cb)
  * inject_write(address, value, size, cpu)
  * read(address, size, cpu)
  * get_qom_property(path, property)
  * set_qom_property(path, property, value)
  * set_gpio(path, gpio, num, value)

Empty Example
-------------

This is an empty example to begin:

import fault_injection
import sys

framework = None

def main():
    # The injection framework will parse the command line automatically
    # (eg: the qmp socket/port.. etc)
    sys.stdout.write('Fault Injection Example\n')
    global framework
    framework = fault_injection.FaultInjectionFramework(sys.argv[1])

    framework.run()
    sys.exit(1)

if __name__ == '__main__':
    main()

To run the example just save the example in `script/qmp/example_scenario`
Run qemu with the additional arguments: `-S -qmp unix:/path/to/qmp-sock,server`
in order to wait for a qmp connection and stop the QEMU machine.
Run the example with: `./example_scenario /path/to/qmp-sock`

It will start the simulation inside QEMU and do nothing else.

Adding a callback at a given time
---------------------------------

As described above a callback can be added in the python scenario.
For example we can create the following callback which write 0xDEADBEEF @0 with
a size of 4 from cpu 0 and then reads it back:

def write_mem_callback():
    print 'write_mem_callback()'
    framework.write(0x0, 0xDEADBEEF, 4, 0)
    val = framework.read(0x0, 4, 0)
    print('value read: 0x' + str(val['value']))

Then we can notify it in the main function before framework.run():
`framework.notify(1000000000, write_mem_callback)`

The script works as expected:

write_mem_callback()
value read: 0xDEADBEEF

Using the python interpreter
----------------------------

The Python interpreter can be used to send the command above:
For example to set the vinithi bit to 1 for the /rpu_cpu@0 the following
commands can be done in the script/qmp directory:

$ python
>>> import fault_injection
>>> inj=fault_injection.FaultInjectionFramework("../../qmp-sock", 0)
Connected to QEMU 2.2.50

>>> inj.help()

Fault Injection Framework Commands
==================================

cont()
 * Resume the simulation when the Virtual Machine is stopped.

run()
 * Start the simulation when the notify are set.

notify(time_ns, cb)
 * Notify the callback cb in guest time time_ns.

write(address, value, size, cpu)
 * Write @value of size @size at @address from @cpu.
 * @cpu can be either a qom path or the cpu id.

read(address, size, cpu)
 * Read a value of size @size at @address from @cpu.
 * @cpu can be either a qom path or the cpu id.
 * Returns the value.

get_qom_property(path, property)
 * Get a qom property.
 * Returns the qom property named @property in @path.

set_qom_property(path, property, value)
 * Set the property named @property in @path with @value.

set_gpio(path, gpio, num, value)
 * Set the gpio named @gpio number @num in @path with the @val.
 * @val is a boolean.

>>> inj.set_gpio('/rpu_cpu@0', 'vinithi', 0, 1)

Notes
-----

The user can turn debug information on by passing a level to the framework
constructor eg:
"framework = fault_injection.FaultInjectionFramework(1)" will print timed traces
such as write or read.
"framework = fault_injection.FaultInjectionFramework(2)" will print the QMP
commands as well.

