diff options
-rw-r--r-- | hw/goldfish_timer.c | 63 | ||||
-rw-r--r-- | vl-android.c | 24 |
2 files changed, 49 insertions, 38 deletions
diff --git a/hw/goldfish_timer.c b/hw/goldfish_timer.c index d5c9a33..ca90e0e 100644 --- a/hw/goldfish_timer.c +++ b/hw/goldfish_timer.c @@ -14,6 +14,7 @@ #include "cpu.h" #include "arm_pic.h" #include "goldfish_device.h" +#include "hw/hw.h" enum { TIMER_TIME_LOW = 0x00, // get low bits of current time and update TIMER_TIME_HIGH @@ -26,25 +27,35 @@ enum { struct timer_state { struct goldfish_device dev; - uint32_t alarm_low; - int32_t alarm_high; - int64_t now; + uint32_t alarm_low_ns; + int32_t alarm_high_ns; + int64_t now_ns; int armed; QEMUTimer *timer; }; +/* Converts nanoseconds into ticks */ +static int64_t ns2tks(int64_t ns) { + return muldiv64(ns, get_ticks_per_sec(), 1000000000); +} + +/* Converts ticks into nanoseconds */ +static int64_t tks2ns(int64_t tks) { + return muldiv64(tks, 1000000000, get_ticks_per_sec()); +} + #define GOLDFISH_TIMER_SAVE_VERSION 1 static void goldfish_timer_save(QEMUFile* f, void* opaque) { struct timer_state* s = opaque; - qemu_put_be64(f, s->now); /* in case the kernel is in the middle of a timer read */ + qemu_put_be64(f, s->now_ns); /* in case the kernel is in the middle of a timer read */ qemu_put_byte(f, s->armed); if (s->armed) { - int64_t now = qemu_get_clock(vm_clock); - int64_t alarm = muldiv64(s->alarm_low | (int64_t)s->alarm_high << 32, get_ticks_per_sec(), 1000000000); - qemu_put_be64(f, alarm-now); + int64_t now_tks = qemu_get_clock(vm_clock); + int64_t alarm_tks = ns2tks(s->alarm_low_ns | (int64_t)s->alarm_high_ns << 32); + qemu_put_be64(f, alarm_tks - now_tks); } } @@ -55,18 +66,19 @@ static int goldfish_timer_load(QEMUFile* f, void* opaque, int version_id) if (version_id != GOLDFISH_TIMER_SAVE_VERSION) return -1; - s->now = qemu_get_be64(f); - s->armed = qemu_get_byte(f); + s->now_ns = qemu_get_sbe64(f); /* using qemu_get_be64 (without 's') causes faulty code generation + in the compiler, dropping the 32 most significant bits */ + s->armed = qemu_get_byte(f); if (s->armed) { - int64_t now = qemu_get_clock(vm_clock); - int64_t diff = qemu_get_be64(f); - int64_t alarm = now + diff; + int64_t now_tks = qemu_get_clock(vm_clock); + int64_t diff_tks = qemu_get_be64(f); + int64_t alarm_tks = now_tks + diff_tks; - if (alarm <= now) { + if (alarm_tks <= now_tks) { goldfish_device_set_irq(&s->dev, 0, 1); s->armed = 0; } else { - qemu_mod_timer(s->timer, alarm); + qemu_mod_timer(s->timer, alarm_tks); } } return 0; @@ -77,35 +89,34 @@ static uint32_t goldfish_timer_read(void *opaque, target_phys_addr_t offset) struct timer_state *s = (struct timer_state *)opaque; switch(offset) { case TIMER_TIME_LOW: - s->now = muldiv64(qemu_get_clock(vm_clock), 1000000000, get_ticks_per_sec()); - return s->now; + s->now_ns = tks2ns(qemu_get_clock(vm_clock)); + return s->now_ns; case TIMER_TIME_HIGH: - return s->now >> 32; + return s->now_ns >> 32; default: cpu_abort (cpu_single_env, "goldfish_timer_read: Bad offset %x\n", offset); return 0; } } -static void goldfish_timer_write(void *opaque, target_phys_addr_t offset, uint32_t value) +static void goldfish_timer_write(void *opaque, target_phys_addr_t offset, uint32_t value_ns) { struct timer_state *s = (struct timer_state *)opaque; - int64_t alarm, now; + int64_t alarm_tks, now_tks; switch(offset) { case TIMER_ALARM_LOW: - s->alarm_low = value; - alarm = muldiv64(s->alarm_low | (int64_t)s->alarm_high << 32, get_ticks_per_sec(), 1000000000); - now = qemu_get_clock(vm_clock); - if (alarm <= now) { + s->alarm_low_ns = value_ns; + alarm_tks = ns2tks(s->alarm_low_ns | (int64_t)s->alarm_high_ns << 32); + now_tks = qemu_get_clock(vm_clock); + if (alarm_tks <= now_tks) { goldfish_device_set_irq(&s->dev, 0, 1); } else { - qemu_mod_timer(s->timer, alarm); + qemu_mod_timer(s->timer, alarm_tks); s->armed = 1; } break; case TIMER_ALARM_HIGH: - s->alarm_high = value; - //printf("alarm_high %d\n", s->alarm_high); + s->alarm_high_ns = value_ns; break; case TIMER_CLEAR_ALARM: qemu_del_timer(s->timer); diff --git a/vl-android.c b/vl-android.c index 07ef4e2..0cd6b52 100644 --- a/vl-android.c +++ b/vl-android.c @@ -1351,30 +1351,30 @@ void qemu_get_timer(QEMUFile *f, QEMUTimer *ts) static void timer_save(QEMUFile *f, void *opaque) { -#if 0 - if (cpu_ticks_enabled) { + TimersState *s = opaque; + + if (s->cpu_ticks_enabled) { hw_error("cannot save state if virtual timers are running"); } - qemu_put_be64(f, cpu_ticks_offset); + qemu_put_be64(f, s->cpu_ticks_offset); qemu_put_be64(f, ticks_per_sec); - qemu_put_be64(f, cpu_clock_offset); -#endif + qemu_put_be64(f, s->cpu_clock_offset); } static int timer_load(QEMUFile *f, void *opaque, int version_id) { -#if 0 + TimersState *s = opaque; + if (version_id != 1 && version_id != 2) return -EINVAL; - if (cpu_ticks_enabled) { + if (s->cpu_ticks_enabled) { return -EINVAL; } - cpu_ticks_offset=qemu_get_be64(f); - ticks_per_sec=qemu_get_be64(f); + s->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); + s->cpu_clock_offset = qemu_get_be64(f); } -#endif return 0; } @@ -6414,7 +6414,7 @@ int main(int argc, char **argv, char **envp) if (drive_init(&drives_opt[i], snapshot, machine) == -1) exit(1); - register_savevm("timer", 0, 2, timer_save, timer_load, NULL); + register_savevm("timer", 0, 2, timer_save, timer_load, &timers_state); register_savevm_live("ram", 0, 3, ram_save_live, NULL, ram_load, NULL); #ifndef _WIN32 |