Merge remote-tracking branch 'qmp/for-anthony' into staging
This commit is contained in:
commit
924f766af9
54
QMP/qmp.py
54
QMP/qmp.py
@ -22,19 +22,24 @@ class QMPCapabilitiesError(QMPError):
|
||||
pass
|
||||
|
||||
class QEMUMonitorProtocol:
|
||||
def __init__(self, address):
|
||||
def __init__(self, address, server=False):
|
||||
"""
|
||||
Create a QEMUMonitorProtocol class.
|
||||
|
||||
@param address: QEMU address, can be either a unix socket path (string)
|
||||
or a tuple in the form ( address, port ) for a TCP
|
||||
connection
|
||||
@note No connection is established, this is done by the connect() method
|
||||
@param server: server mode listens on the socket (bool)
|
||||
@raise socket.error on socket connection errors
|
||||
@note No connection is established, this is done by the connect() or
|
||||
accept() methods
|
||||
"""
|
||||
self.__events = []
|
||||
self.__address = address
|
||||
self.__sock = self.__get_sock()
|
||||
self.__sockfile = self.__sock.makefile()
|
||||
if server:
|
||||
self.__sock.bind(self.__address)
|
||||
self.__sock.listen(1)
|
||||
|
||||
def __get_sock(self):
|
||||
if isinstance(self.__address, tuple):
|
||||
@ -43,7 +48,18 @@ class QEMUMonitorProtocol:
|
||||
family = socket.AF_UNIX
|
||||
return socket.socket(family, socket.SOCK_STREAM)
|
||||
|
||||
def __json_read(self):
|
||||
def __negotiate_capabilities(self):
|
||||
self.__sockfile = self.__sock.makefile()
|
||||
greeting = self.__json_read()
|
||||
if greeting is None or not greeting.has_key('QMP'):
|
||||
raise QMPConnectError
|
||||
# Greeting seems ok, negotiate capabilities
|
||||
resp = self.cmd('qmp_capabilities')
|
||||
if "return" in resp:
|
||||
return greeting
|
||||
raise QMPCapabilitiesError
|
||||
|
||||
def __json_read(self, only_event=False):
|
||||
while True:
|
||||
data = self.__sockfile.readline()
|
||||
if not data:
|
||||
@ -51,7 +67,8 @@ class QEMUMonitorProtocol:
|
||||
resp = json.loads(data)
|
||||
if 'event' in resp:
|
||||
self.__events.append(resp)
|
||||
continue
|
||||
if not only_event:
|
||||
continue
|
||||
return resp
|
||||
|
||||
error = socket.error
|
||||
@ -66,14 +83,19 @@ class QEMUMonitorProtocol:
|
||||
@raise QMPCapabilitiesError if fails to negotiate capabilities
|
||||
"""
|
||||
self.__sock.connect(self.__address)
|
||||
greeting = self.__json_read()
|
||||
if greeting is None or not greeting.has_key('QMP'):
|
||||
raise QMPConnectError
|
||||
# Greeting seems ok, negotiate capabilities
|
||||
resp = self.cmd('qmp_capabilities')
|
||||
if "return" in resp:
|
||||
return greeting
|
||||
raise QMPCapabilitiesError
|
||||
return self.__negotiate_capabilities()
|
||||
|
||||
def accept(self):
|
||||
"""
|
||||
Await connection from QMP Monitor and perform capabilities negotiation.
|
||||
|
||||
@return QMP greeting dict
|
||||
@raise socket.error on socket connection errors
|
||||
@raise QMPConnectError if the greeting is not received
|
||||
@raise QMPCapabilitiesError if fails to negotiate capabilities
|
||||
"""
|
||||
self.__sock, _ = self.__sock.accept()
|
||||
return self.__negotiate_capabilities()
|
||||
|
||||
def cmd_obj(self, qmp_cmd):
|
||||
"""
|
||||
@ -106,9 +128,11 @@ class QEMUMonitorProtocol:
|
||||
qmp_cmd['id'] = id
|
||||
return self.cmd_obj(qmp_cmd)
|
||||
|
||||
def get_events(self):
|
||||
def get_events(self, wait=False):
|
||||
"""
|
||||
Get a list of available QMP events.
|
||||
|
||||
@param wait: block until an event is available (bool)
|
||||
"""
|
||||
self.__sock.setblocking(0)
|
||||
try:
|
||||
@ -118,6 +142,8 @@ class QEMUMonitorProtocol:
|
||||
# No data available
|
||||
pass
|
||||
self.__sock.setblocking(1)
|
||||
if not self.__events and wait:
|
||||
self.__json_read(only_event=True)
|
||||
return self.__events
|
||||
|
||||
def clear_events(self):
|
||||
|
@ -740,10 +740,11 @@ ETEXI
|
||||
#if defined(TARGET_I386)
|
||||
{
|
||||
.name = "nmi",
|
||||
.args_type = "cpu_index:i",
|
||||
.params = "cpu",
|
||||
.help = "inject an NMI on the given CPU",
|
||||
.mhandler.cmd = do_inject_nmi,
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "inject an NMI on all guest's CPUs",
|
||||
.user_print = monitor_user_noop,
|
||||
.mhandler.cmd_new = do_inject_nmi,
|
||||
},
|
||||
#endif
|
||||
STEXI
|
||||
|
19
monitor.c
19
monitor.c
@ -2544,16 +2544,21 @@ static void do_wav_capture(Monitor *mon, const QDict *qdict)
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
static void do_inject_nmi(Monitor *mon, const QDict *qdict)
|
||||
static int do_inject_nmi(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
||||
{
|
||||
CPUState *env;
|
||||
int cpu_index = qdict_get_int(qdict, "cpu_index");
|
||||
|
||||
for (env = first_cpu; env != NULL; env = env->next_cpu)
|
||||
if (env->cpu_index == cpu_index) {
|
||||
cpu_interrupt(env, CPU_INTERRUPT_NMI);
|
||||
break;
|
||||
}
|
||||
for (env = first_cpu; env != NULL; env = env->next_cpu) {
|
||||
cpu_interrupt(env, CPU_INTERRUPT_NMI);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int do_inject_nmi(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
||||
{
|
||||
qerror_report(QERR_UNSUPPORTED);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
4
qerror.c
4
qerror.c
@ -200,6 +200,10 @@ static const QErrorStringTable qerror_table[] = {
|
||||
.error_fmt = QERR_UNDEFINED_ERROR,
|
||||
.desc = "An undefined error has ocurred",
|
||||
},
|
||||
{
|
||||
.error_fmt = QERR_UNSUPPORTED,
|
||||
.desc = "this feature or command is not currently supported",
|
||||
},
|
||||
{
|
||||
.error_fmt = QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
.desc = "'%(device)' uses a %(format) feature which is not "
|
||||
|
3
qerror.h
3
qerror.h
@ -169,6 +169,9 @@ QError *qobject_to_qerror(const QObject *obj);
|
||||
#define QERR_UNDEFINED_ERROR \
|
||||
"{ 'class': 'UndefinedError', 'data': {} }"
|
||||
|
||||
#define QERR_UNSUPPORTED \
|
||||
"{ 'class': 'Unsupported', 'data': {} }"
|
||||
|
||||
#define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \
|
||||
"{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }"
|
||||
|
||||
|
@ -427,6 +427,33 @@ Example:
|
||||
"filename": "/tmp/physical-mem-dump" } }
|
||||
<- { "return": {} }
|
||||
|
||||
EQMP
|
||||
|
||||
{
|
||||
.name = "inject-nmi",
|
||||
.args_type = "",
|
||||
.params = "",
|
||||
.help = "",
|
||||
.user_print = monitor_user_noop,
|
||||
.mhandler.cmd_new = do_inject_nmi,
|
||||
},
|
||||
|
||||
SQMP
|
||||
inject-nmi
|
||||
----------
|
||||
|
||||
Inject an NMI on guest's CPUs.
|
||||
|
||||
Arguments: None.
|
||||
|
||||
Example:
|
||||
|
||||
-> { "execute": "inject-nmi" }
|
||||
<- { "return": {} }
|
||||
|
||||
Note: inject-nmi is only supported for x86 guest currently, it will
|
||||
returns "Unsupported" error for non-x86 guest.
|
||||
|
||||
EQMP
|
||||
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user