...

среда, 13 ноября 2013 г.

[Из песочницы] Теория и практика EFI Byte Code

В конце 90-х компания Number Nine Visual Technology, тогдашний светоч дизайна видеокарт, предлагала на сайте VGA BIOS для своих PCI-устройств. Ничего примечательного в этом событии нет. Разве что, видеокарты Number Nine могли работать как на IBM PC-совместимых платформах, так и в MAC-системах, использующих Power PC. Поэтому одно и то же устройство комплектовалось различными файлами BIOS.

Скорее всего, тогда и не могло быть иначе. Как сейчас дело обстоит с поддержкой устройств, рассчитанных на работу в разных аппаратных средах? Ответ на это вопрос дает спецификация UEFI, в рамках которой предлагается изящное решение – EFI Byte Code или EBC. С его помощью можно создавать кроссплатформенные приложения для firmware.


Как работает EBC




В рамках UEFI-стандарта определяется архитектура виртуальной машины регистрового типа EFI Byte Code Virtual Machine. Интерпретатор команд входит в состав firmware системной платы. Встроенное программное обеспечение плат расширения пишется в системе команд виртуальной машины, в идеале, без использования инструкций центрального процессора. Таким образом, плата расширения будет работоспособна на любой системной плате, поддерживающей EBC, независимо от типа центрального процессора. На сегодня их список не блещет разнообразием: как обычно, здесь есть AMD и Intel в 32-битном и 64-битном вариантах, Itanium, ARM.

Архитектура виртуального процессора EBC




64-разрядный виртуальный процессор EBC содержит 8 регистров общего назначения (R0-R7), поддерживает прямую, косвенную и непосредственную адресацию операндов. Система команд включает арифметические и логические операции, сдвиги, пересылки операндов с поддержкой знакового расширения, условную и безусловную передачу управления, вызовы подпрограмм и возвраты, а также ряд вспомогательных операций. Поддерживается стек, при этом указатель стека (регистр R0) согласно традициям архитектуры x86, классифицируется как регистр общего назначения. Примечательно, что специальная форма инструкции CALL, позволяет из EBC-подпрограмм вызывать подпрограммы, написанные на «родном» языке платформы, в силу того, что иногда такая необходимость все же возникает. Таким же образом из EBC-программ можно вызывать процедуры поддержки UEFI-протоколов, используя при этом модель передачи входных и выходных параметров, не зависящую от типа центрального процессора.

Приступаем к экспериментам




Предлагаемый пример «Hello, EBC!» является UEFI-приложением, написанным в системе команд виртуальной машины EBC (EFI Byte Code). Как уже сказано выше, интерпретатор команд EBC, позволяющий запускать модули данного типа, резидентно входит в состав UEFI firmware системной платы. Использование EBC вместо машинного кода позволяет создавать кроссплатформенные приложения и драйверы, включая firmware различных плат расширения, что делает данные устройства совместимыми с платформами, использующими центральные процессоры архитектуры, отличной от x86.

Пояснения к примеру




Программа выводит текстовое сообщение, используя процедуру вывода строки из набора функций EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL. Рассмотрим детальнее ее исходный код.

Для вызова данной EFI-функции в стеке необходимо передать два параметра: указатель на интерфейсный блок используемого протокола и указатель на строку, представленную в формате UNICODE. Эти параметры подготавливаются в регистрах R1 и R2, затем заносятся в стек инструкциями PUSHn, начиная с последнего параметра. Затем, в регистре R3 размещается адрес для вызова процедуры, прочитанный из интерфейсного блока используемого протокола и выполняется вызов целевой процедуры вывода строки. После возврата, освобождаем стек инструкциями POPn.


Системные таблицы и кроссплатформенность




Для вызова сервисных процедур UEFI-протоколов, приложения используют указатели, находящиеся в системных таблицах UEFI и различных интерфейсных блоках. В 32-битных реализациях UEFI используются указатели размером 4 байта, в 64-битных – размером 8 байт. Следовательно, адрес указателя внутри таблицы будет зависеть от разрядности центрального процессора. Как же обеспечивается кроссплатформенность?

Рассмотрим пример инструкции, передающей в регистр R1 содержимое ячейки памяти, адрес которой равен исходному значению регистра R1 плюс смещение.


MOVnw R1,@R1(+5,+24)


Смещение задано в виде двух слагаемых: +5 и +24.


Первое слагаемое +5 является номером адресуемого указателя. Интерпретатор команд EBC умножает это значение на размер указателя, который равен 4 для 32-битных реализаций UEFI и 8 для 64-битных.


Второе слагаемое +24 является константой, не зависящей от типа платформы. Оно используется для задания размера заголовка таблицы EFI_SYSTEM_TABLE.


Подобным образом работают инструкции PUSHn (Push Natural), используемые при подготовке стекового фрейма для вызываемых процедур. Разрядность параметров, записываемых в стек (32 или 64 бита) зависит от разрядности центрального процессора. Так обеспечивается шлюзование между EBC-кодом приложения и процедурами, входящими в состав UEFI-firmware написанными в системе команд центрального процессора.


Трансляция и запуск




Для трансляции программы и генерации EBC-приложения используется FASM 1.69.50. Инструкции виртуальной машины EFI Byte Code заданы в виде шестнадцатеричных констант. Руководствуясь исследовательским интересом, мы намеренно отказались от использования языков высокого уровня и написали наш пример на ассемблере EBC. При этом нам пришлось решить несколько задач, связанных с тем, что транслятор FASM не поддерживает EBC.

После трансляции, в заголовке файла helloebc.efi, по адресам 84h, 85h байты 64h, 86h необходимо заменить на BCh, 0Eh. Таким образом, поле Machine Type, исходно содержащее 8664h (x86-64 machine) заменяем на 0EBCh (EBC machine). Для запуска редактора, встроенного в UEFI Shell, в командной строке требуется набрать: hexedit helloebc.efi.


Коррекция поля Machine Type в заголовке приложения


Рис 1. Коррекция поля Machine Type в заголовке приложения


После этого можно запускать приложение.


Результат работы приложения


Рис 2. Результат работы приложения


Приложение также можно запустить под отладчиком Intel EBC Debugger.


Загрузка отладчика командой load и запуск EBC-приложения


Рис 3. Загрузка отладчика командой load и запуск EBC-приложения под отладчиком Intel EBC Debugger


Резюме




Работу тестового примера мы проверили в средах IA32 EFI и x64 UEFI. Теоретически, он должен работать на платформах с процессорами Itanium и ARM, но из-за недоступности указанных систем мы не смогли в этом убедиться.

Приложение транслируется в режиме PE64 (Portable Executable 64-bit). Некоторые устаревшие EFI-реализации (например, эмулятор Intel EFI Version 1.10.14.59 Sample Implementation , запускаемый с загрузочной дискеты) не совместимы с данным форматом приложения. Это выражается в некорректной интерпретации таблицы перемещаемых элементов, используемой при настройке модуля на адреса загрузки. Один из путей решения – выполнять настройку программно.


Так как транслятор FASM не поддерживает EFI Byte Code, для обеспечения эффективного программирования на уровне ассемблера EBC в среде FASM, нам предстоит сделать следующее:



  1. Написать небольшую сервисную утилиту для автоматизации перезаписи поля Machine Type в заголовке UEFI-приложения с пересчетом контрольной суммы модуля.

  2. Подготовить набор макросов для использования ассемблерных мнемоник EBC в среде FASM.


Источники информации




This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends:



Комментариев нет:

Отправить комментарий