Защищенный режим процессора это
- Real-Mode - реальный, системная поддержка в виде BIOS;
- Protected-Mode - защищённый, поддержка Win и никсы;
- Virtual-Mode - для эмуляции реального режима, из защищённого;
- System-Management-Mode – реальный из защищённого, без эмуляции.
В Real-моде, программист полноправный хозяин системы и имеет дело только с физической памятью. Ему доступны буквально все инструкции процессора, прямой доступ к портам оборудования, и многое другое. Здесь не задают вопросов типа “Вы уверены? Да/Нет”, и за необдуманные действия ответственность несёте только вы. Бонусом идёт программирование вообще без системы, на одних только функциях биос (благо его и сейчас эмулируют все EFI). Основной задачей ОС является как-раз абстрагирование пользователя от реальных устройств, которые он может по неосторожности вывести из строя. Одним словом, зевать от скуки тут не приходится, и нужно быть всегда на чеку.
У первых процессоров 8086 шина-адреса(A) была 20-битная. Такая ширина позволяет адресовать всего FFFFF байт памяти. Запускаем виндовый калькулятор, переводим его и BIN, и введём 20 единиц. Именно такой вид имела шина(А) на физическом уровне.
Посмотрим на рисунок, где изображены проводники системной шины, как они идут с процессора. Шина эта – мультиплексная, т.е. единственная и для адреса, и для данных. Сначала на шину выставляется адрес, после которого по ней-же отправляются и данные:
Как видим, увеличение разрядности шины увеличивает кол-во адресуемых ячеек памяти. Это хорошо.. Но регистры ЦП были в то время 16-битными (без приставки ‘E’), и ими можно было дотянуться максимум до 64 Кб физической памяти (см.рис). Как вместить в 16-битный регистр 20-битный адрес? Было решено разбить всю память на логические сегменты, и адресовать её через регистровую пару в формате сегмент+смещение. Формула и вид получился такой:
Здесь видно, что три средние тетрады перекрываются. Для сегментных регистров типа СS остаются только смещённые влево 4-бита, которыми можно выбрать один из 16-ти сегментов. Под смещение выделяется как и прежде 16-бит, а это 64 Кб внутри выбранного сегмента памяти. Таким образом, размер сегмента в реальном режиме равен 64К, а всего сегментов =16. В сумме они дают: 64К х16=1М памяти.
Однако это не табу, и ничто не мешает нам перевернуть ‘пластинку’ наоборот, ведь мы имеем дело с логическим адресом. Тогда получим 65.536 сегментов, по 16-байт в каждом. Эти 16-байт назвали ‘параграф’ и это мин.размер одного сегмента в R-моде. Такая картина позволяет операционной системе (например DOS) эффективно распределять память, которой и так с гулькин-нос. Сегменты по 64К бывают только на бумажке, а на практике - это просто макс предел, который выделяет ОС под один сегмент.
Во-первых, среди одного мегабайта, 64К непрерывной памяти у системы может и не быть, а во-вторых - если у программы в сегменте-данных всего три строчки текста, зачем выделять для них 64К памяти? Система просто выравнит эти данные до 16-байтного параграфа, и вручит их пользователю. Если (в процессе работы) программе понадобится ещё доп.памяти, то программист должен запросить её у системы, и она без проблем выделит из своего резерва кусок (если таковой остался).
На рисунке выше, я выделил красным одну из линий шины-адреса и вставил туда ключ. Эту линию назвали А20 , поскольку она идёт следующей от 20-битного адреса 0-19. Программист обязательно должен включить её при переводе процессора из реального в защищённый режим работы, иначе не видать нам четырёх гигов памяти. Если линия А20 отключена (а она отключена по-умолчанию), то после 20-битного адреса 0xfffff счётчик адресов опять сбросится в нуль, не давая нам вылезти из первого мегабайта. На аппаратном уровне линией А20 управляет чипсет, через порт 92h системной логики.
Асматикам старой школы издавна не давала покоя мысль, поиметь 4 гига в реальном режиме. Это открывало большие перспективы, поскольку в R-моде нет многозадачности, и все ресурсы процессора полностью принадлежат только одному приложению. На современных процессорах, оно будет летать как истребитель. И нужно сказать, что энтузиастам это удалось! 4Gb памяти в реальном режиме это не сказка, а недокументированный режим, который назвали UnReal-Mode (можете погуглить).
Если коротко, то выделяется один сегментный регистр (как правило ES), который будет играть роль торпеды в 4Gb пространство. Для него подготавливается соответствующий дескриптор с базой(0) и лимитом в 4Gb. Запихать этот дескриптор в ES находясь в реальном режиме процессор не позволит, поэтому нужно перевести его в защищённый режим, обновить ES и вернуться обратно в R-моду. Теперь через ES можно гулять по 4G пространству, как у себя дома. Позже, когда приём вылез из хакерских нор и получил огласку, его взяли на вооружение чуть-ли не все досовские игры. В практической части мы ещё вспомним про UnReal, а пока топаем дальше..
2.1. Память защищённого режима
Процессор переводится в Рrotected-моду всего одним\нулевым битом в регистре CR0 . Сразу-же о сегментной памяти реального режима можно забыть. Хотя сегменты по-прежнему и присутствуют, они несут в себе уже другую нагрузку. Адрес теперь не состоит из двух составляющих Seg:Offs , а вся память приобретает плоский FLAT вид. В игру вступают защитные механизмы, которыми природа щедро одарила этот режим.
- CS – Code Segment – сегмент кода;
- DS – Data Segment – сегмент данных;
- SS – Stack Segment – сегмент стека;
- ES – Extended Segment – дополнительный для данных;
- GS – General Segment – добавлен для РМ-моды
- FS – Безымянный (сл.по алфавиту) для РМ-моды.
По большому счёту, возиться с дескрипторами приходится только тем, кто пишет свою ОС. В остальных случаях они уже настроены системой и трогать их не имеет смысла. Поэтому обратим внимание только на основные моменты.
Логический адрес состоит из сегмента+смещения, например CS:EIP, DS:ESI, ES:EDI и т.д.. MMU собирает эти составляющие, преобразуя лог.адрес в линейный, в диапазоне 0..N. Если в регистре CR0 включён страничный режим, то в дело вступает транслятор страниц в MMU. Если-же страничное преобразование выключено, то линейный адрес совпадает с физическим (здесь он выключен). На рисунке ниже, в сегментных регистрах лежит 2-байтный селектор сегмента, адрес процессора – это смещение, сегментацией и трансляцией занимается блок MMU процессора, РА – это PhysicalAddress:
Таким образом, память в защищённом режиме работы процессора – вся линейна. Сегментные регистры служат только для защиты доступа к памяти. В дескрипторах всех сегментных регистров, всегда устанавливается база(0) с максимальным лимитом в 4Gb, и никак иначе. Транслятор страниц постоянно включён, и разбивает большие сегменты на мелкие страницы памяти, размером по 4К-байт каждая. Любая из страниц имеет свои атрибуты защиты, не считая защиты верхнего уровня родительских сегментов. Это огромная корпорация, которая следит за всеми, и жёстко пресекает любое нарушение установленных прав. Одним словом – защищённый режим это руль! ..который позже согнём в баранку.
----------------------------------------
PS\\: Кстати в отладчике OllyDbg можно наглядно увидеть значения дескрипторов в шести сегментных регистрах. Как-видим, особняком стоит тут только FS , который система всегда держит при себе, и программисту трогать его не советует. Это указатель на системную таблицу РЕВ - Process Environment Block, куда система сбрасывает информацию о текущем процессе – т.н. окружение процесса.
Для того, чтобы писать операционку, нужно разбираться во многих деталях. Вот давайте я вас немного просвещу, (но давайте договоримся, что маны вы будете читать сами, чтобы было о чём побеседовать).
Честно говоря, на просторах сети есть туча тучная материалов по PM, да и ileyи pehat несколько рассказали об этом режиме, но меня попросили всё равно описать в общих рамках его. Сейчас кратко выдам теорию (вообще то специально для этого Intel маны писала), потом начнём писать код.
Введение в защищённый режим.
Итак, PM значительно отличается от всем привычного ещё со времён DOS’a реального режима (RM). Теперь придётся привыкать: здесь нет статичных, 64 килобайтных сегментов, таблицы прерываний в 1’ом килобайте, адресов баз сегментов в сегментных регистрах, в общем совершенно новый мир.
Теперь сегменты описываются в Global Descriptor Table (GDT). Сия таблица может быть только в одном экземпляре. Она структура в памяти. Не сегмент! Может располагаться в памяти где угодно, но её адрес и лимит записываются в регистр GDTR. Вот его структура:
1. Segment Limit:
Назначение этого поля понятно по названию, но есть тонкость. Собака зарыта в бите G (Granularity).
Если он неустановлен, то память ‘отсчитывается’ в байтах. В таком случае размер сегмента может варьироваться от 1 байта до 1 мегабайта на размер в 1 байт.
Если установим его в 1, то будет введена страничная адресация памяти. Тогда мы сможем адресовать от 4 килобайт до 4 гигабайт оперативки с изменением размера на 4 килобайта (размер страницы). Вообще страничная адресация предпочтительней (сравните (1Мб+64Кб-16байт) и 4Гб ). Давайте в этом посте поговорим только о сегментной адресации. Paging заслуживает отдельного разговора.
2. Base Address:
Здесь указываем физический адрес базы.
3. Type field:
Комбинации битов определяют тип сегмента:
4. S (descriptor type):
В документации интеловской сказано, что если этот бит не установлен, то этот дескриптор для системного сегмента, иначе – кода или данных. Под системным подразумевается LDT, TSS, Interrupt Gates и иже с ними (о них позже).
5. DPL (Descriptor Privilege Level):
Привилегии описываемого сегмента. Всем знакомые Rings.
7. D/B:
Для сегментов разного типа по-разному трактуется.
1. Для сегментов кода:
32 или 16 битная длина эффективного адреса и размерность операндов.
(1-32; 0-16);
2. Для стека:
Указатель стека 32 или 16 битный. (1-32; 0-16);
8. G:
Влияет на то, в каких единицах (байты, страницы) измеряется лимит сегмента. Вообще Paging можно включить при переходе в PM, установив 31 бит регистра CR0.
Ещё немного информации:
Догадываемся, что слово Global поставили не напрасно. Значит есть ещё какая-то табличка. Верно, есть также Local Descriptor Table. Их может быть великое множество. К примеру они могут использоваться в реализации задач и.т.д. А вот LDT уже представляет собой сегмент! Так что привыкайте к фразам типа ‘дескриптор сегмента локальной таблички дескрипторов’.
После того, как мы описали таблицу, нужно ей загрузить в регистр GDTR. Это делается далеко не mov’ом. GDTR заполняется командой lgdt fword (значение). То есть надо сформировать самостоятельно эту структуру и загрузить в вышеупомянутый регистр. Есть ещё команды работы с этим регистром, но мы несёмся галопом по Европам.
Ещё один момент. В PM в сегментных регистрах хранятся не базовые адреса сегментов (как в RM), а специально обученные штуки, под названием селекторы. Их структура такова:
Здесь Index – порядковый номер дескриптора в таблице.
TI показывает где искать дескриптор (в GDT или LDT).
Теперь, когда уже понятно как строить таблицу, поговорим о том, как перейти в PM (замечу, это можно сделать только из RM). Вообще … нужно всего установить бит 0 управляющего регистра CR0. Хотя вру. Для начала нужно запретить все прерывания (NMI (Non Maskable Interrupts) в том числе), открыть адресную линию A20 (чтобы была доступна 32-битная адресация), загрузить GDTR, и прыгнуть на метку – старт.
Давайте воспользуемся загрузчиком (можно KOLIBRI’ский взять), который будет грузить наш код по адресу 1000h:0 (RM’овский, замечу, адрес).
Здесь будет не всё так гладко, как в тех манах, когда в PM переходят прям из бутлоадера. Всё чуточку сложнее. Но сначала давайте разберём код, который бутлоадер будет загружать (всё пишем на FASM'е). Это своеобразный helloworld. Загрузимся, перейдём в PM и напечатаем приветствие. Всё.
format binary
xor ax,ax
cli ;реинициализируем сегментные регистры
mov ss,ax
xor sp,sp
sti
mov ax,3
int 10h
mov ax,1000h;перенастраиваем регистры
mov ds,ax
mov es,ax
in al, 0x92;включаем A20
or al, 2
out 0x92, al
cli ;запрещаем прерывания
mov al,8Fh;запрещаем NMI
out 70h,al
in al,71h
lgdt fword [GDTR];загружаем регистр GDTR
mov eax,cr0
or al,1;устанавливаем 0-вой бит
mov cr0,eax;включаем PM
jmp fword 08h:Startup32; прыгаем в PM
align 8 ;процессор быстрее обращается с выравненной табличкой
GDT:
dq 0 ;пустой
db 0FFh,0FFh,0,0,0,9Ah,0CFh,0 ;код
db 0FFh,0FFh,0,0,0,92h,0CFh,0;данные
db 0FFh,0FFh,0,80h,0Bh,92h,40h,0 ;видеосегмент
label GDT_SIZE at $-GDT
GDTR:
dw GDT_SIZE-1
dd GDT+10000h
; нужно записать 32-битный адрес. Сейчас мы находимся в сегменте 1000h, база которого 1000h*10h (по ;физическому адресу) => физический адрес GDTR (метки!) = 10000h (физический адрес базы сегмента)+offset
virtual ;теперь, фактически, забиваем пространство до конца сегмента
rb 10000h-$;
end virtual
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;PM32 Entry;;;;;;;;;;;;;;;;;;;
use32
org $+10000h;вот для чего: в PM мы работаем с Flat-сегментами, и если мы оставим код ;для PM перед org’ом, то ;внутрисегментный адрес не будет совпадать с Flat адресом. Так вот.
Startup32: ;точка входа в PM
mov ax,10h ;здесь пихаем селекторы. Зачастую (! не забываем про порядковый номер в
mov es,ax ;таблице) селектор сегмент кода - 08h. данных - 10h, видеосегмент - 18h
mov ds,ax
mov fs,ax
mov ss,ax
mov esp,10000h;стек
mov ax,18h
mov gs,ax
mov esi,hi_string ;покажем, что мы удачно перешли
call print
jmp $
;ESI - адрес строки
print:
pushad
xor ebx,ebx
mov ah,07h;атрибут
puts:
mov al,[esi+ebx]
mov [gs:(ebx*2)],ax
inc ebx
test al,al
jnz puts
popad
ret
hi_string db ‘Welcome to PM, dude’,0
Что мы сделали? Загрузчик нас успешно загрузил по адресу 1000h:0, откуда мы и продолжили выполнение. Сначала включили А20, запретили все прерывания, загрузили в GDTR подходящее значение, прыгнули на метку входа. Замечу, что прыгали мы на
jmp fword 08h:Startup32
Т.е 08h — селектор дескриптора кода. Привыкайте.
Теперь как сие чудо запустить. Лично я пользуюсь WinImage и VirtualBox. Запихиваем загрузчик в бутсектор дискеты и кладём .bin’овский файл в корень. Сохраняем в .vfd, прописываем путь к образу дискеты в свойствах виртуальной машины, запускаем и видим результат.
В следующем выпуске рассмотрим interrupts, faults, traps, aborts и как они работают, ловятся и отлаживаются. Начнём говорить об архитектуре.
Источники информации.
1) Сразу хочу выразить благодарность Phantom_84 aka egos за то, что указал на путь истинный и помог мне в самом начале. Без него мне было бы гораздо труднее разобраться.
2) Статьи BrokenSword’a Статьи BrokenSword’a. На них стоит обратить внимание.
3) Intel System Programming Guides
В отличие от реального режима, когда в сегментном регистре находится базовый адрес сегмента, в защищенном режиме в нем находится более сложная информация, которая называется селектором. Селектор служит для поиска дескриптора (описателя) сегмента в таблице. Относительный номер дескриптора в таблице называется INDEX. Его значение указывается в селекторе с 3 по 15 разряд. Остальные разряды используются следующим образом.
RPL – уровень прав доступа вызывающей программы.TI – тип дескрипторной таблицы: 0 - глобальная дескрипторная таблица, 1 - локальная дескрипторная таблица.
Защищённый режим (режим защищённой виртуальной адресации) — режим работы процессора. В защищённом режиме процессор может адресовать до 16 Мбайт виртуальной памяти за счёт изменения механизма адресации. Логический адрес преобразуется в физический адрес автоматически с помощью схемы управления памятью (MMU). Благодаря защищённому режиму, в памяти может храниться только та часть программы, которая необходима в данный момент, а остальная часть может храниться во внешней памяти (например, на жёстком диске). Следовательно, становятся допустимыми программы, размер которых больше объема имеющейся памяти, и пользователю кажется, что он работает с большей памятью, чем на самом деле.
Физический адрес формируется следующим образом. В сегментных регистрах хранится селектор, содержащий индекс дескриптора в таблице дескрипторов (13 бит), 1 бит, определяющий к какой таблице дескрипторов будет производиться обращение (к локальной или к глобальной) и 2 бита запрашиваемого уровня привилегий. Далее происходит обращение к соответствующей таблице дескрипторов и соответствующему дескриптору, который содержит начальный 24-битный адрес сегмента, размер сегмента и права доступа, после чего вычисляется необходимый физический адрес путём сложения адреса сегмента со смещением из 16-разрядного регистра.
В 1976 году фирма Intel закончила разработку 16-разрядного микропроцессора i8086. Он имел разрядность регистров 16 бит и системной шины адреса 20 бит, за счет чего мог адресовать до 1 Мбайт оперативной памяти.
В 1982 году был создан i80286. Этот микропроцессор представлял собой улучшенный вариант i8086. Он поддерживал уже несколько режимов работы: реальный, когда формирование адреса производилось по правилам i8086, и защищенный, который аппаратно реализовывал многозадачность и управление виртуальной памятью, i80286 имел также большую разрядность шины адреса — 24 разряда против 20 у i8086, и поэтому он мог адресовать до 16 Мбайт оперативной памяти. Первые компьютеры на базе этого микропроцессора появились в 1984 году.
В 1985 году фирма Intel представила первый 32-разрядный микропроцессор i80386, аппаратно совместимый снизу вверх со всеми предыдущими микропроцессорами этой фирмы. Он был гораздо мощнее своих предшественников, имел 32-разрядную архитектуру и мог прямо адресовать до 4 Гбайт оперативной памяти. Микропроцессор i386 стал поддерживать новый режим работы — режим виртуального i8086, который обеспечил не только большую эффективность работу программ, разработанных для i8086, но и позволил осуществлять параллельную работу нескольких таких программ.
В настоящее время микропроцессор с 32-битной Intel-архитектурой может работать в одном из четырех режимов:
- реальный режим
- системный режим
- защищенный режим
- режим виртуального i8086
Реальный режим (Real Mode)
После инициализации (системного сброса) центральный процессор находится в реальном режиме. В реальном режиме центральный процессор работает как очень быстрый i8086 с возможностью использования 32-битных расширений. Механизм адресации, размеры памяти и обработка прерываний (с их последовательными ограничениями) микропроцессор 8086 полностью совпадают с аналогичными функциями других микропроцессоров с 32-битной Intel архитектурой в реальном режиме.
Режим системного управления (System Management Mode).
Защищенный режим (Protected Mode)
Защищенный режим является основным режимом работы микропроцессора. Ключевые особенности защищенного режима: виртуальное адресное пространство, защита и многозадачность. В защищенном режиме программа оперирует с адресами, которые могут относиться к физически отсутствующим ячейкам памяти, поэтому такое адресное пространство называется виртуальным . Размер виртуального адресного пространства программы может превышать емкость физической памяти и достигать 64Тбайт.
Виртуальный режим i8086 (V86)
В режим V86 процессор может перейти из защищённого режима, если установить в регистре флагов EFLAGS бит виртуального режима (VM-бит, бит 17). Когда процессор находится в виртуальном режиме, его поведение во многом напоминает поведение процессора i8086. В частности, для адресации памяти используется схема , размер сегмента составляет 64 килобайта, а размер адресуемой в этом режиме памяти — 1 мегабайт. Виртуальный режим предназначен для работы программ, ориентированных на процессор i8086 (или i8088). Но виртуальный режим – это не реальный режим процессора i8086, имеются существенные отличия. Процессор фактически продолжает использовать схему преобразования адресов памяти и средства мультизадачности защищённого режима.
В виртуальном режиме используется трансляция страниц памяти. Это позволяет в мультизадачной операционной системе создавать несколько задач, работающих в виртуальном режиме. Каждая из этих задач может иметь собственное адресное пространство, каждое размером в 1 мегабайт.
Все задачи виртуального режима обычно выполняются в третьем, наименее привилегированном кольце защиты. Когда в такой задаче возникает прерывание, процессор автоматически переключается из виртуального режима в защищённый. Поэтому все прерывания отображаются в операционную систему, работающую в защищённом режиме.
Обработчики прерываний защищённого режима могут моделировать функции соответствующих прерываний реального режима, что необходимо для правильной работы программ, ориентированных на реальный режим операционной системы MS-DOS.
Режимы работы микропроцессора. Персональный компьютер, в зависимости от микропроцессора, может работать в однозадачном режиме, многозадачном режиме, в режиме виртуальных машин. В однозадачном режиме, находиться в оперативной памяти и выполняться может только одна пользовательская программа; в многозадачном режиме в памяти хранятся и попеременно выполняются несколько пользовательских программ, при этом возможны два варианта многозадачности-однопользовательский многозадачный и многопользовательский многозадачный режим; система виртуальных машин означает имитацию одновременной работы нескольких процессоров. Основной признак виртуальности микропроцессора- это не только многозадачность, но и возможность одновременной работы на компьютере нескольких операционных систем. Такой режим работы предусмотрен технологией IVT (Intel Virtualisation Technology), поддерживаемой современными процессорами Intel. Сходная по назначению технология, называемая AMD-V (AMD Virtualisation), используется и в микропроцессорах компании AMD.
Процессоры могут работать в различных режимах. Под термином «режим» подразумевается способы, которым процессор создает (и обеспечивает) для себя рабочую среду. Режим работы процессора задает способ адресации к оперативной памяти и способ управления отдельными задачами. Процессоры персональных компьютеров могут работать в трех режимах: реальном, защищенном и виртуальном режимах.
Реальный режим
Это режим работы первых 16-битовых микропроцессоров. Наличие его обусловлено тем, что необходимо обеспечить в новых моделях микропроцессоров функционирование программ, разработанных для старых моделей.
Защищенный режим (protected mode)
Означает, что параллельные вычисления могут быть защищены программно-аппаратным путем.
Позволяет полностью использовать все возможности, предоставляемые микропроцессором. Все современные многозадачные ОС работают в этом режиме.
Создан для работы нескольких независимых программ. Для обеспечения совместной работы нескольких задач необходимо защитить их от взаимного влияния, взаимодействие задач должно регулироваться.
Программы, разработанные для реального режима, не могут функционировать в защищенном режиме. (Физический адрес формируется по другим принципам.)
Читайте также: