Автор: MRatnikov , 22 мая 2015
Добрый день.

Вопрос к специалистам по поведению BIOS. :-)
Есть у меня задача - запустить BIOS на QEMU. Выбрали старый гигабитовский AWARD. Добрался я до появления авардовской картинки (т.е. уже несколько модулей распаковали и отработали) и следующим этапом должно стать уже определение модели процессора и матплаты. И вот уперся я в такой момент:
BIOS работает, конфигурирует систему, после чего доходит до таких команд:
0x00000000000e00a0: movb $0x81,0x8b
0x00000000000e00a5: push %cs
0x00000000000e00a6: push $0xb1
0x00000000000e00a9: push $0x2e8c
0x00000000000e00ac: ljmp $0xe000,$0x8000

Этот фрагмент кода уже даже исполнялся несколько раз и все было нормально. Но незадолго до этого были в очередной раз исправлены значения в регистрах 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-областями.
Учебник Салихана прочитан, но он в подробном разборе до этого места не добрался.
Вот и просьба к уважаемым знатокам - может кто-нибудь пояснить что влияет на ремаппинг областей при загрузке или потыкать носом туда, где это можно прочесть?
Ну или, вдруг, кто-нибудь уже подробно такой акробатикой занимался и может подсказать куда копать....
Содержимое данного поля является приватным и не предназначено для показа.

BBCode

  • HTML-теги не обрабатываются и показываются как обычный текст
  • You may use the following BBCode tags:
    • [align]
    • [b]
    • [code]
    • [color]
    • [font]
    • [hr]
    • [i]
    • [img]
    • [list]
    • [quote]
    • [s]
    • [size]
    • [spoiler]
    • [sub]
    • [sup]
    • [table]
    • [u]
    • [url]
  • Адреса веб-страниц и email-адреса преобразовываются в ссылки автоматически.

i8088

10 лет 10 месяцев назад


Этот фрагмент кода уже даже исполнялся несколько раз и все было нормально. Но незадолго до этого были в очередной раз исправлены значения в регистрах PAM. И сейчас сегмент 0xe8000 -указывает в DMI, т.е. на оригинальный код BIOS.


Если раньше код по адресу 0xe8000 исполнялся из RAM( распакованный original.tmp по адресам
0xE0000 - 0xFFFFF), то после изменения PAM по адресу 0xe8000(0xE000 : 0x8000) - содержимое
микросхемы BIOS(как Вы писали, там запакованный модуль). По моему изменение PAM
в данном случае недопустимо, тк приводит к бессмысленной передаче управления.

Довольно часто случается что диззасемблирование с неправильного адреса,
диззасемблирование данных как кода, диззасемблирование с неверным начальным
режимом описания сегмента(use16/use32) приводит к на первый взгдяд нормальным
командам. Но как правило рано или поздно попадаем на двоичные данные, которые
не могут быть диззасемблированы как команды или просто бессмысленым операциям.

savely

10 лет 10 месяцев назад

С утра пытался написать, но трезвость мешала, счас тормозов поменьше, можно и догадок/полубреда написать.

Дизассемблирование здесь ни при чем - человек же в рантайме работает, как я понимаю.
IMHO - косячит QEMU.

Если раньше код по адресу 0xe8000 исполнялся из RAM( распакованный original.tmp по адресам
0xE0000 - 0xFFFFF), то после изменения PAM по адресу 0xe8000(0xE000 : 0x8000) - содержимое
микросхемы BIOS(как Вы писали, там запакованный модуль).

Да, ситуация ПРИМЕРНО где-то рядом - по 0xE8000 неожиданно "мусор"/"не то". НО

По моему изменение PAM в данном случае недопустимо, тк приводит к бессмысленной передаче управления.

Оно допустимо. На реальной системе. Ибо это BIOS, на реальной системе класса P2 типа работающий (как минимум теоретически, как я понимаю). Т.е. недопустимых с точки зрения реальной системы вещей в нем быть не может. Так?

Вообще-то я бы порыл те же исходники SeaBios (штатный для QEMU) и, в частности, запрос Гуглу
"SeaBIOS 0xe8000 qemu" (это не рецепт, это "на подумать").

savely

10 лет 10 месяцев назад

P.S.
приводит к на первый взгдяд нормальным командам


0x00000000000e8000: in $0x45,%al
0x00000000000e8002: mov $0xc084,%bp
0x00000000000e8005: xorb $0xfa,0x5c5c(%bp)
0x00000000000e800a: dec %ax
0x00000000000e800b: int $0xa2


На мой первый взгляд - это ненормальные команды. Начиная с первой. Да и автор уже это понял/озвучил (что это не код).

savely

10 лет 10 месяцев назад

P.P.S. Ну, что за "старый гигабитовский AWARD" - мы без понятия. У QEMU вроде как 440FX чипсетом.

И вообще - задачи такого плана (Legacy AWARD в QEMU) уж лет 5 как кажутся мне просто тренировкой мозга.

i8088

10 лет 10 месяцев назад

To Savely
Я возможно неправильно выразился - под недопустимостью я понимал не
невозможность изменения PAM и последующей передачи управления, а то что
автор писал, что он изменял PAM самостоятельно, что вполне может сломать
нормально работающий код.

Этот фрагмент кода уже даже исполнялся несколько раз и все было нормально. Но незадолго до этого были в очередной раз исправлены значения в регистрах PAM.

То есть код BIOS уже не-оригинальный и может не работать. Изменения PAM нарушили
нормальную(задуманную разработчиками) работу кода BIOS, что и привело к
бессмысленным командам.

Я никогда не пользовался QEMU, а дизассемблирование упомянул тк при передаче
управления в произвольную(какую-попало) точку происходит примерно то-же самое,
что при дизассемблировании с произвольной точки кода(если там вообще код, а не
данные). Только в качестве дизассемблера выступает сам CPU:)
В нашем случае QEMU эмулирует СPU, но сути дела это не меняет.

И вопрос к автору - для чего Вы собственно изменяли PAM?
Для этого вносились временные измененя в код BIOS?

savely

10 лет 10 месяцев назад

То есть код BIOS уже не-оригинальный и может не работать. Изменения PAM нарушили
нормальную(задуманную разработчиками) работу кода BIOS, что и привело к
бессмысленным командам.


Ну, я лично фразу автора понял как "незадолго до этого оригинальный(!) код BIOS был замечен в изменении PAM".

i8088

10 лет 10 месяцев назад

OK просто фраза автора "были в очередной раз исправлены значения"
у меня вызвала ассоциацию с ручным вмешательством.

Если так, тогда абсолютно согласен,что как Вы писали виноват QEMU, тк не
работать этот код код не может, на своей плате то он работает.

В соответствии со спецификацией чипсета (какого?) под который написан Gigabyte
BIOS(какой платы?), я бы посмотрел правильно ли интерпретирует QEMU значения в
регистрах PAM, может быть просто баг в эмуляторе(или эмулируемый чипсет не
соответствует настоящему, под который код BIOS написан).

MRatnikov

10 лет 10 месяцев назад

Благодарю за ответы.
Попробую ответить на возникшие вопросы:
В соответствии с тегами в качестве подопытного был выбран 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 регистров проца, но там задается только политика кэширования, конкретно ремаппингом эти регистры не занимаются.

i8088

10 лет 10 месяцев назад


Сейчас исполняется код из флешки и есть мысль что тут что-то не так, как надо. Очередная идея - автор BIOS рассчитывал на те инструкции, которые попали в кэш (в самом QEMU кэш как сущность не очень заметен).

Что-то подобное может-быть возможно было бы сделать используя SMM, на это уже атака
(грязный прием, противоречащий Intel рекомендациям по написанию BIOS), не думаю что в
нормальном коде BIOS будет что-то подобное.
http://www.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, но я все же решил написать об этом.

MRatnikov

10 лет 10 месяцев назад

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