This Readme is obsolete due to a new kernel version.
Copy this files into your linux kernel.
For new kernel:
Don't forget to disable rdtscp in your qemu xml config:
Add rdtscp=off to your qemu:arg, so it will look similar to this:
You can play with ticks if you want to.
For Intel users:
For AMD users:
If you have trouble to build your kernel with files from this repository, you can try to modify vmx and svm files in your kernel by yourself.
Open vmx.c in text editor.
First you need to find _setup_vmcsconfig function (about 2500 lines) and add this line:
CPU_BASED_CR3_LOAD_EXITING |
CPU_BASED_CR3_STORE_EXITING |
CPU_BASED_UNCOND_IO_EXITING |
CPU_BASED_MOV_DR_EXITING |
CPU_BASED_USE_TSC_OFFSETTING |
CPU_BASED_MWAIT_EXITING |
CPU_BASED_MONITOR_EXITING |
CPU_BASED_INVLPG_EXITING |
CPU_BASED_RDPMC_EXITING |
CPU_BASED_RDTSC_EXITING; //added line
Next you need to find an array of pointers to handlers initialization called _static int (kvm_vmx_exit_handlers[])(struct kvm_vcpu vcpu)_ and add the line to the end:
[EXIT_REASON_PREEMPTION_TIMER] = handle_preemption_timer,
[EXIT_REASON_ENCLS] = handle_encls,
[EXIT_REASON_BUS_LOCK] = handle_bus_lock_vmexit,
[EXIT_REASON_RDTSC] = handle_rdtsc, //added line
};
Then add this code before _static int (kvm_vmx_exit_handlers[])(struct kvm_vcpu vcpu)_:
static u32 print_once = 1;
static int handle_rdtsc(struct kvm_vcpu *vcpu)
{
static u64 rdtsc_fake = 0;
static u64 rdtsc_prev = 0;
u64 rdtsc_real = rdtsc();
if(print_once)
{
printk("[handle_rdtsc] fake rdtsc vmx function is working\n");
print_once = 0;
rdtsc_fake = rdtsc_real;
}
if(rdtsc_prev != 0)
{
if(rdtsc_real > rdtsc_prev)
{
u64 diff = rdtsc_real - rdtsc_prev;
u64 fake_diff = diff / 16; // if you have 4.2Ghz on your vm, change 16 to 20
rdtsc_fake += fake_diff;
}
}
if(rdtsc_fake > rdtsc_real)
{
rdtsc_fake = rdtsc_real;
}
rdtsc_prev = rdtsc_real;
vcpu->arch.regs[VCPU_REGS_RAX] = rdtsc_fake & -1u;
vcpu->arch.regs[VCPU_REGS_RDX] = (rdtsc_fake >> 32) & -1u;
return skip_emulated_instruction(vcpu);
}
Open svm.c in text editor.
Find _static int (const svm_exit_handlers[])(struct kvm_vcpu vcpu)_ (~2700 lines) and add this line:
[SVM_EXIT_AVIC_INCOMPLETE_IPI] = avic_incomplete_ipi_interception,
[SVM_EXIT_AVIC_UNACCELERATED_ACCESS] = avic_unaccelerated_access_interception,
[SVM_EXIT_VMGEXIT] = sev_handle_vmgexit,
[SVM_EXIT_RDTSC] = handle_rdtsc_interception, //added line
};
Next find _static void init_vmcb(struct kvmvcpu *vcpu) (~1000 lines) and add this line:
svm_set_intercept(svm, INTERCEPT_RDPRU);
svm_set_intercept(svm, INTERCEPT_RSM);
svm_set_intercept(svm, INTERCEPT_RDTSC); //added line
After that add this code on top of _static int (const svm_exit_handlers[])(struct kvm_vcpu vcpu)_:
static u32 print_once = 1;
static int handle_rdtsc_interception(struct kvm_vcpu *vcpu)
{
static u64 rdtsc_fake = 0;
static u64 rdtsc_prev = 0;
u64 rdtsc_real = rdtsc();
if(print_once)
{
printk("[handle_rdtsc] fake rdtsc svm function is working\n");
print_once = 0;
rdtsc_fake = rdtsc_real;
}
if(rdtsc_prev != 0)
{
if(rdtsc_real > rdtsc_prev)
{
u64 diff = rdtsc_real - rdtsc_prev;
u64 fake_diff = diff / 20; // if you have 3.2Ghz on your vm, change 20 to 16
rdtsc_fake += fake_diff;
}
}
if(rdtsc_fake > rdtsc_real)
{
rdtsc_fake = rdtsc_real;
}
rdtsc_prev = rdtsc_real;
vcpu->arch.regs[VCPU_REGS_RAX] = rdtsc_fake & -1u;
vcpu->arch.regs[VCPU_REGS_RDX] = (rdtsc_fake >> 32) & -1u;
return skip_emulated_instruction(vcpu);
}
sudo apt-get install build-essential libncurses-dev bison flex libssl-dev libelf-dev
cp -v /boot/config-$(uname -r) .config
make -j $(nproc)
sudo make INSTALL_MOD_STRIP=1 modules_install && sudo make install
uname -a