@@ -131,6 +131,7 @@ struct kvmppc_host_state {
u64 cfar;
u64 ppr;
u64 host_fscr;
+ u64 tb_offset; /* Timebase offset: keeps correct timebase while on guest */
#endif
};
@@ -706,6 +706,7 @@ int main(void)
HSTATE_FIELD(HSTATE_CFAR, cfar);
HSTATE_FIELD(HSTATE_PPR, ppr);
HSTATE_FIELD(HSTATE_HOST_FSCR, host_fscr);
+ HSTATE_FIELD(HSTATE_TB_OFFSET, tb_offset);
#endif /* CONFIG_PPC_BOOK3S_64 */
#else /* CONFIG_PPC_BOOK3S */
@@ -699,7 +699,8 @@ EXPORT_SYMBOL_GPL(tb_to_ns);
*/
notrace unsigned long long sched_clock(void)
{
- return mulhdu(get_tb() - boot_tb, tb_to_ns_scale) << tb_to_ns_shift;
+ return mulhdu(get_tb() - boot_tb - local_paca->kvm_hstate.tb_offset, tb_to_ns_scale)
+ << tb_to_ns_shift;
}
@@ -3491,6 +3491,7 @@ static int kvmhv_load_hv_regs_and_go(struct kvm_vcpu *vcpu, u64 time_limit,
if ((tb & 0xffffff) < (new_tb & 0xffffff))
mtspr(SPRN_TBU40, new_tb + 0x1000000);
vc->tb_offset_applied = vc->tb_offset;
+ local_paca->kvm_hstate.tb_offset = vc->tb_offset;
}
if (vc->pcr)
@@ -3594,6 +3595,7 @@ static int kvmhv_load_hv_regs_and_go(struct kvm_vcpu *vcpu, u64 time_limit,
if ((tb & 0xffffff) < (new_tb & 0xffffff))
mtspr(SPRN_TBU40, new_tb + 0x1000000);
vc->tb_offset_applied = 0;
+ local_paca->kvm_hstate.tb_offset = 0;
}
mtspr(SPRN_HDEC, 0x7fffffff);
@@ -632,6 +632,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
cmpdi r8,0
beq 37f
std r8, VCORE_TB_OFFSET_APPL(r5)
+ std r8, HSTATE_TB_OFFSET(r13)
mftb r6 /* current host timebase */
add r8,r8,r6
mtspr SPRN_TBU40,r8 /* update upper 40 bits */
@@ -1907,6 +1908,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
beq 17f
li r0, 0
std r0, VCORE_TB_OFFSET_APPL(r5)
+ std r0, HSTATE_TB_OFFSET(r13)
mftb r6 /* current guest timebase */
subf r8,r8,r6
mtspr SPRN_TBU40,r8 /* update upper 40 bits */
Before guest entry, TBU40 register is changed to reflect guest timebase. After exitting guest, the register is reverted to it's original value. If one tries to get the timestamp from host between those changes, it will present an incorrect value. An example would be trying to add a tracepoint in kvmppc_guest_entry_inject_int(), which depending on last tracepoint acquired could actually cause the host to crash. Save the Timebase Offset to PACA and use it on sched_clock() to always get the correct timestamp. Signed-off-by: Leonardo Bras <leobras.c@gmail.com> --- arch/powerpc/include/asm/kvm_book3s_asm.h | 1 + arch/powerpc/kernel/asm-offsets.c | 1 + arch/powerpc/kernel/time.c | 3 ++- arch/powerpc/kvm/book3s_hv.c | 2 ++ arch/powerpc/kvm/book3s_hv_rmhandlers.S | 2 ++ 5 files changed, 8 insertions(+), 1 deletion(-)