aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hw/goldfish_timer.c63
-rw-r--r--vl-android.c24
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