Merge remote-tracking branch 'qmp/for-anthony' into staging

This commit is contained in:
Anthony Liguori 2011-06-08 12:16:24 -05:00
commit 924f766af9
6 changed files with 91 additions and 25 deletions

View File

@ -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 @@ def __get_sock(self):
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 @@ def __json_read(self):
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 @@ def connect(self):
@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 @@ def cmd(self, name, args=None, id=None):
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 @@ def get_events(self):
# 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):

View File

@ -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

View File

@ -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

View File

@ -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 "

View File

@ -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 } }"

View File

@ -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
{