blob: d693d83d80529c85eb515ec94dd89c96b6136770 [file] [log] [blame]
/*
* QEMU System Emulator
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/* the following is needed on Linux to define ptsname() in stdlib.h */
#if defined(__linux__)
#define _GNU_SOURCE 1
#endif
#include "qemu-common.h"
#include "net.h"
#include "console.h"
#include "qemu-timer.h"
#include "qemu-char.h"
#include "block.h"
#include "audio/audio.h"
#include "android/android.h"
#include "charpipe.h"
#include "android/globals.h"
#include "android/utils/bufprint.h"
#include "android/utils/system.h"
#ifdef CONFIG_MEMCHECK
#include "memcheck/memcheck.h"
#endif // CONFIG_MEMCHECK
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
#include <errno.h>
#include <sys/time.h>
#include <zlib.h>
/* Needed early for CONFIG_BSD etc. */
#include "config-host.h"
#ifndef _WIN32
#include <libgen.h>
#include <pwd.h>
#include <sys/times.h>
#include <sys/wait.h>
#include <termios.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/resource.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#if defined(__NetBSD__)
#include <net/if_tap.h>
#endif
#ifdef __linux__
#include <linux/if_tun.h>
#endif
#include <arpa/inet.h>
#include <dirent.h>
#include <netdb.h>
#include <sys/select.h>
#ifdef CONFIG_BSD
#include <sys/stat.h>
#if defined(__FreeBSD__) || defined(__DragonFly__)
#include <libutil.h>
#else
#include <util.h>
#endif
#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)
#include <freebsd/stdlib.h>
#else
#ifdef __linux__
#include <pty.h>
#include <malloc.h>
#include <linux/rtc.h>
/* For the benefit of older linux systems which don't supply it,
we use a local copy of hpet.h. */
/* #include <linux/hpet.h> */
#include "hpet.h"
#include <linux/ppdev.h>
#include <linux/parport.h>
#endif
#ifdef __sun__
#include <sys/stat.h>
#include <sys/ethernet.h>
#include <sys/sockio.h>
#include <netinet/arp.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h> // must come after ip.h
#include <netinet/udp.h>
#include <netinet/tcp.h>
#include <net/if.h>
#include <syslog.h>
#include <stropts.h>
#endif
#endif
#endif
#if defined(__OpenBSD__)
#include <util.h>
#endif
#if defined(CONFIG_VDE)
#include <libvdeplug.h>
#endif
#ifdef _WIN32
#include <windows.h>
#include <malloc.h>
#include <sys/timeb.h>
#include <mmsystem.h>
#define getopt_long_only getopt_long
#define memalign(align, size) malloc(size)
#endif
#ifdef CONFIG_COCOA
#undef main
#define main qemu_main
#endif /* CONFIG_COCOA */
#include "qemu-timer.h"
#include "qemu-char.h"
#if defined(CONFIG_SKINS) && !defined(CONFIG_STANDALONE_CORE)
#undef main
#define main qemu_main
#endif
#include "qemu_socket.h"
static const char *data_dir;
static DisplayState *display_state;
DisplayType display_type = DT_DEFAULT;
const char* keyboard_layout = NULL;
int64_t ticks_per_sec;
int vm_running;
static int autostart;
QEMUClock *rtc_clock;
#ifdef TARGET_SPARC
int graphic_width = 1024;
int graphic_height = 768;
int graphic_depth = 8;
#else
int graphic_width = 800;
int graphic_height = 600;
int graphic_depth = 15;
#endif
static int full_screen = 0;
#ifdef CONFIG_SDL
static int no_frame = 0;
#endif
int no_quit = 0;
int smp_cpus = 1;
const char *vnc_display;
int acpi_enabled = 1;
int no_reboot = 0;
int no_shutdown = 0;
int cursor_hide = 1;
int graphic_rotate = 0;
#ifndef _WIN32
int daemonize = 0;
#endif
#ifdef TARGET_ARM
int old_param = 0;
#endif
const char *qemu_name;
int alt_grab = 0;
static QEMUTimer *nographic_timer;
uint8_t qemu_uuid[16];
extern int android_display_width;
extern int android_display_height;
extern int android_display_bpp;
extern void dprint( const char* format, ... );
#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
/* compute with 96 bit intermediate result: (a*b)/c */
uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
{
union {
uint64_t ll;
struct {
#ifdef HOST_WORDS_BIGENDIAN
uint32_t high, low;
#else
uint32_t low, high;
#endif
} l;
} u, res;
uint64_t rl, rh;
u.ll = a;
rl = (uint64_t)u.l.low * (uint64_t)b;
rh = (uint64_t)u.l.high * (uint64_t)b;
rh += (rl >> 32);
res.l.high = rh / c;
res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c;
return res.ll;
}
/***********************************************************/
/* I/O handling */
typedef struct IOHandlerRecord {
int fd;
IOCanReadHandler *fd_read_poll;
IOHandler *fd_read;
IOHandler *fd_write;
int deleted;
void *opaque;
/* temporary data */
struct pollfd *ufd;
struct IOHandlerRecord *next;
} IOHandlerRecord;
static IOHandlerRecord *first_io_handler;
/* XXX: fd_read_poll should be suppressed, but an API change is
necessary in the character devices to suppress fd_can_read(). */
int qemu_set_fd_handler2(int fd,
IOCanReadHandler *fd_read_poll,
IOHandler *fd_read,
IOHandler *fd_write,
void *opaque)
{
IOHandlerRecord **pioh, *ioh;
if (!fd_read && !fd_write) {
pioh = &first_io_handler;
for(;;) {
ioh = *pioh;
if (ioh == NULL)
break;
if (ioh->fd == fd) {
ioh->deleted = 1;
break;
}
pioh = &ioh->next;
}
} else {
for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) {
if (ioh->fd == fd)
goto found;
}
ANEW0(ioh);
ioh->next = first_io_handler;
first_io_handler = ioh;
found:
ioh->fd = fd;
ioh->fd_read_poll = fd_read_poll;
ioh->fd_read = fd_read;
ioh->fd_write = fd_write;
ioh->opaque = opaque;
ioh->deleted = 0;
}
return 0;
}
int qemu_set_fd_handler(int fd,
IOHandler *fd_read,
IOHandler *fd_write,
void *opaque)
{
return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
}
/***********************************************************/
/* main execution loop */
static void gui_update(void *opaque)
{
uint64_t interval = GUI_REFRESH_INTERVAL;
DisplayState *ds = opaque;
DisplayChangeListener *dcl = ds->listeners;
dpy_refresh(ds);
while (dcl != NULL) {
if (dcl->gui_timer_interval &&
dcl->gui_timer_interval < interval)
interval = dcl->gui_timer_interval;
dcl = dcl->next;
}
qemu_mod_timer(ds->gui_timer, interval + qemu_get_clock(rt_clock));
}
static void nographic_update(void *opaque)
{
uint64_t interval = GUI_REFRESH_INTERVAL;
qemu_mod_timer(nographic_timer, interval + qemu_get_clock(rt_clock));
}
static int shutdown_requested = 0;
void qemu_system_shutdown_request(void)
{
shutdown_requested = 1;
}
static int qemu_event_init(void)
{
return 0;
}
static int qemu_init_main_loop(void)
{
return qemu_event_init();
}
#define qemu_mutex_lock_iothread() do { } while (0)
#define qemu_mutex_unlock_iothread() do { } while (0)
#ifdef _WIN32
static void host_main_loop_wait(int *timeout)
{
}
#else
static void host_main_loop_wait(int *timeout)
{
}
#endif
void main_loop_wait(int timeout)
{
IOHandlerRecord *ioh;
fd_set rfds, wfds, xfds;
int ret, nfds;
struct timeval tv;
host_main_loop_wait(&timeout);
/* poll any events */
/* XXX: separate device handlers from system ones */
nfds = -1;
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_ZERO(&xfds);
for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) {
if (ioh->deleted)
continue;
if (ioh->fd_read &&
(!ioh->fd_read_poll ||
ioh->fd_read_poll(ioh->opaque) != 0)) {
FD_SET(ioh->fd, &rfds);
if (ioh->fd > nfds)
nfds = ioh->fd;
}
if (ioh->fd_write) {
FD_SET(ioh->fd, &wfds);
if (ioh->fd > nfds)
nfds = ioh->fd;
}
}
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
if (ret > 0) {
IOHandlerRecord **pioh;
for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) {
if (!ioh->deleted && ioh->fd_read && FD_ISSET(ioh->fd, &rfds)) {
ioh->fd_read(ioh->opaque);
}
if (!ioh->deleted && ioh->fd_write && FD_ISSET(ioh->fd, &wfds)) {
ioh->fd_write(ioh->opaque);
}
}
/* remove deleted IO handlers */
pioh = &first_io_handler;
while (*pioh) {
ioh = *pioh;
if (ioh->deleted) {
*pioh = ioh->next;
AFREE(ioh);
} else
pioh = &ioh->next;
}
}
qemu_run_all_timers();
}
static void main_loop(void)
{
while (!shutdown_requested) {
main_loop_wait(qemu_calculate_timeout());
}
}
#ifndef _WIN32
static void termsig_handler(int signal)
{
/* qemu_system_shutdown_request(); */
}
static void sigchld_handler(int signal)
{
waitpid(-1, NULL, WNOHANG);
}
static void sighandler_setup(void)
{
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = termsig_handler;
sigaction(SIGINT, &act, NULL);
sigaction(SIGHUP, &act, NULL);
sigaction(SIGTERM, &act, NULL);
act.sa_handler = sigchld_handler;
act.sa_flags = SA_NOCLDSTOP;
sigaction(SIGCHLD, &act, NULL);
}
#endif
#define QEMU_FILE_TYPE_BIOS 0
#define QEMU_FILE_TYPE_KEYMAP 1
char *qemu_find_file(int type, const char *name)
{
int len;
const char *subdir;
char *buf;
/* If name contains path separators then try it as a straight path. */
if ((strchr(name, '/') || strchr(name, '\\'))
&& access(name, R_OK) == 0) {
return strdup(name);
}
switch (type) {
case QEMU_FILE_TYPE_BIOS:
subdir = "";
break;
case QEMU_FILE_TYPE_KEYMAP:
subdir = "keymaps/";
break;
default:
abort();
}
len = strlen(data_dir) + strlen(name) + strlen(subdir) + 2;
buf = android_alloc0(len);
snprintf(buf, len, "%s/%s%s", data_dir, subdir, name);
if (access(buf, R_OK)) {
AFREE(buf);
return NULL;
}
return buf;
}
#ifdef _WIN32
static BOOL WINAPI qemu_ctrl_handler(DWORD type)
{
exit(STATUS_CONTROL_C_EXIT);
return TRUE;
}
#endif
int main(int argc, char **argv, char **envp)
{
DisplayState *ds;
DisplayChangeListener *dcl;
init_clocks();
#ifndef _WIN32
{
struct sigaction act;
sigfillset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &act, NULL);
}
#else
SetConsoleCtrlHandler(qemu_ctrl_handler, TRUE);
/* Note: cpu_interrupt() is currently not SMP safe, so we force
QEMU to run on a single CPU */
{
HANDLE h;
DWORD mask, smask;
int i;
h = GetCurrentProcess();
if (GetProcessAffinityMask(h, &mask, &smask)) {
for(i = 0; i < 32; i++) {
if (mask & (1 << i))
break;
}
if (i != 32) {
mask = 1 << i;
SetProcessAffinityMask(h, mask);
}
}
}
#endif
autostart= 1;
if (qemu_init_main_loop()) {
fprintf(stderr, "qemu_init_main_loop failed\n");
exit(1);
}
if (init_timer_alarm() < 0) {
fprintf(stderr, "could not initialize alarm timer\n");
exit(1);
}
#ifdef _WIN32
socket_init();
#endif
#ifndef _WIN32
/* must be after terminal init, SDL library changes signal handlers */
sighandler_setup();
#endif
/* just use the first displaystate for the moment */
ds = display_state = get_displaystate();
if (display_type == DT_DEFAULT) {
display_type = DT_SDL;
}
switch (display_type) {
case DT_NOGRAPHIC:
break;
case DT_SDL:
sdl_display_init(ds, full_screen, no_frame);
break;
default:
break;
}
dpy_resize(ds);
dcl = ds->listeners;
while (dcl != NULL) {
if (dcl->dpy_refresh != NULL) {
ds->gui_timer = qemu_new_timer(rt_clock, gui_update, ds);
qemu_mod_timer(ds->gui_timer, qemu_get_clock(rt_clock));
}
dcl = dcl->next;
}
if (display_type == DT_NOGRAPHIC || display_type == DT_VNC) {
nographic_timer = qemu_new_timer(rt_clock, nographic_update, NULL);
qemu_mod_timer(nographic_timer, qemu_get_clock(rt_clock));
}
//qemu_chr_initial_reset();
main_loop();
quit_timers();
return 0;
}