Базовые средства программирования защищенного режима
Сегмент данных data начинается с описания важнейшей системной структуры – таблицы глобальных дескрипторов. Как уже отмечалось выше, обращение к сегментам в защищенном режиме возможно исключительно через дескрипторы этих сегментов. Таким образом, в таблице дескрипторов должно быть описано столько дескрипторов, сколько сегментов использует программа. В нашем случае в таблицу включены, помимо обязательного нулевого дескриптора, всегда занимающего первое место в таблице, четыре дескриптора для сегментов данных, команд, стека и дополнительного сегмента данных, который мы наложим на видеобуфер, чтобы обеспечить возможность вывода в него символов. Порядок дескрипторов в таблице (кроме нулевого) не имеет значения.
Поля дескрипторов для наглядности заполнены конкретными данными явным образом, хотя объявление структуры dcr с нулями во всех полях позволяет описать дескрипторы несколько короче, например:
gdt_null dcr <>; Селектор 0 – обязательный нулевой дескриптор gdt_data dcr <data_size – l,,, 92h>; Селектор 8 – сегмент данных
В дескрипторе gdt_data, описывающем сегмент данных программы, заполняется поле границы сегмента (фактическое значение размера сегмента data_size будет вычислено транслятором, см. последнее предложение сегмента данных), а также байт атрибутов 1. База сегмента, т.е. линейный адрес его начата, в явной форме в программе отсутствует, поэтому ее придется программно вычислить и занести в дескриптор уже на этапе выполнения.
Дескриптор gdt_codc сегмента команд заполняется схожим образом.
Дескриптор gdt_stack сегмента стека имеет, как и любой сегмент данных, код атрибута 92h, что разрешает его чтение и запись, и явным образом заданную границу – 255 байт, что соответствует размеру стека. Базовый адрес сегмента стека так же придется вычислить на этапе выполнения программы.
Последний дескриптор gdt_scrcen описывает страницу 0 видеобуфера. Размер видеостраницы, как известно, составляет 4096 байт, поэтому в поле границы указано число 4095. Базовый физический адрес страницы известен, он равен BS000h. Младшие 16 бит базы (число 8000И) заполняют слово base_l дескриптора, биты 16…19 (число OBU) – байт base_m. Биты 20…31 базового адреса равны 0, поскольку видеобуфер размещается в первом мегабайте адресного пространства.
Первая половина программы посвящена подготовке перехода в защищенный режим. Прежде всего надо завершить формирование дескрипторов сегментов программы, в которых остались незаполненными базовые адреса сегментов.
Базовые (32-битовые) адреса определяются путем умножения значений сегментных адресов на 16. После обнуления регистра ЕАХ и инициализации сегментного регистра DS, которая позволит нам обращаться к полям данных программы в реальном режиме, содержимое ЕАХ командой sill сдвигается влево на 4 бита, образуя линейный 32-битовый адрес. Поскольку этот адрес будет использоваться и в последующих фрагментах программы, он запоминается в регистре ЕВР (или любом другом свободном регистре общего назначения).
В ВХ загружается адрес дескриптора данных, после чего в дескриптор заносится младшая половина линейного адреса из регистра АХ. Поскольку к старшей половине регистра ЕАХ (где нас интересуют биты 17…24) обратиться невозможно, над всем содержимым ЕАХ с помощью команды rol выполняется циклический сдвиг на 16 бит, в результате которого младшая и старшая половины ЕАХ меняются местами.
После сдвига содержимое AL (где теперь находятся биты 17…24 линейного адреса) заносится в поле base_m дескриптора. Аналогично Вычисляются линейные адреса сегмента команд и сегмента стека.
Следующий этап подготовки к переходу в защищенный режим – загрузка в регистр процессора GDTR (Global Descriptor Table Register, регистр таблицы глобальных дескрипторов) информации о таблице глобальных дескрипторов. Эта информация включает в себя линейный базовый адрес таблицы и ее границу и размещается в 6 байтах поля данных, называемого иногда псевдодескриптором. Для загрузки GDTR предусмотрена специальная привилегированная команда Igdt (load global descriptor table, загрузка таблицы глобальных дескрипторов), которая требует указания в качестве операнда имени псевдодескриптора. Формат псевдодескриптора приведен на рис. 4.10.
Рис. 4.10. Формат псевдодескриптора.
В нашем примере заполнение псевдодескриптора упрощается вследствие того, что таблица глобальных дескрипторов расположена в начале сегмента данных, и ее базовый адрес совпадает с базовым адресом всего сегмента, который мы благоразумно сохранили в регистре ЕВР. Границу GDT в нашем случае легко вычислить в уме: 5 дескрипторов по 8 байт занимают объем 40 байт, и, следовательно, граница равна 39. Команда Igdt загружает регистр GDTR и сообщает процессору о местонахождении и размере GDT.