Protected Mode
by Marius Marcu
Memory Managment
Ключ к пониманию Protected Mode лежит в адресации памяти.
Почти все расширенные возможности процессора основаны на этом.
Многозадачность , привилегии , доступ к 4 гигам памяти происходят именно отсюда.
Для 286 с его 24 адресными линиями и 16-битными регистрами , доступ к 4 GB невозможен.
Эти возможности появились в 386.
Виртуальная адресация
Сегменты в защищенном режиме можно разбить на кодовые и сегменты данных.
В отличие от реального режима , процессор рассматривает память виртуально,
что означает,что про реальные физические адреса программы понятия не имеют.
По необходимости , операционная система может поместить код или данные на диск.
Виртуальный адрес - 16-битный селектор плюс 32-битное смещение.
Сначала селектор должен быть загружен в один из сегментных регистров - CS, DS, ES, FS или GS,
а затем уже грузится смещение внутри этого сегмента.
Также нужно понимать тот факт , что селектор - это не реальный адрес памяти.
Это индекс сегментного дескриптора в специальной таблице , или указатель на реальный
адрес . А уже этот адрес, помимо реального физического содержания, содержит в себе
дополнительные битовые атрибуты , характеризующие данный сегмент, размер сегмента.
И уже окончательный адрес памяти строится как комбинация селектора плюс смещения
Дескрипторы
Дескриптор - это специальная структура.Его размер = 8 байт.
Его атрибуты :
* реальный физический стартовый адрес сегмента (32 Bit)
* длина сегмента (20 Bit)
* дополнительные биты : права , тип и т.д.
Следующая картинка показывает дескриптор 80386 :
Дополнительная битовая информация о сегменте хранится в 6 и 7 байтах.
6- байт :
Поле TYPE определяет тип сегмента и набор разрешенных операций:
Следующая таблица дает набор возможных комбинаций типов сегментов :
Номер | Значение TYPE | Тип сегмента | 0 | 000b | Datasegment (read only) | 1 | 001b | Datasegment | 2 | 010b | reserved | 3 | 011b | "expand down" Datasegment | 4 | 100b | Codesegment (not readable, execute only) | 5 | 101b | Codesegment | 6 | 110b | "Conforming"-Codesegment (not readable, execute only) | 7 | 111b | "Conforming"-Codesegment |
Дополнительная информация хранится в 7-м байте :
Пример дескриптора
Создадим дескриптор со следующими характеристиками :
* стартовый физический адрес сегмента - 01F2E3Dh
* длина сегмента - 2 метра (2097152d=200000h)
* это сегмент данных (читаемый и записываемый)
* DPL= 2
* тип сегмента - 80386-segment
Напишем несколько строк асм-кода :
my_descriptor: dw 0200h ; размер сегмента (bit 0..15)
dw 2E3Dh ; базовый адрес сегмента (bit 0..15)
db 1Fh ; базовый адрес сегмента (bit 16..23)
db 11010010b ; доступ и тип
db 11000000b ; дополнительная информация и размер (bit 16.19)
db 0 ; базовый адрес сегмента (bit 24..31)
Первое слово в дескрипторе - размер сегмента. Он у нас 2 метра .
Поскольку размер сегмента больше метра ,
устанавливаем бит granularity в единицу - т.е. размер страницы памяти равен теперь 4 KB (это в 7-м байте).
Поскольку размер в 2 MB характеризует т.н. большой сегмент , нужно выполнить 3 условия :
1. Тип сегмента - 80386 (контролируется битом B в байте 7).
2. Бит Granularity нужно установить в 1 для постраничной организации
размером 4096 byte (G-бит в байте 7).
3 Длину сегмента нужно сконвертировать в формат 4 KB unit
(т.е. разделить размер сегмента на 4096).
2 MB= 2097152d / 4096d=512d= 200h.
Второе слово - это биты с 16 по 32 - содержат базовый адрес сегмента
(в данном случае младшее слово в адресе 001F 2E3Dh, т.е. 2E3Dh)
Третье слово состоит из 2-х байтов. нижний байт включает биты 16..23 базового адреса сегмента
(в нашем примере: 1Fh).Старший байт включает параметры доступа и типа :
Биты доступа / типа : 1 10 1 001 0:
o первый бит слева - сегмент доступен
o следующие 2 бита - уровень привилегии (10 = уровень 2).
o следующий бит=1 - это тип - сегмент
o следующие 3 бита - поле TYPE - сегмент типа 1 (data segment, reading + writing)
o последний бит - ACCESS = 0
4-е слово состоит из 2-х байтов.
Старший , 8-й байт , включает биты 24..31 базового сегментного адреса, в нашем случае (001F 2E3Dh).
7-й байт включает : 16..19 - биты длины сегмента.
Дескрипторные таблицы
Дескрипторы сводятся в линейную таблицу.
В такой таблице может быть не более 8192 дескрипторов ( 64 KB (65536) / 8 = 8192)
"Global Descriptor Table" - GDT .
"Interrupt Descriptor Table" - IDT - включает специальные дескрипторы - гейты - Gates.
Гейт используется для хранения адреса процедуры прерывания.
Операционная система обязана обрабатывать любое потенциальное исключение.
Также дескрипторную таблицу можно создать для любой задачи - это будет LDT.
В следующем примере показаны 3 дескриптора таблицы GDT :
descriptor_0 db 8 dup (?)
descriptor_1 db 8 dup (?)
descriptor_2 db 8 dup (?)
Адрес Самой GDT надо загрузить в регистр GDTR :
GDTSTRUC STRUC
Limit dw ?
BaseAddr dd ?
GDTSTRUC ENDS
gdt_adr GDTSTRUC ?
; определим размер Global Descriptor Table
; размер GDT = 3*8 42 байта
mov [ gdt_adr.Limit ], 3*8
; установим базовый адрес
; преобразование логического адресатипа segment:offset
; в 32-битный линейный адрес
xor eax,eax
mov ax,seg descriptor_0
shl eax,4
add eax,offset descriptor_0
mov [ gdt_adr.BaseAdr ],eax
; загружаем регистр GDTR
lgdt gdt_adr
Селектор
Виртуальный адрес состоит из 2-х частей - селектора и смещения.
Смещение мы только что рассмотрели.
Селектор имеет бит TI ("Table Indicator") , который указывает либо на GDT ,
либо на LDT. Также имеется бит RPL ("Requested Privilege Level") - бит уровня привилегий :
Рассмотрим селектор :
Selector: 02FBh (binary: 0000001011111011b)
TI bit = 0 ==> таблица GDT
RPL = 11b ==> уровень привилегий (3)
Index = 0000001011111b = 05Fh
Для селектора есть особенность - он не может быть загружен напрямую в селектор командой MOV.
А обойти это можно так :
MOV AX,02FBh
MOV DS,AX
Инициализация защищенного режима
Интеловские процессоры при загрузке начинают работать в Realmode .
Protected Mode нужно активировать. Для этого нужно установить бит PE регистра CR0.
Это нельзя сделать напрямую с помощью команды MOV. Это можно сделать так :
mov eax,cr0
or eax,1 ; PE=1
mov cr0,eax
Перед установкой бита PE нужно проинициализировать GDT .
Также необходимо проинициализировать IDT , которая будет обрабатывать
исключения и прерывания.
Для непосредственного перехода из real mode в protected mode нужно сделать
т.н. FAR-JMP (например JMP 02FB:0000).
IDT
Концепция защиты подразумевает , что пользовательские программы выполняются
на ином уровне привилегий , нежели операционная система.
Ошибка внутри пользовательской программы не должна затрагивать работу
самой операционной системы.
Для того чтобы пользовательский процесс общался с операционной системой ,
существуют гейты. Существуют 4 основных типа гейтов :
Gate |
Function |
Call |
Вызов системной подпрограммы |
Interrupt |
прерывания как от железа , так и от софта (INT) |
Trap |
также 2 типа : hardware Interrupts и INT-инструкции |
Task |
команды: CALL, JMP, INT и hardware Interrupts) |
Гейты trap и interrupt отличаются только битом IF ("Interrupt Enable Flag") флагового регистра.
Гейт interrupt сначала обнуляет этот бит , потом восстанавливает его после команды IRET.
Гейт trap его вообще не трогает.
|