diff options
-rw-r--r-- | CHANGES.TXT | 6 | ||||
-rwxr-xr-x | android-configure.sh | 2 | ||||
-rw-r--r-- | android/config/darwin-x86/config-host.h | 1 | ||||
-rw-r--r-- | android/config/freebsd-x86/config-host.h | 1 | ||||
-rw-r--r-- | android/config/linux-x86/config-host.h | 1 | ||||
-rw-r--r-- | android/config/windows/config-host.h | 1 | ||||
-rw-r--r-- | android/console.c | 159 | ||||
-rw-r--r-- | console.h | 5 | ||||
-rw-r--r-- | docs/CHAR-DEVICES.TXT | 6 | ||||
-rw-r--r-- | monitor.c | 35 | ||||
-rw-r--r-- | monitor.h | 5 | ||||
-rw-r--r-- | qemu-char-android.c | 11 | ||||
-rw-r--r-- | readline.c | 9 | ||||
-rw-r--r-- | readline.h | 2 | ||||
-rw-r--r-- | telephony/android_modem.c | 2 |
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 } }; @@ -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). @@ -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; @@ -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); @@ -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); + } +} @@ -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; } |