Содержание

Инициализация в защищенном режиме

     
   Эта глава  дает  ключевой  пример  инициализации  80386-го  в
32-битном     функционировании.      Системная	    конфигурация
устанавливается как простейшая защищенная система, как описано в
главе  8,  с   4-гигабайтной   областью   прямой   адресации   и
двухуровневой системой защиты.
			    

Цели

С минимумом кодов и данных программа, представленная в этой главе, инициализирует 80386-й для работы как 32-битный процессор. Таким образом, эта программа разрешает защищенный режим. Используются 2 привилегированных уровня: наиболее привилегированный - для кода и данных супервизора, и менее привилегированный уровень - для кода и данных пользователя. Программа разрешает доступ ко всей 4-гигабайтной области прямой адресации.

Механизм

Программа инициализирует несколько системных регистров 80386-го, чтобы сделать возможным защищенный режим и доступ к необходимым таблицам дескрипторов GDT и IDT. Хотя и не существует единой последовательности кодов, которая должна быть использована для инициализации 80386 в 32-битном режиме работы, важные пункты должны быть хорошо поняты, и они могут быть об`единены в некоторую заданную программу инициализации. Эти пункты перечислены ниже. 1. Программа сконструирована так, чтобы выполняться немедленно после восстановления процессора. Для простоты эта процедура должна находиться в EPROM, и она начинает выполняться с исходного адреса. При перезагрузке 80386-й находится в реальном режиме, но база кодового сегмента изначально задана FFFF0000h (64К от вершины 4-гигабайтного физического адресного пространства, величина, превосходящая нормальное 1-мегабайтное адресное пространство реального режима. IP задан FFF0h, что приводит к тому, что начальный адрес вызова будет FFFF0000h + FFF0h (адрес базы кодового сегмента + значение IP) = FFFFFFF0h в физической памяти. Заметим, что базовые адреса сегмента и IP, как они заданы, допускают самозагрузку кода в EPROM, который помещается на вершину 4-гигабайтной физической памяти. 2. Первая команда в виде программы - JMP. Т.к. этот пример сделан так, чтобы постоянно находиться в самозагрузчике EPROM в вершине физического адресного пространства, эта JMP должна быть внутрисегментной JMP (код операции Е9h, прямой переход внутрь кодового сегмента), чтобы избежать перезагрузки адреса код-сегментной базы. 3. Во время работы программы системные регистры GDTR и IDTR 80386-го загружаются значениями, которые указывают на две таблицы дескрипторов, рассмотренные в главе 8, GDT и IDT. Образы структур GDT и IDT также включены в самозагрузчик в EPROM. Важно: все дескрипторы кодов и данных в EPROM-образе GDT должны иметь набор битов доступа. Дескриптор TSS должен иметь набор битов доступа и бит восстановления. Замечание: образы GDT и IDT могут быть скопированы в RAM, если это понадобится, позволяя изменять таблицы, также как и системные запуски. Для мультизадачной системы таблицы должны быть расположены в RAM так, чтобы 80386 мог как следует контролировать занятые биты нескольких дескрипторов TSS, существующих в такой системе. 4. Когда таблицы установлены, как показано выше, программа разрешает защищенный режим путем загрузки значений в CR0 ,который устанавливает PE (возможность защиты)бит (бит, обеспечивающий защиту).Сейчас защищенный режим установлен, и это означает, что следующие загрузки селекторов в сегментный регистр вызовут то, что 80386 будет обращаться к GDT, считывать дескриптор для сегмента и сохранять информацию дескриптора во внутреннем дескрипторном КЭШ-регистре. Загрузки селекторов могут быть выполнены с помощью команды MOV или, для регистра CS, через интерсегментные команды JMP, CALL, INTn, RET или IRET. 5. Программа продолжает инициализировать КЭШ 80386-го для каждого сегментного регистра. Программа смещает селектор для сегмента данных супервизора (селектор = 0018h) в сегментные регистры SS, DS, ES, FS, и GS. Значение селектора таково, что он ссылается на дескриптор для сегмента данных уровня супервизора(уровня 0). Этим действием программа делает доступным большой сегмент данных супервизора. Как определено дескриптором сегмента данных в GDT, сегмент данных - 32-битный сегмент, т.к. бит дескриптора D=1. Дескриптор сегмента данных, который появляется, как показано на рис.8.3, приводится как дескриптор CDT 3 на рис.11.2. Этот дескриптор сегмента данных показывает базовый адрес 00000000h и границу максимального размера FFFFFFFFh. Сегмент данных супервизора, таким образом, охватывает всю 4-гигабайтную область прямой адресации. Регис- тры SS, DS, ES, FS, и GS все описывают тот же сегмент максимального размера. 6. Остается загрузить один последний сегментный регистр - регистр CS. Это завершается не командой MOV (MOV в CS - недопустимый код операции), а командой JMP. Т.к. команда JMP должна загрузить новое значение селектора в CS, необходимо выполнить интерсегментную JMP (код операции EAh, прямой интерсегментный переход). Интерсегментная команда JMP определяет селектор кодового сегмента супервизора (селектор = 0010h) и смещение внутри этого принимающего сегмента ( смещение = линейный адрес команды, следующей за JMP). Кодовый сегмент, как описывается дескриптором кодового сегмента в GDT, есть 32-битный сегмент (D=1). Дескриптор кодового сегмента, приведенный как дескриптор GDT_2 на рис.11.2, показывает базовый адрес 00000000h и границу максимального размера FFFFFFFFh. Сегмент кода супервизора, таким образом, охватывает всю 4-гигабайтную область прямой адресации. Интерсегментная команда JMP будет использовать значение селектора, который обращается к дескриптору для кодового сегмента уровня супервизора (уровня 0). Она будет использовать смещение, которое определяет адресат информации относительно вновь загруженного сегментного кода. Как описано, база этого кодового сегмента - 00000000h, таким образом определение смещения n приводит к адресу n адресата информации внутри 4-гигабайтной области прямой адресации. 7. На адресате информации JMP-команды желательно иметь команду, которая инициализирует стек супервизора. Перемещение начального значения в регистр ESP - это все, что требуется. Т.к. базовый адрес всех сегментов определен как 00000000h, и границы определены как FFFFFFFFh, эта конфигурация устанавливается так, что сегментные регистры мало используются когда процедура инициализации закончена. 4-гигабайтная линейная область делается доступной кодам и данным. 8. Команда LTR инициализирует регистр задачи, указывающий ей на TSS для этой (и только этой) задачи. TSS требуется, т.к. система допускает пользователь/суперпользовательскую архитектуру. Когда обрабатывающийся код находится на пользовательском уровне, TSS сохраняет начальный указатель стека супервизора.

Процедура 32-битной инициализации супервизора и данных

Программа - коды и данные, используемые для инициализации 80386-го в 32-битном режиме. Программа реализует все шаги, описанные на страницах . Необходимые структуры данных - рис.11.2 включает образ GDT с нулевым дескриптором, 4-сегментных дескриптора. Последняя необходимая структура данных - образ IDT. Каждый вход IDT - вентиль, а не селектор, и к нему обращаются по его позиционному номеру в IDT. Например, команда INTn будет давать направление через вентиль n в IDT. Этот код и данные разрешают 80386-му защищенный режим. Т.к. сегментный дескриптор супервизора и сегментный дескриптор кода пользователя имеют D=1, 32-битный размер операнда и 32-битный размер адреса - по умолчанию. ASSUME CS:INITIAL,DS:TABLEDATA INITIAL SEGMENT PUBLIC AT 0F00h ORG FFF0h ASSUME CS:INITIAL,DS:NOTHING,ES:NOTHING RES_ADR: JMP BODY ORG 0D000h BODY: LGDT GDT_PTR LIDT IDT_PTR MOV EAX,CR0 OR EAX,00000001h MOV CR0,EAX MOV AX,0018h MOV SS,AX MOV DS,AX MOV ES,AX MOV FS,AX MOV GS,AX JMP DEST_0FFSET,DEST_SEL DEST: MOV ESP,00400000h LTR SIMPLE_TSS_SEL YOUR_SUPERVISOR: ..... ..... ..... INITIAL ENDS Рис.11.1 32-битный защищенный супервизор INITIAL SEGMENT PUBLIC AT 0F000h ORG 0BFF0h GDT_PTR: DW 002Fh DW C000h DW 0FFFFh IDT_PTR: DW 07FFh DW C030h DW 0FFFFh ORG 0C000h GDT: GDT_0: DD 00000000b DD 00000000b GDT_1: DW 0067h DW 8000h DB 0FFh DB 10001011b DB 00000000b DB 0FFh GDT_2: DW 0FFFFh DW 0000h DB 0FFh DB 10011011b DB 10001111b DB 0FFh GDT_3: DW 0FFFFh DW 0000h DB 0FFh DB 10010011b DB 10001111b DB 0FFh GDT_4: DW 0FFFFh DW 0000h DB 0FFh DB 11111011b DB 10001111b DB 0FFh GDT_5: DW 0FFFFh DW 0000h DB 0FFh DB 11110011b DB 10001111b DB 0FFh GDT_END: IDT: IDT_0: DW XXXXh DW 0010h DB 00h DB 11101111h DW XXXXh IDT_32: DW XXXXh DW 0010h DB 00h DB 11100101h DW XXXXh IDT_33: DW XXXXh DW 0010h DB 00h DB 11100101h DW XXXXh IDT_END: INITIAL ENDS Рис.11.2 TABLEDATASEGMENT TSS: DD 00000000h DD 00400000h DW 0000h DW 0018h DD 00000000h DD 00000000h DD 00000000h DD 00000000h DD 00000000h DD 00000000h DD 00000000h DD 00000000h DD 00000000h DD 00000000h DD 00000000h DD 00000000h DD 00000000h DD 00000000h DD 00000000h DW 0000h DW 0000h DW 0000h DW 0000h DW 0000h DW 0000h DW 0000h DW 0000h DW 0000h DW 0000h DW 0000h DW 0000h DW 0000h DW 0000h DW 0000h DW 0FFFFh TSS_END: TABLEDATAENDS Рис.11.3

Начальная диспетчеризация программы пользовательского уровня.

Когда код супервизора используется для того, чтобы диспетчеризовать пользовательскую программу (т.е. начать выполнение программы пользовательского уровня), контроль должен быть перенесен командой RET или IRET, почти также, как обслуживающая процедура завершается командой IRET. Однако, т.к. код пользователя фактически вызывается с уровня супервизора, код супервизора должен создавать кадр стека на этот стек. Требования кадра стека перед выполнением RET или IRET изображены на рис.11.4. Заметим, что показанный кадр стека должен быть только кадром на стек супервизора, когда RET или IRET выполняются. Это требование позволяет установить стек супервизора, используя значения SS и ESP, содержащиеся в TSS.

Установка сегмента данных пользователя

То, о чем особенно нужно упомянуть, возникает как раз перед диспетчеризацией супервизором кода пользователя. Необходимо, чтобы супервизор перемещал селектор для сегмента данных пользователя в каждый сегментный регистр DS, ES, FS, и GS. Значение селектора таково, что он обращается к дескриптору для сегмента данных пользовательского уровня (уровня 3). Этим действием программа делает доступным большой сегмент данных пользователя. Как описывается дескриптором сегмента данных в GDT, сегмент данных - 32-битный сегмент, т.к. бит D дескриптора равен 1. Дескриптор сегмента данных появляется как показано на рис.8.3 и приводится как дескриптор GDT_5 на рис.11.2. Этот дескриптор сегмента данных указывает адрес 00000000h и предел максимального размера FFFFFFFFh. Сегмент данных пользователя, таким образом, охватывает всю 4-гигабайтную область прямой адресации. Регистры SS, DS, ES, FS и GS все описывают один и тот же сугмент максимального размера. Регистр SS загружается с селектором в сегмент данных пользователя командами RET и IRET, используемыми для диспетчеризации программы пользователя. RET или IRET выделяют переходы привилегированного уровня, т.к. они выталкивают из кадра стека значение CS адресата информации. Адресат информации CPL определяется в низших двух битах CS селектора. При чтении значения адресата информации CPL, отличного от настоящего значения CPL, 80386-й отмечает, что предполагается переход с уровня на уровень. Т.к. для адресата информации привилегированного уровня должен быть использован отдельный стек, 80386, таким образом, продолжает работу до выталкивания из стека информации, а именно значения ESP адресата информации и селектора SS адресата информации. Принимая во внимание вышеизложенное, пример кода супервизора, предназначенный для диспетчеризации пользовательской программы, показан на рис.11.5. Пример создает кадр стека супервизора, загружает DS, ES, FS и GS c селектором в сегмент данных пользователя и выполняет команду IRET чтобы произвести диспетчеризацию. Заметим, что предположение об этом подходе позволяет коду пользователя полностью не касаться регистров сегмента; сегмент данных пользователя доступен, начиная с момента, когда код пользователя начинает выполнение. Возможно, конечно, позволить коду пользователя загружать селектор сегмента данных, но это грубый подход, т.к. он требует, чтобы код пользователя "знал" необходимое точное значение селектора. Когда код пользователя последовательно вызывает программу в коде супервизора, программа супервизора должна протолкнуть по стеку значение сегментного регистра, который будет использоваться, и, соответственно, в конце обслуживающей программы вытолкнуть начальные значения селектора пользователя обратно в сегментные регистры перед выполнением команды IRET на пользовательском уровне. PUSHF SUB ESP,16 MOV [ESP+12],USER_STK_SEL MOV [ESP+8], USER_STK_PTR MOV [ESP+4], USER_CODE_SEL MOV [ESP], USER_INSTR_PTR MOV ESP,EBP MOV AX,USER_DATA_SEL MOV DS,AX MOV ES,AX MOV FS,AX MOV GS,AX IRET Рис.11.5
Содержание Вперед
Сайт создан в системе uCoz