X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=vl.c;h=867111c1eb320dc9131e3c3e6737b7157d70d570;hb=f654d9e20a9fb1971c6c8fe07c3b9164e9d22926;hp=0a47d2a4e79994b324a5f6619237bb88e8f6753f;hpb=6e29f5da4de7b3686609e92f2d4b3119762a744a;p=qemu diff --git a/vl.c b/vl.c index 0a47d2a..867111c 100644 --- a/vl.c +++ b/vl.c @@ -138,6 +138,7 @@ int main(int argc, char **argv) #include "hw/isa.h" #include "hw/baum.h" #include "hw/bt.h" +#include "hw/watchdog.h" #include "hw/smbios.h" #include "hw/xen.h" #include "bt-host.h" @@ -252,6 +253,8 @@ int graphic_rotate = 0; #ifndef _WIN32 int daemonize = 0; #endif +WatchdogTimerModel *watchdog = NULL; +int watchdog_action = WDT_RESET; const char *option_rom[MAX_OPTION_ROMS]; int nb_option_roms; int semihosting_enabled = 0; @@ -934,7 +937,7 @@ static struct qemu_alarm_timer *alarm_timer; struct qemu_alarm_win32 { MMRESULT timerId; unsigned int period; -} alarm_win32_data = {0, NULL, -1}; +} alarm_win32_data = {0, -1}; static int win32_start_timer(struct qemu_alarm_timer *t); static void win32_stop_timer(struct qemu_alarm_timer *t); @@ -1346,20 +1349,20 @@ static void host_alarm_handler(int host_signum) qemu_get_clock(vm_clock))) || qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], qemu_get_clock(rt_clock))) { - CPUState *env = next_cpu; - qemu_event_increment(); alarm_timer->flags |= ALARM_FLAG_EXPIRED; - if (env) { +#ifndef CONFIG_IOTHREAD + if (next_cpu) { /* stop the currently executing cpu because a timer occured */ - cpu_exit(env); + cpu_exit(next_cpu); #ifdef CONFIG_KQEMU - if (env->kqemu_enabled) { - kqemu_cpu_interrupt(env); + if (next_cpu->kqemu_enabled) { + kqemu_cpu_interrupt(next_cpu); } #endif } +#endif timer_alarm_pending = 1; qemu_notify_event(); } @@ -1866,29 +1869,45 @@ int get_param_value(char *buf, int buf_size, return 0; } -int check_params(char *buf, int buf_size, - const char * const *params, const char *str) +int check_params(const char * const *params, const char *str) { + int name_buf_size = 1; const char *p; - int i; + char *name_buf; + int i, len; + int ret = 0; + + for (i = 0; params[i] != NULL; i++) { + len = strlen(params[i]) + 1; + if (len > name_buf_size) { + name_buf_size = len; + } + } + name_buf = qemu_malloc(name_buf_size); p = str; while (*p != '\0') { - p = get_opt_name(buf, buf_size, p, '='); - if (*p != '=') - return -1; + p = get_opt_name(name_buf, name_buf_size, p, '='); + if (*p != '=') { + ret = -1; + break; + } p++; for(i = 0; params[i] != NULL; i++) - if (!strcmp(params[i], buf)) + if (!strcmp(params[i], name_buf)) break; - if (params[i] == NULL) - return -1; + if (params[i] == NULL) { + ret = -1; + break; + } p = get_opt_value(NULL, 0, p); if (*p != ',') break; p++; } - return 0; + + qemu_free(name_buf); + return ret; } /***********************************************************/ @@ -2241,7 +2260,7 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque) "cache", "format", "serial", "werror", NULL }; - if (check_params(buf, sizeof(buf), params, str) < 0) { + if (check_params(params, str) < 0) { fprintf(stderr, "qemu: unknown parameter '%s' in '%s'\n", buf, str); return -1; @@ -2518,7 +2537,7 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque) drives_table[drives_table_idx].unit = unit_id; drives_table[drives_table_idx].onerror = onerror; drives_table[drives_table_idx].drive_opt_idx = arg - drives_opt; - strncpy(drives_table[nb_drives].serial, serial, sizeof(serial)); + strncpy(drives_table[drives_table_idx].serial, serial, sizeof(serial)); nb_drives++; switch(type) { @@ -3537,6 +3556,9 @@ static void vm_state_notify(int running, int reason) } } +static void resume_all_vcpus(void); +static void pause_all_vcpus(void); + void vm_start(void) { if (!vm_running) { @@ -3544,6 +3566,7 @@ void vm_start(void) vm_running = 1; vm_state_notify(1, 0); qemu_rearm_alarm_timer(alarm_timer); + resume_all_vcpus(); } } @@ -3602,6 +3625,7 @@ static void do_vm_stop(int reason) if (vm_running) { cpu_disable_ticks(); vm_running = 0; + pause_all_vcpus(); vm_state_notify(0, reason); } } @@ -3654,18 +3678,13 @@ void qemu_system_powerdown_request(void) qemu_notify_event(); } -void qemu_notify_event(void) +#ifdef CONFIG_IOTHREAD +static void qemu_system_vmstop_request(int reason) { - CPUState *env = cpu_single_env; - - if (env) { - cpu_exit(env); -#ifdef USE_KQEMU - if (env->kqemu_enabled) - kqemu_cpu_interrupt(env); -#endif - } + vmstop_requested = reason; + qemu_notify_event(); } +#endif #ifndef _WIN32 static int io_thread_fd = -1; @@ -3713,6 +3732,8 @@ static int qemu_event_init(void) (void *)(unsigned long)fds[0]); io_thread_fd = fds[1]; + return 0; + fail: close(fds[0]); close(fds[1]); @@ -3742,6 +3763,16 @@ static void qemu_event_increment(void) } #endif +static int cpu_can_run(CPUState *env) +{ + if (env->stop) + return 0; + if (env->stopped) + return 0; + return 1; +} + +#ifndef CONFIG_IOTHREAD static int qemu_init_main_loop(void) { return qemu_event_init(); @@ -3761,11 +3792,32 @@ int qemu_cpu_self(void *env) return 1; } +static void resume_all_vcpus(void) +{ +} + +static void pause_all_vcpus(void) +{ +} + void qemu_cpu_kick(void *env) { return; } +void qemu_notify_event(void) +{ + CPUState *env = cpu_single_env; + + if (env) { + cpu_exit(env); +#ifdef USE_KQEMU + if (env->kqemu_enabled) + kqemu_cpu_interrupt(env); +#endif + } +} + #define qemu_mutex_lock_iothread() do { } while (0) #define qemu_mutex_unlock_iothread() do { } while (0) @@ -3774,6 +3826,321 @@ void vm_stop(int reason) do_vm_stop(reason); } +#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 qemu_wait_io_event(CPUState *env) +{ + while (!tcg_has_work()) + qemu_cond_timedwait(env->halt_cond, &qemu_global_mutex, 1000); + + qemu_mutex_unlock(&qemu_global_mutex); + + /* + * Users of qemu_global_mutex can be starved, having no chance + * to acquire it since this path will get to it first. + * So use another lock to provide fairness. + */ + qemu_mutex_lock(&qemu_fair_mutex); + qemu_mutex_unlock(&qemu_fair_mutex); + + qemu_mutex_lock(&qemu_global_mutex); + if (env->stop) { + env->stop = 0; + env->stopped = 1; + qemu_cond_signal(&qemu_pause_cond); + } +} + +static int qemu_cpu_exec(CPUState *env); + +static void *kvm_cpu_thread_fn(void *arg) +{ + CPUState *env = arg; + + block_io_signals(); + qemu_thread_self(env->thread); + + /* signal CPU creation */ + qemu_mutex_lock(&qemu_global_mutex); + env->created = 1; + qemu_cond_signal(&qemu_cpu_cond); + + /* and wait for machine initialization */ + while (!qemu_system_ready) + qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100); + + while (1) { + if (cpu_can_run(env)) + qemu_cpu_exec(env); + qemu_wait_io_event(env); + } + + return NULL; +} + +static void tcg_cpu_exec(void); + +static void *tcg_cpu_thread_fn(void *arg) +{ + CPUState *env = arg; + + block_io_signals(); + qemu_thread_self(env->thread); + + /* signal CPU creation */ + qemu_mutex_lock(&qemu_global_mutex); + for (env = first_cpu; env != NULL; env = env->next_cpu) + env->created = 1; + qemu_cond_signal(&qemu_cpu_cond); + + /* and wait for machine initialization */ + while (!qemu_system_ready) + qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100); + + while (1) { + tcg_cpu_exec(); + qemu_wait_io_event(cur_cpu); + } + + return NULL; +} + +void qemu_cpu_kick(void *_env) +{ + CPUState *env = _env; + qemu_cond_broadcast(env->halt_cond); + if (kvm_enabled()) + qemu_thread_signal(env->thread, SIGUSR1); +} + +int qemu_cpu_self(void *env) +{ + return (cpu_single_env != NULL); +} + +static void cpu_signal(int sig) +{ + if (cpu_single_env) + cpu_exit(cpu_single_env); +} + +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); +} + +static void qemu_signal_lock(unsigned int msecs) +{ + qemu_mutex_lock(&qemu_fair_mutex); + + while (qemu_mutex_trylock(&qemu_global_mutex)) { + qemu_thread_signal(tcg_cpu_thread, SIGUSR1); + if (!qemu_mutex_timedlock(&qemu_global_mutex, msecs)) + break; + } + qemu_mutex_unlock(&qemu_fair_mutex); +} + +static void qemu_mutex_lock_iothread(void) +{ + if (kvm_enabled()) { + qemu_mutex_lock(&qemu_fair_mutex); + qemu_mutex_lock(&qemu_global_mutex); + qemu_mutex_unlock(&qemu_fair_mutex); + } else + qemu_signal_lock(100); +} + +static void qemu_mutex_unlock_iothread(void) +{ + qemu_mutex_unlock(&qemu_global_mutex); +} + +static int all_vcpus_paused(void) +{ + CPUState *penv = first_cpu; + + while (penv) { + if (!penv->stopped) + return 0; + penv = (CPUState *)penv->next_cpu; + } + + return 1; +} + +static void pause_all_vcpus(void) +{ + CPUState *penv = first_cpu; + + while (penv) { + penv->stop = 1; + qemu_thread_signal(penv->thread, SIGUSR1); + qemu_cpu_kick(penv); + penv = (CPUState *)penv->next_cpu; + } + + while (!all_vcpus_paused()) { + qemu_cond_timedwait(&qemu_pause_cond, &qemu_global_mutex, 100); + penv = first_cpu; + while (penv) { + qemu_thread_signal(penv->thread, SIGUSR1); + penv = (CPUState *)penv->next_cpu; + } + } +} + +static void resume_all_vcpus(void) +{ + CPUState *penv = first_cpu; + + while (penv) { + penv->stop = 0; + penv->stopped = 0; + qemu_thread_signal(penv->thread, SIGUSR1); + qemu_cpu_kick(penv); + penv = (CPUState *)penv->next_cpu; + } +} + +static void tcg_init_vcpu(void *_env) +{ + CPUState *env = _env; + /* share a single thread for all cpus with TCG */ + if (!tcg_cpu_thread) { + env->thread = qemu_mallocz(sizeof(QemuThread)); + env->halt_cond = qemu_mallocz(sizeof(QemuCond)); + qemu_cond_init(env->halt_cond); + qemu_thread_create(env->thread, tcg_cpu_thread_fn, env); + while (env->created == 0) + qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100); + tcg_cpu_thread = env->thread; + tcg_halt_cond = env->halt_cond; + } else { + env->thread = tcg_cpu_thread; + env->halt_cond = tcg_halt_cond; + } +} + +static void kvm_start_vcpu(CPUState *env) +{ + kvm_init_vcpu(env); + env->thread = qemu_mallocz(sizeof(QemuThread)); + env->halt_cond = qemu_mallocz(sizeof(QemuCond)); + qemu_cond_init(env->halt_cond); + qemu_thread_create(env->thread, kvm_cpu_thread_fn, env); + while (env->created == 0) + qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100); +} + +void qemu_init_vcpu(void *_env) +{ + CPUState *env = _env; + + if (kvm_enabled()) + kvm_start_vcpu(env); + else + tcg_init_vcpu(env); +} + +void qemu_notify_event(void) +{ + qemu_event_increment(); +} + +void vm_stop(int reason) +{ + QemuThread me; + qemu_thread_self(&me); + + if (!qemu_thread_equal(&me, &io_thread)) { + qemu_system_vmstop_request(reason); + /* + * FIXME: should not return to device code in case + * vm_stop() has been requested. + */ + if (cpu_single_env) { + cpu_exit(cpu_single_env); + cpu_single_env->stop = 1; + } + return; + } + do_vm_stop(reason); +} + +#endif + + #ifdef _WIN32 static void host_main_loop_wait(int *timeout) { @@ -3910,9 +4277,11 @@ void main_loop_wait(int timeout) } /* vm time timers */ - if (vm_running && likely(!(cur_cpu->singlestep_enabled & SSTEP_NOTIMER))) - qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], - qemu_get_clock(vm_clock)); + if (vm_running) { + if (!cur_cpu || likely(!(cur_cpu->singlestep_enabled & SSTEP_NOTIMER))) + qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], + qemu_get_clock(vm_clock)); + } /* real time timers */ qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME], @@ -3966,7 +4335,7 @@ static int qemu_cpu_exec(CPUState *env) static void tcg_cpu_exec(void) { - int ret; + int ret = 0; if (next_cpu == NULL) next_cpu = first_cpu; @@ -3979,17 +4348,24 @@ static void tcg_cpu_exec(void) timer_alarm_pending = 0; break; } - ret = qemu_cpu_exec(env); + if (cpu_can_run(env)) + ret = qemu_cpu_exec(env); +#ifndef CONFIG_GDBSTUB if (ret == EXCP_DEBUG) { gdb_set_stop_cpu(env); debug_requested = 1; break; } +#endif } } static int cpu_has_work(CPUState *env) { + if (env->stop) + return 1; + if (env->stopped) + return 0; if (!env->halted) return 1; if (qemu_cpu_has_work(env)) @@ -4073,16 +4449,27 @@ static void main_loop(void) { int r; +#ifdef CONFIG_IOTHREAD + qemu_system_ready = 1; + qemu_cond_broadcast(&qemu_system_cond); +#endif + for (;;) { do { #ifdef CONFIG_PROFILER int64_t ti; #endif +#ifndef CONFIG_IOTHREAD tcg_cpu_exec(); +#endif #ifdef CONFIG_PROFILER ti = profile_getclock(); #endif +#ifdef CONFIG_IOTHREAD + main_loop_wait(1000); +#else main_loop_wait(qemu_calculate_timeout()); +#endif #ifdef CONFIG_PROFILER dev_time += profile_getclock() - ti; #endif @@ -4097,13 +4484,17 @@ static void main_loop(void) } else break; } - if (qemu_reset_requested()) + if (qemu_reset_requested()) { + pause_all_vcpus(); qemu_system_reset(); + resume_all_vcpus(); + } if (qemu_powerdown_requested()) qemu_system_powerdown(); if ((r = qemu_vmstop_requested())) vm_stop(r); } + pause_all_vcpus(); } static void version(void) @@ -4531,6 +4922,8 @@ int main(int argc, char **argv, char **envp) tb_size = 0; autostart= 1; + register_watchdogs(); + optind = 1; for(;;) { if (optind >= argc) @@ -4922,6 +5315,17 @@ int main(int argc, char **argv, char **envp) serial_devices[serial_device_index] = optarg; serial_device_index++; break; + case QEMU_OPTION_watchdog: + i = select_watchdog(optarg); + if (i > 0) + exit (i == 1 ? 1 : 0); + break; + case QEMU_OPTION_watchdog_action: + if (select_watchdog_action(optarg) == -1) { + fprintf(stderr, "Unknown -watchdog-action parameter\n"); + exit(1); + } + break; case QEMU_OPTION_virtiocon: if (virtio_console_index >= MAX_VIRTIO_CONSOLES) { fprintf(stderr, "qemu: too many virtio consoles\n");