mirror of https://github.com/xqemu/xqemu.git
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
|
pass
|
||||||
|
|
||||||
class QEMUMonitorProtocol:
|
class QEMUMonitorProtocol:
|
||||||
def __init__(self, address):
|
def __init__(self, address, server=False):
|
||||||
"""
|
"""
|
||||||
Create a QEMUMonitorProtocol class.
|
Create a QEMUMonitorProtocol class.
|
||||||
|
|
||||||
@param address: QEMU address, can be either a unix socket path (string)
|
@param address: QEMU address, can be either a unix socket path (string)
|
||||||
or a tuple in the form ( address, port ) for a TCP
|
or a tuple in the form ( address, port ) for a TCP
|
||||||
connection
|
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.__events = []
|
||||||
self.__address = address
|
self.__address = address
|
||||||
self.__sock = self.__get_sock()
|
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):
|
def __get_sock(self):
|
||||||
if isinstance(self.__address, tuple):
|
if isinstance(self.__address, tuple):
|
||||||
|
@ -43,7 +48,18 @@ class QEMUMonitorProtocol:
|
||||||
family = socket.AF_UNIX
|
family = socket.AF_UNIX
|
||||||
return socket.socket(family, socket.SOCK_STREAM)
|
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:
|
while True:
|
||||||
data = self.__sockfile.readline()
|
data = self.__sockfile.readline()
|
||||||
if not data:
|
if not data:
|
||||||
|
@ -51,7 +67,8 @@ class QEMUMonitorProtocol:
|
||||||
resp = json.loads(data)
|
resp = json.loads(data)
|
||||||
if 'event' in resp:
|
if 'event' in resp:
|
||||||
self.__events.append(resp)
|
self.__events.append(resp)
|
||||||
continue
|
if not only_event:
|
||||||
|
continue
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
error = socket.error
|
error = socket.error
|
||||||
|
@ -66,14 +83,19 @@ class QEMUMonitorProtocol:
|
||||||
@raise QMPCapabilitiesError if fails to negotiate capabilities
|
@raise QMPCapabilitiesError if fails to negotiate capabilities
|
||||||
"""
|
"""
|
||||||
self.__sock.connect(self.__address)
|
self.__sock.connect(self.__address)
|
||||||
greeting = self.__json_read()
|
return self.__negotiate_capabilities()
|
||||||
if greeting is None or not greeting.has_key('QMP'):
|
|
||||||
raise QMPConnectError
|
def accept(self):
|
||||||
# Greeting seems ok, negotiate capabilities
|
"""
|
||||||
resp = self.cmd('qmp_capabilities')
|
Await connection from QMP Monitor and perform capabilities negotiation.
|
||||||
if "return" in resp:
|
|
||||||
return greeting
|
@return QMP greeting dict
|
||||||
raise QMPCapabilitiesError
|
@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):
|
def cmd_obj(self, qmp_cmd):
|
||||||
"""
|
"""
|
||||||
|
@ -106,9 +128,11 @@ class QEMUMonitorProtocol:
|
||||||
qmp_cmd['id'] = id
|
qmp_cmd['id'] = id
|
||||||
return self.cmd_obj(qmp_cmd)
|
return self.cmd_obj(qmp_cmd)
|
||||||
|
|
||||||
def get_events(self):
|
def get_events(self, wait=False):
|
||||||
"""
|
"""
|
||||||
Get a list of available QMP events.
|
Get a list of available QMP events.
|
||||||
|
|
||||||
|
@param wait: block until an event is available (bool)
|
||||||
"""
|
"""
|
||||||
self.__sock.setblocking(0)
|
self.__sock.setblocking(0)
|
||||||
try:
|
try:
|
||||||
|
@ -118,6 +142,8 @@ class QEMUMonitorProtocol:
|
||||||
# No data available
|
# No data available
|
||||||
pass
|
pass
|
||||||
self.__sock.setblocking(1)
|
self.__sock.setblocking(1)
|
||||||
|
if not self.__events and wait:
|
||||||
|
self.__json_read(only_event=True)
|
||||||
return self.__events
|
return self.__events
|
||||||
|
|
||||||
def clear_events(self):
|
def clear_events(self):
|
||||||
|
|
|
@ -740,10 +740,11 @@ ETEXI
|
||||||
#if defined(TARGET_I386)
|
#if defined(TARGET_I386)
|
||||||
{
|
{
|
||||||
.name = "nmi",
|
.name = "nmi",
|
||||||
.args_type = "cpu_index:i",
|
.args_type = "",
|
||||||
.params = "cpu",
|
.params = "",
|
||||||
.help = "inject an NMI on the given CPU",
|
.help = "inject an NMI on all guest's CPUs",
|
||||||
.mhandler.cmd = do_inject_nmi,
|
.user_print = monitor_user_noop,
|
||||||
|
.mhandler.cmd_new = do_inject_nmi,
|
||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
STEXI
|
STEXI
|
||||||
|
|
19
monitor.c
19
monitor.c
|
@ -2544,16 +2544,21 @@ static void do_wav_capture(Monitor *mon, const QDict *qdict)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(TARGET_I386)
|
#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;
|
CPUState *env;
|
||||||
int cpu_index = qdict_get_int(qdict, "cpu_index");
|
|
||||||
|
|
||||||
for (env = first_cpu; env != NULL; env = env->next_cpu)
|
for (env = first_cpu; env != NULL; env = env->next_cpu) {
|
||||||
if (env->cpu_index == cpu_index) {
|
cpu_interrupt(env, CPU_INTERRUPT_NMI);
|
||||||
cpu_interrupt(env, CPU_INTERRUPT_NMI);
|
}
|
||||||
break;
|
|
||||||
}
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static int do_inject_nmi(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
||||||
|
{
|
||||||
|
qerror_report(QERR_UNSUPPORTED);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
4
qerror.c
4
qerror.c
|
@ -200,6 +200,10 @@ static const QErrorStringTable qerror_table[] = {
|
||||||
.error_fmt = QERR_UNDEFINED_ERROR,
|
.error_fmt = QERR_UNDEFINED_ERROR,
|
||||||
.desc = "An undefined error has ocurred",
|
.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,
|
.error_fmt = QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||||
.desc = "'%(device)' uses a %(format) feature which is not "
|
.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 \
|
#define QERR_UNDEFINED_ERROR \
|
||||||
"{ 'class': 'UndefinedError', 'data': {} }"
|
"{ 'class': 'UndefinedError', 'data': {} }"
|
||||||
|
|
||||||
|
#define QERR_UNSUPPORTED \
|
||||||
|
"{ 'class': 'Unsupported', 'data': {} }"
|
||||||
|
|
||||||
#define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \
|
#define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \
|
||||||
"{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }"
|
"{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }"
|
||||||
|
|
||||||
|
|
|
@ -427,6 +427,33 @@ Example:
|
||||||
"filename": "/tmp/physical-mem-dump" } }
|
"filename": "/tmp/physical-mem-dump" } }
|
||||||
<- { "return": {} }
|
<- { "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
|
EQMP
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue