qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] Stable clock source


From: Fabrice Bellard
Subject: Re: [Qemu-devel] Stable clock source
Date: Tue, 11 Jul 2006 23:50:55 +0200
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20040913

Hi malc,

In fact I am already working on the issue. My solution is different and it seems to work too.

Fabrice.

malc wrote:
Hello,

Attached is a patch that implements non-rdtsc based[1] clock source.
Gotchas:

1. Only works on Linux
2. Only works on i386 Linux
3. Only works on i386 Linux with ACPI enabled
4. Requires root privileges (though they will be dropped)

Perhaps this will be useful to someone.

--
mailto:address@hidden


------------------------------------------------------------------------

Index: vl.c
===================================================================
RCS file: /cvsroot/qemu/qemu/vl.c,v
retrieving revision 1.197
diff -u -r1.197 vl.c
--- vl.c        27 Jun 2006 21:02:43 -0000      1.197
+++ vl.c        11 Jul 2006 21:07:35 -0000
@@ -23,6 +23,7 @@
  */
 #include "vl.h"
+#include <err.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <signal.h>
@@ -157,6 +158,10 @@
 int acpi_enabled = 1;
 int fd_bootchk = 1;
+#if !(defined TARGET_I386) || !(defined __linux__)
+#define USE_RDTSC
+#endif
+
 /***********************************************************/
 /* x86 ISA bus support */
@@ -515,7 +520,33 @@ #elif defined(__i386__) -int64_t cpu_get_real_ticks(void)
+#ifndef USE_RDTSC
+#include <unistd.h>
+#include <sys/io.h>
+#define ACPI_PM_TMR_FREQ 3579545
+
+static uint32_t acpi_prev_ticks;
+static uint32_t acpi_max_ticks;
+static uint32_t acpi_pm_tmr_addr;
+static int64_t acpi_old_ticks;
+
+static int64_t acpi_get_ticks(void)
+{
+    uint32_t ticks = inl_p (acpi_pm_tmr_addr);
+    uint32_t prev = acpi_prev_ticks;
+
+    acpi_prev_ticks = ticks;
+    if (ticks < prev)
+        ticks += (acpi_max_ticks - prev);
+    acpi_old_ticks += ticks;
+    return acpi_old_ticks;
+}
+int64_t (*cpu_get_real_ticks)(void);
+#else
+#define cpu_get_real_ticks rdtsc_get_ticks
+#endif
+
+static int64_t rdtsc_get_ticks(void)
 {
 #ifdef _WIN32
     LARGE_INTEGER ti;
@@ -5597,6 +5628,97 @@
#define MAX_NET_CLIENTS 32 +#ifdef USE_RDTSC
+#define acpi_calibrate_ticks cpu_calibrate_ticks
+#else
+static void acpi_calibrate_ticks(void)
+{
+    int fd;
+    ssize_t nread;
+    uint32_t flags;
+    off_t off;
+    int err;
+    uid_t uid;
+
+    uid = getuid ();
+    if (uid == (uid_t) -1) {
+        warn ("could not get user id");
+        goto std_calibrate1;
+    }
+
+    err = setuid (0);
+    if (err) {
+        warn ("could not setuid 0");
+        goto std_calibrate1;
+    }
+
+    fd = open ("/proc/acpi/fadt", O_RDONLY);
+    if (fd < 0) {
+        warn ("could not open fadt");
+        goto std_calibrate;
+    }
+
+    off = lseek (fd, 76, SEEK_SET);
+    if (off - 76) {
+        warn ("could not seek");
+        goto std_calibrate;
+    }
+
+    nread = read (fd, &acpi_pm_tmr_addr, 4);
+    if (nread - 4) {
+        warn ("could not read pm timer io port address nread=%d", nread);
+        goto std_calibrate;
+    }
+
+    off = lseek (fd, 112, SEEK_SET);
+    if (off - 112) {
+        warn ("could not seek");
+        goto std_calibrate;
+    }
+
+    nread = read (fd, &flags, 4);
+    if (nread - 4) {
+        warn ("could not read pm timer facp flags nread=%d", nread);
+        goto std_calibrate;
+    }
+
+    if (!(flags & (1 << 8)))
+        acpi_max_ticks = (1 << 24) - 1;
+    else
+        acpi_max_ticks = ~0U;
+
+    err = close (fd);
+    if (err)
+        warn ("could not close fadt");
+
+    if (iopl (3)) {
+        warn ("could not change iopl");
+        goto std_calibrate2;
+    }
+
+    err = setuid (uid);
+    if (err)
+        warn ("could not restore uid");
+
+    ticks_per_sec = ACPI_PM_TMR_FREQ;
+    cpu_get_real_ticks = &acpi_get_ticks;
+    return;
+
+ std_calibrate:
+    err = close (fd);
+    if (err)
+        warn ("could not close fadt");
+ std_calibrate2:
+    err = setuid (uid);
+    if (err)
+        warn ("could not restore uid");
+ std_calibrate1:
+    fprintf (stderr, "falling back on rdtsc clock\n");
+    cpu_get_real_ticks = &rdtsc_get_ticks;
+    cpu_calibrate_ticks();
+}
+#endif
+
 int main(int argc, char **argv)
 {
 #ifdef CONFIG_GDBSTUB
@@ -6128,7 +6250,7 @@
     register_savevm("ram", 0, 1, ram_save, ram_load, NULL);
init_ioports();
-    cpu_calibrate_ticks();
+    acpi_calibrate_ticks();
/* terminal init */
     if (nographic) {


------------------------------------------------------------------------

_______________________________________________
Qemu-devel mailing list
address@hidden
http://lists.nongnu.org/mailman/listinfo/qemu-devel





reply via email to

[Prev in Thread] Current Thread [Next in Thread]