mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-18 21:27:56 +00:00
nova: support transfer of IA32_TSC_AUX MSR for vCPUs
The 32-bit MSR is returned by rdtscp in ecx register and used to detect the CPU ID the timestamp was taken on. Issue #4314
This commit is contained in:
parent
f4e52863c0
commit
533015b93e
@ -316,6 +316,7 @@ namespace Nova {
|
||||
R8_R15 = 1U << 22, /* R8 .. R15 */
|
||||
SYSCALL_SWAPGS = 1U << 23, /* SYSCALL and SWAPGS MSRs */
|
||||
TPR = 1U << 24, /* TPR and TPR threshold */
|
||||
TSC_AUX = 1U << 25, /* IA32_TSC_AUX used by rdtscp */
|
||||
FPU = 1U << 31, /* FPU state */
|
||||
|
||||
IRQ = EFL | STA | INJ | TSC,
|
||||
@ -590,7 +591,7 @@ namespace Nova {
|
||||
mword_t reserved1;
|
||||
#endif
|
||||
} gdtr, idtr;
|
||||
unsigned long long tsc_val, tsc_off;
|
||||
unsigned long long tsc_val, tsc_off, tsc_aux;
|
||||
} __attribute__((packed));
|
||||
mword_t mr[(4096 - 4 * sizeof(mword_t)) / sizeof(mword_t)];
|
||||
};
|
||||
|
@ -1 +1 @@
|
||||
2ff8c9abf7389a2bdb7e0aa8aa4d2fec688c51af
|
||||
b06f9132099cd798147f6951f27a5d3a17f28fa4
|
||||
|
@ -4,7 +4,7 @@ DOWNLOADS := nova.git
|
||||
|
||||
# r10 branch
|
||||
URL(nova) := https://github.com/alex-ab/NOVA.git
|
||||
REV(nova) := 5c64bba1ee59902eb2a4ce4abe4b867eaf085dac
|
||||
REV(nova) := 825c1f94c82ae03f554c02b91430eca6983329da
|
||||
DIR(nova) := src/kernel/nova
|
||||
|
||||
PATCHES := $(sort $(wildcard $(REP_DIR)/patches/*.patch))
|
||||
|
@ -31,7 +31,7 @@ CC_OPT += -DCONFIG_MEMORY_DYN_MIN=0x1c00000 \
|
||||
CC_OPT_PIC :=
|
||||
ifeq ($(filter-out $(SPECS),32bit),)
|
||||
override CC_MARCH = -m32
|
||||
CC_WARN += -Wframe-larger-than=96
|
||||
CC_WARN += -Wframe-larger-than=104
|
||||
CC_OPT += -mpreferred-stack-boundary=2 -mregparm=3
|
||||
else
|
||||
ifeq ($(filter-out $(SPECS),64bit),)
|
||||
|
@ -135,6 +135,7 @@ struct Nova_vcpu : Rpc_client<Vm_session::Native_vcpu>, Noncopyable
|
||||
mtd |= Nova::Mtd::INJ;
|
||||
mtd |= Nova::Mtd::STA;
|
||||
mtd |= Nova::Mtd::TSC;
|
||||
mtd |= Nova::Mtd::TSC_AUX;
|
||||
mtd |= Nova::Mtd::EFER;
|
||||
mtd |= Nova::Mtd::PDPTE;
|
||||
mtd |= Nova::Mtd::SYSCALL_SWAPGS;
|
||||
@ -316,6 +317,10 @@ void Nova_vcpu::_read_nova_state(Nova::Utcb &utcb, unsigned exit_reason,
|
||||
state().tsc_offset.charge(utcb.tsc_off);
|
||||
}
|
||||
|
||||
if (utcb.mtd & Nova::Mtd::TSC_AUX) {
|
||||
state().tsc_aux.charge(utcb.tsc_aux);
|
||||
}
|
||||
|
||||
if (utcb.mtd & Nova::Mtd::EFER) {
|
||||
state().efer.charge(utcb.read_efer());
|
||||
}
|
||||
@ -508,6 +513,11 @@ void Nova_vcpu::_write_nova_state(Nova::Utcb &utcb)
|
||||
utcb.tsc_off = state().tsc_offset.value();
|
||||
}
|
||||
|
||||
if (state().tsc_aux.charged()) {
|
||||
utcb.mtd |= Nova::Mtd::TSC_AUX;
|
||||
utcb.tsc_aux = state().tsc_aux.value();
|
||||
}
|
||||
|
||||
if (state().efer.charged()) {
|
||||
utcb.mtd |= Nova::Mtd::EFER;
|
||||
utcb.write_efer(state().efer.value());
|
||||
|
@ -145,6 +145,7 @@ class Genode::Vcpu_state
|
||||
|
||||
Register<uint64_t> tsc;
|
||||
Register<uint64_t> tsc_offset;
|
||||
Register<uint64_t> tsc_aux;
|
||||
|
||||
Register<addr_t> efer;
|
||||
|
||||
|
@ -25,6 +25,9 @@ if { [get_cmd_switch --autopilot] } {
|
||||
}
|
||||
}
|
||||
|
||||
# ia32_tsc_aux with rdtscp
|
||||
set test_rdtscp [have_spec nova]
|
||||
|
||||
set build_components {
|
||||
core init
|
||||
timer
|
||||
@ -114,6 +117,8 @@ unify_output "vcpu 0 : XX. vm exit - reason 0x4e handled by 'ep'" ""
|
||||
unify_output "vcpu 0 : XX. vm exit - reason 0x30 handled by 'ep'" ""
|
||||
unify_output "vcpu 0 : XX. vm exit - guest fault address: 0xfffffff0" ""
|
||||
unify_output "vcpu 0 : XX. vm exit - resume vcpu" ""
|
||||
# remove rdtscp output from unified output, some kernel don't support tsc_aux
|
||||
unify_output {vcpu 0 : XX. vm exit - rdtscp.* host=0x[0-9]} ""
|
||||
trim_lines
|
||||
set output_0 $output
|
||||
|
||||
@ -130,6 +135,8 @@ unify_output "vcpu 1 : XX. vm exit - reason 0x4e handled by 'ep'" ""
|
||||
unify_output "vcpu 1 : XX. vm exit - reason 0x30 handled by 'ep'" ""
|
||||
unify_output "vcpu 1 : XX. vm exit - guest fault address: 0xfffffff0" ""
|
||||
unify_output "vcpu 1 : XX. vm exit - resume vcpu" ""
|
||||
# remove rdtscp output from unified output, some kernel don't support tsc_aux
|
||||
unify_output {vcpu 1 : XX. vm exit - rdtscp.* host=0x[0-9]} ""
|
||||
trim_lines
|
||||
set output_1 $output
|
||||
|
||||
@ -146,6 +153,8 @@ unify_output "vcpu 2 : XX. vm exit - reason 0x4e handled by 'second ep'" ""
|
||||
unify_output "vcpu 2 : XX. vm exit - reason 0x30 handled by 'second ep'" ""
|
||||
unify_output "vcpu 2 : XX. vm exit - guest fault address: 0xfffffff0" ""
|
||||
unify_output "vcpu 2 : XX. vm exit - resume vcpu" ""
|
||||
# remove rdtscp output from unified output, some kernel don't support tsc_aux
|
||||
unify_output {vcpu 2 : XX. vm exit - rdtscp.* host=0x[0-9]} ""
|
||||
trim_lines
|
||||
set output_2 $output
|
||||
|
||||
@ -162,18 +171,44 @@ unify_output "vcpu 3 : XX. vm exit - reason 0x4e handled by 'second ep'" ""
|
||||
unify_output "vcpu 3 : XX. vm exit - reason 0x30 handled by 'second ep'" ""
|
||||
unify_output "vcpu 3 : XX. vm exit - guest fault address: 0xfffffff0" ""
|
||||
unify_output "vcpu 3 : XX. vm exit - resume vcpu" ""
|
||||
# remove rdtscp output from unified output, some kernel don't support tsc_aux
|
||||
unify_output {vcpu 3 : XX. vm exit - rdtscp.* host=0x[0-9]} ""
|
||||
trim_lines
|
||||
set output_3 $output
|
||||
|
||||
if {$test_rdtscp} {
|
||||
set output $output_saved
|
||||
grep_output {^\[init -> vmm\] vcpu [0-9]+ :.*rdtscp cx.*}
|
||||
unify_output {\[init -> vmm\] vcpu 0 : [0-9]+} "vcpu 0 : XX"
|
||||
unify_output {\[init -> vmm\] vcpu 1 : [0-9]+} "vcpu 1 : XX"
|
||||
unify_output {\[init -> vmm\] vcpu 2 : [0-9]+} "vcpu 2 : XX"
|
||||
unify_output {\[init -> vmm\] vcpu 3 : [0-9]+} "vcpu 3 : XX"
|
||||
set output [lsort -stride 11 -index 1 $output]
|
||||
unify_output "vcpu" "\nvcpu"
|
||||
set output_rdtscp $output
|
||||
}
|
||||
|
||||
puts "\ncomparing output ..."
|
||||
|
||||
if {$test_rdtscp} {
|
||||
puts $output_rdtscp
|
||||
puts ""
|
||||
set output $output_rdtscp
|
||||
compare_output_to {
|
||||
vcpu 0 : XX. vm exit - rdtscp cx guest=0xaffe0000 host=0x0
|
||||
vcpu 1 : XX. vm exit - rdtscp cx guest=0xaffe0001 host=0x0
|
||||
vcpu 2 : XX. vm exit - rdtscp cx guest=0xaffe0002 host=0x1
|
||||
vcpu 3 : XX. vm exit - rdtscp cx guest=0xaffe0003 host=0x1
|
||||
}
|
||||
}
|
||||
|
||||
puts $output_0
|
||||
set output $output_0
|
||||
compare_output_to {
|
||||
[init -> vmm] vcpu 0 : created
|
||||
vcpu 0 : XX. vm exit - reason 0xfe handled by 'ep'
|
||||
vcpu 0 : XX. vm exit - reason 0x78 handled by 'ep'
|
||||
vcpu 0 : XX. vm exit - halting vCPU - guest called HLT - ip=0xfff0
|
||||
vcpu 0 : XX. vm exit - halting vCPU - guest called HLT - ip=0xfff3
|
||||
}
|
||||
|
||||
puts $output_1
|
||||
@ -182,19 +217,19 @@ compare_output_to {
|
||||
[init -> vmm] vcpu 1 : created
|
||||
vcpu 1 : XX. vm exit - reason 0xfe handled by 'ep'
|
||||
vcpu 1 : XX. vm exit - reason 0x78 handled by 'ep'
|
||||
vcpu 1 : XX. vm exit - halting vCPU - guest called HLT - ip=0xfff0
|
||||
vcpu 1 : XX. vm exit - halting vCPU - guest called HLT - ip=0xfff3
|
||||
vcpu 1 : XX. vm exit - reason 0xff handled by 'ep'
|
||||
vcpu 1 : XX. vm exit - due to pause() request - ip=0xfff0
|
||||
vcpu 1 : XX. vm exit - due to pause() request - ip=0xfff3
|
||||
vcpu 1 : XX. vm exit - reason 0x78 handled by 'ep'
|
||||
vcpu 1 : XX. vm exit - halting vCPU - guest called HLT - ip=0xfff0
|
||||
vcpu 1 : XX. vm exit - halting vCPU - guest called HLT - ip=0xfff3
|
||||
vcpu 1 : XX. vm exit - reason 0xff handled by 'ep'
|
||||
vcpu 1 : XX. vm exit - due to pause() request - ip=0xfff0
|
||||
vcpu 1 : XX. vm exit - due to pause() request - ip=0xfff3
|
||||
vcpu 1 : XX. vm exit - reason 0xff handled by 'ep'
|
||||
vcpu 1 : XX. vm exit - due to pause() request - ip=0xfff2
|
||||
vcpu 1 : XX. vm exit - due to pause() request - ip=0xfff5
|
||||
vcpu 1 : XX. vm exit - reason 0x78 handled by 'ep'
|
||||
vcpu 1 : XX. vm exit - halting vCPU - guest called HLT - ip=0xfff4
|
||||
vcpu 1 : XX. vm exit - halting vCPU - guest called HLT - ip=0xfff7
|
||||
vcpu 1 : XX. vm exit - reason 0xff handled by 'ep'
|
||||
vcpu 1 : XX. vm exit - due to pause() request - ip=0xfff4
|
||||
vcpu 1 : XX. vm exit - due to pause() request - ip=0xfff7
|
||||
}
|
||||
|
||||
puts $output_2
|
||||
@ -203,17 +238,17 @@ compare_output_to {
|
||||
[init -> vmm] vcpu 2 : created
|
||||
vcpu 2 : XX. vm exit - reason 0xfe handled by 'second ep'
|
||||
vcpu 2 : XX. vm exit - reason 0x78 handled by 'second ep'
|
||||
vcpu 2 : XX. vm exit - halting vCPU - guest called HLT - ip=0xfff0
|
||||
vcpu 2 : XX. vm exit - halting vCPU - guest called HLT - ip=0xfff3
|
||||
vcpu 2 : XX. vm exit - reason 0xff handled by 'second ep'
|
||||
vcpu 2 : XX. vm exit - due to pause() request - ip=0xfff0
|
||||
vcpu 2 : XX. vm exit - due to pause() request - ip=0xfff3
|
||||
vcpu 2 : XX. vm exit - reason 0x78 handled by 'second ep'
|
||||
vcpu 2 : XX. vm exit - halting vCPU - guest called HLT - ip=0xfff0
|
||||
vcpu 2 : XX. vm exit - halting vCPU - guest called HLT - ip=0xfff3
|
||||
vcpu 2 : XX. vm exit - reason 0xff handled by 'second ep'
|
||||
vcpu 2 : XX. vm exit - due to pause() request - ip=0xfff0
|
||||
vcpu 2 : XX. vm exit - due to pause() request - ip=0xfff3
|
||||
vcpu 2 : XX. vm exit - reason 0x78 handled by 'second ep'
|
||||
vcpu 2 : XX. vm exit - halting vCPU - guest called HLT - ip=0xfff1
|
||||
vcpu 2 : XX. vm exit - halting vCPU - guest called HLT - ip=0xfff4
|
||||
vcpu 2 : XX. vm exit - reason 0xff handled by 'second ep'
|
||||
vcpu 2 : XX. vm exit - due to pause() request - ip=0xfff1
|
||||
vcpu 2 : XX. vm exit - due to pause() request - ip=0xfff4
|
||||
}
|
||||
|
||||
puts $output_3
|
||||
@ -222,7 +257,7 @@ compare_output_to {
|
||||
[init -> vmm] vcpu 3 : created
|
||||
vcpu 3 : XX. vm exit - reason 0xfe handled by 'second ep'
|
||||
vcpu 3 : XX. vm exit - reason 0x78 handled by 'second ep'
|
||||
vcpu 3 : XX. vm exit - halting vCPU - guest called HLT - ip=0xfff0
|
||||
vcpu 3 : XX. vm exit - halting vCPU - guest called HLT - ip=0xfff3
|
||||
}
|
||||
|
||||
set output $output_saved
|
||||
|
@ -55,6 +55,13 @@ namespace Vmm {
|
||||
Vm_connection::Exit_config const exit_config {
|
||||
/* ... */
|
||||
};
|
||||
|
||||
static uint32_t rdtscp()
|
||||
{
|
||||
uint32_t lo = 0, hi = 0, tsc_aux = 0;
|
||||
asm volatile ("rdtscp" : "=a" (lo), "=d" (hi), "=c" (tsc_aux) :: "memory");
|
||||
return tsc_aux;
|
||||
}
|
||||
}
|
||||
|
||||
class Vmm::Vcpu
|
||||
@ -82,6 +89,7 @@ class Vmm::Vcpu
|
||||
/* test state end */
|
||||
unsigned _exit_count { 0 };
|
||||
unsigned _pause_count { 0 };
|
||||
unsigned _hlt_count { 0 };
|
||||
unsigned _timer_count { 0 };
|
||||
unsigned _pause_at_timer { 0 };
|
||||
|
||||
@ -90,7 +98,10 @@ class Vmm::Vcpu
|
||||
void _cpu_init()
|
||||
{
|
||||
enum { INTEL_CTRL_PRIMARY_HLT = 1 << 7 };
|
||||
enum { INTEL_CTRL_SECOND_UG = 1 << 7 };
|
||||
enum {
|
||||
INTEL_CTRL_SECOND_UG = 1 << 7,
|
||||
INTEL_CTRL_SECOND_RDTSCP_ENABLE = 1 << 3,
|
||||
};
|
||||
enum { AMD_CTRL_SECOND_VMRUN = 1 << 0 };
|
||||
|
||||
/* http://www.sandpile.org/x86/initial.htm */
|
||||
@ -122,13 +133,18 @@ class Vmm::Vcpu
|
||||
|
||||
if (_vmx) {
|
||||
state.ctrl_primary.charge(INTEL_CTRL_PRIMARY_HLT);
|
||||
/* required for seL4 */
|
||||
state.ctrl_secondary.charge(INTEL_CTRL_SECOND_UG);
|
||||
state.ctrl_secondary.charge(INTEL_CTRL_SECOND_UG | /* required for seL4 */
|
||||
INTEL_CTRL_SECOND_RDTSCP_ENABLE);
|
||||
}
|
||||
if (_svm) {
|
||||
/* required for native AMD hardware (!= Qemu) for NOVA */
|
||||
state.ctrl_secondary.charge(AMD_CTRL_SECOND_VMRUN);
|
||||
}
|
||||
|
||||
/* Store id of CPU for rdtscp, similar as some OS do and some
|
||||
* magic number to check for testing purpuse
|
||||
*/
|
||||
state.tsc_aux.charge((0xaffeU << 16) | _id);
|
||||
}
|
||||
|
||||
public:
|
||||
@ -276,13 +292,17 @@ class Vmm::Vm
|
||||
|
||||
/* prepare guest memory with some instructions for testing */
|
||||
uint8_t * guest = env.rm().attach(_memory);
|
||||
// *(guest + 0xff0) = 0x0f; /* CPUID instruction */
|
||||
// *(guest + 0xff1) = 0xa2;
|
||||
*(guest + 0xff0) = 0xf4; /* HLT instruction */
|
||||
*(guest + 0xff1) = 0xf4; /* HLT instruction */
|
||||
*(guest + 0xff2) = 0xeb; /* JMP - endless loop to RIP */
|
||||
*(guest + 0xff3) = 0xfe; /* JMP of -2 byte (size of JMP inst) */
|
||||
*(guest + 0xff4) = 0xf4; /* HLT instruction */
|
||||
unsigned byte = 0xff0;
|
||||
|
||||
guest[byte++] = 0x0f; /* rdtscp */
|
||||
guest[byte++] = 0x01;
|
||||
guest[byte++] = 0xf9;
|
||||
|
||||
guest[byte++] = 0xf4; /* HLT instruction */
|
||||
guest[byte++] = 0xf4; /* HLT instruction */
|
||||
guest[byte++] = 0xeb; /* JMP - endless loop to RIP */
|
||||
guest[byte++] = 0xfe; /* JMP of -2 byte (size of JMP inst) */
|
||||
guest[byte++] = 0xf4; /* HLT instruction */
|
||||
env.rm().detach(guest);
|
||||
|
||||
log ("let vCPUs run - first EP");
|
||||
@ -448,7 +468,16 @@ void Vmm::Vcpu::_handle_vcpu_exit()
|
||||
case Exit::AMD_HLT:
|
||||
log("vcpu ", _id, " : ", _exit_count, ". vm exit - "
|
||||
" halting vCPU - guest called HLT - ip=", Hex(state.ip.value()));
|
||||
|
||||
if (_hlt_count == 0) {
|
||||
uint32_t const tsc_aux_host = rdtscp();
|
||||
|
||||
log("vcpu ", _id, " : ", _exit_count, ". vm exit - rdtscp cx"
|
||||
" guest=", Hex(state.cx.value()), " host=", Hex(tsc_aux_host));
|
||||
}
|
||||
|
||||
_test_state = State::HALTED;
|
||||
_hlt_count ++;
|
||||
return;
|
||||
|
||||
case Exit::INTEL_EPT:
|
||||
|
Loading…
Reference in New Issue
Block a user