Make sure timers don't go completely out of sync upon altering TSC via WRMSR

This commit is contained in:
Cacodemon345
2024-06-18 20:05:44 +06:00
parent 382b941ff9
commit 2b3d3ad5bd
3 changed files with 38 additions and 6 deletions

View File

@@ -40,6 +40,7 @@
#include <86box/nmi.h> #include <86box/nmi.h>
#include <86box/pic.h> #include <86box/pic.h>
#include <86box/pci.h> #include <86box/pci.h>
#include <86box/timer.h>
#include <86box/gdbstub.h> #include <86box/gdbstub.h>
#include <86box/plat_fallthrough.h> #include <86box/plat_fallthrough.h>
#include <86box/plat_unused.h> #include <86box/plat_unused.h>
@@ -3492,7 +3493,7 @@ cpu_WRMSR(void)
break; break;
/* Time Stamp Counter */ /* Time Stamp Counter */
case 0x10: case 0x10:
tsc = EAX | ((uint64_t) EDX << 32); timer_set_new_tsc(EAX | ((uint64_t) EDX << 32));
break; break;
/* Performance Monitor - Control and Event Select */ /* Performance Monitor - Control and Event Select */
case 0x11: case 0x11:
@@ -3568,7 +3569,7 @@ cpu_WRMSR(void)
break; break;
/* Time Stamp Counter */ /* Time Stamp Counter */
case 0x10: case 0x10:
tsc = EAX | ((uint64_t) EDX << 32); timer_set_new_tsc(EAX | ((uint64_t) EDX << 32));
break; break;
/* PERFCTR0 - Performance Counter Register 0 - aliased to TSC */ /* PERFCTR0 - Performance Counter Register 0 - aliased to TSC */
case 0xc1: case 0xc1:
@@ -3664,7 +3665,7 @@ cpu_WRMSR(void)
break; break;
/* Time Stamp Counter */ /* Time Stamp Counter */
case 0x00000010: case 0x00000010:
tsc = EAX | ((uint64_t) EDX << 32); timer_set_new_tsc(EAX | ((uint64_t) EDX << 32));
break; break;
/* Array Access Register */ /* Array Access Register */
case 0x00000082: case 0x00000082:
@@ -3834,7 +3835,7 @@ amd_k_invalid_wrmsr:
/* Time Stamp Counter */ /* Time Stamp Counter */
case 0x00000010: case 0x00000010:
case 0x80000010: case 0x80000010:
tsc = EAX | ((uint64_t) EDX << 32); timer_set_new_tsc(EAX | ((uint64_t) EDX << 32));
break; break;
/* Performance Monitor - Control and Event Select */ /* Performance Monitor - Control and Event Select */
case 0x00000011: case 0x00000011:
@@ -3919,7 +3920,7 @@ pentium_invalid_wrmsr:
msr.tr5 = EAX & 0x008f0f3b; msr.tr5 = EAX & 0x008f0f3b;
/* Time Stamp Counter */ /* Time Stamp Counter */
case 0x10: case 0x10:
tsc = EAX | ((uint64_t) EDX << 32); timer_set_new_tsc(EAX | ((uint64_t) EDX << 32));
break; break;
/* Performance Monitor - Control and Event Select */ /* Performance Monitor - Control and Event Select */
case 0x11: case 0x11:
@@ -3952,7 +3953,7 @@ pentium_invalid_wrmsr:
break; break;
/* Time Stamp Counter */ /* Time Stamp Counter */
case 0x10: case 0x10:
tsc = EAX | ((uint64_t) EDX << 32); timer_set_new_tsc(EAX | ((uint64_t) EDX << 32));
break; break;
/* Unknown */ /* Unknown */
case 0x18: case 0x18:

View File

@@ -185,6 +185,9 @@ timer_set_p(pc_timer_t *timer, void *priv)
extern void timer_stop(pc_timer_t *timer); extern void timer_stop(pc_timer_t *timer);
extern void timer_on_auto(pc_timer_t *timer, double period); extern void timer_on_auto(pc_timer_t *timer, double period);
/* Change TSC, taking into account the timers. */
extern void timer_set_new_tsc(uint64_t new_tsc);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -253,3 +253,31 @@ timer_on_auto(pc_timer_t *timer, double period)
else else
timer_stop(timer); timer_stop(timer);
} }
void
timer_set_new_tsc(uint64_t new_tsc)
{
pc_timer_t *timer = NULL;
/* Run timers already expired. */
#ifdef USE_DYNAREC
if (cpu_use_dynarec)
update_tsc();
#endif
if (!timer_head) {
tsc = new_tsc;
return;
}
timer = timer_head;
timer_target = new_tsc + (int32_t)(timer_get_ts_int(timer_head) - (uint32_t)tsc);
while (timer) {
int32_t offset_from_current_tsc = (int32_t)(timer_get_ts_int(timer) - (uint32_t)tsc);
timer->ts.ts32.integer = new_tsc + offset_from_current_tsc;
timer = timer->next;
}
tsc = new_tsc;
}