static void icount_warp_rt(void *opaque) { if (vm_clock_warp_start == -1) { return; } if (vm_running) { int64_t clock = qemu_get_clock_ns(rt_clock); int64_t warp_delta = clock - vm_clock_warp_start; if (use_icount == 1) { qemu_icount_bias += warp_delta; } else { /* * In adaptive mode, do not let the vm_clock run too * far ahead of real time. */ int64_t cur_time = cpu_get_clock(); int64_t cur_icount = qemu_get_clock_ns(vm_clock); int64_t delta = cur_time - cur_icount; qemu_icount_bias += MIN(warp_delta, delta); } if (qemu_timer_expired(active_timers[QEMU_CLOCK_VIRTUAL], qemu_get_clock_ns(vm_clock))) { qemu_notify_event(); } } vm_clock_warp_start = -1; }
static void icount_warp_rt(void *opaque) { if (vm_clock_warp_start == -1) { return; } if (runstate_is_running()) { int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); int64_t warp_delta = clock - vm_clock_warp_start; if (use_icount == 1) { qemu_icount_bias += warp_delta; } else { /* * In adaptive mode, do not let QEMU_CLOCK_VIRTUAL run too * far ahead of real time. */ int64_t cur_time = cpu_get_clock(); int64_t cur_icount = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); int64_t delta = cur_time - cur_icount; qemu_icount_bias += MIN(warp_delta, delta); } if (qemu_clock_expired(QEMU_CLOCK_VIRTUAL)) { qemu_clock_notify(QEMU_CLOCK_VIRTUAL); } } vm_clock_warp_start = -1; }
static void icount_adjust(void) { int64_t cur_time; int64_t cur_icount; int64_t delta; static int64_t last_delta; /* If the VM is not running, then do nothing. */ if (!vm_running) return; cur_time = cpu_get_clock(); cur_icount = qemu_get_clock_ns(vm_clock); delta = cur_icount - cur_time; /* FIXME: This is a very crude algorithm, somewhat prone to oscillation. */ if (delta > 0 && last_delta + ICOUNT_WOBBLE < delta * 2 && icount_time_shift > 0) { /* The guest is getting too far ahead. Slow time down. */ icount_time_shift--; } if (delta < 0 && last_delta - ICOUNT_WOBBLE > delta * 2 && icount_time_shift < MAX_ICOUNT_SHIFT) { /* The guest is getting too far behind. Speed time up. */ icount_time_shift++; } last_delta = delta; qemu_icount_bias = cur_icount - (qemu_icount << icount_time_shift); }
/* disable cpu_get_ticks() : the clock is stopped. You must not call cpu_get_ticks() after that. */ void cpu_disable_ticks(void) { if (timers_state.cpu_ticks_enabled) { timers_state.cpu_ticks_offset = cpu_get_ticks(); timers_state.cpu_clock_offset = cpu_get_clock(); timers_state.cpu_ticks_enabled = 0; } }
/** * Allows S2E to slow down the VM clock while executing LLVM instructions. * Assumes that rt_clock == vm_clock. * scale == 1 is the normal speed. */ void cpu_enable_scaling(int scale) { assert(scale >= 1); if (!timers_state.clock_scale_enable) { timers_state.cpu_clock_prev = cpu_get_clock(); timers_state.cpu_clock_prev_scaled = timers_state.cpu_clock_prev; } timers_state.clock_scale = scale; timers_state.clock_scale_enable = 1; }
static int64_t qemu_icount_delta(void) { if (use_icount == 1) { /* When not using an adaptive execution frequency we tend to get badly out of sync with real time, so just delay for a reasonable amount of time. */ return 0; } else { return cpu_get_icount() - cpu_get_clock(); } }
int64_t qemu_get_clock_ns(QEMUClock *clock) { switch(clock->type) { case QEMU_CLOCK_REALTIME: return get_clock(); default: case QEMU_CLOCK_VIRTUAL: return cpu_get_clock(); case QEMU_CLOCK_HOST: return get_clock_realtime(); } }
int64_t qemu_get_clock(QEMUClock *clock) { switch(clock->type) { case QEMU_CLOCK_REALTIME: return get_clock() / 1000000; default: case QEMU_CLOCK_VIRTUAL: if (use_icount) { return cpu_get_icount(); } else { return cpu_get_clock(); } case QEMU_CLOCK_HOST: return get_clock_realtime(); } }
int64_t qemu_get_clock(QEMUClock *clock) { switch(clock->type) { case QEMU_CLOCK_REALTIME: return get_clock() / 1000000; default: case QEMU_CLOCK_VIRTUAL: #ifdef MARSS_QEMU if (in_simulation) { return cpu_get_sim_clock(); } #endif if (use_icount) { return cpu_get_icount(); } else { return cpu_get_clock(); } case QEMU_CLOCK_HOST: return get_clock_realtime(); } }
int64_t qemu_get_clock_ns(QEMUClock *clock) { int64_t now, last; switch(clock->type) { case QEMU_CLOCK_REALTIME: return get_clock(); default: case QEMU_CLOCK_VIRTUAL: if (use_icount) { return cpu_get_icount(); } else { return cpu_get_clock(); } case QEMU_CLOCK_HOST: now = get_clock_realtime(); last = clock->last; clock->last = now; if (now < last) { notifier_list_notify(&clock->reset_notifiers, &now); } return now; } }