Почему точка входа в BIOS начинается с инструкции WBINVD? - PullRequest
0 голосов
/ 20 января 2019

Я изучаю код BIOS на моей машине (x86_64 Linux, IvyBridge).Я использую следующую процедуру для выгрузки кода BIOS:

$ sudo cat /proc/iomem | grep ROM
  000f0000-000fffff : System ROM
$ sudo dd if=/dev/mem of=bios.dump bs=1M count=1

Затем я использую radare2, чтобы прочитать и разобрать двоичный дамп:

$ r2 -b 16 bios.dump 
[0000:0000]> s 0xffff0
[f000:fff0]> pd 3
        :   f000:fff0      0f09           wbinvd
        `=< f000:fff2      e927f5         jmp 0xff51c
            f000:fff5      0000           add byte [bx + si], al

Я знаю, что инициализация процессора x86 всегда начинаетсяс 16-битной средой 8086, и первая команда, которая должна быть выполнена, находится в f000:fff0, то есть 0xffff0.Поэтому я иду в это место и разбираю код.

К моему удивлению, первая инструкция - WBINVD, чья функциональность заключается в аннулировании кэша, который, кажется, не имеет значения, когдапроцессор включен или сброшен.Я ожидал бы, что первая инструкция будет просто jmp с меньшим адресом памяти.

Почему существует WBINVD до jmp?

Я уже искал соответствующую часть руководств Intel, том 3, глава 9 «Управление процессорами и инициализация», но это не так »Не могу ничего сказать о WBINVD.Я также искал некоторые онлайн-ресурсы, но не нашел никакого объяснения.

Редактировать для получения дополнительной информации:

После выполнения инструкции jmp для 0xff51c код более интересен;он выполняет самопроверку:

[f000:f51c]> pd
            f000:f51c      dbe3           fninit
            f000:f51e      0f6ec0         movd mm0, eax
            f000:f521      6631c0         xor eax, eax
            f000:f524      8ec0           mov es, ax
            f000:f526      8cc8           mov ax, cs
            f000:f528      8ed8           mov ds, ax
            f000:f52a      b800f0         mov ax, 0xf000
            f000:f52d      8ec0           mov es, ax
            f000:f52f      6726a0f0ff00.  mov al, byte es:[0xfff0]     ; [0xfff0:1]=0
            f000:f536      3cea           cmp al, 0xea
        ,=< f000:f538      750f           jne 0xff549
        |   f000:f53a      b91b00         mov cx, 0x1b
        |   f000:f53d      0f32           rdmsr  ; check BSP (Boot Strap Processor) flag, if set, loop back to 0xffff0; otherwise, infinite hlt
        |   f000:f53f      f6c401         test ah, 1
       ,==< f000:f542      7441           je 0xff585
      ,===< f000:f544      eaf0ff00f0     ljmp 0xf000:0xfff0
      ||`-> f000:f549      b001           mov al, 1
      ||    f000:f54b      e680           out 0x80, al
      ||    f000:f54d      66be8cfdffff   mov esi, 0xfffffd8c          ; 4294966668
      ||    f000:f553      662e0f0114     lgdt cs:[si]
      ||    f000:f558      0f20c0         mov eax, cr0
      ||    f000:f55b      6683c803       or eax, 3
      ||    f000:f55f      0f22c0         mov cr0, eax
      ||    f000:f562      0f20e0         mov eax, cr4
      ||    f000:f565      660d00060000   or eax, 0x600
      ||    f000:f56b      0f22e0         mov cr4, eax
      ||    f000:f56e      b81800         mov ax, 0x18
      ||    f000:f571      8ed8           mov ds, ax
      ||    f000:f573      8ec0           mov es, ax
      ||    f000:f575      8ee0           mov fs, ax
      ||    f000:f577      8ee8           mov gs, ax
      ||    f000:f579      8ed0           mov ss, ax
      ||    f000:f57b      66be92fdffff   mov esi, 0xfffffd92          ; 4294966674
      ||    f000:f581      662eff2c       ljmp cs:[si]
      |`.-> f000:f585      fa             cli
      | :   f000:f586      f4             hlt
      | `=< f000:f587      ebfc           jmp 0xff585

Чтобы сделать вывод о странности, этот код BIOS читает себя в 0xffff0 и сравнивает байт с 0xea, который в точности является кодом операции для дальнего перехода:

            f000:f52a      b800f0         mov ax, 0xf000
            f000:f52d      8ec0           mov es, ax
            f000:f52f      6726a0f0ff00.  mov al, byte es:[0xfff0]     ; [0xfff0:1]=0
            f000:f536      3cea           cmp al, 0xea

Если он обнаружит, что код на 0xffff0 - это большой скачок, то он пойдет в бесконечный цикл.

Точнее, точки доступа (процессоры приложений) будут зацикливаться бесконечно.по команде hlt, в то время как BSP (загрузочный процессор) вернется к началу 0xffff0.Поскольку код в 0xffff0 не будет изменен, мы можем заключить, что BSP всегда найдет байт 0xea и никогда не выйдет из цикла.

Так какова цель этогопроверка?Я с трудом могу поверить, что это наивная попытка предотвратить модификацию.

1 Ответ

0 голосов
/ 20 января 2019

Хотя об этом трудно думать, помните, что загрузка mov al, byte es:[0xfff0] не считывает данные из первой инструкции BIOS, даже если es установлен на 0xf000.

Первая инструкция считывается из 0xfffffff0, при сбросе PCH, вероятно, будет также псевдоним 0xf0000-0xfffff - 0xffff0000-0xffffffff, поэтому при загрузке BSP он выполнит код, который вы сбросили.
IIRC, AP не загружаются, если явно не проснуться.

Затем BSP продолжит инициализацию HW (судя по дампу).
В какой-то момент он установит карту атрибутов для 0xf0000-0xfffff, чтобы управлять чтением и записью (или просто записывать изатем читает) в память.
Конечным результатом является то, что когда процессор (поток HW) загружается, он будет выполнять код с флэш-памяти, пока не выполнит дальний переход.
В этот момент база csправильно вычислено согласно правилам реального режима (почти как в нереальном режиме), и инструкция будет извлечена из 0xf0000-0xfffff (то есть из ОЗУ).
Все это, в то время как значение сегмента cs не былофактически изменится.

BSP в какой-то момент начнет свою процедуру инициализации мультипроцессора, где он передает каждому (включая себя) широковещательный INIT-SIPI-SIPI, который приведет к сну для AP и ljmp 0xf000:0xfff0для BSP.
Хитрость в том, что цель перехода, 0xf000:0xfff0, не совпадает с адресом шины инструкции wbinvd.
Может быть что-то ещездесь, вероятно, другая процедура инициализации.

В конце инициализации BIOS может просто сбросить атрибуты 0xf0000-0xfffff, чтобы провалиться на флэш-память (так что возможен сброс программного обеспечения), предотвращая (не намеренно)) дамп промежуточного кода.

Это не очень эффективно, но BIOS обычно не являются шедеврами кода.

У меня недостаточно элементов, чтобы быть уверенным в том, что происходит, я хочу сказать, что ljmp 0xf000:0xfff0 и mov al, byte es:[0xfff0] не должны читать из того же региона, в котором они находятся.
Имея это в виду, все ставки отключены.
Только правильный обратный инжиниринг скажет.

Что касается wbinvd, я предположил в комментарии, что это может быть связано ссредство для «горячей» загрузки, и Питер Кордес предположил, что это может иметь отношение к кэш-памяти как оперативной памяти.
Это имеет смысл, я думаю, никогда не будет уверен, хотя.где программист посчитал инструкцию необходимой на основе слухов.

...