Make tsc_offset 64-bit integer, save and restore it correctly

This commit is contained in:
Fabian 2018-01-28 14:02:00 -06:00
parent 27b0ab71b1
commit 2b75cff787
5 changed files with 30 additions and 15 deletions

View file

@ -148,7 +148,8 @@ function CPU(bus, wm, codegen, coverage_logger)
this.mul32_result = new Int32Array(wm.memory.buffer, 544, 2);
this.div32_result = new Float64Array(2);
this.tsc_offset = new Int32Array(wm.memory.buffer, 652, 1);
this.tsc_offset = new Uint32Array(wm.memory.buffer, 544, 2); // 64 bit
this.current_tsc = new Uint32Array(wm.memory.buffer, 956, 2); // 64 bit
this.phys_addr = new Int32Array(wm.memory.buffer, 656, 1);
@ -240,7 +241,7 @@ function CPU(bus, wm, codegen, coverage_logger)
this.update_operand_size();
this.tsc_offset[0] = v86.microtick();
wm.exports["_set_tsc"](0, 0);
this.debug_init();
@ -369,6 +370,9 @@ CPU.prototype.get_state = function()
state[41] = this.dreg;
state[42] = this.mem8;
this.wm.exports["_store_current_tsc"]();
state[43] = this.current_tsc;
state[45] = this.devices.virtio;
state[46] = this.devices.apic;
state[47] = this.devices.rtc;
@ -453,6 +457,8 @@ CPU.prototype.set_state = function(state)
this.dreg.set(state[41]);
this.mem8.set(state[42]);
this.wm.exports["_set_tsc"](state[43][0], state[43][1]);
this.devices.virtio = state[45];
this.devices.apic = state[46];
this.devices.rtc = state[47];
@ -491,7 +497,6 @@ CPU.prototype.set_state = function(state)
this.fpu_opcode[0] = state[75];
this.full_clear_tlb();
// tsc_offset?
this.update_operand_size();
};
@ -628,7 +633,7 @@ CPU.prototype.reset = function()
this.last_op2.fill(0);
this.last_op_size.fill(0);
this.tsc_offset[0] = v86.microtick();
this.wm.exports["_set_tsc"](0, 0);
this.instruction_pointer[0] = 0xFFFF0;
this.switch_cs_real_mode(0xF000);

View file

@ -1241,9 +1241,20 @@ int32_t decr_ecx_asize()
return is_asize_32() ? --reg32s[ECX] : --reg16[CX];
}
void set_tsc(uint32_t low, uint32_t high)
{
uint64_t new_value = low | (uint64_t)high << 32;
uint64_t current_value = read_tsc();
*tsc_offset = current_value - new_value;
}
uint64_t read_tsc()
{
double_t n = microtick() - tsc_offset[0]; // XXX: float
n = n * TSC_RATE;
return n;
double_t n = microtick() * TSC_RATE;
return (uint64_t)n - *tsc_offset;
}
void store_current_tsc()
{
*current_tsc = read_tsc();
}

View file

@ -133,6 +133,7 @@ int32_t get_reg_asize(int32_t reg);
void set_ecx_asize(int32_t value);
void add_reg_asize(int32_t reg, int32_t value);
int32_t decr_ecx_asize(void);
void set_tsc(uint32_t, uint32_t);
uint64_t read_tsc(void);
bool vm86_mode(void);
int32_t getiopl(void);

View file

@ -23,7 +23,7 @@ static int32_t* const flags = (int32_t* const) 536;
static bool* const page_fault = (bool* const) 540;
// gap 12
static uint64_t* const tsc_offset = (uint64_t* const) 544;
static bool* const a20_enabled = (bool* const) 552;
static int32_t* const instruction_pointer = (int32_t* const) 556;
@ -45,7 +45,7 @@ static int32_t* const sysenter_cs = (int32_t* const) 636;
static int32_t* const sysenter_esp = (int32_t* const) 640;
static int32_t* const sysenter_eip = (int32_t* const) 644;
static uint8_t* const prefixes = (uint8_t* const) 648;
static int32_t* const tsc_offset = (int32_t* const) 652;
// gap
static int32_t* const phys_addr = (int32_t* const) 656;
static int32_t* const phys_addr_high = (int32_t* const) 660;
static uint32_t* const timestamp_counter = (uint32_t* const) 664;
@ -69,6 +69,8 @@ static int32_t* const mxcsr = (int32_t* const) 824;
static union reg128* const reg_xmm = (union reg128* const) 828; // length 128
static uint64_t* const current_tsc = (uint64_t* const) 956;
static uint8_t* const codegen_buffers = (uint8_t* const) 2048; // length 2048
static uint8_t* const tlb_info = (uint8_t* const) 4096; // length 0x100000

View file

@ -736,10 +736,7 @@ void instr_0F30() {
break;
case IA32_TIME_STAMP_COUNTER:
{
uint64_t new_tick = (low) + 0x100000000 * (high);
tsc_offset[0] = microtick() - new_tick / TSC_RATE; // XXX: float
}
set_tsc(low, high);
break;
case IA32_BIOS_SIGN_ID:
@ -768,13 +765,12 @@ void instr_0F31() {
if(!cpl[0] || !(cr[4] & CR4_TSD))
{
//dbg_assert(isFinite(n), "non-finite tsc: " + n);
uint64_t tsc = read_tsc();
reg32s[EAX] = tsc;
reg32s[EDX] = tsc >> 32;
//dbg_log("rdtsc edx:eax=" + h(reg32[EDX], 8) + ":" + h(reg32[EAX], 8));
//dbg_log("rdtsc edx:eax=%x:%x", reg32s[EDX], reg32s[EAX]);
}
else
{