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 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):

View File

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

View File

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

View File

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

View File

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

View File

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