Разделы

Новое

Беседы про BIOS и UEFI

Утилиты

Реклама

Обзоры компьютерных гаджетов, которые должны быть всегда под рукой

Новости

23.11.2016

Инициативы компании Apple по отказу от классических ...

  • Все новости (32)
  • Спонсоры



        Яндекс.Метрика
    Главная » Статьи » EFI Byte Code: первые шаги

    EFI Byte Code: первые шаги

    В недавно опубликованной статье «Теория и практика EFI Byte Code» мы рассмотрели технологию EBC, получившую развитие в рамках стандарта UEFI. Универсальные драйверы и приложения, написанные на языке виртуальной машины EBC, могут выполняться на широком спектре платформ, не совместимых между собой (IA32, x64, Itanium, ARM), причем, без перекомпиляции.

    Постановка задачи

    Сегодня мы рассмотрим пример информационной утилиты под кодовым названием uefiinfo, визуализирующей следующие параметры платформы:

    1. Версия спецификации UEFI.
    2. Версия firmware.
    3. Текстовая строка, идентифицирующая производителя firmware.
    4. Версия интерпретатора EFI Byte Code Virtual Machine.
    5. Наличие Compatibility Support Module.

    Казалось бы, задачи простые и их решения очевидны. Но не торопитесь с выводами: наше приложение полностью написано в системе команд EFI Byte Code.

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

    Ассемблирование программы и генерация EBC-приложения выполняется с помощью FASM 1.69.50. В исходных текстах используются длинные имена файлов, поэтому, трансляция в среде DOS не предусмотрена. Для ассемблирования инструкций виртуальной машины EBC нам потребовалось создать набор макросов. Решение об использовании длинных имен было продиктовано желанием обеспечить соответствие имен файлов макроопределений для каждой EBC-инструкции мнемонике данной инструкции.

    После трансляции, в заголовке файла UEFI-приложения, необходимо выполнить патч. А именно, заменить значение поля Machine Type, исходно содержащее 8664h (x86-64 machine) на 0EBCh (EBC machine). Эту операцию автоматически выполняет утилита EBCPATCH.EXE.

    Для последовательного запуска программ FASM.EXE и EBCPATCH.EXE предусмотрен файл ASM.BAT. Утилита EBCPATCH.EXE находится в рабочем каталоге. Путь для запуска FASM.EXE потребуется отредактировать в соответствии с конфигурацией.

    Пояснения к исходному тексту программы

    Трансляция утилиты UEFIInfo
    Рис 1. Трансляция утилиты UEFIInfo

    Результат работы программы UEFIInfo в эмуляторе IA32 EFI
    Рис 2. Результат работы программы UEFIInfo в эмуляторе IA32 EFI

    Проанализируем выполнение программы по ее исходному тексту. Основной модуль — AsmUefiInfo.asm. Дополнительные каталоги:

    AsmMacroEbc: содержит файлы макросов для ассемблирования EBC-инструкций.

    AsmLibrary: библиотека подпрограмм общего назначения.

    AsmHandlers: библиотека подпрограмм получения системной информации.

    AsmData: содержит текстовые строки, декларацию переменных и констант.

    Краткое описание действий программы:

    1. Сохранение параметров, передаваемых родительской задачей при запуске приложения: базовый адрес корневой таблицы (EFI System Table) и номер, присвоенный данному приложению (Handle).
    2. Выдача текстовых строк информации о программе и разработчике. Для вывода на экран используется Simple Text Output Protocol.
    3. Получение параметров UEFI specification revision, Firmware revision, Firmware vendor с использованием таблицы EFI System Table.
    4. Получение номера версии интерпретатора EBC с использованием EBC-инструкции системного вызова BREAK 1.
    5. Детектирование наличия модуля Compatibility Support Module (CSM). Для этого детектируется Legacy BIOS Protocol посредством функции Locate Protocol с использованием идентификатора GUID .
    6. Визуализация параметров, полученных на шагах 3-5.
    7. Ожидание нажатия клавиши. Для опроса клавиатуры используется Simple Text Input Protocol.
    8. Возврат в родительскую задачу, в качестве которой может выступать UEFI Shell или UEFI firmware.

    Выравнивание стека: как это делается для EBC

    Согласно спецификации UEFI, при вызове сервисных процедур обслуживания UEFI-протоколов, стек должен быть выровнен на 16 байт (значение указателя стека должно быть кратно 16). Это позволяет процедурам UEFI firmware использовать более производительные SSE-инструкции при доступе к параметрам в стеке. Например, команды MOVAPS и MOVUPS выполняют одну и ту же операцию – пересылку 128-битного операнда, но инструкция MOVAPS ориентирована на частный случай (адрес кратен 16) и может выполняться быстрее. Для IA32 требование выравнивания относится к 32-битному указателю стека ESP, для x64 оно относится к 64-битному указателю стека RSP. Виртуальная машина EBC в качестве указателя стека использует регистр R0. К нему также предъявляется требование выравнивания. Уточним, значение регистра R0 должно быть кратно 16 после записи в стек входных параметров вызываемой процедуры.

    Заметим, что EBC-инструкция вызова подпрограммы CALL при записи адреса возврата в стек, резервирует 16-байтный блок (регистр R0 уменьшается на 16). Если бы, в соответствии с разрядностью адреса, резервировался 8-байтный блок, инструкция CALL приводила бы к нарушению выравнивания при нечетной степени вложения подпрограмм и необходимости его восстановления.

    Спецификация UEFI устанавливает требование выравнивания стека для всех вызываемых UEFI-протоколов. Реальные прецеденты «зависания» из-за нарушения этого требования были отмечены на ряде платформ, при вызове сервисных функций Graphics Output Protocol и Simple Text Output Protocol в случае работы с выключенным режимом совместимости (в CMOS Setup опция Compatibility Support Module в состоянии Disabled). Это может показаться смешным, но наличие таких «зависаний» можно рассматривать как плюс исследуемой платформе, ведь оно указывает на использование процедурами firmware производительных SSE-инструкций.

    Конфликты мнемоник: проблема и решение

    В идеале, для устранения зависимости от архитектуры центрального процессора, кросс-платформенное EBC-приложение не должно содержать процедур в машинных кодах. Наш пример соответствует этому требованию, но при разработке более сложных приложений оно не всегда выполнимо. Поэтому, в системе команд виртуальной машины EBC предусмотрены специальные инструкции (Call External) для вызова подпрограмм в машинных кодах, передача управления на которые возможна после распознавания типа процессора. Проблема в том, что ряд инструкций, например команда возврата из подпрограммы RET имеют совпадающие мнемоники в ассемблерах EBC и x86. Для разрешения конфликта, при программировании с помощью нашего набора макроопределений, инструкции EBC записываются заглавным шрифтом, инструкции процессора – обычным. Например:

    Запись RET означает EBC-инструкцию RET и генерирует 16-битное слово 0004h. Запись ret означает x86-инструкцию RET и генерирует байт с одним из двух значений в зависимости от типа подпрограммы: 0C3h (внутрисегментный возврат) или 0CBh (межсегментный возврат).

    Резюме

    Очевидно, современным трендом в разработке firmware является использование языков высокого уровня. Но в силу природной склонности к садомазохизму необходимости непосредственного взаимодействия с программно-аппаратными ресурсами платформы и их глубокого исследования, мы реализовали наш пример на ассемблере.

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



    28.07.2017