Фантазии о Вселенной и мой личный сайт
Глобальная дескрипторная таблица

Глобальная дескрипторная таблица

Прежде, чем процессор перейдёт в защищённый режим, должна быть определена глобальная дескрипторная таблица GDT (Global Descriptor Table), так как все сегменты и прочие системные объекты должны быть описаны в дескрипторной таблице.

Глобальная дескрипторная таблица GDT - это область памяти, в которой находятся дескрипторы. Процессору всё равно, где именно вы расположили эту таблицу, но в любом случает она будет находится в первом мегабайте адресного пространства, потому что только из режима реальных адресов можно перевести процессор в защищённый режим. Также подразумевается, что сама таблица GDT будет выравнена на границу 8 байт, так как дескрипторы, из которых она состоит, имеют 8-байтный размер. Такое выравнивание позволит процессору максимально быстро обращаться к дескрипторам, что, естественно, увеличивает производительность.

Число дескрипторов, определённых в GDT, может быть любым, от 0 до 8192. Нулевой дескриптор, т.е. определённый в самом начале GDT, процессор не использует, обращение к такому дескриптору могло бы быть, когда поле Index селектора равно 0. Если всё же в программе встречается обращение к нулевому дескриптору, то процессор генерирует исключение и не позволит доступ к такому дескриптору. В связи с этим, везде в литературе рекомендуется использовать нулевой дескриптор как шаблон, на основе которого программа может создавать новые дескрипторы, но на практике их удобнее создавать иными способами, о которых мы ещё будем говорить.

GDT используется процессором всё время, пока он находится в защищённом режиме. Параметры GDT хранятся в специальном 48-разрядном регистре GDTR:


4716150
Адрес GDTПределGDTR

Формат регистра GDTR следующий:

 0..15: 16-разрядный предел GDT
15..47: 32-разрядный адрес начала GDT

Адрес начала GDT - это тот адрес, по которому вы разместили GDT.

Предел таблицы GDT - это максимальное смещение относительно её начала.

Например, вы создаёте GDT, состоящую из 3-х дескрипторов - для сегментов кода, стека и данных. Общее число дескрипторов будет равно четырём, потому что первым по счёту будет идти нулевой дескриптор, а за ним уже остальные три:


Смещение от начала GDT Назначение дескриптора
0 Нулевой
8 Сегмент кода
16 Сегмент стека
24 Сегмент данных

Размер GDT в данном случае будет равен 32 байтам, следовательно, предельное смещение в таблице будет равно 31 - это и есть предел GDT.

Для загрузки значения в регистр GDTR используется команда LGDT. Операндом этой команды является 48-разрядное значение адреса в памяти, где размещается адрес и предел GDT. Вы также можете сохранить содержимое GDTR командой SGDT, указав в операнде адрес 48-разрядной переменной в памяти.

Далее приводится пример подготовки параметров GDT и их загрузки в регистр GDTR.


Подготовка параметров GDT и их загрузка в регистр GDTR.

  1. Вычисляем 32-разрядный адрес GDT
  2. Вычисляем размер GDT
  3. Сохраняем параметры GDT в 48-разрядную переменную
  4. Загружаем значение в регистр GDTR
; 1. Вычисляем 32-разрядный адрес GDT

    xor    eax, eax     ; EAX = 0 адрес будем вычислять в регистре EAX
    mov    ax, cs       ; Подразумевается, что GDT находится в текущем сегменте данных
    shl    eax, 4       ; EAX = адрес начала сегмента DS
    xor    edx, edx     ; EDX = 0
    lea    dx, [GDT]    ; EDX = DX = смещение начала GDT относительно DS
    add    eax, edx     ; EAX = полный физический адрес GDT в памяти

; 2. Вычисляем размер GDT

    mov    cx, 4        ; CX = число дескрипторов + нулевой дескриптор
    shl    cx, 3        ; CX = CX * 8 - столько байт будут занимать в GDT эти дескрипторы
    dec    cx           ; Предел меньше размера на 1

; 3. Сохраняем параметры GDT в 48-разрядную переменную

    mov    [GDT_address], eax
    mov    [GDT_limit], cx

; 4. Загружаем значение в регистр GDTR

    lgdt    [GDT_params]

; --------------------------------------------------

GDT_params:

    GDT_limit    dw    ?
    GDT_address  dd    ?

GDT:
    dq    ?     ; 0-й дескриптор
    dq    ?     ; 1-й дескриптор (код)
    dq    ?     ; 2-й дескриптор (стек)
    dq    ?     ; 3-й дескриптор (данные)

Остаётся добавить, что размер GDT желательно не менять в процессе выполнения программ в защищённом режиме. Если ваша программа будет динамически создавать новые дескрипторы, то размер GDT лучше всего заранее задать достаточно большим, например, 64 Кб (максимальный размер). Однако, следует учитывать, что при обращении процессора к несуществующим дескрипторам, его поведение непредсказуемо, хотя оно, скорее всего, закончится зависанием.