aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid 'Digit' Turner <digit@android.com>2010-09-07 06:21:25 -0700
committerDavid 'Digit' Turner <digit@android.com>2010-09-08 02:33:45 -0700
commite92bc56ef89ab8b51c4c89d4d9779b64e9491b9b (patch)
treecb39ae2fb8b3cdd445b74f6b43b4d37280eb320c
parenta7f114bcbd85d71f59f716df5a38340bdfe30637 (diff)
downloadexternal_qemu-e92bc56ef89ab8b51c4c89d4d9779b64e9491b9b.zip
external_qemu-e92bc56ef89ab8b51c4c89d4d9779b64e9491b9b.tar.gz
external_qemu-e92bc56ef89ab8b51c4c89d4d9779b64e9491b9b.tar.bz2
Add new "qemu monitor" command to the console.
This allows you to access the QEMU virtual machine monitor directly from the console (instead of playing with the command-line to do it). The implementation of the 'quit' command has been modified to simply close the connection, instead of stopping the emulator program. This patch introduces changes that allow a console session to be detached and redirected at runtime to other internal services of the emulator program. This will be useful in the future to implement other features. + doc typo + add proper definitions for CONFIG_ANDROID on config-host.h + remove obsolete sysdeps.h dependency in android/console.c Change-Id: If16cfe41c12a26eb8f56e3a9c24452eafa5efab4
-rw-r--r--CHANGES.TXT6
-rwxr-xr-xandroid-configure.sh2
-rw-r--r--android/config/darwin-x86/config-host.h1
-rw-r--r--android/config/freebsd-x86/config-host.h1
-rw-r--r--android/config/linux-x86/config-host.h1
-rw-r--r--android/config/windows/config-host.h1
-rw-r--r--android/console.c159
-rw-r--r--console.h5
-rw-r--r--docs/CHAR-DEVICES.TXT6
-rw-r--r--monitor.c35
-rw-r--r--monitor.h5
-rw-r--r--qemu-char-android.c11
-rw-r--r--readline.c9
-rw-r--r--readline.h2
-rw-r--r--telephony/android_modem.c2
15 files changed, 162 insertions, 84 deletions
diff --git a/CHANGES.TXT b/CHANGES.TXT
index 726701c..183c45e 100644
--- a/CHANGES.TXT
+++ b/CHANGES.TXT
@@ -62,6 +62,12 @@ OTHER:
- Add a PulseAudio audio backend on Linux. It will be used by default
unless it's impossible to connect to the PA daemon.
+ - It is now possible to access the QEMU monitor from the console.
+ Just type "qemu monitor" and you will be at the monitor prompt.
+
+ Note that the monitor 'quit' command will not stop the emulator,
+ but will simply close the connection instead.
+
==============================================================================
Changes between 7.0 and 6.0
diff --git a/android-configure.sh b/android-configure.sh
index 70cd3de..8b65c22 100755
--- a/android-configure.sh
+++ b/android-configure.sh
@@ -466,6 +466,8 @@ if [ $BSD = 1 ] ; then
echo "#define MAP_ANONYMOUS MAP_ANON" >> $config_h
fi
+echo "#define CONFIG_ANDROID 1" >> $config_h
+
log "Generate : $config_h"
echo "Ready to go. Type 'make' to build emulator"
diff --git a/android/config/darwin-x86/config-host.h b/android/config/darwin-x86/config-host.h
index b25d8fe..f02a109 100644
--- a/android/config/darwin-x86/config-host.h
+++ b/android/config/darwin-x86/config-host.h
@@ -13,3 +13,4 @@
#define CONFIG_BSD 1
#define CONFIG_SKINS 1
#define CONFIG_UNAME_RELEASE ""
+#define CONFIG_ANDROID 1
diff --git a/android/config/freebsd-x86/config-host.h b/android/config/freebsd-x86/config-host.h
index 805e5de..844698a 100644
--- a/android/config/freebsd-x86/config-host.h
+++ b/android/config/freebsd-x86/config-host.h
@@ -11,3 +11,4 @@
#define CONFIG_BSD 1
#define CONFIG_UNAME_RELEASE ""
#define CONFIG_SKINS 1
+#define CONFIG_ANDROID 1
diff --git a/android/config/linux-x86/config-host.h b/android/config/linux-x86/config-host.h
index 904dbfa..1a86213 100644
--- a/android/config/linux-x86/config-host.h
+++ b/android/config/linux-x86/config-host.h
@@ -12,3 +12,4 @@
#define CONFIG_IOTHREAD 1
#define CONFIG_IOVEC 1
#define CONFIG_FDATASYNC 1
+#define CONFIG_ANDROID 1
diff --git a/android/config/windows/config-host.h b/android/config/windows/config-host.h
index 6e18a02..a1b022e 100644
--- a/android/config/windows/config-host.h
+++ b/android/config/windows/config-host.h
@@ -9,3 +9,4 @@
#define QEMU_PKGVERSION "Android"
#define CONFIG_SKINS 1
#define CONFIG_UNAME_RELEASE ""
+#define CONFIG_ANDROID 1
diff --git a/android/console.c b/android/console.c
index c3500e4..d341d71 100644
--- a/android/console.c
+++ b/android/console.c
@@ -38,6 +38,7 @@
#include "android/utils/stralloc.h"
#include "tcpdump.h"
#include "net.h"
+#include "monitor.h"
#include <stdlib.h>
#include <stdio.h>
@@ -55,13 +56,6 @@
#include "libslirp.h"
#endif
-/* set to 1 to use the i/o and event functions
- * defined in "telephony/sysdeps.h"
- */
-#define USE_SYSDEPS 0
-
-#include "sysdeps.h"
-
#define DEBUG 1
#if 1
@@ -88,12 +82,7 @@ typedef struct {
} RedirRec, *Redir;
-#if USE_SYSDEPS
-typedef SysChannel Socket;
-#else /* !USE_SYSDEPS */
-typedef int Socket;
-#endif /* !USE_SYSDEPS */
-
+typedef int Socket;
typedef struct ControlClientRec_
{
@@ -178,19 +167,53 @@ control_global_del_redir( ControlGlobal global,
return -1;
}
+/* Detach the socket descriptor from a given ControlClient
+ * and return its value. This is useful either when destroying
+ * the client, or redirecting the socket to another service.
+ *
+ * NOTE: this does not close the socket.
+ */
+static int
+control_client_detach( ControlClient client )
+{
+ int result;
+
+ if (client->sock < 0)
+ return -1;
+
+ qemu_set_fd_handler( client->sock, NULL, NULL, NULL );
+ result = client->sock;
+ client->sock = -1;
+
+ return result;
+}
+
+static void control_client_read( void* _client ); /* forward */
+
+/* Reattach a control client to a given socket.
+ * Return the old socket descriptor for the client.
+ */
+static int
+control_client_reattach( ControlClient client, int fd )
+{
+ int result = control_client_detach(client);
+ client->sock = fd;
+ qemu_set_fd_handler( fd, control_client_read, NULL, client );
+ return result;
+}
+
static void
control_client_destroy( ControlClient client )
{
ControlGlobal global = client->global;
ControlClient *pnode = &global->clients;
+ int sock;
D(( "destroying control client %p\n", client ));
-#if USE_SYSDEPS
- sys_channel_on( client->sock, 0, NULL, NULL );
-#else
- qemu_set_fd_handler( client->sock, NULL, NULL, NULL );
-#endif
+ sock = control_client_detach( client );
+ if (sock >= 0)
+ socket_close(sock);
for ( ;; ) {
ControlClient node = *pnode;
@@ -204,18 +227,9 @@ control_client_destroy( ControlClient client )
pnode = &node->next;
}
-#if USE_SYSDEPS
- sys_channel_close( client->sock );
- client->sock = NULL;
-#else
- socket_close( client->sock );
- client->sock = -1;
-#endif
-
free( client );
}
-static void control_client_read( void* _client ); /* forward */
static void control_control_write( ControlClient client, const char* buff, int len )
@@ -226,11 +240,7 @@ static void control_control_write( ControlClient client, const char* buff, in
len = strlen(buff);
while (len > 0) {
-#if USE_SYSDEPS
- ret = sys_channel_write( client->sock, buff, len );
-#else
ret = socket_send( client->sock, buff, len);
-#endif
if (ret < 0) {
if (errno != EINTR && errno != EWOULDBLOCK && errno != EAGAIN)
return;
@@ -263,23 +273,15 @@ control_client_create( Socket socket,
ControlClient client = calloc( sizeof(*client), 1 );
if (client) {
-#if !USE_SYSDEPS
socket_set_nodelay( socket );
socket_set_nonblock( socket );
-#endif
client->finished = 0;
client->global = global;
client->sock = socket;
client->next = global->clients;
global->clients = client;
-#if USE_SYSDEPS
- sys_channel_on( socket, SYS_EVENT_READ,
- (SysChannelCallback) control_client_read,
- client );
-#else
qemu_set_fd_handler( socket, control_client_read, NULL, client );
-#endif
}
return client;
}
@@ -490,11 +492,7 @@ control_client_read( void* _client )
int size;
D(( "in control_client read: " ));
-#if USE_SYSDEPS
- size = sys_channel_read( client->sock, buf, sizeof(buf) );
-#else
size = socket_recv( client->sock, buf, sizeof(buf) );
-#endif
if (size < 0) {
D(( "size < 0, exiting with %d: %s\n", errno, errno_str ));
if (errno != EWOULDBLOCK && errno != EAGAIN && errno != EINTR)
@@ -549,13 +547,6 @@ control_global_accept( void* _global )
D(( "control_global_accept: just in (fd=%p)\n", (void*)global->listen_fd ));
-#if USE_SYSDEPS
- fd = sys_channel_create_tcp_handler( global->listen_fd );
- if (fd == NULL) {
- perror("accept");
- return;
- }
-#else
for(;;) {
fd = socket_accept( global->listen_fd, NULL );
if (fd < 0 && errno != EINTR) {
@@ -569,7 +560,6 @@ control_global_accept( void* _global )
}
socket_set_xreuseaddr( fd );
-#endif
D(( "control_global_accept: creating new client\n" ));
client = control_client_create( fd, global );
@@ -586,28 +576,11 @@ control_global_init( ControlGlobal global,
int control_port )
{
Socket fd;
-#if !USE_SYSDEPS
int ret;
SockAddress sockaddr;
-#endif
memset( global, 0, sizeof(*global) );
- sys_main_init();
-
-#if USE_SYSDEPS
- fd = sys_channel_create_tcp_server( control_port );
- if (fd == NULL) {
- return -1;
- }
-
- D(("global fd=%p\n", fd));
-
- global->listen_fd = fd;
- sys_channel_on( fd, SYS_EVENT_READ,
- (SysChannelCallback) control_global_accept,
- global );
-#else
fd = socket_create_inet( SOCKET_STREAM );
if (fd < 0) {
perror("socket");
@@ -637,7 +610,6 @@ control_global_init( ControlGlobal global,
global->listen_fd = fd;
qemu_set_fd_handler( fd, control_global_accept, NULL, global );
-#endif
return 0;
}
@@ -1959,7 +1931,7 @@ do_geo_nmea( ControlClient client, char* args )
static int
do_geo_fix( ControlClient client, char* args )
{
-#define MAX_GEO_PARAMS 4
+#define MAX_GEO_PARAMS 5
char* p = args;
int n_params = 0;
double params[ MAX_GEO_PARAMS ];
@@ -2151,6 +2123,49 @@ static const CommandDefRec window_commands[] =
/********************************************************************************************/
/********************************************************************************************/
/***** ******/
+/***** Q E M U C O M M A N D S ******/
+/***** ******/
+/********************************************************************************************/
+/********************************************************************************************/
+
+static int
+do_qemu_monitor( ControlClient client, char* args )
+{
+ char socketname[32];
+ int fd;
+ CharDriverState* cs;
+
+ if (args != NULL) {
+ control_write( client, "KO: no argument for 'qemu monitor'\r\n" );
+ return -1;
+ }
+ /* Detach the client socket, and re-attach it to a monitor */
+ fd = control_client_detach(client);
+ snprintf(socketname, sizeof socketname, "tcp:socket=%d", fd);
+ cs = qemu_chr_open("monitor", socketname, NULL);
+ if (cs == NULL) {
+ control_client_reattach(client, fd);
+ control_write( client, "KO: internal error: could not detach from console !\r\n" );
+ return -1;
+ }
+ monitor_init(cs, MONITOR_USE_READLINE|MONITOR_QUIT_DOESNT_EXIT);
+ control_client_destroy(client);
+ return 0;
+}
+
+static const CommandDefRec qemu_commands[] =
+{
+ { "monitor", "enter QEMU monitor",
+ "Enter the QEMU virtual machine monitor\r\n",
+ NULL, do_qemu_monitor, NULL },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+
+/********************************************************************************************/
+/********************************************************************************************/
+/***** ******/
/***** M A I N C O M M A N D S ******/
/***** ******/
/********************************************************************************************/
@@ -2212,6 +2227,10 @@ static const CommandDefRec main_commands[] =
"allows you to modify the emulator window\r\n", NULL,
NULL, window_commands },
+ { "qemu", "QEMU-specific commands",
+ "allows to connect to the QEMU virtual machine monitor\r\n", NULL,
+ NULL, qemu_commands },
+
{ NULL, NULL, NULL, NULL, NULL, NULL }
};
diff --git a/console.h b/console.h
index fd283ba..3d0c4f4 100644
--- a/console.h
+++ b/console.h
@@ -330,9 +330,4 @@ char *vnc_display_local_addr(DisplayState *ds);
/* curses.c */
void curses_display_init(DisplayState *ds, int full_screen);
-#if defined(CONFIG_ANDROID)
-/* android-display.c */
-void android_display_init(DisplayState *ds);
-#endif
-
#endif
diff --git a/docs/CHAR-DEVICES.TXT b/docs/CHAR-DEVICES.TXT
index 9805a4a..d6b2701 100644
--- a/docs/CHAR-DEVICES.TXT
+++ b/docs/CHAR-DEVICES.TXT
@@ -20,9 +20,9 @@ a few important functions:
were really written (which can be 0) and the caller must deal with it.
This is very similar to writing to a non-blocking BSD socket on Unix.
- int qemu_chr_read( CharDriverState* cs,
- const uint8_t* data,
- int datalen );
+ int qemu_chr_write( CharDriverState* cs,
+ const uint8_t* data,
+ int datalen );
This function may return -1 in case of error, but this depends entirely
on the underlying implementation (some of them will just return 0 instead).
diff --git a/monitor.c b/monitor.c
index f640bf8..3c23397 100644
--- a/monitor.c
+++ b/monitor.c
@@ -70,6 +70,8 @@ typedef struct mon_cmd_t {
const char *help;
} mon_cmd_t;
+#define MON_CMD_T_INITIALIZER { NULL, NULL, NULL, NULL, NULL }
+
struct Monitor {
CharDriverState *chr;
int flags;
@@ -81,6 +83,7 @@ struct Monitor {
BlockDriverCompletionFunc *password_completion_cb;
void *password_opaque;
QLIST_ENTRY(Monitor) entry;
+ int has_quit;
};
static QLIST_HEAD(mon_list, Monitor) mon_list;
@@ -409,7 +412,11 @@ static void do_info_cpu_stats(Monitor *mon)
static void do_quit(Monitor *mon)
{
- exit(0);
+ if ((mon->flags & MONITOR_QUIT_DOESNT_EXIT) == 0) {
+ exit(0);
+ }
+ /* we cannot destroy the monitor just yet, so flag it instead */
+ mon->has_quit = 1;
}
static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
@@ -1661,7 +1668,7 @@ static void do_acl(Monitor *mon,
static const mon_cmd_t mon_cmds[] = {
#include "qemu-monitor.h"
- { NULL, NULL, },
+ MON_CMD_T_INITIALIZER
};
/* Please update qemu-monitor.hx when adding or changing commands */
@@ -1741,7 +1748,7 @@ static const mon_cmd_t info_cmds[] = {
"", "show balloon information" },
{ "qtree", "", do_info_qtree,
"", "show device tree" },
- { NULL, NULL, },
+ MON_CMD_T_INITIALIZER
};
/*******************************************************************/
@@ -1759,6 +1766,8 @@ typedef struct MonitorDef {
int type;
} MonitorDef;
+#define MONITOR_DEF_INITIALIZER { NULL, 0, NULL, 0 }
+
#if defined(TARGET_I386)
static target_long monitor_get_pc (const struct MonitorDef *md, int val)
{
@@ -2085,7 +2094,7 @@ static const MonitorDef monitor_defs[] = {
{ "fprs", offsetof(CPUState, fprs) },
#endif
#endif
- { NULL },
+ MONITOR_DEF_INITIALIZER
};
static void expr_error(Monitor *mon, const char *msg)
@@ -2938,6 +2947,8 @@ static int monitor_can_read(void *opaque)
return (mon->suspend_cnt == 0) ? 128 : 0;
}
+static void monitor_done(Monitor *mon); // forward
+
static void monitor_read(void *opaque, const uint8_t *buf, int size)
{
Monitor *old_mon = cur_mon;
@@ -2955,6 +2966,9 @@ static void monitor_read(void *opaque, const uint8_t *buf, int size)
monitor_handle_command(cur_mon, (char *)buf);
}
+ if (cur_mon->has_quit) {
+ monitor_done(cur_mon);
+ }
cur_mon = old_mon;
}
@@ -3046,6 +3060,19 @@ void monitor_init(CharDriverState *chr, int flags)
cur_mon = mon;
}
+static void monitor_done(Monitor *mon)
+{
+ if (cur_mon == mon)
+ cur_mon = NULL;
+
+ QLIST_REMOVE(mon, entry);
+
+ readline_free(mon->rs);
+ qemu_chr_close(mon->chr);
+
+ qemu_free(mon);
+}
+
static void bdrv_password_cb(Monitor *mon, const char *password, void *opaque)
{
BlockDriverState *bs = opaque;
diff --git a/monitor.h b/monitor.h
index 13e8cc7..5a4eef8 100644
--- a/monitor.h
+++ b/monitor.h
@@ -8,8 +8,9 @@
extern Monitor *cur_mon;
/* flags for monitor_init */
-#define MONITOR_IS_DEFAULT 0x01
-#define MONITOR_USE_READLINE 0x02
+#define MONITOR_IS_DEFAULT 0x01
+#define MONITOR_USE_READLINE 0x02
+#define MONITOR_QUIT_DOESNT_EXIT 0x04 /* prevent 'quit' from exiting the emulator */
void monitor_init(CharDriverState *chr, int flags);
diff --git a/qemu-char-android.c b/qemu-char-android.c
index b468606..ca854b9 100644
--- a/qemu-char-android.c
+++ b/qemu-char-android.c
@@ -2088,6 +2088,17 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
fd = unix_connect(host_str);
}
} else {
+#ifdef CONFIG_ANDROID
+ if (!strncmp(host_str,"socket=",7)) {
+ char *end;
+ long val = strtol(host_str+7, &end, 10);
+ if (val <= 0 || end == host_str+7) {
+ printf("Invalid socket number: '%s'\n", host_str+7);
+ goto fail;
+ }
+ fd = (int) val;
+ } else
+#endif
if (is_listen) {
fd = inet_listen(host_str, chr->filename + offset, 256 - offset,
SOCKET_STREAM, 0);
diff --git a/readline.c b/readline.c
index 92f9cd1..16ec704 100644
--- a/readline.c
+++ b/readline.c
@@ -474,3 +474,12 @@ ReadLineState *readline_init(Monitor *mon,
return rs;
}
+
+void readline_free(ReadLineState *rs)
+{
+ if (rs) {
+ rs->mon = NULL;
+ rs->completion_finder = NULL;
+ qemu_free(rs);
+ }
+}
diff --git a/readline.h b/readline.h
index fc9806e..f46f92a 100644
--- a/readline.h
+++ b/readline.h
@@ -52,4 +52,6 @@ void readline_show_prompt(ReadLineState *rs);
ReadLineState *readline_init(Monitor *mon,
ReadLineCompletionFunc *completion_finder);
+void readline_free(ReadLineState *rs);
+
#endif /* !READLINE_H */
diff --git a/telephony/android_modem.c b/telephony/android_modem.c
index 1e060dd..2f4c98e 100644
--- a/telephony/android_modem.c
+++ b/telephony/android_modem.c
@@ -359,6 +359,8 @@ amodem_create( int base_port, AModemUnsolFunc unsol_func, void* unsol_opaque
modem->sim = asimcard_create(base_port);
+ sys_main_init();
+
return modem;
}