From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from [140.186.70.92] (port=47779 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Q8zNj-0000wq-PU for qemu-devel@nongnu.org; Sun, 10 Apr 2011 14:29:08 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Q8zNi-0004kh-Ni for qemu-devel@nongnu.org; Sun, 10 Apr 2011 14:29:07 -0400 Received: from moutng.kundenserver.de ([212.227.126.186]:62928) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Q8zNi-0004kP-CC for qemu-devel@nongnu.org; Sun, 10 Apr 2011 14:29:06 -0400 From: Stefan Weil Date: Sun, 10 Apr 2011 20:28:43 +0200 Message-Id: <1302460123-25704-5-git-send-email-weil@mail.berlios.de> In-Reply-To: <1302460123-25704-1-git-send-email-weil@mail.berlios.de> References: <1302460123-25704-1-git-send-email-weil@mail.berlios.de> Subject: [Qemu-devel] [PATCH 4/4] qemu-timer: Fix timers for w32 List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Anthony Liguori Cc: Paolo Bonzini , QEMU Developers 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 Signed-off-by: Stefan Weil --- qemu-timer.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 96 insertions(+), 0 deletions(-) diff --git a/qemu-timer.c b/qemu-timer.c index 26e5ea3..a57197b 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -209,6 +209,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); @@ -301,6 +305,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 @@ -949,6 +955,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)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)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; -- 1.7.2.5