Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Лучше всего познавать язык на реальном проекте, поэтому, когда я решил поэкспериментировать с адой, я поставил себе реальную и интересную задачу: написать утилиту для детекта работы в гипервизоре. Это само по себе занятно, а новый язык программирования позволит вывести развлечение на новый уровень.
Нередко бывает, что в теории язык или его конкретная реализация выглядит хорошо, но попытки использовать его на практике упираются в труднопреодолимые препятствия: сложность взаимодействия с другими языками или распространения исполняемых файлов.
Когда я впервые познакомился с адой, мне стало интересно попробовать ее в реальности, но мне была нужна подходящая задача — достаточно небольшая, чтобы цена провала оказалась невелика, но и достаточно сложная, чтобы выявить как можно больше потенциальных проблем.
Про сборку программ на аде было рассказано в моей предыдущей статье, но если пропустил — не страшно, ничего сложного в этом нет. Нужно поставить GNAT — он входит в состав GCC и всегда есть в репозиториях, — сохранить код в файл something.adb
и выполнить gnatmake something.adb
.
Желательно, чтобы на месте something
в имени файла было имя основной процедуры, иначе компилятор выдаст предупреждение. Исполняемый файл gnatmake
автоматически назовет по имени файла с кодом, а не a.out
.
По ряду причин я решил написать утилиты для определения гипервизора, в котором работает виртуальная машина. В VyOS мы включаем эту информацию в вывод команды show version
. Для получения самой информации исторически использовалась самописная утилита на довольно грязном C, которая не поддерживала некоторые менее популярные гипервизоры, и у меня давно было желание ее чем-нибудь заменить.
Существующие решения, такие как virt-what, вызывают у меня смешанные чувства. Смесь C и скриптовых языков, на мой взгляд, выглядит неэстетично. Эстетика — вещь субъективная, но есть и объективные проблемы, например поддержка только GNU/Linux и отказ работать без прав суперпользователя.
Мне хотелось, чтобы замена старому коду принесла пользу не только мне и пользователям VyOS, поэтому я поставил следующие требования:
Задача мне показалась вполне подходящей для тестирования нового языка. В случае провала я всегда мог бы переписать код на Rust или взять одну из существующих утилит. Эксперимент завершился, на мой взгляд, успешно, результат был назван hvinfo и уже давно используется в VyOS. Исходный код можно найти по адресу github.com/dmbaturin.
В этой статье мы рассмотрим проект изнутри и познакомимся с возможностями языка ада и инструментами GNAT, которые потребовались для его разработки.
Как, собственно, определить, работает ли система в виртуальной машине, и если да, то на каком гипервизоре? На платформе x86 все системы виртуализации с этой точки зрения можно поделить на две группы: одни поддерживают общий стандарт de facto — передачу информации через вызов инструкции cpuid
, другие не поддерживают.
cpuid
К первой группе относятся Xen в режиме аппаратной виртуализации, KVM, bhyve, VMware и Hyper-V. Я не уверен, кто из них ввел этот механизм первым, но работает он у всех одинаково.
Инструкция cpuid
была впервые реализована компанией Intel и с тех пор присутствует во всех процессорах x86. Стоит отметить, что для совместимости она использует 32-разрядные регистры даже в 64-разрядном режиме. Вид возвращаемой информации зависит от значения в регистре eax
.
Гипервизоры из первой группы перехватывают вызовы cpuid
и обладают дополнительными возможностями. Для передачи информации о самом факте работы ОС в виртуальной машине применяется разряд 31-го регистра ecx
. На физических машинах он всегда установлен на ноль согласно документации Intel, а гипервизоры устанавливают его на единицу.
Получить название гипервизора можно, вызвав cpuid
со значением 0x40000000
в регистре eax
. Название передается в виде строки длиной до двенадцати символов в регистрах ebx
, ecx
и edx
. К примеру, Xen использует строку XenVMMXenVMM
, а VMware — VMwareVMware
.
Использование инструкций процессора дает нам отличную возможность увидеть работу с ассемблерными вставками, двоичную арифметику и условную компиляцию.
Некоторые гипервизоры не используют сложившийся интерфейс cpuid
, несмотря на полную виртуализацию, например VirtualBox в режиме двоичной трансляции. Паравиртуальный Xen просто не может его использовать.
В этих случаях приходится применять другие способы, такие как проверка названия производителя из SMBIOS или наличия специфичных устройств PCI, вроде видеокарты innotek Gmbh в VirtualBox.
Эти способы, в отличие от cpuid
, не так универсальны, и на разных ОС их придется реализовать по-разному. Чтобы это сделать, нам придется использовать интерфейс с libc и работу с файлами.
Ада проектировалась как язык системного программирования, а какое системное программирование совсем без машинного кода? Все возможности для этого присутствуют.
Прежде всего нам потребуются беззнаковые целочисленные типы. Пакет Interfaces предоставляет все распространенные типы, включая нужный нам для работы с 32-разрядными регистрами Unsigned_32
.
Источник: xakep.ru