diff options
-rw-r--r-- | cpus.c | 20 | ||||
-rw-r--r-- | cpus.h | 2 | ||||
-rw-r--r-- | qemu-timer.c | 2 | ||||
-rw-r--r-- | qemu-timer.h | 1 | ||||
-rw-r--r-- | qtest.c | 45 |
5 files changed, 69 insertions, 1 deletions
@@ -34,6 +34,7 @@ #include "qemu-thread.h" #include "cpus.h" +#include "qtest.h" #include "main-loop.h" #ifndef _WIN32 @@ -238,6 +239,20 @@ static void icount_warp_rt(void *opaque) vm_clock_warp_start = -1; } +void qtest_clock_warp(int64_t dest) +{ + int64_t clock = qemu_get_clock_ns(vm_clock); + assert(qtest_enabled()); + while (clock < dest) { + int64_t deadline = qemu_clock_deadline(vm_clock); + int64_t warp = MIN(dest - clock, deadline); + qemu_icount_bias += warp; + qemu_run_timers(vm_clock); + clock = qemu_get_clock_ns(vm_clock); + } + qemu_notify_event(); +} + void qemu_clock_warp(QEMUClock *clock) { int64_t deadline; @@ -264,6 +279,11 @@ void qemu_clock_warp(QEMUClock *clock) return; } + if (qtest_enabled()) { + /* When testing, qtest commands advance icount. */ + return; + } + vm_clock_warp_start = qemu_get_clock_ns(rt_clock); deadline = qemu_clock_deadline(vm_clock); if (deadline > 0) { @@ -11,6 +11,8 @@ void cpu_synchronize_all_states(void); void cpu_synchronize_all_post_reset(void); void cpu_synchronize_all_post_init(void); +void qtest_clock_warp(int64_t dest); + /* vl.c */ extern int smp_cores; extern int smp_threads; diff --git a/qemu-timer.c b/qemu-timer.c index d7f56e5..80bcc56 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -397,7 +397,7 @@ int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time) return qemu_timer_expired_ns(timer_head, current_time * timer_head->scale); } -static void qemu_run_timers(QEMUClock *clock) +void qemu_run_timers(QEMUClock *clock) { QEMUTimer **ptimer_head, *ts; int64_t current_time; diff --git a/qemu-timer.h b/qemu-timer.h index de17f3b..661bbe7 100644 --- a/qemu-timer.h +++ b/qemu-timer.h @@ -59,6 +59,7 @@ int qemu_timer_pending(QEMUTimer *ts); int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time); uint64_t qemu_timer_expire_time_ns(QEMUTimer *ts); +void qemu_run_timers(QEMUClock *clock); void qemu_run_all_timers(void); int qemu_alarm_pending(void); void configure_alarms(char const *opt); @@ -18,6 +18,7 @@ #include "memory.h" #include "hw/irq.h" #include "sysemu.h" +#include "cpus.h" #define MAX_IRQ 256 @@ -44,6 +45,30 @@ static bool qtest_opened; * * Valid requests * + * Clock management: + * + * The qtest client is completely in charge of the vm_clock. qtest commands + * let you adjust the value of the clock (monotonically). All the commands + * return the current value of the clock in nanoseconds. + * + * > clock_step + * < OK VALUE + * + * Advance the clock to the next deadline. Useful when waiting for + * asynchronous events. + * + * > clock_step NS + * < OK VALUE + * + * Advance the clock by NS nanoseconds. + * + * > clock_set NS + * < OK VALUE + * + * Advance the clock to NS nanoseconds (do nothing if it's already past). + * + * PIO and memory access: + * * > outb ADDR VALUE * < OK * @@ -299,6 +324,25 @@ static void qtest_process_command(CharDriverState *chr, gchar **words) qtest_send_prefix(chr); qtest_send(chr, "OK\n"); + } else if (strcmp(words[0], "clock_step") == 0) { + int64_t ns; + + if (words[1]) { + ns = strtoll(words[1], NULL, 0); + } else { + ns = qemu_clock_deadline(vm_clock); + } + qtest_clock_warp(qemu_get_clock_ns(vm_clock) + ns); + qtest_send_prefix(chr); + qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_get_clock_ns(vm_clock)); + } else if (strcmp(words[0], "clock_set") == 0) { + int64_t ns; + + g_assert(words[1]); + ns = strtoll(words[1], NULL, 0); + qtest_clock_warp(ns); + qtest_send_prefix(chr); + qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_get_clock_ns(vm_clock)); } else { qtest_send_prefix(chr); qtest_send(chr, "FAIL Unknown command `%s'\n", words[0]); @@ -377,6 +421,7 @@ int qtest_init(void) g_assert(qtest_chrdev != NULL); + configure_icount("0"); chr = qemu_chr_new("qtest", qtest_chrdev, NULL); qemu_chr_add_handlers(chr, qtest_can_read, qtest_read, qtest_event, chr); |