Программирование процессоров Intel x86 в защищённом режиме
Введение

Автор: sergh
The RSDN Group

Версия текста: 1.0

Историческая справка
О содержании курса
По главам
Не вошло
Выходит за рамки
О том, зачем и кому это нужно
О принципах создания курса
Уровень детализации
Эпиграфы
Теория
Примеры
Задания
Общее
О минимальной конфигурации
Знания
Железо и ПО
Об источниках
Об обозначениях
Ссылка на литературу
Термины
Числа
Числительные
Благодарности


Защищенный режим (protected mode) – наиболее «естественный» режим
работы современных процессоров Intel x86. Именно в этом режиме
Intel-совместимых процессоров работают такие всемирно известные
операционные системы как Windows, Linux, FreeBSD. Поэтому, покупая 
новый компьютер, убедитесь, что его процессор поддерживает 
работу в защищённом режиме. Используйте защищённый режим
в своих программах и откройте для себя этот удивительный мир
неограниченных возможностей!!!

Вымышленный рекламный лозунг. Однако, почти всё правда.

Историческая справка

В 1982 году, с появлением процессора 80286, фирма Intel ввела понятие «режим работы процессора». Режим, совместимый с процессором 8086, был назван режимом реальной адресации (Real-Address Mode) или просто реальным (Real Mode), новый режим – защищённым (Protected Mode). Программный интерфейс процессора в разных режимах отличается весьма существенно, так, при работе в защищённом режиме, 80286 поддерживает управление памятью, виртуальную память (пока только для сегментов), переключение задач и уровни привилегий, то есть практически всё, что необходимо для реализации многозадачной операционной системы.

На этом прогресс не остановился, и в 1985 году был выпущен 32-разрядный процессор Intel386, который работал уже в трёх режимах:

ПРИМЕЧАНИЕ

Поскольку термины «реальный/защищённый/… режим» относятся к режимам работы процессора, говорить о том, что в реальном/защищённом/.. режиме работает какая-либо программа не совсем корректно. Правильнее было бы сказать, что программа исполняется процессором, находящимся в реальном/защищённом/… режиме. Но, так как первый вариант в два раза короче, общепринят и не вносит путаницы, используется он.

Последующие поколения процессоров добавили к программному интерфейсу защищенного режима несколько новых понятий, флагов и команд, но никаких фундаментальных изменений не принесли.

ПРИМЕЧАНИЕ

Начиная с Pentium и некоторых поздних моделей Intel486, появился четвёртый режим: режим системного управления (System Management Mode; SMM), но он в курсе не рассматривается.

О содержании курса

Как и следует из названия, курс посвящен изучению программирования процессоров Intel x86 в защищенном режиме.

По главам

Информация расположена следующим образом:

Обзор защищённого режима

Основное предназначение главы – описание задач, стоявших перед разработчиками защищённого режима и некоторых следствий из них. Задумываться на тему «зачем же они всё это придумали?» чрезвычайно полезно, так как только взгляд с этой точки зрения позволяет объяснить причины принятия тех или иных архитектурных решений. Как это ни странно, несмотря на не слишком большую сложность такого анализа, я не встретил ничего подобного ни в одном из источников.

В качестве примера – наиболее простая из виденных мною программ, переключающаяся в защищённый режим.

Управление памятью: сегменты и дескрипторы

Описание базового механизма управления памятью в защищённом режиме – сегментации (segmentation). Объясняются основные понятия, описывается упрощённый формат дескриптора сегмента (segment descriptor), глобальная таблица дескрипторов (Global Descriptor Table; GDT), упрощённый формат селектора (selector).

Примеры: unreal-mode и переключение сегмента кода.

Программные прерывания

Основные сведения об обработке прерываний в защищенном режиме: программные прерывания, таблица дескрипторов прерываний (Interrupt Descriptor Table, IDT), упрощённый формат дескриптора шлюза ловушки (trap gate descriptor).

Пример – обработка программного прерывания int 0.

Исключения

Рассуждения на тему «а зачем вообще нужны исключения», перечисление существующих типов исключений, описание отличий механизма обработки исключений от программных прерываний. Длинная, но несложная глава.

Пример – программа, приводящая к исключению #GP (General Protection) и успешно его обрабатывающая.

Внешние прерывания

Рассуждения на тему «а зачем вообще нужны внешние прерывания», описание механизма возникновения и обработки внешних прерываний, взаимодействия процессора и ПКП (программируемый контроллер прерываний), управление стандартным ПКП. В главе много фактических данных, не относящихся напрямую к архитектуре процессора, но без них не обойтись.

Пример – программа, обрабатывающая прерывание от RTC (Real Time Clock, часы реального времени).

Теоретическое введение в защиту

Да, вы угадали. Начинается всё с рассуждений на тему «а зачем вообще нужна защита». Дальше всё как обычно: дескрипторы, уровни привилегий, DPL, CPL, RPL.

Пример – программа, приводящая к #GP из-за высокого уровня RPL, и успешно исправляющая ситуацию в обработчике исключения.

Первая преамбула: одна задача

Кратко описан сегмент состояния задачи (task state segment, TSS), его дескриптор, инструкция ltr. Всего пять страниц (вместе с кодом!), никаких рассуждений, очень простой пример, заданий нет вообще. Глава не имеет самостоятельной ценности, а является первым введением к главе «Защита: передача управления».

Вторая преамбула: дескриптор шлюза вызова

Описан дескриптор шлюза вызова (call gate descriptor), его формат и использование. В сумме получилось семь страниц, но в основном за счёт примера. Заданий опять нет. Как и предыдущая, глава не имеет самостоятельной ценности, а является вторым введением к главе «Защита: передача управления».

Защита: передача управления

Самая сложная и важная глава – она сводит воедино всё, что было написано до неё и закрывает большинство хвостов. Вводится модель защищённой ОС, с её помощью определяются приблизительные требования к подсистеме (если так можно выразиться) передачи управления. Потом описывается фактический процесс передачи управления со сменой уровней привилегий – проверки и переключения стеков (stack switching).

Пример инициализирует защищённый режим, после чего передаёт управление пользовательскому коду (с уровнем привилегий 3), который, в свою очередь, дважды вызывает системную функцию (с уровнем привилегий 0), второй вызов переводит процессор в реальный режим и завершает работу программы.

Защита: ввод-вывод

ПРИМЕЧАНИЕ

Когда напишу, тогда и узнаем

Страничная адресация

ПРИМЕЧАНИЕ

Когда напишу, тогда и узнаем

Многозадачность

ПРИМЕЧАНИЕ

Когда напишу, тогда и узнаем

Приложение

ПРИМЕЧАНИЕ

Когда напишу, тогда и узнаем точно

Несколько вопросов, которые, с одной стороны, хочется рассмотреть (потому что интересно или нужно), с другой стороны, не хочется ради этого заводить по отдельной главе на каждый или расширять существующие главы. А именно:

Не вошло

По причине ограниченности моих возможностей, многие интересные смежные темы исключены из рассмотрения. Вам не встретятся:

Выходит за рамки

К теме курса не относятся:

О том, зачем и кому это нужно

Все знают пользу полезного, но никто не знает пользы бесполезного

Чжуан-цзы

Три чукотских мудреца
Твердят, твердят мне без конца
Металл не принесёт плода,
Игра не стоит свеч, а результат – труда
Но я сажаю алюминиевые огурцы а-а, 
на брезентовом поле 

Виктор Цой

Это не нужно почти никому и почти низачем. 99% – умение программировать процессоры Intel x86 в защищённом режиме вам не пригодится никогда вообще, 99.99% – оно пригодится вам не более чем косвенно. Непосредственно «программировать защищённый режим» нужно только при написании некоторых частей ядра ОС. Сколько раз вы писали ядра ОС за последние два года? А, как думаете, сколько напишете в ближайшие 10 лет? Правильно, и я тоже 0, причём на оба вопроса. Но.

В общем, на 99% – just for fun, но про 1% тоже не стоит забывать :)

О принципах создания курса

Есть несколько факторов, мешающих просто и понятно описать защищённый режим:

Тем не менее, я пытался писать именно «просто и понятно», руководствуясь следующим.

Уровень детализации

Сначала два общеизвестных утверждения:

В приложении к курсу, это будет звучать так:

Именно это – выбранный уровень детализации. Описано, зачем вообще нужен защищённый режим, почему он именно такой, и как на его основе реализуются необходимые для работы ОС механизмы. Следующий шаг «вглубь» не делается, рассмотрение базы, на которой построен сам защищённый режим (особенностей реализации процессора) находится далеко за рамками курса.

Эпиграфы

От улыбки хмурый день светлей
От улыбки в небе радуга проснётся

Михаил Пляцковский

Как известно, с музыкой и помирать легче. А уж изучать защищённый режим – тем более. Забавные и не очень, самописные и выдернутые из классиков, эпиграфы предназначены для того, чтобы прогнать излишнюю серьёзность, усталость и напряженность, которые очень мешают думать (они могут помочь делать вид, что думаешь, но это не входит в нашу задачу). В первую очередь, конечно, прогнать от меня – не всё же писать про дескрипторы с таблицами прерываний, надо иногда и отдыхать. Но, надеюсь, вам эпиграфы тоже помогут.

Теория

Всё должно быть просто, настолько просто, насколько возможно, но не проще.

Альберт Эйнштейн

Весь теоретический материал, посвященный защищённому режиму, можно разбить на «ядро» и «всё остальное» так, что:

По моему мнению, при разбиении по этим правилам, в «ядро» входят:

ПРИМЕЧАНИЕ

Кстати, Intel думает похожим образом. Именно это нужно изучить для того, чтобы «по всем правилам» переключаться из реального режима в защищённый и обратно.

Особенность этих тем в том, что их желательно каким-то образом изучать все одновременно, иначе будет довольно трудно понять. К сожалению, я не умею распараллеливать процесс обучения, и прибегаю к многочисленным ссылкам вперёд («предназначение вот этих двух полей будет описано в следующих трёх главах») и назад («как вы помните, этот вопрос подробно обсуждался четыре главы назад»), которые затрудняют восприятие информации. Освоение «ядра» – наиболее сложная часть изучения защищённого режима и именно это – основная задача курса. Поэтому всё, что можно было безболезненно выкинуть из «ядра» – выкинуто.

Так как после изучения и понимания «ядра», остальные темы не должны вызывать особых сложностей, большинство из них не вошли в курс. Вошли только показавшиеся мне наиболее интересными:

Ядро описывается в первых десяти главах, на каждую из «остальных» тем хватило по главе.

Естественно, приведённая в курсе информация, мягко говоря, не полна. Дополнительную информацию можно найти в источниках, перечисленных в библиографии. После изучения курса читать их будет значительно легче.

Примеры

Примеры должны были удовлетворять следующим требованиям:

Поэтому:

Не смотря на все старания, примеры получились довольно объёмные, и, что характерно, чем дальше, тем хуже. Но так как последующие примеры обычно довольно просто получаются из предыдущих, если разбираться в них последовательно, начиная с начала, проблем быть не должно.

Задания

Один сиcтемный администратор другому:
- Мой друг вчера сервер уронил.
- Он что, хакер?
- Он идиот!

Просто анекдот.

Вы будете смеяться, но это курс лабораторных работ для студентов, поэтому он содержит некоторое количество заданий. Я, конечно, не надеюсь, что вы будете их выполнять, но тем не менее…

Исходя из того, что «цель – не продукт, а исследование», задания, так же как и примеры, редко делают что-то полезное. Обычно задание формулируется так: «проверьте утверждение Х» или «что будет если Y». То есть, нужно написать программу, воспроизводящую некоторую ситуацию, запустить её и посмотреть, что получится.

Для многих (но не для всех) заданий «получится» крах системы (аварийная перезагрузка или зависание), не пугайтесь, это нормально. Но просто уронить машину недостаточно (см. эпиграф), само по себе это не принесёт вам знаний. Необходимо добиться устойчивых результатов (не важно каких), после чего проанализировать и, по возможности, объяснить их.

Цель заданий – более свободное обращение с компьютером вообще и с процессором в защищённом режиме в частности. Побочным эффектом является проверка прочитанной и осознанной теории и, в удачном случае, приобретение некоторой уверенности в её правдивости.

ПРИМЕЧАНИЕ

В очень удачном случае, какой-то аспект теории стабильно опровергается, что побуждает нашедшего ошибку погрузиться в эксперименты/документацию значительно глубже, более полно изучить защищённый режим и, в конце концов, выработать более совершенную версию теории.

Специально таких «подстав» не делал.

Общее

Одна глава – одна законченная тема

Одна тема потому, что так проще воспринимать, поэтому лучше три маленьких понятных главы про прерывания, чем одна большая и непонятная.

Законченная тема потому, что к ней можно привести работающий пример. Без примера, опять же, воспринимается плохо.

Понимание полезнее заучивания

Люди, разрабатывавшие защищённый режим, занимались этим не просто так, перед ними стояли некоторые задачи, и не менее некоторые ограничения. Если попытаться представить себе эти задачи и ограничения, можно довольно логично объяснить многие архитектурные решения. Там где у меня есть объяснение, я стараюсь его привести.

Классика

То, о чём говорят все и всегда:

О минимальной конфигурации

Знания

Для понимания механизмов потребуется:

Кроме того, для понимания примеров понадобится:

Железо и ПО

Для запуска примеров необходимо:

Не необходимо, но очень полезно:

Основная польза от виртуальной машины в том, что можно сидеть в DOS и одновременно слушать музыку :) Или читать документацию, если вдруг что-то забудете… Кроме того, последствия (неминуемого, уверяю вас!) краха реальной системы могут быть довольно неприятными, а тут хоть какая-то гарантия.

Об источниках

Список источников приведён в библиографии, но два основных стоит упомянуть отдельно:

ПРИМЕЧАНИЕ

Ещё три слова о примерах из «Assembler. Для DOS, Windows, Unix»:

- их можно скачать с сайта издательства http://www.dmk.ru

- на мой взгляд, автору удалось почти невозможное, его примеры действительно собираются разными версиями ассемблеров! Я оценил масштаб достижения только когда попытался повторить…

- при всём уважении к Сергею Владимировичу, написанный им код я отношу к разряду «с-большим-трудом-читабельного» или «читабельного-только-за-счёт-комментариев» (кстати, за комментарии отдельное большое спасибо). Никак не могу понять, почему он практически не использует такой элемент структурирования кода, как подпрограмма… В своих примерах я постарался не повторять этой ошибки.

Об обозначениях

Ссылка на литературу

В квадратных скобках пишется имя автора и год издания. Например, [Зубков 1999] или [Intel 2004].

Термины

Если термин встречается в тексте первый раз, он выделяется курсивом, в скобках даётся соответствующий английский термин, иногда аббревиатура, иногда альтернативный вариант перевода. Например: термин (term; может переводиться как срок, предел, семестр и т.п.).

Числа

Все числа даны в стандартном ассемблерном формате. То есть:

Другие системы счисления не используются.

Числительные

Я сегодня – не мужчина,
Я сегодня – программист.

Числительные это проблема. Когда нормальный человек засыпает и считает слоников, он нумерует их так: «первый, второй, третий, …». Это грамотно с точки зрения русского языка, считать слоников, начиная с «нулевого», вряд ли кому-то придёт в голову. В результате получается «слон №1, слон №2, слон №3, …».

В программировании (и схемотехнике), увы, не так. Первому элементу последовательности (биты в байте, байты в массиве, линии шины, ножки микросхемы, etc.) принято присваивать номер 0. Если нумеровать элементы по-русски, то есть «первый», «второй», «третий» и т.п., то для того чтобы получить номер, придётся мысленно вычитать единицу, а об этом довольно просто забыть. Если начинать нумерацию с «нулевого», единицу вычитать не надо, но так как все уже более-менее привыкли вычитать, это тоже может привести к неоднозначности. В общем, хорошего простого решения не видно.

Поэтому я выбрал не очень хорошее, зато понятное: всё, что можно нумеровать, нумеруется с нуля. Байт состоит из нулевого, первого, второго, третьего, четвёртого, пятого, шестого и седьмого битов, двойное слово – из нулевого, первого, второго и третьего байта, и т.п. Где уместно, я буду об этом напоминать.

Благодарности

With a little help from my friends

John Lennon

Так или иначе, написать всё это мне помогли (в порядке, близком к хронологическому):

Спасибо им всем!


Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав.