From: Fabrice Bellard <fabrice@bellard.org>
To: qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] Stable clock source
Date: Tue, 11 Jul 2006 23:50:55 +0200 [thread overview]
Message-ID: <44B41D3F.7030908@bellard.org> (raw)
In-Reply-To: <Pine.LNX.4.64.0607120112010.3918@home.oyster.ru>
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
next prev parent reply other threads:[~2006-07-11 21:54 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-07-11 21:15 [Qemu-devel] Stable clock source malc
2006-07-11 21:50 ` Fabrice Bellard [this message]
2006-07-11 22:06 ` malc
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=44B41D3F.7030908@bellard.org \
--to=fabrice@bellard.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).