Предел сегмента GDT Bochs смещается влево в 3 раза в шестнадцатеричном формате и добавляется 0xFFF. Это нормально? - PullRequest
1 голос
/ 03 мая 2019

Я сейчас настраиваю GDT для моего загрузчика.У меня есть 3 (4) сегмента:

  • (нулевой сегмент)
  • Сегмент кода ядра 4 ГБ
  • Сегмент данных ядра 4 ГБ
  • 2 ГБ стека данныхраздел (я забыл установить 1 бит в 0, когда я сделал скриншоты. Позже это будет 1 МБ)

Вот мой код для настройки GDT:

  7 ; GDT null segment
  8 gdt_null:
  9     dq 0x00
 10 
 11 ; GDT code segment (4GB)
 12 gdt_code:
 13     dw 0xFFFF
 14     dw 0x00
 15     db 0x00
 16     db 10011010b
 17     db 11001111b
 18     db 0x00
 19 
 20 ; GDT data segment (4GB)
 21 gdt_data:
 22     dw 0xFFFF
 23     dw 0x00
 24     db 0x00
 25     db 10010010b
 26     db 11001111b
 27     db 0x00                                                                                          
 28 
 29 ; Extra segmet for stack
 30 ; Preventing bufferoverflows from stack could write into other data
 31 ; Size is 1M (0x100 * 4kb) startting from base 7e00 (512 bytes after 7c00)
 32 gdt_stack:
 33     dw 0x0100
 34     dw 0x7e00
 35     db 0x00
 36     db 10010010b
 37     db 11001000b
 38     db 0x00

Но когда я загружаю двоичный файл в bochs, он дает мне следующий результат: GDT Image

Байты, загруженные в точности так, как я определил их в памяти: Memory Image

Здесь я понял, что добавлено 0xFFFкаждый раз в сегмент.Это потому, что я использовал 4kb как гранулярность?

Когда я выберу 0xFF в качестве размера с гранулярностью 4kb, это будет увеличено до 0xFFFFF, поэтому я могу сделать только сегмент размером 1 Мб - 1 байт?

1 Ответ

2 голосов
/ 03 мая 2019

Да, это потому, что вы используете гранулярность 4 КБ в записи GDT. Из Руководства разработчика архитектур Intel® 64 и IA-32: Vol. 3A относительно 5.3 Проверка пределов :

Когда флаг G сброшен (гранулярность байта), эффективным пределом является значение 20-битного поля предела в сегменте дескриптор. Здесь предел находится в диапазоне от 0 до FFFFFH (1 МБайт). Когда установлен флаг G (гранулярность страницы 4 КБ), процессор масштабирует значение в поле предела в 2 ^ 12 (4 КБ) . В этом случае диапазон эффективных пределов от FFFH (4 КБ) до FFFFFFFFH (4 ГБ). Обратите внимание, что при использовании масштабирования (установлен флаг G) младшие 12 битов смещение сегмента (адрес) не проверяется по пределу; например, обратите внимание, что если предел сегмента равен 0, смещения от 0 до FFFH все еще действительны.

Из Руководство разработчика по архитектуре Intel® 64 и IA-32: Vol. 2A инструкция LSL содержит описание используемого механизма и описывает поведение, которое вы видите в BOCHS:

Предел сегмента - это 20-битное значение, содержащееся в байтах 0 и 1 и в первых 4 битах байта 6 сегмента. дескриптор. Если дескриптор имеет ограничение байтового сегмента сегмента (флаг гранулярности установлен в 0), назначение операнд загружается с байтовым гранулярным значением (байтовый предел). Если дескриптор имеет предел сегментированного сегмента страницы ( флаг гранулярности установлен в 1), инструкция LSL преобразует гранулярный предел страницы (ограничение страницы) в байтовый предел перед загрузкой в ​​операнд назначения. Перевод выполняется смещением 20-битного «сырого» предела влево. 12 биты и заполнение младших 12 бит 1с.

Вы задали вопрос Когда я выберу 0xFF, поскольку размер с гранулярностью 4 КБ будет увеличен до 0xFFFFF, поэтому я могу сделать только сегмент размером 1 Мб - 1 байт? . При детализации страницы предел сегмента 0xFF сдвигается на 12 бит влево, давая 0xFF000, а младшие 12 битов устанавливаются на 1. Результатом является фактическое ограничение в 0xFFFFF байтов. Этот предел позволяет адресовать 1 МБ памяти, что составляет от 0 до 0xFFFFF (включительно) от указанной базы. Если вы хотите, чтобы сегмент имел определенный размер в байтах (от 0x00000 до 0xFFFFF), вы можете использовать гранулярность байтов. Можно иметь дескрипторы, определенные с разной степенью детализации.

...