WYOS - Выпуск №4
Защищенный режим процессора
commrade, Вторник, 29 Июнь 2004, 23:42

<p>Приветствую вас, о светлейшие из светлейших, о
наумнейшие из суперумных!</p>

<p>Меня зовут commrade. Со мной можно связаться по email: <a href="mailto:sergo92@yandex.ru">sergo92@yandex.ru</a>, либо по ICQ: 248544753. В этом выпуске я вам расскажу о защищенном режиме работы процессора. О режиме, в котором работает
UNIX, XENIX, OS/2, PC-MOS, QNX, Desk View, сетевая операционная система NOVELL,
операционная система Microsoft WINDOWS, драйверы расширенной памяти EMM386 и
QEMM и СУБД ORACLE. </p>

Введение
Защищенный режим работы процессора это режим, в котором реализуются такие возможности современных процессоров, как: многозадачность изолированностьодного приложения от другого, работа с большим объемом оперативной памяти, использование виртуальной памяти, использование на полную катушку всех возможностей "".
Основные отличия реального режима от защищенного
<p>В основном эти два режима между собой отличаются, в следующем:</p>

<ol>
<li>Адресация памяти.

<p>В реальном режиме работы процессора память адресуется посредством
двухкомпонентноо логического адреса (пример: <tt>A700:FFFFh</tt>). Делается это потому что для представления
физического адреса в компьютерах IBM PC и IBM XT используется двадцать двоичных
или пять шестнадцатеричнх разрядов. Но все регистры процессора i8086 являются
16-разрядными. Для разрешения этой проблемы используется двухкомпонентны
логический адрес. Логический адрес состоит из 16-разрядных компонент:
компоненты сегмента памяти и компоненты смещения внутри сегмента. Такой способ
адресации накладывает ограничение на адресное пространство до 1 мегабайта плюс
примерно 64 килобайта старшей области памяти для процессоров i80286, i80386 и
i80486.</p>

<p>При работе в защищенном режиме используется более сложный способ адресации памяти, который позволяет избежать ограничения в 1 мегабайт
памяти. Для получения физического адреса памяти используется так называемый
селектор, который фактически является индексом к таблице дескрипторов, где
храняться 24-разрядные базовые адреса, а физический адрес получается сложением
этого базового адреса и смещения.</p>
</li>
<li>Защита

<p>В реальном режиме работы процессора есть свободный доступ для любых программ
к любым областям данных, что представляет потенциальную опасность для
целостности операционной системы. В защищенном режиме работы программа имеют
доступ только к той области данных которую ей выделяет
процессор. Грубо говоря любой процесс (программа)
видит только свою <tt>LDT</tt>. Также для защиты памяти и файлов операционной системы
используется поле <tt>RPL</tt> в селекторе.</p>
</li>
<li>Виртуальная память
<p>Основная идея виртуальной памяти заключается в том, чтобы хранить (и
обновлять) содержимое большой виртуальной памяти на диске, подкачивая отдельные
участки виртуальной памяти в реальную оперативную память по необходимости.
Данная возможность доступна только в защищенном режиме работы </p>
</li>
</ol>

Локальная и глобальная таблицы дескрипторов
Селектор - индекс к таблице дескрипторов, где храняться 24-разрядные
базовые адреса для вычисления физического адреса сегмента.

<p><img border=0 src='files/images/articles/wyos/selector.png'></p>
<p>Формат селектора следующий (см. рисунок): с 3 бита по 15 отводится под сам
индекс, бит 2 это так называемый индикатор таблицы (Table Indicator далее <tt>TI</tt>),
если этот бит равен нулю, для преобразования адреса
используется так называемая глобальная таблица дескрипторов (Global Descriptor
Table далее <tt>GDT</tt>), в противном случае - локальная таблица дескрипторов (Local
Descriptor Table далее <tt>LDT</tt>). Биты с 0 по 1 задают запрошенный
программой уровень привилегий (Requested Privilege Level далее <tt>RPL</tt>). Поле <tt>TI</tt>
(Table Indicator) состоит из одного бита. Если этот бит
равен нулю, для преобразования адреса используется так называемая глобальная
таблица дескрипторов <tt>GDT</tt> (Global Descriptor Table), в противном случае -
локальная таблица дескрипторов <tt>LDT</tt> (Local Descriptor Table).</p>
<b>Таблица дескрипторов - это просто таблица преобразования адресов,
содержащая базовые 24-разрядные физические адреса сегментов и некоторую другую
информацию. То есть каждый элемент таблицы дескрипторов (дескриптор)
содержит 24-разрядный базовый адрес сегмента и другую информацию, описывающую
сегмент.</b>
<p>Таблица <tt>GDT</tt> - единственная в системе. Обычно в ней находятся описания
сегментов операционной системы. Таблиц <tt>LDT</tt> может быть много. Эти таблицы
содержат описания сегментов программ, работающих под управлением операционной
системы, т.е. отдельных задач. В отдельный момент времени процессор может
использовать только одну таблицу <tt>LDT</tt>. Процессор имеет два регистра,
предназначенныхдля адресации используемых в настоящий момент таблиц <tt>GDT</tt> и <tt>LDT</tt>.
Регистр <tt>GDTR</tt> описывает расположение и размер таблицы <tt>GDT</tt>, а регистр <tt>LDTR</tt>
содержит ссылку на использующуюся в настоящее время таблицу <tt>LDT</tt>.
Регистры процессора <tt>GDTR</tt> и <tt>LDTR</tt> определяют расположение в памяти таблиц <tt>GDT</tt> и
<tt>LDT</tt> соответственно. Формат регистра <tt>GDTR</tt> показан на рисунке:</p>
<p><img border=0 src='files/images/articles/wyos/gdtr.png'></p>
<p>Таблицы <tt>GDT</tt> и <tt>LDT</tt> содержат дескрипторы, описывающие сегменты памяти. В этих
дескрипторах, помимо другой информации содержится 24-разрядный базовый адрес
сегмента. Старшие 13 битов селектора выбирают элемент из таблицы <tt>GDT</tt> или <tt>LDT</tt> в
зависимости от состояния бита <tt>TI</tt> селектора. Извлечённый из таблицы дескрипторов
базовый адрес сегмента складывается процессором для получения 24-разрядного
физического адреса. Структура дескриптора следующая (см. рисунок):</p>
<p><img border=0 src='files/images/articles/wyos/descript.png'></p>
<p>Назначения этих полей следующие:</p>

<p>Базовый адрес – 24-разрядное чило указывающие на физический адрес сегмента.</p>

<p>Резерв – дополнительное 16-разрядное число, совместно с базовым адресом
указывающие на физический адрес сегмента, в основном используется
процессорами i80386, i80486 и выше, т.к. разрядность шины адреса у этих
процессоров 32-бита (<i>Khimov Roman:</i> начиная с Pentium II шина адреса Intel'овских процеесоров - 36 бит (причем, заметьте - в Celeron от Pentium II адресная шина была по прежнему 32-битная!). AMD не отстает... .</p>

<p>Доступ – 8-разрядное число говорящее о том, к каком типу данных принадлежит тот или иной
сегмент, возможно ли чтение или запись данных в этот сегмент.</p>

<p>Предел – указывает на размер сегмента в байтах, уменьшенный на единицу.</p>

<p>Если с базовым адресом, резервом, и пределом все понятно, то полем доступа
не все так просто. В защищенном режиме существует три типа сегмента. Сегмент
кода, сегмент данных и системный сегмент. Структура этих сегментов покзана на
рисунке ниже:</p>
<p><img border=0 src='files/images/articles/wyos/seg.png'></p>
<p>Остановимся на назначении битов в поле доступа для каждого типа сегмента.
Поле доступа дескриптора сегментов кода содержит битовое поле <tt>R</tt>, называемое
битом разрешения чтения сегмента. Если этот бит
установлен в 1, программа может считывать содержимое сегмента кода. В противном
случае процессор может только выполнять этот код. Поле <tt>W</tt>, поле доступа сегмента
данных, называется битом разрешения записи в сегмент. Бит <tt>C</tt> называется битом
подчинения. Бит <tt>P</tt> называется битом присутствия сегмента в памяти. Для тех
сегментов, которые находятся в физической памяти бит должен быть установлен в
1. Бит <tt>A</tt> называется битом обращения к сегменту. Поле
<tt>D</tt> задаёт направление расширения сегмента. Обычный сегмент данных расширяется в
область старших адресов. Если же в сегменте расположен стек, расширение
происходит в обратном направлении - в область младших адресов. Для сегментов, в
которых организуются стеки, необходимо устанавливать поле <tt>D</tt> равным 1.
Поле <tt>DPL</tt>, используюется для организации защиты сегментов. Данное поле
очень тесно связано полем <tt>RPL</tt> селектора. Дескрипторы
системных сегментов содержат поле <tt>TYPE</tt>, определяющее тип системного сегмента. В
таблице приведены возможные для этого поля значения.</p>

<table border=1 cellpadding=0>
<tr>
<td>
Поле <tt>TYPE</tt>
</td>
<td>
Тип сегмента
</td>
</tr>
<tr>
<td>
0
</td>
<td>
Запрещённое значение
</td>
</tr>
<tr>
<td>
1
</td>
<td>
Доступный <tt>TSS</tt> для процессора i80286
</td>
</tr>
<tr>
<td>
2
</td>
<td>
Сегмент <tt>LDT</tt>
</td>
</tr>
<tr>
<td>
3
</td>
<td>
Занятый <tt>TSS</tt> для процессора i80286
</td>
</tr>
<tr>
<td>
4
</td>
<td>
Вентиль вызова для процессора i80286
</td>
</tr>
<tr>
<td>
5
</td>
<td>
Вентиль задачи для процессоров i80286 и i80386
</td>
</tr>
<tr>
<td>
6
</td>
<td>
Вентиль прерывания для процессора i80286
</td>
</tr>
<tr>
<td>
7
</td>
<td>
Вентиль исключения для процессора i80286
</td>
</tr>
<tr>
<td>
8
</td>
<td>
Запрещённое значение
</td>
</tr>
<tr>
<td>
9
</td>
<td>
Доступный <tt>TSS</tt> для процессора i80386
</td>
</tr>
<tr>
<td>
A
</td>
<td>
Зарезервировано
</td>
</tr>
<tr>
<td>
B
</td>
<td>
Занятый <tt>TSS</tt> для процессора i80386
</td>
</tr>
<tr>
<td>
C
</td>
<td>
Вентиль вызова для процессора i80386
</td>
</tr>
<tr>
<td>
D
</td>
<td>
Зарезервировано
</td>
</tr>
<tr>
<td>
E
</td>
<td>
Вентиль прерывания для процессора i80386
</td>
</tr>
<tr>
<td>
F
</td>
<td>
Вентиль ловушки для процессора i80386
</td>
</tr>
</table>

<p>Программы
реального режима работают всегда с сегментами размером 64 килобайта. Если
программа состоит из нескольких сегментов, то некоторые сегменты могут
перекрываться. Существует потенциальная опасность, что в результате программной
ошибки (например, выхода индекса массива за допустимые пределы) произойдёт
запись в другой сегмент. Процессор i80286 позволяет создавать сегменты любого
размера в пределах 64 килобайт (процессоры i80386 и i80486 могут работать с
сегментами размером 4 гигабайта). Кроме того, он следит за тем, чтобы при
адресации памяти не происходил выход за границы сегмента. Границы сегмента
задаются полем предела в дескрипторе сегмента. Мы уже говорили, что значение
этого поля должно быть равно размеру сегмента в байтах минус единица.
Интерпретация поля предела зависит от состояния бита <tt>D</tt> поля доступа. Для
сегментов стеков необходимо устанавливать поле <tt>D</tt> равным 1.
В этом случае попытка записи в переполненный стек вызовет прерывание программы.
В ответ на это прерывание операционная система может, например, выделить
дополнительную память для стека. В реальном режиме переполнение стека никак не
контролируется и может привести к разрушению самой программы или операционной
системы.</p>

Команды защищенного режима

<p>Все
описанные выше структуры данных легко можно описать и задать с помощью
ассемблера для этих целей подойдет как TASM (как наиболее популярный интерпретатор) так и FASM (как наиболее простой в
использовании). У этих двух ассемблерных интепретаторов имеются команды для
работы в защищенном режиме и выхода в защищенный режим. Вот основные команды
ассемблера для выхода и работы в защищенном режиме (более детально данные
команды нужно рассматривать исходя из конкретного
интепретатора):</p>

<table border=1 cellpadding=0>
<tr>
<td>
Команда
</td>
<td>
Выполняемые функции
</td>
</tr>
<tr>
<td>
<tt>LGDT</tt>
</td>
<td>
Загрузка регистра глобальной таблицы дескрипторов <tt>GDTR</tt>
</td>
</tr>
<tr>
<td>
<tt>LLDT</tt>
</td>
<td>
Загрузка регистра локальной таблицы дескрипторов <tt>LDTR</tt>
</td>
</tr>
<tr>
<td>
<tt>LIDT</tt>
</td>
<td>
Загрузка регистра таблицы дескрипторов прерываний <tt>IDTR</tt>
</td>
</tr>
<tr>
<td>
<tt>LTR</tt>
</td>
<td>
Загрузка регистра задачи <tt>TR</tt>
</td>
</tr>
<tr>
<td>
<tt>LMSW</tt>
</td>
<td>
Загрузка слова состояния машины <tt>MSW</tt>
</td>
</tr>
<tr>
<td>
<tt>CLTS</tt>
</td>
<td>
Сброс флага переключения задачи
</td>
</tr>
<tr>
<td>
<tt>HLT</tt>
</td>
<td>
Останов процессора
</td>
</tr>
</table>

Выход в защищенный режим

<p>Перед тем, как переключить процессор в защищённый режим, надо выполнить
некоторые подготовительны действия, а именно:</p>
<ol>
<li>Подготовить в оперативной памяти глобальную таблицу дескрипторов <tt>GDT</tt>. В
этой таблице должны быть созданы дескрипторы для всех сегментов, которые будут
нужны программе сразу после того, как она переключится в защищённый режим.
Впоследствии, находясь в защищённом режиме, программа может модифицировать <tt>GDT</tt>
(если, разумеется, она работает в нулевом кольце защиты). Программа может
модифицировать имеющиеся дескрипторы или добавить новые, загрузив заново
регистр <tt>GDTR</tt>.</li>

<li>Для обеспечения возможности возврата из защищённого режима в реальный
необходимо записать адрес возврата в реальный режим в область данных BIOS по адресу
<tt>0040h:0067h</tt>, а также записать в CMOS-память в ячейку <tt>0Fh</tt> код <tt>5</tt>. Этот код
обеспечит после выполнения сброса процессора передачу управления по адресу,
подготовленномунами в области данных BIOS по адресу <tt>0040h:0067h</tt>.</li>

<li>Запретить все маскируемые и немаскируемые прерывания.</li>

<li>Открыть адресную линию <tt>A20</tt>.</li>

<li>Запомнить в оперативной памяти содержимое сегментных регистров, которые
необходимо сохранить для возврата в реальный режим, в частности, указатель
стека реального режима.</li>

<li>Загрузить регистр <tt>GDTR</tt>. </li>
</ol>

<p>В терминах языка ассемблера структура дескриптора может
быть описана следующим образом (здесь и далее рассматриваеются тексты на языке
ассемблер для TASM 5.0 взятые из статьи [1]:</p>


STRUC desc_struc
     limit     dw 0
         ; предел сегмента
     base_lo   dw 0
         ; младшее слово 24-битового физического адреса сегмента
     base_hi   db 0
         ; старший байт 24-битового физического адреса сегмента
     access    db 0
         ; поле доступа
     reserved  dw 0
         ; зарезервировано для сегментов процессора i80286 должно быть равно нулю
ENDS desc_struc


<p>Тогда мы можем определить таблицу <tt>GDT</tt> как набор дескрипторов со структурой
<tt>desc_struc</tt>:</p>


GDT_BEG = $                       ; отмечаем начало GDT

LABEL gdtadr WORD

  gdt_0   desc_struc <0,0,0,0,0>  ;первый элемент не используется
  gdt_gdt desc_struc 
  gdt_ds  desc_struc 
  gdt_cs  desc_struc 
  gdt_ss  desc_struc 

GDT_SIZE = ($ - GDT_BEG)          ; вычисляем размер GDT



<p>Нам необходимо также замаскировать все маскируемые и
немаскируемые прерывания:</p>



  cli
  mov al,8f
  out CMOS_PORT,al
  jmp next1            ; небольшая задержка

next1:
  mov al,5
  out CMOS_PORT+1,al



<p>Открытие адресной линии <tt>A20</tt> - необходимо в том случае, если
ваша программа будет обращаться к оперативной памяти, лежащей за пределами
первого мегабайта:</p>



;---------------------------------------
; Процедура открывает адресную линию A20
;---------------------------------------
PROC  enable_a20  NEAR
   
   mov al,A20_PORT
   out STATUS_PORT,al
   mov al,A20_ON
   out KBD_PORT_A,al
   ret
   
ENDP  enable_a20



<p>Эта магическая последовательноть команд выдаёт команду <tt>A20_ON</tt> клавиатурному
процессору 8042, к которому подключены схемы управления адресной линией <tt>A20</tt>. После начального сброса
линия <tt>A20</tt> закрыта, и расширенная память за границами первого мегабайта
недоступна. </p>

<p>Следующий этап - запоминание содержимого сегментных
регистров, которые будут нужны при возврате в реальный режим. Это сегментные
регистры <tt>SS</tt> и <tt>ES</tt>:</p>



mov [real_ss],ss     ; запоминаем указатель стека
mov [real_es],es     ; для реального режима



<p>На последнем перед переключением в защищённый режим этапе мы
загружаем регистр <tt>GDTR</tt> адресом подготовленной заранее
<tt>GDT</tt>:</p>



lgdt [QWORD gdt_gdt]



<p>Всё! Можно переключаться в защищённый режим! </p>

Послесловие

<p>Данная статья была в основном написана под впечатлением от книги
"Защищенный режим процессоров Intel 80286/80386/80486" Александр
Фролов, Григорий Фролов. Приведенные здесь примеры кода нетрудно переписать как
под <a href='http://fasm.sourceforge.net'>FASM</a> так и под <a href='http://www.cryogen.com/Nasm'>Nasm</a>. Если вы закачеете файл по ссылке, то вместе с html-вариантом
книги Александра Фроловa вы получите архив с примерами программ для работы в
защищенном режиме. </p>

<p>Вот теперь все. Всех благ! С вами был commrade. </p>

Список использованной при подготовке
материала литературы и ссылки в интернет:


<ol>
<li>
<a href='http://stratum11.pstu.ac.ru/~leonid/base/fv06.zip'>"Защищенный режим процессоров Intel 80286/80386/80486" Александр Фролов, Григорий </a>
</li>
<li>
<a href='http://www.citforum.ru/hardware/'>http://www.citforum.ru/hardware/</a> - море информации по различным
апаратным платформам
</li>
<li>
<a href='http://www.nondot.org/sabre/os/articles'>http://www.nondot.org/sabre/os/articles</a> - информация по различным аспектам написания ОС, правда все на английском
</li>
<li>
<a href='http://lib.prm.ru/'>http://lib.prm.ru/</a> - электронная библиотека
</li>
</ol>

Послесловие от Khimov Roman

<p>
Очередной выпуск. Надеюсь, вы начали читать его не отсюда и уже прочитали <br>
Теперь немного о грустном: некоторое (и довольно длительное) время рассылка будет существовать без основателя, то есть
Wanderer'a. О причинах мы и сами многого не знаем, но ничего не попишешь. В принципе, это не повод расстраиваться,
мы приложим максимум усилий, чтобы рассылка по прежнему выходила раз в неделю.<br>
На время отсутствия Wanderer'а "главным " рассылки остаюсь я, Химов Роман (ну надо же! - по-русски написал! . Так как на этой должности я только осваиваюсь, то вчера вы получили письмо с темой "Test", я проверял как работает рассылка . Дайджест-режим я выключил для всех - так выпуски будут доходить быстрее и менее вероятны глюки
mailman'a (этот товарищ не очень любит дайджесты... . Вопросы, связанные с этим выпуском направляйте выпускающему, то есть <a href='mailto:sergo92@yandex.ru'>commrade</a>. Общие вопросы направляйте мне, на <a href='mailto:khimov@osrc.info?subject=WriteYourOwnOS'>khimov@osrc.info</a>.
</p>
<p>
Следующий выпуск будет посвящен файловым системам, тема обширная, возможно растянем на два выпуска, чтобы поподробнее. Готовить выпуск будет Doberman. Не пропустите!
</p>



это контент от Центр информации по операционным системам
( http://www.osrc.info/plugins/content/content.php?content.8 )