/* * 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" #ifdef CONFIG_MEMCHECK #include "memcheck/memcheck.h" #endif // CONFIG_MEMCHECK #include #include #include #include #include #include #include /* Needed early for CONFIG_BSD etc. */ #include "config-host.h" #ifndef _WIN32 #include #include #include #include #include #include #include #include #include #include #include #if defined(__NetBSD__) #include #endif #ifdef __linux__ #include #endif #include #include #include #include #ifdef CONFIG_BSD #include #if defined(__FreeBSD__) || defined(__DragonFly__) #include #else #include #endif #elif defined (__GLIBC__) && defined (__FreeBSD_kernel__) #include #else #ifdef __linux__ #include #include #include /* For the benefit of older linux systems which don't supply it, we use a local copy of hpet.h. */ /* #include */ #include "hpet.h" #include #include #endif #ifdef __sun__ #include #include #include #include #include #include #include #include // must come after ip.h #include #include #include #include #include #endif #endif #endif #if defined(__OpenBSD__) #include #endif #if defined(CONFIG_VDE) #include #endif #ifdef _WIN32 #include #include #include #include #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; static int rtc_utc = 1; static int rtc_date_offset = -1; /* -1 means no change */ 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) /***********************************************************/ /* real time host monotonic timer */ /* 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; } /***********************************************************/ /* host time/date access */ void qemu_get_timedate(struct tm *tm, int offset) { time_t ti; struct tm *ret; time(&ti); ti += offset; if (rtc_date_offset == -1) { if (rtc_utc) ret = gmtime(&ti); else ret = localtime(&ti); } else { ti -= rtc_date_offset; ret = gmtime(&ti); } memcpy(tm, ret, sizeof(struct tm)); } int qemu_timedate_diff(struct tm *tm) { time_t seconds; if (rtc_date_offset == -1) if (rtc_utc) seconds = mktimegm(tm); else seconds = mktime(tm); else seconds = mktimegm(tm) + rtc_date_offset; return seconds - time(NULL); } /***********************************************************/ /* 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; } ioh = qemu_mallocz(sizeof(IOHandlerRecord)); 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); } #ifdef _WIN32 /***********************************************************/ /* Polling handling */ typedef struct PollingEntry { PollingFunc *func; void *opaque; struct PollingEntry *next; } PollingEntry; static PollingEntry *first_polling_entry; int qemu_add_polling_cb(PollingFunc *func, void *opaque) { PollingEntry **ppe, *pe; pe = qemu_mallocz(sizeof(PollingEntry)); pe->func = func; pe->opaque = opaque; for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next); *ppe = pe; return 0; } void qemu_del_polling_cb(PollingFunc *func, void *opaque) { PollingEntry **ppe, *pe; for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next) { pe = *ppe; if (pe->func == func && pe->opaque == opaque) { *ppe = pe->next; qemu_free(pe); break; } } } /***********************************************************/ /* Wait objects support */ typedef struct WaitObjects { int num; HANDLE events[MAXIMUM_WAIT_OBJECTS + 1]; WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1]; void *opaque[MAXIMUM_WAIT_OBJECTS + 1]; } WaitObjects; static WaitObjects wait_objects = {0}; int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) { WaitObjects *w = &wait_objects; if (w->num >= MAXIMUM_WAIT_OBJECTS) return -1; w->events[w->num] = handle; w->func[w->num] = func; w->opaque[w->num] = opaque; w->num++; return 0; } void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque) { int i, found; WaitObjects *w = &wait_objects; found = 0; for (i = 0; i < w->num; i++) { if (w->events[i] == handle) found = 1; if (found) { w->events[i] = w->events[i + 1]; w->func[i] = w->func[i + 1]; w->opaque[i] = w->opaque[i + 1]; } } if (found) w->num--; } #endif /***********************************************************/ /* bottom halves (can be seen as timers which expire ASAP) */ struct QEMUBH { QEMUBHFunc *cb; void *opaque; int scheduled; int idle; int deleted; QEMUBH *next; }; static QEMUBH *first_bh = NULL; QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque) { QEMUBH *bh; bh = qemu_mallocz(sizeof(QEMUBH)); bh->cb = cb; bh->opaque = opaque; bh->next = first_bh; first_bh = bh; return bh; } int qemu_bh_poll(void) { QEMUBH *bh, **bhp; int ret; ret = 0; for (bh = first_bh; bh; bh = bh->next) { if (!bh->deleted && bh->scheduled) { bh->scheduled = 0; if (!bh->idle) ret = 1; bh->idle = 0; bh->cb(bh->opaque); } } /* remove deleted bhs */ bhp = &first_bh; while (*bhp) { bh = *bhp; if (bh->deleted) { *bhp = bh->next; qemu_free(bh); } else bhp = &bh->next; } return ret; } void qemu_bh_schedule_idle(QEMUBH *bh) { if (bh->scheduled) return; bh->scheduled = 1; bh->idle = 1; } void qemu_bh_schedule(QEMUBH *bh) { if (bh->scheduled) return; bh->scheduled = 1; bh->idle = 0; /* stop the currently executing CPU to execute the BH ASAP */ //qemu_notify_event(); } void qemu_bh_cancel(QEMUBH *bh) { bh->scheduled = 0; } void qemu_bh_delete(QEMUBH *bh) { bh->scheduled = 0; bh->deleted = 1; } void qemu_bh_update_timeout(int *timeout) { QEMUBH *bh; for (bh = first_bh; bh; bh = bh->next) { if (!bh->deleted && bh->scheduled) { if (bh->idle) { /* idle bottom halves will be polled at least * every 10ms */ *timeout = MIN(10, *timeout); } else { /* non-idle bottom halves will be executed * immediately */ *timeout = 0; break; } } } } /***********************************************************/ /* 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)); } #ifndef _WIN32 static int io_thread_fd = -1; static void qemu_event_read(void *opaque) { int fd = (unsigned long)opaque; ssize_t len; /* Drain the notify pipe */ do { char buffer[512]; len = read(fd, buffer, sizeof(buffer)); } while ((len == -1 && errno == EINTR) || len > 0); } static int qemu_event_init(void) { int err; int fds[2]; err = pipe(fds); if (err == -1) return -errno; err = fcntl_setfl(fds[0], O_NONBLOCK); if (err < 0) goto fail; err = fcntl_setfl(fds[1], O_NONBLOCK); if (err < 0) goto fail; qemu_set_fd_handler2(fds[0], NULL, qemu_event_read, NULL, (void *)(unsigned long)fds[0]); io_thread_fd = fds[1]; return 0; fail: close(fds[0]); close(fds[1]); return err; } #else HANDLE qemu_event_handle; static void dummy_event_handler(void *opaque) { } static int qemu_event_init(void) { qemu_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL); if (!qemu_event_handle) { perror("Failed CreateEvent"); return -1; } qemu_add_wait_object(qemu_event_handle, dummy_event_handler, NULL); return 0; } #if 0 static void qemu_event_increment(void) { SetEvent(qemu_event_handle); } #endif #endif #ifndef CONFIG_IOTHREAD 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) #else /* CONFIG_IOTHREAD */ #include "qemu-thread.h" QemuMutex qemu_global_mutex; static QemuMutex qemu_fair_mutex; static QemuThread io_thread; static QemuThread *tcg_cpu_thread; static QemuCond *tcg_halt_cond; static int qemu_system_ready; /* cpu creation */ static QemuCond qemu_cpu_cond; /* system init */ static QemuCond qemu_system_cond; static QemuCond qemu_pause_cond; static void block_io_signals(void); static void unblock_io_signals(void); static int tcg_has_work(void); static int qemu_init_main_loop(void) { int ret; ret = qemu_event_init(); if (ret) return ret; qemu_cond_init(&qemu_pause_cond); qemu_mutex_init(&qemu_fair_mutex); qemu_mutex_init(&qemu_global_mutex); qemu_mutex_lock(&qemu_global_mutex); unblock_io_signals(); qemu_thread_self(&io_thread); return 0; } static void block_io_signals(void) { sigset_t set; struct sigaction sigact; sigemptyset(&set); sigaddset(&set, SIGUSR2); sigaddset(&set, SIGIO); sigaddset(&set, SIGALRM); pthread_sigmask(SIG_BLOCK, &set, NULL); sigemptyset(&set); sigaddset(&set, SIGUSR1); pthread_sigmask(SIG_UNBLOCK, &set, NULL); memset(&sigact, 0, sizeof(sigact)); sigact.sa_handler = cpu_signal; sigaction(SIGUSR1, &sigact, NULL); } static void unblock_io_signals(void) { sigset_t set; sigemptyset(&set); sigaddset(&set, SIGUSR2); sigaddset(&set, SIGIO); sigaddset(&set, SIGALRM); pthread_sigmask(SIG_UNBLOCK, &set, NULL); sigemptyset(&set); sigaddset(&set, SIGUSR1); pthread_sigmask(SIG_BLOCK, &set, NULL); } #endif #ifdef _WIN32 static void host_main_loop_wait(int *timeout) { int ret, ret2, i; PollingEntry *pe; /* XXX: need to suppress polling by better using win32 events */ ret = 0; for(pe = first_polling_entry; pe != NULL; pe = pe->next) { ret |= pe->func(pe->opaque); } if (ret == 0) { int err; WaitObjects *w = &wait_objects; ret = WaitForMultipleObjects(w->num, w->events, FALSE, *timeout); if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) { if (w->func[ret - WAIT_OBJECT_0]) w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]); /* Check for additional signaled events */ for(i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) { /* Check if event is signaled */ ret2 = WaitForSingleObject(w->events[i], 0); if(ret2 == WAIT_OBJECT_0) { if (w->func[i]) w->func[i](w->opaque[i]); } else if (ret2 == WAIT_TIMEOUT) { } else { err = GetLastError(); fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err); } } } else if (ret == WAIT_TIMEOUT) { } else { err = GetLastError(); fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err); } } *timeout = 0; } #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; qemu_bh_update_timeout(&timeout); 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; qemu_mutex_unlock_iothread(); ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv); qemu_mutex_lock_iothread(); 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; qemu_free(ioh); } else pioh = &ioh->next; } } //charpipe_poll(); qemu_run_all_timers(); /* Check bottom-halves last in case any of the earlier events triggered them. */ qemu_bh_poll(); } static void main_loop(void) { #ifdef CONFIG_IOTHREAD qemu_system_ready = 1; qemu_cond_broadcast(&qemu_system_cond); #endif for (;;) { 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 = qemu_mallocz(len); snprintf(buf, len, "%s/%s%s", data_dir, subdir, name); if (access(buf, R_OK)) { qemu_free(buf); return NULL; } return buf; } 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; // register_watchdogs(); #if 0 /* Initialize boot properties. */ boot_property_init_service(); /* Initialize character map. */ if (android_charmap_setup(op_charmap_file)) { if (op_charmap_file) { fprintf(stderr, "Unable to initialize character map from file %s.\n", op_charmap_file); } else { fprintf(stderr, "Unable to initialize default character map.\n"); } exit(1); } #endif 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(); net_cleanup(); return 0; }