Ну, я не разбирал машинный код там, но вот версия с использованием встроенного ассемблера GCC:
int redpill()
{
unsigned char idt_addr[(sizeof(long)==8)?10:6];
__asm__("SIDT (%[ptr])"
: "=m" (idt_addr)
: [ptr] "r" (&idt_addr));
// examine high order byte
return idt_addr[(sizeof(long)==8)?9:5] > 0xd0;
}
Это должно 'работать' даже для 64-битных, но я там не проверял.
ОДНАКО!Это не гарантирует, что вы получите желаемый результат, на всех .Во-первых, он не будет работать с аппаратной виртуализацией, так как вы не видите истинную IDT.Во-вторых, он опирается на детали реализации VMWare и Virtual PC, которые, вероятно, могут быть изменены довольно легко.Это может даже вызвать ложную тревогу, если ваша ОС решит поставить свою IDT на высокий адрес.Поэтому я не рекомендую этот подход вообще.
Для виртуальных машин, использующих аппаратную поддержку VMX, вероятно, лучше всего было бы сделать что-то, что должно быть быстрым в оборудовании, но требует ловушки в виртуальной машине,и проверьте время.Что-то вроде CPUID
было бы хорошей ставкой;сравните его на виртуальной машине и на реальном оборудовании (по сравнению с фиктивным циклом, который выполняет ADD или что-то, что имеет дело с различными тактовыми частотами), и посмотрите, какой профиль тестируемой машины более точно соответствует.Поскольку каждый CPUID
должен будет выходить из виртуальной машины, чтобы спросить ядро хоста о том, какие возможности он хочет предоставить, потребуется гораздо больше времени, чем на реальном оборудовании.
Для других типов виртуальных машин вы могли бы сделатьаналогичная проверка синхронизации просто путем загрузки управляющего или отладочного регистра - виртуальной машине придется перехватить ее или заменить эмулированным кодом.Если вы работаете с чем-то вроде VMware, он может заменить ловушку некоторым эмулированным кодом - в этом случае вы сможете определить его по времени , изменив код, содержащий управляющий регистр или операцию регистра отладки.Это заставит виртуальную машину сделать недействительным свой кэшированный код, что потребует дорогой ловушки для виртуальной машины, которая будет отображаться в вашем тесте.
Обратите внимание, что оба эти подхода потребуют помощи от ядра ОС - это происходитбыть очень трудно определить, если вы находитесь в виртуальной машине, если у вас нет контроля над эмулируемым ядром по крайней мере.И если виртуальная машина действительно сложна, она может также подделать синхронизацию, в этот момент все становится действительно сложно - но это приводит к снижению производительности и приводит к смещению часов (легко определить, если вы можете подключиться к Интернету и запросить времягде-нибудь!), поэтому большинство коммерческих виртуальных машин этого не делают.