qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] Stable clock source
@ 2006-07-11 21:15 malc
  2006-07-11 21:50 ` Fabrice Bellard
  0 siblings, 1 reply; 3+ messages in thread
From: malc @ 2006-07-11 21:15 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: TEXT/PLAIN, Size: 312 bytes --]

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:malc@pulsesoft.com

[-- Attachment #2: Type: TEXT/PLAIN, Size: 3919 bytes --]

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) {

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [Qemu-devel] Stable clock source
  2006-07-11 21:15 [Qemu-devel] Stable clock source malc
@ 2006-07-11 21:50 ` Fabrice Bellard
  2006-07-11 22:06   ` malc
  0 siblings, 1 reply; 3+ messages in thread
From: Fabrice Bellard @ 2006-07-11 21:50 UTC (permalink / raw)
  To: qemu-devel

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:malc@pulsesoft.com
> 
> 
> ------------------------------------------------------------------------
> 
> 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
> Qemu-devel@nongnu.org
> http://lists.nongnu.org/mailman/listinfo/qemu-devel

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [Qemu-devel] Stable clock source
  2006-07-11 21:50 ` Fabrice Bellard
@ 2006-07-11 22:06   ` malc
  0 siblings, 0 replies; 3+ messages in thread
From: malc @ 2006-07-11 22:06 UTC (permalink / raw)
  To: qemu-devel

On Tue, 11 Jul 2006, Fabrice Bellard wrote:

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

Great news, i don't particulary like mine (mainly because of requiring
CAP_SYS_RAWIO and ioperm working only on <0x3ff ports), but i had an
idle moment and wrote this, wouldn't hurt anyone i guess.

--
mailto:malc@pulsesoft.com

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2006-07-11 22:06 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-07-11 21:15 [Qemu-devel] Stable clock source malc
2006-07-11 21:50 ` Fabrice Bellard
2006-07-11 22:06   ` malc

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).