Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Разработка операционных систем - для начинающих и не только!


Информационный Канал Subscribe.Ru

Разработка операционных систем

Выпуск 6 от 2003-05-20

Сегодня в номере:

Intro

Начиная с этого выпуска, уважаемые подписчики, мы по мере надобности будем изучать архитектуру системного уровня процессоров IA-32. Тема очень сложная, поэтому - пишите, если что-нибудь будет непонятно изложено.

Обзор архитектуры IA-32

Напомню, что архитектуру IA-32 (Intel Architecture 32-bit) имеют все 32-разрядные процессоры Intel от Intel386 до Pentium 4 и Xeon. Все они являются обратно совместимыми вплоть до процессора 8086 (который даже к IA-32 не относится, хотя иногда Intel называет его 16-битным IA-32 процессором - получается что-то вроде 16-разрядный представитель семейства 32-разрядных процессоров :)). Другое название этой архитектуры (которое очень любит фирма AMD) - x86 или 80x86.

Эта архитектура занимает лидирующее положение на рынке процессоров для персональных компьютеров. Но за это лидирование фирме Intel пришлось заплатить большую цену - по выражению Энди Танненбаума, при разработке Pentium II основополагающими были 3 фактора:

  1. Совместимость с предыдущими моделями процессоров
  2. Совместимость с предыдущими моделями процессоров
  3. Совместимость с предыдущими моделями процессоров

Необходимость совместимости наложила огромный отпечаток на архитектуру - система команд процессора очень сложна и запутанна, программисту предоставляется слишком мало регистров (и, вследствие чего, зачастую для временного хранения данных приходится использовать оперативную память). По некоторым расчетам, избавившись от вороха старья, тянущегося еще со времен 8080 и 8086, инженеры Intel могли бы повысить производительность процессора на 20-30%.

Тем не менее, нам эту несовершенную архитектуру придется воспринимать как должное, ибо первый аппаратно-зависимый слой нашей ОС будет предназначен именно для нее.

Процессоры IA-32 могут функционировать в двух основных режимах: режиме реальных адресов (или реальном режиме) и защищенном режиме. Так же имеется псевдо-режим виртуального 8086 и режим SMM (system management mode).

В реальном режиме процессор функционирует практически также как 8086, за исключением возможности использовать 32-битные регистры и появившиеся в последующих процессорах новые непривилегированные команды. Еще одна особенность - находясь в реальном режиме, процессор может быть переведен в защищенный режим. Реальный режим предназначен только для совместимости с предыдущими моделями процессоров и механизмов защиты в нем нет

Защищенный режим - основной режим процессора, который должны использовать современные операционные системы, и который позволяет использовать все возможности процессора (включая 32-битную адресацию памяти, все инструкции, аппаратную многозадачность, механизмы защиты и пр.). Впервые защищенный режим появился в процессоре 80286 (тогда он еще был 16-битным) и принял современный вид в процессоре 80386. Процессоры 80386 и все последующие, в отличие от 80286, предоставляют возможность перехода из защищенного режима обратно в реальный

Задача защищенного режима (при условии использования аппаратной многозадачности) может выполняться в режиме виртуального 8086 (VM86) - т.е. в режиме эмуляции 8086, который очень похож на реальный режим. Таким образом, например, осуществляется эмуляция MS-DOS в системе Windows

Режим SMM предназначен для более полного контроля аппаратуры, энергопотребления и пр. Вход в него осуществляется только при получения сигнала на входе #SMI (system management interrupt) процессора. Он предоставляет изолированную среду выполнения (которая не пересекается с другими режимами, в каком бы из них процессор не находился при получении #SMI). Этот режим нам не понадобится и рассматривать его подробно мы не будем

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

Введение в защищенный режим IA-32

Для поддержки различных функциональных возможностей процессора (многозадачность, виртуальная память, мультипроцессорность, обработка прерываний и др.), IA-32 предоставляет набор системных регистров и различных управляющих структур.

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

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

В чем смысл применения сегментации? Она позволяет реализовать механизм защиты на уровне сегментов. Например ядро операционной системы можно (и нужно) разместить в сегменте с уровнем привилегий 0, а пользовательскую программу - в сегменте с уровнем привилегий 3. В результате пользовательская программа не сможет вмешаться в работу ядра ОС.

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

Переключение процессора в защищенный режим (практическая часть)

Размер сегментных регистров в защищенном режиме - 10 байт. Из них 8 недоступны для пользователя и называются теневой частью или кэшем дескриптора. Доступные 2 байта сегментных регистров содержат селектор, формат которого таков:

биты 16-3: номер дескриптора сегмента в таблице (от 0 до 8191)
бит 2: используемая таблица (0 - глобальная, 1 - локальная)
биты 1-0: запрашиваемый уровень привилегий (RPL)

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

Для того, чтобы перевести процессор в защищенный режим нам понадобится глобальная таблица дескрипторов. Она содержит по одному восьмибайтному дескриптору для каждого сегмента. Дескриптор содержит 32-разрядный адрес начала сегмента (База), 20-битный размер сегмента (Лимит) и 12 бит описывающих тип сегмента. Ниже приводится полный формат дескриптора:

          бит 7   бит 6   бит 5   бит 4   бит 3   бит 2   бит 1   бит 0
        +-------+-------+-------+-------+-------+-------+-------+-------+
байт 0  | <--------------- биты 7-0 лимита сегмента ------------------> |
        +-------+-------+-------+-------+-------+-------+-------+-------+

        +-------+-------+-------+-------+-------+-------+-------+-------+
байт 1  | <--------------- биты 15-8 лимита сегмента -----------------> |
        +-------+-------+-------+-------+-------+-------+-------+-------+

        +-------+-------+-------+-------+-------+-------+-------+-------+
байт 2  | <--------------- биты 7-0 базы сегмента --------------------> |
        +-------+-------+-------+-------+-------+-------+-------+-------+

        +-------+-------+-------+-------+-------+-------+-------+-------+
байт 3  | <--------------- биты 15-8 базы сегмента -------------------> |
        +-------+-------+-------+-------+-------+-------+-------+-------+

        +-------+-------+-------+-------+-------+-------+-------+-------+
байт 4  | <--------------- биты 23-16 базы сегмента ------------------> |
        +-------+-------+-------+-------+-------+-------+-------+-------+

        +-------+-------+-------+-------+-------+-------+-------+-------+
байт 5  |   P   |      DPL      |   S   | <------ Тип сегмента -------> |
        +-------+-------+-------+-------+-------+-------+-------+-------+


P - бит присутствия сегмента. Пока мы не реализовываем виртуальную память,
он должен быть всегда установлен в 1

DPL - уровень привилегий дескриптора (Descriptor Privelege Level)
Пока мы используем только нулевой (высший) уровень привилегий

S - указывает является ли дескриптор системным (0) или обычным дескриптором
сегмента кода или данных (1)

Формат четырехбитного поля "тип сегмента" зависит от типа дескриптора.
Более подробно мы рассмотрим его в следующий раз, ну а пока используем
такие значения:
0010 - для дескриптора сегмента данных
1010 - для дескриптора сегмента кода


            7       6       5      4        3       2       1       0
        +-------+-------+-------+-------+-------+-------+-------+-------+
байт 6  |   G   |   B   |   0   |  AVL  |   биты 19-16 лимита сегмента  |
        +-------+-------+-------+-------+-------+-------+-------+-------+


G - бит гранулярности лимита. Если он установлен в 0, то лимит измеряется
в байтах (мы помним, что на лимит отводится 20 бит) и составляет от 0
до одного мегабайта. Если же установлен в 1, то лимит измеряется в
4-килобайтных единицах и составляет тогда от 0 до 4 гигабайт.

B - бит разрядности сегмента (0 - 16-битный сегмент, 1 - 32-битный)

Бит 5 должен быть установлен в 0

Бит 4 не используется процессором и, следовательно, может использоваться
операционной системой



        +-------+-------+-------+-------+-------+-------+-------+-------+
байт 7  | <--------------- биты 31-24 базы сегмента ------------------> |
        +-------+-------+-------+-------+-------+-------+-------+-------+



Фактически, за вход в защищенный режим отвечает нулевой бит регистра CR0, который также называется битом PE (Protection Enable). Но перед включением защищенного режима шестибайтная структура, состоящая из 32-разрядного линейного адреса таблицы дескрипторов (GDT) и 16-битного лимита таблицы (количества элементов таблицы; можно указывать 8192), должна быть загружена в регистр GDTR.

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

И еще один момент - необходимо включить адресную линию A20, которая для совместимости с 80186 отключена при старте компьютера. Если мы этого не сделаем, то все обращения к нечетным мегабайтам памяти будут отображаться на четные, т.е. обращение, допустим, по адресу 1.5 мб на самом деле произойдет по адресу 0.5 мб.

Итак, наша задача такова:

  • Построить GDT с двумя дескрипторами: сегмента кода и данных. Каждый сегмент будет иметь базу 0 и лимит 4 Гб, что покроет всю адресуемую процессором память
  • Включить адресную линию A20
  • Установить бит PE регистра CR0 в 1
  • Выполнить длинный прыжок в 32-битный сегмент
Вот, что у меня получилось:

[BITS 16]
[ORG 0x7c00]
_start:
cli
mov ax, cs
mov ds, ax
mov ss, ax
mov sp, _start

;; Загрузка регистра GDTR:
lgdt [gd_reg]

;; Включение A20:
in al, 0x92
or al, 2
out 0x92, al

;; Установка бита PE регистра CR0
mov eax, cr0
or al, 1
mov cr0, eax

;; С помощью длинного прыжка мы загружаем
;; селектор нужного сегмента в регистр CS
;; (напрямую это сделать нельзя)
;; 8 (1000b) - первый дескриптор в GDT, RPL=0
jmp 0x8: _protected


[BITS 32]
_protected:
;; Загрузим регистры DS и SS селектором
;; сегмента данных
mov ax, 0x10
mov ds, ax
mov ss, ax

mov esi, msg_hello
call kputs

;; Завесим процессор
hlt
jmp short $


cursor:dd 0
%define VIDEO_RAM 0xB8000

;; Функция выполняет прямой вывод в память видеоадаптера
;; которая находится в VGA-картах (и не только) по адресу 0xB8000

kputs:
pusha
 .loop:
lodsb
test al, al
jz .quit

mov ecx, [cursor]
mov [VIDEO_RAM+ecx*2], al
inc dword [cursor]
jmp short .loop

 .quit:
popa
ret


gdt:
dw 0, 0, 0, 0; Нулевой дескриптор

db 0xFF; Сегмент кода с DPL=0
db 0xFF; Базой=0 и Лимитом=4 Гб
db 0x00
db 0x00
db 0x00
db 10011010b
db 0xCF
db 0x00

db 0xFF; Сегмент данных с DPL=0
db 0xFF; Базой=0 и Лимитом=4Гб
db 0x00
db 0x00
db 0x00
db 10010010b
db 0xCF
db 0x00


;; Значение, которое мы загрузим в GDTR:
gd_reg:
dw 8192
dd gdt

msg_hello:db "Hello from the world of 32-bit Protected Mode",0

times 510-($-$$) db 0
db 0xaa, 0x55

Эту программу необходимо откомпилировать с помощью NASM в чистый бинарный формат и записать в загрузочный сектор дискеты (точно также как мы делали это во втором выпуске)

Outro

На сегодня все, уважаемые подписчики
Как всегда, мой почтовый ящик открыт для вас:
lonesome@lowlevel.ru
Также вы можете задавать интересующие вас вопросы в форуме lowlevel.ru
Предыдущие выпуски рассылки вы можете найти по этому адресу:
http://subscribe.ru/archive/comp.soft.prog.osdev
Всего наилучшего!
Lonesome



http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу

В избранное