?? vl.c
字號:
ts->next = NULL; /* run the callback (the timer list can be modified) */ ts->cb(ts->opaque); }}int64_t qemu_get_clock(QEMUClock *clock){ switch(clock->type) { case QEMU_TIMER_REALTIME: return get_clock() / 1000000; default: case QEMU_TIMER_VIRTUAL: return cpu_get_clock(); }}static void init_timers(void){ init_get_clock(); ticks_per_sec = QEMU_TIMER_BASE; rt_clock = qemu_new_clock(QEMU_TIMER_REALTIME); vm_clock = qemu_new_clock(QEMU_TIMER_VIRTUAL);}/* save a timer */void qemu_put_timer(QEMUFile *f, QEMUTimer *ts){ uint64_t expire_time; if (qemu_timer_pending(ts)) { expire_time = ts->expire_time; } else { expire_time = -1; } qemu_put_be64(f, expire_time);}void qemu_get_timer(QEMUFile *f, QEMUTimer *ts){ uint64_t expire_time; expire_time = qemu_get_be64(f); if (expire_time != -1) { qemu_mod_timer(ts, expire_time); } else { qemu_del_timer(ts); }}static void timer_save(QEMUFile *f, void *opaque){ if (cpu_ticks_enabled) { hw_error("cannot save state if virtual timers are running"); } qemu_put_be64(f, cpu_ticks_offset); qemu_put_be64(f, ticks_per_sec); qemu_put_be64(f, cpu_clock_offset);}static int timer_load(QEMUFile *f, void *opaque, int version_id){ if (version_id != 1 && version_id != 2) return -EINVAL; if (cpu_ticks_enabled) { return -EINVAL; } cpu_ticks_offset=qemu_get_be64(f); ticks_per_sec=qemu_get_be64(f); if (version_id == 2) { cpu_clock_offset=qemu_get_be64(f); } return 0;}#ifdef _WIN32void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)#elsestatic void host_alarm_handler(int host_signum)#endif{#if 0#define DISP_FREQ 1000 { static int64_t delta_min = INT64_MAX; static int64_t delta_max, delta_cum, last_clock, delta, ti; static int count; ti = qemu_get_clock(vm_clock); if (last_clock != 0) { delta = ti - last_clock; if (delta < delta_min) delta_min = delta; if (delta > delta_max) delta_max = delta; delta_cum += delta; if (++count == DISP_FREQ) { printf("timer: min=%" PRId64 " us max=%" PRId64 " us avg=%" PRId64 " us avg_freq=%0.3f Hz\n", muldiv64(delta_min, 1000000, ticks_per_sec), muldiv64(delta_max, 1000000, ticks_per_sec), muldiv64(delta_cum, 1000000 / DISP_FREQ, ticks_per_sec), (double)ticks_per_sec / ((double)delta_cum / DISP_FREQ)); count = 0; delta_min = INT64_MAX; delta_max = 0; delta_cum = 0; } } last_clock = ti; }#endif if (alarm_has_dynticks(alarm_timer) || qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL], qemu_get_clock(vm_clock)) || qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], qemu_get_clock(rt_clock))) {#ifdef _WIN32 struct qemu_alarm_win32 *data = ((struct qemu_alarm_timer*)dwUser)->priv; SetEvent(data->host_alarm);#endif CPUState *env = next_cpu; alarm_timer->flags |= ALARM_FLAG_EXPIRED; if (env) { /* stop the currently executing cpu because a timer occured */ cpu_interrupt(env, CPU_INTERRUPT_EXIT);#ifdef USE_KQEMU if (env->kqemu_enabled) { kqemu_cpu_interrupt(env); }#endif } event_pending = 1; }}static uint64_t qemu_next_deadline(void){ int64_t nearest_delta_us = INT64_MAX; int64_t vmdelta_us; if (active_timers[QEMU_TIMER_REALTIME]) nearest_delta_us = (active_timers[QEMU_TIMER_REALTIME]->expire_time - qemu_get_clock(rt_clock))*1000; if (active_timers[QEMU_TIMER_VIRTUAL]) { /* round up */ vmdelta_us = (active_timers[QEMU_TIMER_VIRTUAL]->expire_time - qemu_get_clock(vm_clock)+999)/1000; if (vmdelta_us < nearest_delta_us) nearest_delta_us = vmdelta_us; } /* Avoid arming the timer to negative, zero, or too low values */ if (nearest_delta_us <= MIN_TIMER_REARM_US) nearest_delta_us = MIN_TIMER_REARM_US; return nearest_delta_us;}#ifndef _WIN32#if defined(__linux__)#define RTC_FREQ 1024static void enable_sigio_timer(int fd){ struct sigaction act; /* timer signal */ sigfillset(&act.sa_mask); act.sa_flags = 0; act.sa_handler = host_alarm_handler; sigaction(SIGIO, &act, NULL); fcntl(fd, F_SETFL, O_ASYNC); fcntl(fd, F_SETOWN, getpid());}static int hpet_start_timer(struct qemu_alarm_timer *t){ struct hpet_info info; int r, fd; fd = open("/dev/hpet", O_RDONLY); if (fd < 0) return -1; /* Set frequency */ r = ioctl(fd, HPET_IRQFREQ, RTC_FREQ); if (r < 0) { fprintf(stderr, "Could not configure '/dev/hpet' to have a 1024Hz timer. This is not a fatal\n" "error, but for better emulation accuracy type:\n" "'echo 1024 > /proc/sys/dev/hpet/max-user-freq' as root.\n"); goto fail; } /* Check capabilities */ r = ioctl(fd, HPET_INFO, &info); if (r < 0) goto fail; /* Enable periodic mode */ r = ioctl(fd, HPET_EPI, 0); if (info.hi_flags && (r < 0)) goto fail; /* Enable interrupt */ r = ioctl(fd, HPET_IE_ON, 0); if (r < 0) goto fail; enable_sigio_timer(fd); t->priv = (void *)(long)fd; return 0;fail: close(fd); return -1;}static void hpet_stop_timer(struct qemu_alarm_timer *t){ int fd = (long)t->priv; close(fd);}static int rtc_start_timer(struct qemu_alarm_timer *t){ int rtc_fd; TFR(rtc_fd = open("/dev/rtc", O_RDONLY)); if (rtc_fd < 0) return -1; if (ioctl(rtc_fd, RTC_IRQP_SET, RTC_FREQ) < 0) { fprintf(stderr, "Could not configure '/dev/rtc' to have a 1024 Hz timer. This is not a fatal\n" "error, but for better emulation accuracy either use a 2.6 host Linux kernel or\n" "type 'echo 1024 > /proc/sys/dev/rtc/max-user-freq' as root.\n"); goto fail; } if (ioctl(rtc_fd, RTC_PIE_ON, 0) < 0) { fail: close(rtc_fd); return -1; } enable_sigio_timer(rtc_fd); t->priv = (void *)(long)rtc_fd; return 0;}static void rtc_stop_timer(struct qemu_alarm_timer *t){ int rtc_fd = (long)t->priv; close(rtc_fd);}static int dynticks_start_timer(struct qemu_alarm_timer *t){ struct sigevent ev; timer_t host_timer; struct sigaction act; sigfillset(&act.sa_mask); act.sa_flags = 0; act.sa_handler = host_alarm_handler; sigaction(SIGALRM, &act, NULL); ev.sigev_value.sival_int = 0; ev.sigev_notify = SIGEV_SIGNAL; ev.sigev_signo = SIGALRM; if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) { perror("timer_create"); /* disable dynticks */ fprintf(stderr, "Dynamic Ticks disabled\n"); return -1; } t->priv = (void *)host_timer; return 0;}static void dynticks_stop_timer(struct qemu_alarm_timer *t){ timer_t host_timer = (timer_t)t->priv; timer_delete(host_timer);}static void dynticks_rearm_timer(struct qemu_alarm_timer *t){ timer_t host_timer = (timer_t)t->priv; struct itimerspec timeout; int64_t nearest_delta_us = INT64_MAX; int64_t current_us; if (!active_timers[QEMU_TIMER_REALTIME] && !active_timers[QEMU_TIMER_VIRTUAL]) return; nearest_delta_us = qemu_next_deadline(); /* check whether a timer is already running */ if (timer_gettime(host_timer, &timeout)) { perror("gettime"); fprintf(stderr, "Internal timer error: aborting\n"); exit(1); } current_us = timeout.it_value.tv_sec * 1000000 + timeout.it_value.tv_nsec/1000; if (current_us && current_us <= nearest_delta_us) return; timeout.it_interval.tv_sec = 0; timeout.it_interval.tv_nsec = 0; /* 0 for one-shot timer */ timeout.it_value.tv_sec = nearest_delta_us / 1000000; timeout.it_value.tv_nsec = (nearest_delta_us % 1000000) * 1000; if (timer_settime(host_timer, 0 /* RELATIVE */, &timeout, NULL)) { perror("settime"); fprintf(stderr, "Internal timer error: aborting\n"); exit(1); }}#endif /* defined(__linux__) */static int unix_start_timer(struct qemu_alarm_timer *t){ struct sigaction act; struct itimerval itv; int err; /* timer signal */ sigfillset(&act.sa_mask); act.sa_flags = 0; act.sa_handler = host_alarm_handler; sigaction(SIGALRM, &act, NULL); itv.it_interval.tv_sec = 0; /* for i386 kernel 2.6 to get 1 ms */ itv.it_interval.tv_usec = 999; itv.it_value.tv_sec = 0; itv.it_value.tv_usec = 10 * 1000; err = setitimer(ITIMER_REAL, &itv, NULL); if (err) return -1; return 0;}static void unix_stop_timer(struct qemu_alarm_timer *t){ struct itimerval itv; memset(&itv, 0, sizeof(itv)); setitimer(ITIMER_REAL, &itv, NULL);}#endif /* !defined(_WIN32) */#ifdef _WIN32static int win32_start_timer(struct qemu_alarm_timer *t){ TIMECAPS tc; struct qemu_alarm_win32 *data = t->priv; UINT flags; data->host_alarm = CreateEvent(NULL, FALSE, FALSE, NULL); if (!data->host_alarm) { perror("Failed CreateEvent"); return -1; } memset(&tc, 0, sizeof(tc)); timeGetDevCaps(&tc, sizeof(tc)); if (data->period < tc.wPeriodMin) data->period = tc.wPeriodMin; timeBeginPeriod(data->period); flags = TIME_CALLBACK_FUNCTION; if (alarm_has_dynticks(t)) flags |= TIME_ONESHOT; else flags |= TIME_PERIODIC; data->timerId = timeSetEvent(1, // interval (ms) data->period, // resolution host_alarm_handler, // function (DWORD)t, // parameter flags); if (!data->timerId) { perror("Failed to initialize win32 alarm timer"); timeEndPeriod(data->period); CloseHandle(data->host_alarm); return -1; } qemu_add_wait_object(data->host_alarm, NULL, NULL); return 0;}static void win32_stop_timer(struct qemu_alarm_timer *t){ struct qemu_alarm_win32 *data = t->priv; timeKillEvent(data->timerId); timeEndPeriod(data->period); CloseHandle(data->host_alarm);}static void win32_rearm_timer(struct qemu_alarm_timer *t){ struct qemu_alarm_win32 *data = t->priv; uint64_t nearest_delta_us; if (!active_timers[QEMU_TIMER_REALTIME] && !active_timers[QEMU_TIMER_VIRTUAL]) return; nearest_delta_us = qemu_next_deadline(); nearest_delta_us /= 1000; timeKillEvent(data->timerId); data->timerId = timeSetEvent(1, data->period, host_alarm_handler, (DWORD)t, TIME_ONESHOT | TIME_PERIODIC); if (!data->timerId) { perror("Failed to re-arm win32 alarm timer"); timeEndPeriod(data->period); CloseHandle(data->host_alarm); exit(1); }}#endif /* _WIN32 */static void init_timer_alarm(void){ struct qemu_alarm_timer *t; int i, err = -1; for (i = 0; alarm_timers[i].name; i++) { t = &alarm_timers[i]; err = t->start(t); if (!err) break; } if (err) { fprintf(stderr, "Unable to find any suitable alarm timer.\n"); fprintf(stderr, "Terminating\n"); exit(1); } alarm_timer = t;}static void quit_timers(void){ alarm_timer->stop(alarm_timer); alarm_timer = NULL;}/***********************************************************//* character device */static void qemu_chr_event(CharDriverState *s, int event){ if (!s->chr_event) return; s->chr_event(s->handler_opaque, event);}static void qemu_chr_reset_bh(void *opaque){ CharDriverState *s = opaque; qemu_chr_event(s, CHR_EVENT_RESET); qemu_bh_delete(s->bh); s->bh = NULL;}void qemu_chr_reset(CharDriverState *s){ if (s->bh == NULL) { s->bh = qemu_bh_new(qemu_chr_reset_bh, s); qemu_bh_schedule(s->bh); }}int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len){ return s->chr_write(s, buf, len);}int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg){ if (!s->chr_ioctl) return -ENOTSUP; return s->chr_ioctl(s, cmd, arg);}int qemu_chr_can_read(CharDriverState *s){ if (!s->chr_can_read) return 0; return s->chr_can_read(s->handler_opaque);}void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -