Загрузчик - переключение процессора в защищенный режим
У меня возникают трудности с пониманием того, как работает простой загрузчик. Загрузочный загрузчик, о котором я говорю, - это курс 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, и исполняемая команда различны? У меня есть догадка, что это связано с защищенным режимом и тем, как он преобразует адреса, но я действительно не понимаю.
Буду признателен за любую помощь!
Ответы
Ответ 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, я не могу вспомнить где.