diff options
author | Stefan Weil <weil@mail.berlios.de> | 2011-04-05 18:34:21 +0200 |
---|---|---|
committer | Stefan Weil <weil@mail.berlios.de> | 2011-04-27 13:30:18 +0200 |
commit | 2f9cba0c148af32fad6813480f5c92efe17c2d49 (patch) | |
tree | 2cd99c0c3cc1e88050db47e9a887a423c7c5c08b /qemu-timer.c | |
parent | cd0544ee550cb125d752f765e9d9e7c3fdf464b2 (diff) |
qemu-timer: Fix timers for w32
Commit 68c23e5520e8286d79d96ab47c0ea722ceb75041 removed the
multimedia timer, but this timer is needed for certain
Linux kernels. Otherwise Linux boot stops with this error:
MP-BIOS bug: 8254 timer not connected to IO-APIC
So the multimedia timer is added again here.
Cc: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Stefan Weil <weil@mail.berlios.de>
Diffstat (limited to 'qemu-timer.c')
-rw-r--r-- | qemu-timer.c | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/qemu-timer.c b/qemu-timer.c index e8e5e15c8e..4141b6edbe 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -215,6 +215,10 @@ static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t) #ifdef _WIN32 +static int mm_start_timer(struct qemu_alarm_timer *t); +static void mm_stop_timer(struct qemu_alarm_timer *t); +static void mm_rearm_timer(struct qemu_alarm_timer *t); + static int win32_start_timer(struct qemu_alarm_timer *t); static void win32_stop_timer(struct qemu_alarm_timer *t); static void win32_rearm_timer(struct qemu_alarm_timer *t); @@ -307,6 +311,8 @@ static struct qemu_alarm_timer alarm_timers[] = { #endif {"unix", unix_start_timer, unix_stop_timer, NULL}, #else + {"mmtimer", mm_start_timer, mm_stop_timer, NULL}, + {"mmtimer2", mm_start_timer, mm_stop_timer, mm_rearm_timer}, {"dynticks", win32_start_timer, win32_stop_timer, win32_rearm_timer}, {"win32", win32_start_timer, win32_stop_timer, NULL}, #endif @@ -1040,6 +1046,96 @@ static void unix_stop_timer(struct qemu_alarm_timer *t) #ifdef _WIN32 +static MMRESULT mm_timer; +static unsigned mm_period; + +static void CALLBACK mm_alarm_handler(UINT uTimerID, UINT uMsg, + DWORD_PTR dwUser, DWORD_PTR dw1, + DWORD_PTR dw2) +{ + struct qemu_alarm_timer *t = alarm_timer; + if (!t) { + return; + } + if (alarm_has_dynticks(t) || qemu_next_alarm_deadline() <= 0) { + t->expired = alarm_has_dynticks(t); + t->pending = 1; + qemu_notify_event(); + } +} + +static int mm_start_timer(struct qemu_alarm_timer *t) +{ + TIMECAPS tc; + UINT flags; + + memset(&tc, 0, sizeof(tc)); + timeGetDevCaps(&tc, sizeof(tc)); + + mm_period = tc.wPeriodMin; + timeBeginPeriod(mm_period); + + flags = TIME_CALLBACK_FUNCTION; + if (alarm_has_dynticks(t)) { + flags |= TIME_ONESHOT; + } else { + flags |= TIME_PERIODIC; + } + + mm_timer = timeSetEvent(1, /* interval (ms) */ + mm_period, /* resolution */ + mm_alarm_handler, /* function */ + (DWORD_PTR)t, /* parameter */ + flags); + + if (!mm_timer) { + fprintf(stderr, "Failed to initialize win32 alarm timer: %ld\n", + GetLastError()); + timeEndPeriod(mm_period); + return -1; + } + + return 0; +} + +static void mm_stop_timer(struct qemu_alarm_timer *t) +{ + timeKillEvent(mm_timer); + timeEndPeriod(mm_period); +} + +static void mm_rearm_timer(struct qemu_alarm_timer *t) +{ + int nearest_delta_ms; + + assert(alarm_has_dynticks(t)); + if (!active_timers[QEMU_CLOCK_REALTIME] && + !active_timers[QEMU_CLOCK_VIRTUAL] && + !active_timers[QEMU_CLOCK_HOST]) { + return; + } + + timeKillEvent(mm_timer); + + nearest_delta_ms = (qemu_next_alarm_deadline() + 999999) / 1000000; + if (nearest_delta_ms < 1) { + nearest_delta_ms = 1; + } + mm_timer = timeSetEvent(nearest_delta_ms, + mm_period, + mm_alarm_handler, + (DWORD_PTR)t, + TIME_ONESHOT | TIME_CALLBACK_FUNCTION); + + if (!mm_timer) { + fprintf(stderr, "Failed to re-arm win32 alarm timer %ld\n", + GetLastError()); + + timeEndPeriod(mm_period); + exit(1); + } +} + static int win32_start_timer(struct qemu_alarm_timer *t) { HANDLE hTimer; |