Добрый день.
Вопрос к специалистам по поведению BIOS.
Есть у меня задача - запустить BIOS на QEMU. Выбрали старый гигабитовский AWARD. Добрался я до появления авардовской картинки (т.е. уже несколько модулей распаковали и отработали) и следующим этапом должно стать уже определение модели процессора и матплаты. И вот уперся я в такой момент:
BIOS работает, конфигурирует систему, после чего доходит до таких команд:
0x00000000000e00a0: movb $0x81,0x8b
0x00000000000e00a5: push %cs
0x00000000000e00a6: push $0xb1
Этот фрагмент кода уже даже исполнялся несколько раз и все было нормально. Но незадолго до этого были в очередной раз исправлены значения в регистрах PAM. И сейчас сегмент 0xe8000 -указывает в DMI, т.е. на оригинальный код BIOS. Попадаем в такой фрагмент:
0x00000000000e8000: in $0x45,%al
0x00000000000e8002: mov $0xc084,%bp
0x00000000000e8005: xorb $0xfa,0x5c5c(%bp)
0x00000000000e800a: dec %ax
0x00000000000e800b: int $0xa2
вектор прерывания 0xA2 в этот момент не определен, соответственно улетаем хз куда:
0x0000000000000000: push %ss
0x0000000000000001: call 0xf004
Ну, а дальше вечный цикл связанный с обработкой исключения "неизвестная команда".
Если посмотреть hex того что лежит в 0xe8000 становится понятно что это незапакованный ncpucode.bin. Т.е. нельзя сказать что обращение туда совсем уж не к месту в данный момент. Но, т.к. это микрокоды, то для исполнения на ЦП файлик ncpucode.bin скорее всего не предназначен, и попадание туда было неправильным. Тогда появляется вопрос - что именно должно было произойти.
Есть у меня подозрение что что-то я не доделал или не понял в механизме управления PAM-областями.
Учебник Салихана прочитан, но он в подробном разборе до этого места не добрался.
Вот и просьба к уважаемым знатокам - может кто-нибудь пояснить что влияет на ремаппинг областей при загрузке или потыкать носом туда, где это можно прочесть?
Ну или, вдруг, кто-нибудь уже подробно такой акробатикой занимался и может подсказать куда копать....
Если раньше код по адресу 0xe8000 исполнялся из RAM( распакованный original.tmp по адресам
0xE0000 - 0xFFFFF), то после изменения PAM по адресу 0xe8000(0xE000 : 0x8000) - содержимое
микросхемы BIOS(как Вы писали, там запакованный модуль). По моему изменение PAM
в данном случае недопустимо, тк приводит к бессмысленной передаче управления.
Довольно часто случается что диззасемблирование с неправильного адреса,
диззасемблирование данных как кода, диззасемблирование с неверным начальным
режимом описания сегмента(use16/use32) приводит к на первый взгдяд нормальным
командам. Но как правило рано или поздно попадаем на двоичные данные, которые
не могут быть диззасемблированы как команды или просто бессмысленым операциям.
С утра пытался написать, но трезвость мешала, счас тормозов поменьше, можно и догадок/полубреда написать.
Дизассемблирование здесь ни при чем - человек же в рантайме работает, как я понимаю.
IMHO - косячит QEMU.
Да, ситуация ПРИМЕРНО где-то рядом - по 0xE8000 неожиданно "мусор"/"не то". НО
Оно допустимо. На реальной системе. Ибо это BIOS, на реальной системе класса P2 типа работающий (как минимум теоретически, как я понимаю). Т.е. недопустимых с точки зрения реальной системы вещей в нем быть не может. Так?
Вообще-то я бы порыл те же исходники SeaBios (штатный для QEMU) и, в частности, запрос Гуглу
"SeaBIOS 0xe8000 qemu" (это не рецепт, это "на подумать").
А кому счас легко...
P.S.
На мой первый взгляд - это ненормальные команды. Начиная с первой. Да и автор уже это понял/озвучил (что это не код).
А кому счас легко...
P.P.S. Ну, что за "старый гигабитовский AWARD" - мы без понятия. У QEMU вроде как 440FX чипсетом.
И вообще - задачи такого плана (Legacy AWARD в QEMU) уж лет 5 как кажутся мне просто тренировкой мозга.
А кому счас легко...
To Savely
Я возможно неправильно выразился - под недопустимостью я понимал не
невозможность изменения PAM и последующей передачи управления, а то что
автор писал, что он изменял PAM самостоятельно, что вполне может сломать
нормально работающий код.
То есть код BIOS уже не-оригинальный и может не работать. Изменения PAM нарушили
нормальную(задуманную разработчиками) работу кода BIOS, что и привело к
бессмысленным командам.
Я никогда не пользовался QEMU, а дизассемблирование упомянул тк при передаче
управления в произвольную(какую-попало) точку происходит примерно то-же самое,
что при дизассемблировании с произвольной точки кода(если там вообще код, а не
данные). Только в качестве дизассемблера выступает сам CPU:)
В нашем случае QEMU эмулирует СPU, но сути дела это не меняет.
И вопрос к автору - для чего Вы собственно изменяли PAM?
Для этого вносились временные измененя в код BIOS?
Ну, я лично фразу автора понял как "незадолго до этого оригинальный(!) код BIOS был замечен в изменении PAM".
А кому счас легко...
OK просто фраза автора "были в очередной раз исправлены значения"
у меня вызвала ассоциацию с ручным вмешательством.
Если так, тогда абсолютно согласен,что как Вы писали виноват QEMU, тк не
работать этот код код не может, на своей плате то он работает.
В соответствии со спецификацией чипсета (какого?) под который написан Gigabyte
BIOS(какой платы?), я бы посмотрел правильно ли интерпретирует QEMU значения в
регистрах PAM, может быть просто баг в эмуляторе(или эмулируемый чипсет не
соответствует настоящему, под который код BIOS написан).
Благодарю за ответы.
Попробую ответить на возникшие вопросы:
В соответствии с тегами в качестве подопытного был выбран Award BIOS от платы Q35M-S2 . Версия F7. Чипсет - Q35 (в официальной ветке QEMU уже года 2-3 в качестве альтернативы 440-му). Собственно решение задачи запуска реального BIOS на QEMU сводится именно к дописыванию в QEMU недостающей функциональности. В частности в QEMU был неполностью реализован механизм PAM. Из-за этого BIOS зависал сильно раньше. После самодельного исправления - появился определенный прогресс. Очередной затык случился на описанном выше месте. Так как никаких изменений в BIOS не вносилось, то не работать сам по себе он не может, но, зато, QEMU может некорректно имитировать реальную систему, что тут, очевидно, и произошло. Также, все значения которые есть в ОЗУ и в регистрах являются следствием работы QEMU и BIOS, вручную никакие области памяти не менялись.
Переходы в 0xe8000 случались и раньше, но конфигурация PAM была другой, обрабатывался код из ОЗУ. Сейчас исполняется код из флешки и есть мысль что тут что-то не так, как надо. Очередная идея - автор BIOS рассчитывал на те инструкции, которые попали в кэш (в самом QEMU кэш как сущность не очень заметен). Но, во-первых: как это проверить, во-вторых: странным выглядит рассчет на то, что некие данные должны быть в кэше (а если их нет, а если было прерывание и т.д....).
Гугление по адресу 0xe8000, как и по ioport 0xA2 ничего не принесло -не удалось найти упоминаний о том, что это какие-либо особенные значения.
QEMU сейчас вполне корректно интерпретирует значения записанные в PAM и перенаправление в PCI вполне законно с точки зрения логики работы PAM регистров. Но есть подозрение что на маппинг может влиять что-то еще. Что именно - пока не знаю. Думал в сторону MTRR регистров проца, но там задается только политика кэширования, конкретно ремаппингом эти регистры не занимаются.
Что-то подобное может-быть возможно было бы сделать используя SMM, на это уже атака
(грязный прием, противоречащий Intel рекомендациям по написанию BIOS), не думаю что в
нормальном коде BIOS будет что-то подобное.
co-c.net/repository-securite-informatique/Papers/smm_cache_fun.pdf
Вы писали что по 0xe8000 ncpucode.bin(запакованный) и соответственно переход заведомо
неверный, анализировать получившиеся "команды" нет смысла.
Вы проанализировали значения PAM регистров, точно соответствует режиму чтения flash?
Если да, то может быть ошибка возникла где-то ранее, что привело к ошибочномуи вызову
процедуры программирования PAM или на упомянутую последовательнось команд,
делающую переход на 0xe8000.
Есть вариант добавить в BIOS отладочный код и исследовать на реальной системе.
Заменяем команду в интересующем месте на near jmp на неиспользуемое место,
(в том же сегменте), где размещаем отладочный код:
ту команду(ы) которые(ми) пришлось заменить вышеупомянутым jmp(то есть
восстанавливаем команды BIOS запорченные jmp) + код выводящий в port 0x80.
Не забываем сохранить и восстановить все регистры использованные кодом вывода
значений в диагностический port!
По окончании отладочного кода jmp обратно. Относительные смещения внутрисегментных
переходов придется рассчитывать. Очень удобно использовать IDA для этого, и легко
убедится, что все адреса переходов рассчитаны верно.
Какую часть кода обходить и продублировать в отладочном коде и что выводить -
зависит от фантазии и конкретной ситуации. Хорошо если POST card имеет дополнительный
индикатор, например для port 0x81, туда можно выводить например дополнительные
значения(Вы отмечали что участок кода с переходм на 0xe8000 исполняется неоднократно).
Можно добавить код чтения PCI PAM reg, по аналогии с основной процедурой, имеющейся
в BIOS и выводить значения в port 0x81).
Можно сделать задержку в отладочном коде, чтобы успеть заметить показания.
Очень полезно иметь POST card, запоминающую историю POST, с целью дальнейшего
анализа. Или можно попробовать снять video и потом в замедленном режиме просматривать.
Можно вообще сделать останов в нужном месте, но после этого придется восстанавливать
BIOS(на Gigabyte Dual-BIOS особо надеяться не стоит).
Я делал подобное при исследовании BIOS платы P3B-F. С современными Award возможны
трудности с внесением изменнений. Здесь немогу подсказать, тк не интересуюсь
современными платформами вообще. Конечно этот способ трудоемок и легко можно
запортить BIOS, но я все же решил написать об этом.
За ссылку спасибо - посмотрю.
Значения в PAM расшифрованы корректно. Ошибочный переход, приеведший к их перезаписи - не уверен, но все бывает, тоже путь для исследования, спасибо.
Отправить комментарий