Защитен режим

от Уикипедия, свободната енциклопедия
(пренасочване от Protected mode)

Защитен режим (на английски: protected mode) е режим на работа на компютърните процесори в архитектурата x86. При защитения режим максималната адресирана памет е 4 GB (232 байта), има странициране и сегментиране на паметта, както и апаратна защита на достъпа до паметта и входно-изходното пространство. Почти всички съвременни операционни системи за x86 процесори работят изключително в защитен режим (и неговия наследник – long mode, въведен с разширенията x86-64).

История[редактиране | редактиране на кода]

Защитеният режим е въведен за пръв път в 16-битовия процесор 80286 на Intel. Въпреки че 80286 има апаратна защита на паметта, той наследява малкото адресно пространство на своя предшественик Intel 8086 и в резултат 16-битовият защитен режим не получава широко разпространение (дори се стига до това, че в следващите процесори от семейството x86 няма обратна съвместимост със 16-битовия защитен режим на 286).

През 1985 г. Intel пуска на пазара първия 32-битов x86 процесор 80386, който поддържа 32-битовия защитен режим. Към средата на 90-те години на 20 век Microsoft започва да използва предимно 32-битов код в своите операционни системи и оттогава нататък 32-битовият защитен режим става основен режим на работа на x86 процесорите.

Към 2006 г. все още над 95% от софтуера за x86 процесори работи в 32-битовия защитен режим, но започват да се появяват операционни системи и приложни програми, които работят в новия 64-битов защитен режим, въведен от AMD под името long mode.

Технология[редактиране | редактиране на кода]

Тъй като защитеният режим е базиран на реалния режим и наследява повечето му архитектурни особености, тук ще бъдат посочени само разликите с реалния режим.

  • Разширяване на всички регистри от 16 на 32 бита.
  • 4 GB (232 байта) адресно пространство.
  • 64 KB (216 байта) входно-изходно адресно пространство.
  • Сегментиране на паметта с гъвкав размер на сегмента.
  • Странициране на паметта.
  • 2 нови типа данни.
  • 5 нови метода за адресиране.
  • Множество нови инструкции.

Регистри[редактиране | редактиране на кода]

При защитения режим всички регистри стават 32-битови, а имената им се образуват от префикса E и името на съответния 16-битов регистър. 32-битовите регистри с общо предназначение са EAX, EBX, ECX, EDX, ESP, EBP, EDI и ESI, флаговият регистър е EFLAGS, а програмият брояч – EIP. Сегментните регистри си остават 16-битови (но адресът се формира по друг начин), като към вече съществуващите CS, DS, SS и ES се прибавят два нови сегментни регистъра, наречени FS и GS.

Няма директен начин за достъп до старшите 16 бита на 32-битовите регистри EAX, EBX, ECX и EDX, но се запазва възможността за директен достъп до младшия и старшия байт на младшите 16 бита под имената AL, AH, BL, BH и т.н.

Всички нови регистри са достъпни в пълния им 32-битов размер и в реален режим, но подразбиращият се размер е 16-битов и трябва да се използва специален префикс на инструкцията, за да се работи с 32-битовите регистри. В реален режим сегментните регистри FS и GS работят като останалите сегментни регистри и дават възможност за достъп до 6 16-битови сегмента наведнъж.

Типове данни[редактиране | редактиране на кода]

В добавка към типовете данни, които могат да бъдат обработвани в реален режим, в защитения режим могат да бъдат обработвани следните типове данни:

  • 32-битови цели числа без знак. Имат диапазон на възможните стойности от 0 до 232 – 1.
  • 32-битови цели числа със знак. Имат диапазон на възможните стойности от -231 до 231 – 1.
  • низ от байтове. Последователност от байтове с максимален размер до 232 – 1 байта.

Методи за адресиране[редактиране | редактиране на кода]

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

Формиране на адресите[редактиране | редактиране на кода]

Ефективният адрес при защитения режим представлява отместване в рамките на един от текущо използваните сегменти (също като при реалния режим). Ефективният адрес се определя по следния начин:

A = B + I * S + O,

където:

A е полученият ефективен адрес на операнда,
B е базов адрес (задава се в някой от регистрите с общо предназначение),
I е индекс (задава се в някой от регистрите с общо предназначение, с изключение на ESP),
S е мащаб (може да бъде 1, 2, 4 или 8) (задава се като непосредствен операнд в самата инструкция),
O е отместване, което е непосредствено закодирано в самата инструкция като 8-, 16-, или 32-битово число със знак.

Както се вижда, адресирането при защитения режим е значително по-гъвкаво от това при реалния режим. Трябва да се има предвид, че при процесорите, които поддръжат защитения режим, горепосочените разширения в начина на адресиране са достъпни и в реален режим.

Сегментиране на паметта[редактиране | редактиране на кода]

Полученият по посочения в предната точка начин ефективен адрес, всъщност представлява отместване в рамките на сегмент от паметта. Докато в реалния режим сегментите се използват само като средство за преодоляване на ограниченото адресно пространство, в защитения режим сегментите служат изключително за осигуряването на апаратна защита на паметта от непозволен достъп.

В защитения режим сегментите са дълги до 4 GB (232 байта), като началният им адрес, размерът им и другите им атрибути са записани в така наречения сегментен дескриптор. Сегментните дескриптори са подредени в таблица в паметта, наречена дескрипторна таблица. Може да има множество такива таблици, като във всеки един момент трябва да има поне 2 дефинирани таблици – глобалната дескрипторна таблица (GDT), която е една и съща за всички процеси; и локалната дескрипторна таблица (LDT), която може да е различна за всеки процес. Адресите на GDT и LDT се зареждат в специални 32-битови регистри.

Всяка дескрипторна таблица може да съдържа до 213 дескриптора на сегменти (213 – 1 за GDT, защото първият запис не се използва). Сегментните регистри съдържат 16-битов индекс на някои от дескрипторите в GDT или LDT. Един от битовете на индекса определя дали се прави достъп до LDT или GDT, други два определят обявеното ниво на привилегированост на сегмента (използва се при защитата на паметта), а останалите 13 бита съдържат номера на съответния дескриптор на сегмент в съответната таблица.

По отношение на защита на паметта, всеки сегмент има като атрибут т. нар. ниво на привилегированост (цяло число от 0 до 3, като 0 е най-привилегированото ниво). Обикновено операционната система работи на ниво 0, а потребителските програми – на ниво 3. Останалите нива не се използват при повечето съвременни операционни системи.

Действието на защатита на паметта може да бъде обобщено по следния начин:

  • От дадено ниво на привилегированост може да се прави достъп до данни само в същото ниво на привилегированост или в по-малко привилегировано ниво.
  • От дадено ниво на привилегированост може да се викат подпрограми и да се предава управлението само в същото ниво на привилегированост или в по-привилегировано ниво.

Странициране на паметта[редактиране | редактиране на кода]

Полученият след сегментирането линеен адрес съвпада с физическия адрес само ако не е включено страницирането на паметта (страницирането на паметта е опционално и може да се изключи). При включено странициране на паметта, линейният адрес се преобразува във физически по описаната по-долу схема.

Страниците на паметта при защитения режим са с размер 4 KB (212 байта) и са подравнени на гранците 4 KB (по-късно са въведени страници с по-голям размер – 4 MB, за да може да се използват по-големи адресни пространства). 32-битовият линеен адрес може да се разглежда като съвкупност от:

  • Най-старшите 10 бита определят индекс в каталога на страниците, който представлява таблица от 1024 елемента в паметта. Всеки от тези елементи сочи към адреса на една от таблиците на страниците, или към началния адрес на страница от 4 MB; или е невалиден.
  • Следващите 10 бита определят индекс на елемент в таблицата на страниците, която също има 1024 елемента, всеки от които или сочи към страница в паметта или е невалиден.
  • Най-младшите 12 бита от адреса опреледят отместването в рамките на една страница. Ако страницата е с размер 4 MB, то най-младшите 22 бита са отместването в страницата.

Създаването на каталога и таблиците на страниците е задължение на операционната система, като началният адрес на каталога на страниците е записан в един от управляващите регистри на процесора.

Страницирането на паметта осигурява възможност за използването на виртуална памет, тъй като една страница може да бъде обявена за невалидна в таблицата на страниците и всеки достъп до нея предизвиква специално прекъсване, което дава възможност на операционната система да зареди съответната страница в паметта.

В съвременните операционни системи за управление на паметта се използва предимно страницирането, а сегментирането почти не се използва (обикновено всички сегменти са с максимален размер и начален адрес 0, което на практика ги обезсмисля). Това се налага поради факта, че при писането на приложни и системни програми сегментирането създава много главоболия и проблеми, а страницирането е напълно невидимо за потребителските програми.

Защитата на паметта от гледна точка на страницирането е доста „орязана“: в описанието на страницата има само 2 еднобитови флага, които осигуряват следните нива на достъп: забранен всякакъв достъп, разрешено четене и разрешено четене и запис. В по-съвременните x86 процесори (произведени след 2003 г.) е въведен т. нар. NX бит, който показва дали е разрешено изпълнението на програмен код в съответната страница. Това повишава сигурността на операционната система, предотвратявайки една от най-често използваните хакерски атаки – препълването на буфер.

Входно-изходно адресно пространство[редактиране | редактиране на кода]

При защитения режим входно-изходното адресно пространство е със същия размер като при реалния режим (64 KB), но достъпа до него е разрешен само при определени условия:

  • Нивото на привилегированост на текущо изпълнявания процес трябва да е по-голямо от зададеното в двубитовото поле IOPL на регистъра EFLAGS. Естествено, съдържанието на IOPL не може да се променя от задачите с ниско ниво на привилегированост.
  • Ако предната проверка е положителна, то се прави допълнителна проверка чрез така наречената таблица за защита на входно-изходното пространство. Тази таблица съдържа по 1 бит за всеки от адресируемите 64 536 входно-изходни порта, като този бит разрешава или забранява достъпа до съответния порт.

Ако някоя от горните проверки даде отрицателен резултат, следните инструкции не могат да бъдат изпълнени:

  • IN, OUT, INS, OUTS (правят се и двете проверки)
  • CLI, STI (прави се само първата проверка)

Както се вижда, освен достъпа до входно-изходното адресно пространство, се ограничава и способността на програмата да маскира прекъсванията, за да не може да „завземе“ процесорното време, игнорирайки прекъсванията от часовника.

Както полето IOPL, така и таблицата за защита на входно-изходното пространство са специфични за всеки процес, която позволява на операционната система да управлява достъпа до входно-изходното пространство изключително гъвкаво.

Инструкции[редактиране | редактиране на кода]

Следва описание на новите инструкции в сравнение с реалния режим. Трябва да се има предвид, че повечето нови инструкции могат да се използват и в реален режим. Новите инструкции, които могат да бъдат използвани само в защитен режим, са специално отбелязани.

Инструкции за трансфер на данни[редактиране | редактиране на кода]

  • MOVSX – разширяване на операнда от 8 до 16 или от 16 до 32 бита с отчитане на знака и прехвърляне на резултата в регистър с общо предназначение.
  • MOVZX – разширяване на операнда от 8 до 16 или от 16 до 32 бита без отчитане на знака (допълване с нули отляво) и прехвърляне на резултата в регистър с общо предназначение.
  • PUSHA – записване на всички регистри с общо предназначение в стека.
  • POPA – зареждане на всички регистри с общо предназначение от стека.

Инструкции за побитови операции[редактиране | редактиране на кода]

  • BSF, BSR – търсене на първия ненулев бит, започвайки съответно от най-старшия и най-младшия бит на операнда.
  • BT – проверка на даден бит (бита се записва в полето CF на регистъра EFLAGS).
  • BTC – също като BT, като стойността на адресирания бит се променя.
  • BTR – също като BT, като адресираният бит се нулира.
  • BTS – също като BT, като адресираният бит се установява в 1.

Инструкции за работа с низове[редактиране | редактиране на кода]

  • INS – зареждане на низ от порт във входно-изходното адресно пространство.
  • OUTS – запис на низ в порт във входно-изходното адресно пространство.

Инструкции за преход[редактиране | редактиране на кода]

  • ENTER – създаване на стек фрейм (stack frame) на подпрограма.
  • LEAVE – освобождаване на стек фрейм (stack frame) на подпрограма.
  • SETO, SETNE, SETB/SETNAE/SETC, SETNB/SETAE/SETNC, SETE/SETZ, SETNE/SETNZ, SETBE/SETNA, SETS, SETNS, SETP/SETPE, SETNP/SETPO, SETL/SETNGE, SETNL/SETGE, SETLE/SETNG, SETNLE/SETJG – условно установяване на байт.

Инструкции, работещи само в защитен режим[редактиране | редактиране на кода]

  • ARPL – настройка на нивото на привилегированост.
  • LAR – процитане на част от дескриптора на сегмент от паметта.
  • LGDT, SGDT – запис и четене на адреса на глобалната дескрипторна таблица в съответния регистър.
  • LIDT, SIDT – запис и четене на адреса на дескрипторната таблица за прекъсванията в съответния регистър.
  • LLDT, SLDT – запис и четене на адреса на локалната дестрипторна таблица.
  • LMSW, SMSW – запис и четене на младшите 16 бита на регистър CR0.
  • LSL – прочитане на размера на сегмент.
  • LTR, STR – запис и четене на регистъра на задачата.
  • VERR, VERW – проверка на сегмент за право на четене и четене/запис.

Проблеми[редактиране | редактиране на кода]

Като цяло защитеният режим е много гъвкав и напълно задоволяваше нуждите на операционните системи и приложните програми през последните 20 години. Все пак съществуват определени проблеми:

  • 32-битовото адресно пространство дава достъп до 4 GB директно адресирирана памет. Към 2006 повечето персонални компютри все още използват значително по-малко памет, но вече не са рядкост приложенията, за които 4 GB памет са недостатъчно. Този проблем бе разрешен от 64-битовото разширение на архитектурата, наречено x86-64.
  • Повечето съвременни операционни системи не използват механизма за сегментиране на паметта, а само този за странициране на паметта. Това е проблем от гледна точка на сигурността, понеже няма начин да се забрани изпълняването на програмен код в дадена страница, ако процеса има достъп за четене до нея. Този пропуск се използва от хакерите чрез т.нар. атака чрез препълване на буфера, при която се записва и изпълнява програмен код в буферите за данни на програмата. Този проблем бе разрешен с добавянето на специален флаг в дескриптора на страницата, наричан NX бит.
  • Броят на регистрите с общо предназначение на x86 процесорите винаги е бил считан за твърде малък. Свръхбързите кеш памети от първо ниво на съвременните процесори донякъде облекчиха този проблем, но истинско подобрение дойде с въвеждането на x86-64, при което бяха добавени още 8 регистъра с общо предназначение.

Приложения[редактиране | редактиране на кода]

Защитеният режим се използва масово във всички съвременни операционни системи и приложения за x86 процесорите. В бъдеще се очаква плавен преход към 64-битовия long mode (дълъг режим), който е пряк наследник на защитения режим. Новите операционни системи се разработват и за двата режима, но повечето приложни програми ще продължат да работят в защитен режим още дълго време, тъй като 64-битовите операционни системи могат да работят с 32-битови програми.

Процесори, които поддържат защитен режим[редактиране | редактиране на кода]

  • Произведени от VIA: C3, C7.

Вижте също[редактиране | редактиране на кода]

Външни препратки[редактиране | редактиране на кода]