§ Описание GDT
Прежде, чем процессор перейдёт в защищённый режим, должна быть определена глобальная дескрипторная таблица GDT (Global Descriptor Table), так как все сегменты и прочие системные объекты должны быть описаны в дескрипторной таблице.Глобальная дескрипторная таблица GDT - это область памяти, в которой находятся дескрипторы. Процессору всё равно, где именно вы расположили эту таблицу, но в любом случает она будет находится в первом мегабайте адресного пространства, потому что только из режима реальных адресов можно перевести процессор в защищённый режим. Также подразумевается, что сама таблица GDT будет выравнена на границу 8 байт, так как дескрипторы, из которых она состоит, имеют 8-байтный размер. Такое выравнивание позволит процессору максимально быстро обращаться к дескрипторам, что, естественно, увеличивает производительность.
Число дескрипторов, определённых в GDT, может быть любым, от 0 до 8192. Нулевой дескриптор, т.е. определённый в самом начале GDT, процессор не использует, обращение к такому дескриптору могло бы быть, когда поле Index селектора равно 0. Если всё же в программе встречается обращение к нулевому дескриптору, то процессор генерирует исключение и не позволит доступ к такому дескриптору. В связи с этим, везде в литературе рекомендуется использовать нулевой дескриптор как шаблон, на основе которого программа может создавать новые дескрипторы, но на практике их удобнее создавать иными способами, о которых мы ещё будем говорить.
GDT используется процессором всё время, пока он находится в защищённом режиме. Параметры GDT хранятся в специальном 48-разрядном регистре GDTR:
47 | 16 | 15 | 0 |
---|---|---|---|
Адрес GDT | Предел |
0..15: 16-разрядный предел GDT 15..47: 32-разрядный адрес начала GDTАдрес начала GDT - это тот адрес, по которому вы разместили GDT.
Предел таблицы GDT - это максимальное смещение относительно её начала.
Например, вы создаёте GDT, состоящую из 3-х дескрипторов - для сегментов кода, стека и данных. Общее число дескрипторов будет равно четырём, потому что первым по счёту будет идти нулевой дескриптор, а за ним уже остальные три:
Смещение от начала GDT | Назначение дескриптора |
0 | Нулевой |
8 | Сегмент кода |
16 | Сегмент стека |
24 | Сегмент данных |
Для загрузки значения в регистр GDTR используется команда LGDT. Операндом этой команды является 48-разрядное значение адреса в памяти, где размещается адрес и предел GDT. Вы также можете сохранить содержимое GDTR командой SGDT, указав в операнде адрес 48-разрядной переменной в памяти.
Далее приводится пример подготовки параметров GDT и их загрузки в регистр GDTR.
§ Подготовка параметров GDT и их загрузка в регистр GDTR.
- Вычисляем 32-разрядный адрес GDT
- Вычисляем размер GDT
- Сохраняем параметры GDT в 48-разрядную переменную
- Загружаем значение в регистр GDTR
1; 1. Вычисляем 32-разрядный адрес GDT 2 3 xor eax, eax ; EAX = 0 адрес будем вычислять в регистре EAX 4 mov ax, cs ; Подразумевается, что GDT находится в текущем сегменте данных 5 shl eax, 4 ; EAX = адрес начала сегмента DS 6 xor edx, edx ; EDX = 0 7 lea dx, [GDT] ; EDX = DX = смещение начала GDT относительно DS 8 add eax, edx ; EAX = полный физический адрес GDT в памяти 9 10; 2. Вычисляем размер GDT 11 12 mov cx, 4 ; CX = число дескрипторов + нулевой дескриптор 13 shl cx, 3 ; CX = CX * 8 - столько байт будут занимать в GDT эти дескрипторы 14 dec cx ; Предел меньше размера на 1 15 16; 3. Сохраняем параметры GDT в 48-разрядную переменную 17 18 mov [GDT_address], eax 19 mov [GDT_limit], cx 20 21; 4. Загружаем значение в регистр GDTR 22 23 lgdt [GDT_params] 24 25; -------------------------------------------------- 26 27GDT_params: 28 29 GDT_limit dw ? 30 GDT_address dd ? 31 32GDT: 33 dq ? ; 0-й дескриптор 34 dq ? ; 1-й дескриптор (код) 35 dq ? ; 2-й дескриптор (стек) 36 dq ? ; 3-й дескриптор (данные)Остаётся добавить, что размер GDT желательно не менять в процессе выполнения программ в защищённом режиме. Если ваша программа будет динамически создавать новые дескрипторы, то размер GDT лучше всего заранее задать достаточно большим, например, 64 Кб (максимальный размер). Однако, следует учитывать, что при обращении процессора к несуществующим дескрипторам, его поведение непредсказуемо, хотя оно, скорее всего, закончится зависанием.