Подтвердить что ты не робот

Загрузчик - переключение процессора в защищенный режим

У меня возникают трудности с пониманием того, как работает простой загрузчик. Загрузочный загрузчик, о котором я говорю, - это курс MIT "Операционные системы".

Во-первых, позвольте мне показать вам фрагмент кода сборки, который выполняет BIOS:

[f000:fec3]    0xffec3: lidtw  %cs:0x7908
[f000:fec9]    0xffec9: lgdtw  %cs:0x7948
[f000:fecf]    0xffecf: mov    %cr0,%eax
[f000:fed2]    0xffed2: or     $0x1,%eax
[f000:fed6]    0xffed6: mov    %eax,%cr0
[f000:fed9]    0xffed9: ljmpl  $0x8,$0xffee1

По внешнему виду, этот код устанавливает таблицу прерываний и таблицу дескрипторов, а затем включает защищенный режим.

  • Почему мы переходим в защищенный режим в BIOS? Не следует загрузчик запускается в реальном режиме (btw - почему он должен работать в реальном режим?)
  • Я искал, но не нашел нигде как именно команда ljmpl работает, и есть разница между это и ljmp и обычный jmp - I было бы признательно, если бы кто-то точки в правильном направлении.
  • Почему мы выполняем прыжок? Что цель этой инструкции?

Переход на код загрузчика -

# Switch from real to protected mode, using a bootstrap GDT
# and segment translation that makes virtual addresses
# identical to their physical addresses, so that the
# effective memory map does not change during the switch.
lgdt    gdtdesc
movl    %cr0, %eax
orl     $CR0_PE_ON, %eax
movl    %eax, %cr0

# Jump to next instruction, but in 32-bit code segment.
# Switches processor into 32-bit mode.
ljmp    $PROT_MODE_CSEG, $protcseg
  • В нем говорится, что процессор находится в реальный режим - но мы просто видели, что BIOS переключается в защищенный режим... Я в замешательстве - как это может быть возможно?
  • Как мы переключаемся на 32-битный режим? Какие заставляет процессор волноваться в 32-битный режим из-за ljmp инструкция?

И еще одна вещь, которую я не понимаю - когда я отслеживаю выполнение загрузчика с помощью gdb, я вижу, что выполняется следующая инструкция (что инструкция ljmp из кода загрузчика):

ljmp   $0x8,$0x7c32

Но когда я заглянул в файл .asm, я увидел следующее:

ljmp   $0xb866,$0x87c32

Полностью потерян здесь. Как получается, что команда, написанная в файле .asm, и исполняемая команда различны? У меня есть догадка, что это связано с защищенным режимом и тем, как он преобразует адреса, но я действительно не понимаю.

Буду признателен за любую помощь!

4b9b3361

Ответ 1

  • Некоторые версии BIOS переходят в защищенный режим перед входом в загрузчик. Большинство нет. Возможно, что BIOS переключится в защищенный режим на короткий период и переключится обратно, прежде чем перейти к загрузчику, что позволит ему использовать некоторые преимущества защищенного режима (например, 32-разрядный размер адреса по умолчанию). Причина, по которой загрузчик должен находиться в реальном режиме, состоит в том, что большинство функций BIOS работают только в реальном режиме, поэтому вы должны находиться в реальном режиме, чтобы использовать их.

  • ljmp указывает сегмент кода для переключения в дополнение к адресу для перехода. Они настолько похожи, что (по крайней мере, в GAS) ассемблер переключит jmp с 2 операндами на ljmp для вас.

  • ljmp - один из способов изменения регистра cs. Это необходимо сделать, чтобы активировать защищенный режим, так как регистр cs должен содержать селектор для сегмента кода в GDT. (В случае, если вы хотите знать, другие способы изменения cs - это дальний вызов, отдаленный возврат и возврат прерывания)

  • См. пункт 1. Либо BIOS переключился обратно в реальный режим, либо этот загрузчик не будет работать с этим BIOS.

  • См. пункт 3. Он изменяет cs для указания сегмента 32-битного кода, поэтому процессор переходит в режим 32 бит.

  • Когда вы смотрели файл .asm, инструкция интерпретировалась так, как если бы размер адреса составлял 32 бита, но GDB интерпретировал его так, как если бы размер адреса составлял 16 бит. Данные по адресу инструкции будут 0xEA 32 7C 08 00 66 B8. EA - код операции с длинным прыжком. В 32-битовом адресном пространстве адрес будет указан с использованием следующих четырех байтов для адреса 0x87C32, но в 16-разрядном адресном пространстве используется только 2 байта для адреса 0x7C32. 2 байта после адреса определяют запрошенный сегмент кода, который будет 0xB866 в 32-битном режиме и 0x0008 в 16-битном режиме. 0x66 B8 - это начало следующей команды, которая перемещает 16-битное мгновенное значение в регистр топора, возможно, для настройки сегментов данных для защищенного режима.

Ответ 2

Почему мы переходим в защищенный режим в BIOS? Не следует ли запускать загрузчик в реальном режиме (btw - зачем его нужно запускать в реальном режиме?)

Защищенный режим просто предлагает гораздо больше возможностей, чем в режиме реального времени: в основном механизм привилегий для защиты процессора Intel (http://en.wikipedia.org/wiki/Ring_(computer_security), 32-разрядный режим и т.д.

Я искал, но не нашел нигде точно, как работает инструкция ljmpl, и есть ли разница между ним и ljmp и регулярным jmp - я был бы признателен, если бы кто-то указал в правильном направлении.

ljmpl и ljmp здесь одно и то же контекстуально.

Почему мы выполняем прыжок? Какова цель этой инструкции?

Это необходимо, как указано в руководстве Intel, и документировано в соответствии с приведенным ниже кодом.

Для перехода с реальной защитой он реализован в загрузчике stage2 здесь:

http://src.illumos.org/source/xref/illumos-gate/usr/src/grub/grub-0.97/stage2/asm.S#real_to_prot

974   /* load the GDT register */
975   DATA32  ADDR32  lgdt    gdtdesc
976 
977   /* turn on protected mode */
978   movl    %cr0, %eax
979   orl $CR0_PE_ON, %eax
980   movl    %eax, %cr0
981 
982   /* jump to relocation, flush prefetch queue, and reload %cs */
983   DATA32  ljmp    $PROT_MODE_CSEG, $protcseg
984

Как можно видеть, каждая часть кода имеет функцию, а ljmp по существу для очистки очереди предварительной выборки, как это требуется в руководстве Intel, я не могу вспомнить где.