Browse Source

Fix pmtimer for Windows XP

The pmtimer clocks updates quickly, much more often than JavaScript's
time functions. Windows XP doesn't handle this properly, so a hack is
required to update the timer even if JavaScript's time hasn't changed
Fabian 6 years ago
parent
commit
81af0bc882
1 changed files with 41 additions and 2 deletions
  1. 41 2
      src/acpi.js

+ 41 - 2
src/acpi.js

@@ -3,7 +3,7 @@
 // http://www.uefi.org/sites/default/files/resources/ACPI_6_1.pdf
 
 /** @const */
-var PMTIMER_FREQ = 3579545;
+var PMTIMER_FREQ_SECONDS = 3579545;
 
 /**
  * @constructor
@@ -31,6 +31,9 @@ function ACPI(cpu)
     // 00:07.0 Bridge: Intel Corporation 82371AB/EB/MB PIIX4 ACPI (rev 08)
     cpu.devices.pci.register_device(acpi);
 
+    this.timer_last_value = 0;
+    this.timer_imprecision_offset = 0;
+
     this.status = 1;
     this.pm1_status = 0;
     this.pm1_enable = 0;
@@ -145,7 +148,43 @@ ACPI.prototype.timer = function(now)
 
 ACPI.prototype.get_timer = function(now)
 {
-    return now * (PMTIMER_FREQ / 1000) | 0;
+    const t = Math.round(now * (PMTIMER_FREQ_SECONDS / 1000));
+
+    // Due to the low precision of JavaScript's time functions we increment the
+    // returned timer value every time it is read
+
+    if(t === this.timer_last_value)
+    {
+        // don't go past 1ms
+
+        if(this.timer_imprecision_offset < PMTIMER_FREQ_SECONDS / 1000)
+        {
+            this.timer_imprecision_offset++;
+        }
+    }
+    else
+    {
+        dbg_assert(t > this.timer_last_value);
+
+        const previous_timer = this.timer_last_value + this.timer_imprecision_offset;
+
+        // don't go back in time
+
+        if(previous_timer <= t)
+        {
+            this.timer_imprecision_offset = 0;
+            this.timer_last_value = t;
+        }
+        else
+        {
+            dbg_log("Warning: Overshot pmtimer, waiting;" +
+                    " current=" + t +
+                    " last=" + this.timer_last_value +
+                    " offset=" + this.timer_imprecision_offset, LOG_ACPI);
+        }
+    }
+
+    return this.timer_last_value + this.timer_imprecision_offset;
 };
 
 ACPI.prototype.get_state = function()