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 #include #include #include @@ -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 +#include +#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) {