Как сделать скриншот в биосе uefi

Обновлено: 07.07.2024

125 килобайт. Естественно, в таком виде на страницу в web его лучше не выкладывать. Желательно сначала переконвертировать BMP-файл в формат PNG при помощи подручных средств (ACDSee, например). Объем полученного в итоге файла RES.PNG в очень редком случае превысит 10..15 килобайт ! И это скриншот всего экрана, не говоря уж об избранных частях картинки.
Примеры: Сравните сами размеры файлов и четкость картинки.

<13764 bytes>











Надеюсь, надобность в дальнейшей рекламе отпала.
Но не все так радужно.
1) Было замечено, что на некоторых платах (обычно производства ASUS) со встроенным видео скриншот может не сохраняться.
2) Некоторые биосы (например, на моей EPoX 8KHA+) перед входом в сетап биоса не передают управление биосам PCI-карточек. В итоге, скриншот на материнках с такими биосами описанным способом сделать невозможно.
Теоретически этот недуг можно побороть, модифицировав биос видеокарты. Заодно появится возможность делать скриншот на этапе определения процессора и тестирования памяти. Но в ближайшее время я этим заниматься не собираюсь.
3) На супер экзотических биосах, работающих в нестандартные видеорежимах, использующих свою собственную палитру и рисующих в других видеостраницах, представленный мною способ работать не будет -- необходима доработка. Правда, таких биосов я пока что еще не встречал.
4) Будьте внимательны ! Покуда в вашем компьютере будет стоять карточка с прошитым псевдобиосом (текущей версией), всегда будет существовать опасность порчи дискеты при случайном нажатии клавиши < PrintScreen>. Причем, как в сетапе биоса, так и в досовском режиме. Даже под виндой для ДОС-окон, если для этих окон разрешина отработка нажатия на < PrintScreen> !
В будущем во избежание порчи дискет, надо бы предварительно записывать на дискету сигнатурку, и проверять ее наличие перед записью скриншота: если ее нет, то на дискету записано ничего не будет. Но это все [опять] когда-нибудь потом.
5) Теоретически, как я уже упоминал, существует возможность интегрировать нужный код под видом ISA/PCI Expansion ROM в биос материнки. Благо для биосов некоторых производителей существуют спец.утилиты: CBROM для AWARD и AMIBCP для AMI. Но я этот способ не испытывал, да и обзорщикам он вряд ли пригодится, т.к. они обозревают обычно самые современные платы, а с ними упомянутые утилиты не всегда безошибочно работают. Да и денег у обзорщиков должно хватать на PCI-карточку с флэшкой на борту.
Можно, опять же теоретически, делать скриншоты сетапов биосов сказевых адаптеров. Но на практике мне такой возможности не предоставлялось. Возможно, предварительно придется поперетыкать PCI-карточки по слотам, чтобы добиться нужной последовательности запуска их набортных биосов.
---
Если еще какие косяки потом вспомню -- обязательно допишу.

ToDo: (что надо бы сделать, но что никогда не сделаю по причине своей природной лени )
1) записывать не один, а несколько скриншотов на дискету;
2) интегрировать программный код в биос контроллера, а не заменять полностью биос этим самым программным кодом; в принципе, я это уже делал, когда возился с антистарфорсовским биосом для SiI0680 -- нужно лишь слегка доработать и написать тулзу для автоматической модификации биосов (в том числе VGA, в том числе объемом больше 64Кб);
3) ввести защиту от записи на произвольные дискеты (об этом уже писал выше);
4) создать вариант кода для нестандартных биосов (нестандартный видеорежим, палитра, страница, прочее);
5) [высший пилотаж - я на это не способен ]: записывать скриншоты на диски прямо в формате BMP (мечты, мечты. ). Объем кода резко возрастет, но зато не понадобится никаких дополнительных утилит (сомительное преимущество).

Вот, пожалуй, и все, что я хотел сообщить сегодня.
Если есть какие-то вопросы, предложения, замечания, то просьба высказывать их в соответствующей ветке форума.

Вадим Карпов
Псков
( 13-06-2006)

[14-06-2006] Небольшое дополнение:
Чтобы не получить картинку с такой вот шапкой



запомните один совет: после смены дискеты для нормального сохранения скриншота желательно нажать клавишу < PrintScreen> не один, а два раза! Можно и больше, но не нужно.

[22-06-2006] Небольшое дополнение:
Как говорится, в семье производителей материнских плат не без ASUS'а.
Вот такой вот "замечательный" скрин получается на материнках этого производителя со встроенным видео:


(ASUS P5P800-MX)

Одна из мамок без встроенного видео (AMI биос):


(ASUS P5GD1 Pro rev. 105)

От себя порекомендую нашему брату-экспериментатору лишний раз с платами этого производителя не связываться. Иначе рискуете наступить на заботливо разложенные данным брэндом фирменные грабельки.

  1. Откомпилировать в TurboAssembler'е.
  2. В полученном .COM файле выдрать весь код (512 bytes начиная с сигнатуры "55h AAh").
  3. Подсчитать контрольную сумму и внести ее в кусок, полученный в п.2 (можно закинуть в последний байт).
  4. Дополнить полученный кусок нулями, увеличив таким образом его размер до размера флэшки.
  5. Залить полученный в п.4 бинарник во флэшку PCI-контроллера (если флэшер позволит).

<PAS> - папка, содержащая исходники утилит для считывания сохраненного образа экрана с дискеты и перевода его в графический файл формата BMP.
Компилировалось в Turbo Pascal'е.
Можно попробовать запихнуть все это хозяйство в один файл ради удобства.
И попутно "портировать" все это под Delphi/VirtualPascal,
но возможно придется немного повозиться с процедурой чтения сектора с дискеты.
-=-
(C) xKVtor ;)


В прошлой статье про SecureBoot мне очень не хватало возможности сделать снимок экрана при настройке UEFI через BIOS Setup, но тогда выручило перенаправление текстовой консоли в последовательный порт. Это отличное решение, но доступно оно на немногих серверных материнских платах, и через него можно получить только псевдографику, а хотелось бы получить настоящую — она и выглядит приятнее, и вырезать ее каждый раз из окна терминала не надо.
Вот именно этим мы и займемся в этой статье, а заодно я расскажу, что такое DXE-драйвер и как написать, собрать и протестировать такой самостоятельно, как работают ввод с клавиатуры и вывод на экран в UEFI, как найти среди подключенных устройств хранения такое, на которое можно записывать файлы, как сохранить что-нибудь в файл из UEFI и как адаптировать какой-то внешний код на С для работы в составе прошивки.
Если вам все еще интересно — жду вас под катом.

Отказ от ответственности

Прежде чем говорить о написании и отладке драйверов для UEFI, стоит сразу же сказать, что эксперименты с прошивкой — дело опасное, они могут привести к «кирпичу», а в самых неудачных редких случаях — к выходу из строя аппаратуры, поэтому я заранее предупреждаю: всё, что вы тут прочитаете, вы используете на свой страх и риск, я не несу и не буду нести ответственность за потерю работоспособности вашей прошивки или платы. Прежде чем начинать любые эксперименты с прошивкой, необходимо сделать полную копию всего содержимого SPI flash при помощи программатора. Только так вы можете гарантировать успешное восстановление прошивки после любого программного сбоя.
Если у вас нет программатора, но попробовать написать и отладить DXE -драйвер очень хочется, используйте для этого OVMF, VmWare Workstation 12 или любые другие системы виртуализации с поддержкой UEFI на ваш выбор.

Что там нужно и почему это DXE-драйвер

Задача наша состоит в том, чтобы снять скриншот со всего экрана во время работы какого-то UEFI-приложения, например BIOS Setup, нажатием определенной комбинации клавиш, найти файловую систему с доступом на запись и сохранить полученный скриншот на нее. Также было бы неплохо получить какую-то индикацию статуса. Т.к. для снятия скриншота потребуется прерывать работу UEFI-приложений, сама программа по их снятию приложением быть не может, ведь никакой вытесняющей многозадачности в UEFI пока еще не предусмотрено, поэтому нам нужен DXE-драйвер.
Схема его работы планируется примерно следующая:
0. Загружаемся только после появления текстового ввода (чтобы обрабатывать нажатия комбинации клавиш) и графического вывода (чтобы было с чего снимать скриншоты).
1. Вешаем обработчик нажатия комбинации LCtrl + LAlt + F12 (или любой другой на ваш вкус) на все доступные входные текстовые консоли.
2. В обработчике находим все выходные графические консоли, делаем с них скриншот и перекодируем его в формат PNG (т.к. UEFI-приложения обычно не используют миллионы цветов, то в этом формате скриншоты получаются размером в десятки килобайт вместо нескольких мегабайт в BMP).
3. В том же обработчике находим первую попавшуюся ФС с возможностью записи в корень и сохраняем туда полученные файлы.
Можно расширить функциональность выбором не первой попавшейся ФС, а, к примеру, только USB-устройств или только разделов ESP , оставим это на самостоятельную работу читателю.

Выбираем SDK

Для написания нового кода для работы в UEFI имеются два различных SDK — более новый EDK2 от UEFI Forum и GNU-EFI от независимых разработчиков, основанный на старом коде Intel. Оба решения подразумевают, что вы будете писать код на C и/или ассемблере, в нашем случае постараемся обойтись чистым C.
Не мне судить, какой SDK лучше, но я предлагаю использовать EDK2, т.к. он официальный и кроссплатформенный, и новые фичи (вместе с исправлением старых багов) появляются в нем значительно быстрее благодаря близости к источнику изменений, плюс именно его используют все известные мне IBV для написания своего кода.
EDK2 находится в процессе постоянной разработки, и в его trunk стабильно добавляют по 2-3 коммита в день, но так как мы здесь за самыми последними веяниями не гонимся (все равно они еще ни у кого не работают), поэтому будем использовать последний на данный момент стабильный срез EDK2, который называется UDK2015.
Чтобы обеспечить кроссплатформенность и возможность сборки различными компиляторами, EDK2 генерирует make-файлы для каждой платформы, используя конфигурационные файлы TXT (конфигурация окружения), DEC, DSC и FDF (конфигурация пакета) и INF (конфигурация компонента), подробнее о них я расскажу по ходу повествования, а сейчас нужно достать EDK2 и собрать HelloWorld, чем и займемся, если же вам не терпится узнать подробности прямо сейчас — проследуйте в документацию.

Настраиваем сборочное окружение

Структура проекта


Приложения и драйверы в EDK2 собираются не отдельно, а в составе т.н Package, т.е. пакета. В пакет, кроме самих приложений, входят еще и библиотеки, наборы заголовочных файлов и файлы с описанием конфигурации пакета и его содержимого. Сделано это для того, чтобы позволить различным драйверам и приложениям использовать различные реализации библиотек, иметь доступ к различным заголовочным файлам и GUID'ам. Мы будем использовать MdeModulePkg, это очень общий пакет без каких-либо зависимостей от архитектуры и железа, и если наш драйвер удастся собрать в нем, он почти гарантированно будет работать на любых реализациях UEFI 2.1 и более новых. Минусом такого подхода является то, что большая часть библиотек в нем (к примеру, DebugLib, используемая для получения отладочного вывода) — просто заглушки, и их придется писать самому, если возникнет такая необходимость.
Для сборки нашего драйвера понадобится INF-файл с информацией о том, какие именно библиотеки, протоколы и файлы ему нужны для сборки, а также добавление пути до этого INF-файла в DSC-файл пакета, чтобы сборочная система вообще знала, что такой INF-файл есть.
Начнем с конца: открываем файл UDK2015/MdeModulePkg/MdeModulePkg.dsc и пролистываем его до раздела [Components] (можно найти его поиском — это быстрее). В разделе перечислены по порядку все файлы, принадлежащие пакету, выглядит начало раздела вот так:Добавляем туда свой будущий INF-файл вместе с путем до него относительно UDK2015. Предлагаю создать для него прямо в MdeModulePkg папку CrScreenshotDxe, а сам INF-файл назвать CrScreenshotDxe.inf. Как вы уже догадались, Cr — это от «CodeRush», а автор этой статьи — сама скромность. В результате получится что-то такое:Сохраняем изменения и закрываем DSC-файл, больше мы его менять не будем, если не захотим настроить отладочный вывод, но это уже совсем другая история.
Теперь нужно заполнить сам INF-файл:
Осталось создать упомянутый выше файл CrScreenshotDxe.с:

Если теперь повторить команду build, она должна быть успешной, иначе вы что-то сделали неправильно.
Вот теперь у нас, наконец, есть заготовка для нашего драйвера, и можно перейти непосредственно к написанию кода. Совершенно ясно, что такая сборочная система никуда не годится, и работать с ней через редактирование текстовых файлов не очень приятно, поэтому каждый из IBV имеет собственное решение по интеграции сборочной системы EDK2 в какую-нибудь современную IDE, к примеру среда AMI Visual eBIOS — это такой обвешенный плагинами Eclipse, а Phoenix и Insyde обвешивают ими же Visual Studio.
Есть еще замечательный проект VisualUefi за авторством известного специалиста по компьютерной безопасности Алекса Ионеску, и если вы тоже любите Visual Studio — предлагаю попробовать его, а мы пока продолжим угарать по хардкору, поддерживать дух старой школы и всё такое.

Реагируем на нажатие комбинации клавиш


Здесь все достаточно просто: при загрузке драйвера переберем все экземпляры протокола SimpleTextInputEx, который публикуется драйвером клавиатуры и чаще всего ровно один, даже в случае, когда к системе подключено несколько клавиатур — буфер то общий, если специально что-то не менять. Тем не менее, на всякий случай переберем все доступные экземпляры, вызвав у каждого функцию RegisterKeyNotify, которая в качестве параметра принимает комбинацию клавиш, на которую мы намерены реагировать, и указатель на callback-функцию, которая будет вызвана после нажатия нужно комбинации, а в ней уже и будет проведена вся основная работа.

Для успешной компиляции пока не хватает функций TakeScreenshot и ShowStatus, о которых ниже.

Ищем ФС с доступом на запись, пишем данные в файл


Прежде, чем искать доступные графические консоли и снимать с них скриншоты, нужно выяснить, можно ли эти самые скриншоты куда-то сохранить. Для этого нужно найти все экземпляры протокола SimpleFileSystem, который публикуется драйвером PartitionDxe для каждого обнаруженного тома, ФС которого известна прошивке. Чаще всего единственные известные ФС — семейство FAT12/16/32 (иногда только FAT32), которые по стандарту UEFI могут использоваться для ESP. Дальше нужно проверить, что на найденную ФС возможна запись, сделать это можно разными способами, самый простой — попытаться создать на ней файл и открыть его на чтение и запись, если получилось — на эту ФС можно писать. Решение, конечно, не самое оптимальное, но работающее, правильную реализацию предлагаю читателям в качестве упражнения.

Этому коду больше ничего не нужно, работает как есть.

Ищем графическую консоль и делаем снимок её экрана


Проверив, что сохранять скриншоты есть на что, займемся их снятием. Для этого понадобится перебрать все экземпляры протокола GOP, который публикуют GOP-драйверы и VideoBIOS'ы (точнее, не сам VBIOS, который ничего не знает ни про какие протоколы, а драйвер ConSplitter, реализующий прослойку между старыми VBIOS и UEFI) для каждого устройства вывода с графикой. У этого протокола есть функция Blt для копирования изображения из фреймбуффера и в него, пока нам понадобится только первое. При помощи объекта Mode того же протокола можно получить текущее разрешение экрана, которое нужно для выделения буффера нужного размера и снятия скриншота со всего экрана, а не с какой-то его части. Получив скриншот, стоит проверить что он не абсолютно черный, ибо сохранять такие — лишняя трата времени и места на ФС, черный прямоугольник нужного размера можно и в Paint нарисовать. Затем нужно преобразовать картинку из BGR (в котором её отдает Blt) в RGB (который нужен энкодеру PNG) иначе цвета на скриншотах будут неправильные. Кодируем полученную после конвертации картинку и сохраняем её в файл на той ФС, которую мы нашли на предыдущем шаге. Имя файла в формате 8.3 соберем из текущей даты и времени, так меньше шанс, что один скриншот перепишет другой.

Для работы не хватает lodepng_encode32 и уже упоминавшейся выше ShowStatus, продолжим.

Кодируем изображение в формат PNG

Выводим статус


Осталось написать функцию ShowStatus и наш драйвер готов. Получать этот самый статус можно разными способами, например, выводить числа от 0x00 до 0xFF в CPU IO-порт 80h, который подключен к POST-кодеру, но есть он далеко не у всех, а на ноутбуках — вообще не встречается. Можно пищать спикером, но это, во-первых, платформо-зависимо, а во-вторых — дико бесит уже после пары скриншотов. Можно мигать лампочками на клавиатуре, это дополнительное задание для читателя, а мы будем показывать статус работы с графической консолью прямо через эту графическую консоль — отображая маленький квадрат нужного цвета в левом верхнем углу экрана. При этом белый квадрат будет означать «драйвер успешно загружен», желтый — «ФС с возможностью записи не найдена», синий — «Скриншот текущей консоли полностью черный, сохранять нет смысла», красный — «произошла ошибка» и, наконец, зеленый — «скриншот снят и сохранен». Выводить это квадрат нужно на все консоли, а после короткого времени восстанавливать тот кусочек изображения, который им был затерт.

Вот теперь все готово и успешно собирается, если нет — пилите, пока не соберется, либо скачайте мой готовый драйвер с GitHub и сравните с вашим, может быть я какие-то изменения банально забыл описать.

Тестируем результат в UEFI Shell



Этот скриншот, как и все последующие, снят нашим драйвером, поэтому квадрата в углу на нем не видно.

Вообще-то никак, и на этом статью уже можно заканчивать. Штатных возможностей, применимых к любой материнской плате любого производителя, не существует. Очевидно считается, что рядовому пользователю такое баловство просто ни к чему. У него хватает и других забот. Однако выход найти можно: есть как минимум несколько путей решения этой проблемы.

Во-первых, можно сделать скриншот с BIOS виртуальной машины. Правда, этот вариант годится исключительно для иллюстративно-обучающих целей. Реальная ценность подобного скриншота невелика – особенно, если у вас возникла проблема, с которой вы хотите обратиться в техподдержку. Но большинство скриншотов, встречаемых в Интернете, делаются именно таким образом. На счастье, «виртуальный» BIOS может отличаться от реального весьма незначительно. Но прежде, чем рассчитывать на полную тождественность, лучше все-таки проверить. Иначе не исключена неприятная и глупая ситуация.

Виртуальный BIOS мало чем отличается от реального

Второй вариант более экзотичен, но в ряде случаев достоин внимания. Значительная часть материнских плат серверного класса оснащена IPMI (Intelligent Platform Management Interface) – интерфейсом для удаленного мониторинга и управления физическим состоянием сервера. Соответственно, при посредничестве IPMI можно делать не только скриншоты, но и записывать видео.

Для бытового использования этот вариант подходит мало – разве что вы содержите дома сервер или являетесь счастливым обладателем материнской платы, предназначенной для рабочих станций (последний вариант, впрочем, не гарантирует наличия соответствующего интерфейса). У IPMI, стоит отметить, существует масса собратьев, среди которых в первую очередь на память приходят IP-KVM, iLo, iDRAC. У некоторых производителей IPMI доступен в качестве отдельного модуля. Который обычно стоит как-то уж совсем нескромно.

IPMI или BIOS-на-вынос

Вариант третий менее экзотичен, но более трудозатратен. Теоретически можно попытаться перехватить и записать сигнал с видеовыхода материнской платы. Для этого требуется внешний видеорекордер. Шансов на то, что такой вариант сработает, честно говоря, не много, но в случае необходимости можно попробовать. Столь же теоретически можно попытаться обойтись двумя ПК и одним HDMI-сплиттером. Но опять же, ответственность за успех подобной операции на себя не возьмет никто. Однако по Интернету упорно ходят слухи об успешности подобных операций.

Безвестный HDMI-сплиттер китайского производства

Вариант четвертый с каждым годом становится все более доступным. Современные материнские платы, как правило, оснащаются UEFI BIOS, где, если вам повезет, будет присутствовать возможность сделать тот самый вожделенный скриншот. Все, что для этого требуется, – какой-либо USB-носитель, отформатированный в файловую систему FAT32. У многих производителей добраться до этой функции можно нажав клавишу F12. В прочем, этот момент лучше уточнить в руководстве пользователя, прилагаемом к большинству материнских плат.

Вариант пятый – самый простой, очевидный и незатейливый. Можно просто сфотографировать экран монитора. В этом нет ничего постыдного – даже многие интернет-издания, занимающиеся обзорами «железа», поступают именно так.

Слухи про универсальность UEFI сильно преувеличены! В этом может убедиться каж­дый, кто захочет сделать скриншот Setup-меню, зайдя в настройки современного BIOS. Причин для сохранения образа экрана тысячи: от элементарного любопытства и по­пыт­ки запомнить начальные установки системы до подготовки графических объектов для интернет-публикаций.

Как сделать скриншот в UEFI?

Итак, исходная позиция такова, что в общем случае снимок экрана не обеспечивается функциональностью интерфейса. В некоторых случаях, которые правильно считать частными, PrintScreen выполняется по клавише F12, но это, по большей части, заслуга кастомизаторов. Как быть разработчика программного обеспечения под UEFI, которые и могут при благоприятном стечении обстоятельств оказаться этими самыми ка­сто­ми­за­то­ра­ми?

Вариант 1. Низкоуровневое программирование

Задача сохранить содержимое экрана в bitmap-файл успешно решена и на языке ассемблера. Рассмотрим процедуру Save_Screen_to_BMP, исходный код которой доступен в файле LIB_SBMP.INC. Ее вызов выполняется из тела утилиты UEFIMark и не требует подготовки специальных параметров. Сама же процедура формирования скриншота заботится о достоверности контекста, сохраняя и восстанавливая содержимое регистров центрального процессора.

Для кодирования цветов экрана используется 24 бита, по 8 бит на каждый цвет: Red, Green, Blue. Полученный файл сохраняется на носителе с исполняемым модулем. Процедура самостоятельно заботится о генерировании имен BMP-файлов в виде PICTxxxx.BMP, где цифровая часть xxxx формируется с автоинкрементом.

К особенностям предлагаемого примера реализации относится вывод в диагностической порт контрольных точек вызова процедуры Save_Screen_to_BMP, и ее завершения. По умолчанию вывод осуществляется в 80-й порт персональной платформы, но этот выбор может быть кастомизирован по желанию программиста. Начало формирования скриншота отмечается появлением кода 0xF4, а завершение — кода 0xF7 в диагностическом порту. Для трассировки и отладки программного обеспечения рекомендуется использовать диагностическую POST-карту IC80 v5.0.

Вариант 2. Высокоуровневое программирование

В некоторых случаях полезной может быть рекомендация Курта Цзяо (Kurt Qiao), изложенная им в своем блоге:

  • Сохраняем данные из видеопамяти в рабочий массив, где они их можно обрабатывать как растровую информацию;
  • Создаем заголовок и корректируем информацию согласно спецификации на bit-map изображения для формирования bmp-файла.

Для 24-битного изображения, например, заголовок BMP-файла будет состоять из 54 байт (включая 14 байт собственно заголовка и 40 байт описания растровой информации), Google формат 24bit файл BMP на себя, чтобы получить больше информации.

Для осуществления задуманного можно воспользоваться EFI_GRAPHICS_OUTPUT_PROTOCOL, используя метод blt() с параметром BltOperation равным 'EfiBltVideoToBltBuffer'.

Типичное решение в данном случае будет выглядеть так:

typedef
EFI_STATUS
(EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_BLT) (
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
IN UINTN SourceX,
IN UINTN SourceY,
IN UINTN DestinationX,
IN UINTN DestinationY,
IN UINTN Width,
IN UINTN Height,
IN UINTN Delta OPTIONAL
);

Читайте также: