Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Процессор Intel в защищенном режиме #5

Поиск

FAQ:

- Чето ты с этими лимитами нездорового напорол в спецвыпуске... Какие то «реальные лимиты», «лимиты в натуре» и т.п. Нельзя ли обойтись без подобных медитаций, просто, как есть на самом деле? Вообще все это напоминает недавний бум с миллениумом: в 1999 году все СМИ как один гудели про то, что новое тысячелетие начнется в 2000 году. Потом посчитали и оказалось, что в 2000 начнется только ПОСЛЕДНИЙ ГОД УХОДЯЩЕГО ТЫСЯЧЕЛЕТИЯ, а новое начнется только в 2001... Вот и я туда же - начал выдумывать какие то "реальные лимиты", к-рые соотвествуют "концу последнего байта в сегменте" и т.п. медитации. Хотел как лучше, получилось как всегда...:(Вот КАК В ШЕСТИ СТРОЧКАХ ВСЕ ВЫГЛЯДИТ НА САМОМ ДЕЛЕ, без вольных импровизаций и медитаций:

При G=0: Адрес последнего байта сегмента = Значение поля «База сегмента» + Значение поля «Лимит сегмента»Размер сегмента = Значение поля «Лимит сегмента» + 1При G=1: Адрес последнего байта сегмента = Значение поля «База сегмента» + Значение поля «Лимит сегмента» * 1000h + 0FFFh Размер сегмента = Значение поля «Лимит сегмента» * 1000h + 1000h

Вообще, ВОТ С ЭТОГО и стоило начинать, и на этом и закончить, ато расписал на 2 выпуска + спецвыпуск какой то мути, всех запутал и напугал новичков... Вообще на этой проблеме не стоит сосредотачиваться, нас ждут вещи поважнее.

РЕЗУЛЬТАТЫ КОНКУРСА:

Правильные ответы:

1. Descr_code db 34h,12h,00h,00h,00h,XXh,0X000000b,00h; сегмент с базой = 0 и размером = 1235h 2. Descr_data db 0C8h,0Dh,36h,12h,00h,XXh,0X100000b,00h; сегмент с базой = 1236h и размером = 0DC9h 3. Descr_stack db 0FFh,00h,00h,20h,00h,XXh,1X000000b,00h; сегмент с базой = 2000h и размером = 100000h 4. Descr_code2 db 0DEh,0BCh,01h,20h,10h,XXh,0X001010b,00h; сегмент с базой = 102001h и размером = 0ABCDFh 5. Descr_data2 db 00h,00h,00h,00h,00h,XXh,0X000000b,10h; сегмент с базой = 10000000h и размером = 1 6. Descr_stack2 db 01h,00h,10h,00h,00h,XXh,0X000001b,10h; сегмент с базой = 10000010h и размером = 10002h 7. Descr_LDT db 04h,00h,00h,00h,00h,XXh,1X000000b,20h; сегмент с базой = 20000000h и размером = 5000h

Дополнительные задания:

Ошибка во втором дескрипторе: бит 21 во втором двойном слове дескриптора ДОЛЖЕН ВСЕГДА равняться нулю.

Те, кто знакомы с компиляторами типа TASM без труда смогут загрузить GDTR так:

mov eax,offset GDTmov dword ptr GDTR+2,eaxlgdt fword ptr GDTR(но вообще это забегая вперед)

Краткое содержание предыдущих серий…

Итак, сначала ты узнал, что программа состоит из сегментов и все они расположены в памяти. Каждый сегмент описывает специальная структура – дескриптор. Дескриптор хранится в специальной таблице. Найти в океане памяти таблицу можно по специальному регистру (GDTR, LDTR). Это как в той сказке: на острове – дуб, на дубе ларец, в ларце – яйцо, в яйце – игла и т.д. Ну и с битом гранулярности вроде разобрались (слава Богу!), теперь пора двигать дальше.

Селектор

«Все это хорошо и понятно» - скажешь ты,- «но вот что-то я ничего пока не слыхал про сегментные регистры (ну те самые – CS, DS, SS…). Что-то они себя пока никак не проявили, а мне казалось, что именно ОНИ, как никто другие, должны служить нам при обращении к памяти и все такое…»

Если ты заметил, то мы все это время спускаемся вниз по ступенькам:

сегмент в памяти <---- дескриптор <---- таблица дескрипторов …

Следующей ступенью будет СЕЛЕКТОР. Не правда ли, где-то это слово уже встречалось? Так вот: селектор – это 16-битная структура данных (что??!! ОПЯТЬ??!!!...), которая является идентификатором сегмента.

- Боже ж ты мой! Сколько это будет продолжаться??!! У каждого сегмента есть свой дескриптор, мы уже прекрасно знаем где этот чертов дескриптор расположен, а ты нам подсовываешь еще какой-то «селектор»!!!

… Селектор указывает не на САМ сегмент в памяти, а на его дескриптор, в таблице дескрипторов… СЕЛЕКТОР ЖИВЕТ В СЕГМЕНТНОМ РЕГИСТРЕ (CS, DS…).

-Неужели…?! Ну и хрена с того?

Спокойно!!!! Вот он:

Поле ИНДЕКС (биты 3-15): указывает на один из 8192 дескрипторов в таблице дескрипторов (GDT или LDT). Почему 8192? А какое максимальное число по-твоему влезет в «биты 3-15»? Во-во…

- Подожжи, подожжи… не так быстро… Ведь дескриптор же занимает 8 байт так? А если индекс равен двойке? Так что это, значит, селектор указывает на второй байт дескриптора в таблице или что?

ИЛИ ЧТО! ПРОЦЕССОР УМНОЖАЕТ значение поля ИНДЕКС НА 8 И ДОБАВЛЯЕТ к полученному значению АДРЕС БАЗЫ ТАБЛИЦЫ. Т.е. процессор умножит «двойку» на 8, а потом прибавит значение регистра таблицы – и мы благополучно указываем НА НАЧАЛО ДЕСКРИПТОРА, как не крути!!!

- Как же узнать, из КАКОЙ ИМЕННО ТАБЛИЦЫ дескриптор?

Вот для этого нужен флажок TI (table indicator) (второй бит). Если он = 0, то прибавится значение регистра GDTR (т.е. дескриптор расположен в таблице GDT), если же установлен – LDTR.

- А шо за RPL?

(Requested Privilege Level) Запрашиваемый уровень привилегий… пока его лучше не трогать. Но видишь, пока что, все что нам не знакомо относится к каким то загадочным уровням привилегий…

Теперь внимательно следи: допустим мы ложим в DS число 0000000000110 0 00b. Что это значит? А смотри: сразу разбиваем DS на кусочки (15-3 биты – индекс, 2 – TI, 1-0 – пока лучше не смотрим на них). Индекс равен 6. Значит, шестой по счету дескриптор. А где? В GDT конечно! (TI=0).

Ложим (кладем:) в ES число 0000000001000 1 00b. Восьмой дескриптор! На этот раз в LDT! Разобрались!

- А учитывается ли нулевой дескриптор (null descriptor) при «счете»?

ОБЯЗАТЕЛЬНО! БОЛЕЕ ТОГО! МЫ ДАЖЕ МОЖЕМ ПОЛОЖИТЬ В сегментный регистр (DS, SS…) СЕЛЕКТОР С ПОЛЕМ ИНДЕКС и TI РАВНЫМИ 0!!! Т.е. фактически мы выбираем НУЛЕВОЙ ДЕСКРИПТОР В ТАБЛИЦЕ GDT!!

-Но это же невероятно и невозможно!!!!:)

Возможно… Ничего страшного не произойдет до тех пор, пока мы не ОБРАТИМСЯ К ПАМЯТИ, используя ТАКОЙ сегментный регистр… А так он может хоть сто лет там пролежать, но как только мы обратимся к памяти используя такой регистр (с индексом = 0) – ВСЕ! ХАНА! #GP!!!!

Преобразование логического адреса в линейный

И вот мы подобрались к самому важному моменту: как же все таки процессор формирует адрес и знает куда обращаться? Для этого нужно собрать все полученные нами знания в кучу. Что для этого нужно сделать? Уважаемый читатель, представь, что ты процессор... Допустим, сейчас ты выполняешь какой то код в оперативной памяти. И вот как ты размышляешь: о местоположении в памяти инструкции тебе ничего не известно, кроме того, что на нее указывает CS:EIP. По сути - это логический (т.е. некий абстрактный адрес). Как же найти линейный адрес в памяти, руководствуясь только этими двумя значениями: CS и EIP? Теперь мы можем это сделать! Сразу смотрим в CS и ищем в нем поле "Индекс" (см. на селектор выше). Смотрим в поле индекс и тут же узнаем о местоположении нужного дескриптора в таблице дескрипторов. Далее нам нужно узнать АДРЕС БАЗЫ сегмента. Узнали. Что теперь? Теперь осталось только одно: сложить этот адрес базы с EIP - и мы получим линейный адрес инструкции в памяти (к-рый при сегментной организации совпадает с физическим, мы об этом говорили ранее). Еще раз: селектор-->дескриптор-->база... +EIP = ЛИНЕЙНЫЙ адрес.

Сегментный регистр

В архитектуре процессоров Intel существуют ШЕСТЬ сегментных регистров:

CS, DS, SS, ES, GS и FS. Каждый из этих регистров отвечает за свой сегмент в памяти (кода, данных или стека). Итак, даже если программа состоит из ТЫСЯЧИ сегментов, ТОЛЬКО 6 из них могут быть доступны В ДАННЫЙ МОМЕНТ ВРЕМЕНИ. Другие сегменты станут доступны ТОЛЬКО ПОСЛЕ ЗАГРУЗКИ СООТВ. селекторов в сегментные регистры.

Помнишь, как в реальном режиме формировались линейные адреса? Значение сегментного регистра умножалось на 10h и прибавлялось смещение. Т.е. никакого селектора явно не существовало, никаких дескрипторов, ничего! Только сегментный регистр и смещение! Один шаг до формирования линейного адреса! В защищеном режиме нужно пройти сквозь огонь, воду и медные трубы (селектор-дескриптор- база...) чтобы докопаться до линейного адреса... Итак, в защищенном режиме сегментный регистр - это 16 битный регистр, содержащий информацию о дескрипторе (а именно - местоположении) и запрашиваемом уровне привилегий. Стоп! Здесь сразу же возникает вопрос: неужели же процессор при каждом обращении к памяти все время повторяет одни и те же действия (ищет дескриптор, потом ищет базу, затем прибавляет к базе смещение...), и так при выполнении фактически каждой команды... КОНЕЧНО ЖЕ НЕТ! НА САМОМ ДЕЛЕ сегментный регистр - это 80-битный регистр (!!! да да!!!), нам же доступны ТОЛЬКО младшие 16 бит, которые и называются СЕЛЕКТОРОМ!!! Остальные 64 бита называются "Теневым регистром" (Shadow register) или "Дескрипторным кэшем" (Descriptor cache), ОНИ И СОДЕРЖИТ ТУ САМУЮ БАЗУ, которую проц по идее должен был бы высчитывать на каждом шаге. Кроме базы этот самый "теневой регистр" содержит еще и лимит, и права доступа. Еще раз: как только мы загружаем в ВИДИМУЮ ЧАСТЬ (в селектор) соответствующее значение, процессор СРАЗУ же по селектору (а конкретно - по полю индекс) выпасает базу, лимит и права доступа из дескриптора и заносит их в "теневую часть" сегмнетного регистра, тем самым облегчая себе жизнь в дальнейшем.

А ТЕПЕРЬ ВНИМАНИЕ!!!

Если мы вдруг решим неожиданно поменять значение базы в дескрипторе для какого-либо сегмента, селектор которого в данный момент УЖЕ находится в сегментном регистре, то мы также должны позаботиться и о ПЕРЕЗАГРУЗКЕ сегментного регистра, т.к. в теневой части остануться СТАРЫЕ ЗНАЧЕНИЯ базы и лимита, и фактически процу абсолютно наплевать на то, что твориться в таблице дескрипторов, он руководствуется только ТЕКУЩИМ ЗНАЧЕНИЕМ БАЗЫ И ЛИМИТА В ТЕНЕВОЙ ЧАСТИ. Короче запомни золотое правило: поменял базу (или лимит) в дескрипторе - перегрузи соотв. сегментный регистр!!!

Загрузить сегментные регистры (явно или неявно) позволяют 16 команд:

ЯВНО:

MOV - ну это и так ясноPOP - значение из стекаLDS - загрузить DSLES - загрузить ESLSS - загрузить SSLGS - загурзить GSLFS - загрузить FS

НЕЯВНО:

CALL, JMP, RET, SYSENTER, SYSEXIT, IRET, INTn, INTO, INT3. Чаще всего "неявные" команды изменяют значение именно CS-регистра, но в некторых случаях и других.

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

СТРАНИЧНАЯ АДРЕСАЦИЯ

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

Прежде всего, нужно понять очень важную вещь: при использовании страничной адресации структуры из сегментной адресации (как то – таблицы дескрипторов, селекторы, регистры таблиц дескрипторов) НИКУДА НЕ ДЕВАЮТСЯ! Все остается на своих местах! Так в чем же тогда заключается страничная адресация? Где же она себя проявляет?

ВАЖНЫЙ МОМЕНТ: ЕДИНСТВЕННОЕ МЕСТО, ГДЕ СТРАНИЧНАЯ АДРЕСАЦИЯ ДЕЙСТВИТЕЛЬНО ВКЛИНИВАЕТСЯ В ПРОЦЕСС РАБОТЫ ПРОЦЕССОРА – ПРИ ПЕРЕВОДЕ ЛИНЕЙНОГО АДРЕСА В ФИЗИЧЕСКИЙ! Вот в этом вся соль! ЭТИМ НУЖНО ПРОНИКНУТЬСЯ!

Придется немного прокрутить пленку назад. Вспомни три понятия: логический, линейный и физический адрес. Логический адрес – это некий абстрактный, на деле ничего не значащий адрес, грубо говоря, CS:EIP – это и есть логический адрес, в самом деле, что он может нам сообщить? Ничего. Только то, что если мы вытащим из CS поле индекс, а затем по этому полю найдем в таблице дескрипторов соотв. дескриптор, а затем к базе из этого дескриптора прибавим EIP – то вот только тогда получим ЛИНЕЙНЫЙ адрес. При использовании сегментной адресации физический адрес совпадает с линейным (физический – это адрес который проц выставляет уже на адресную шину). Т.е. при сегментной адресации проц просто берет линейный адрес и без выкрутасов выставляет на адресную шину. При использовании страничной адресации именно на этапе перевода линейного адреса в физический в действие вступают новые силы, о коих и будет поведано ниже...

При использовании страничной адресации линейный адрес не совпадает с физическим, как в случае с сегментной адресацией. Т.е. мы имеем дело с виртуальной памятью. Процессор делит линейное адресное пространство на страницы фиксированного размера (длиной 4Кб, 2Мб или 4Мб), которые, в свою очередь, уже отображаются в физической памяти (или на диске). Когда программа (или задача) обращается к памяти через логический адрес, процессор переводит его в линейный и затем, используя механизму страничной адресации, переводит его в соответсвтующий физический адрес. Если страницы в данный момент нет в физической памяти, то возникает исключение #PF. Это по сути кульминационный момент: обработчик этого исключения (#PF) должен выполнить соответствующие манипуляции по устранению данной проблемы, т.е. подгрузить страницу с харда (или наоборот – скинуть ненужную страницу на диск).

Вообщем, все знают что такое своп-файл в винде? Вот по сути это и есть те самые странички памяти на харде, которые после возникновения #PF должны быть загружены в оперативку (или наоборот). По сути - #PF это не есть нечто ужасное и недопустимое (как #GP). НАОБОРОТ! #PF «нам строить и жить помогает!!!» Без него вообще ничего бы и не получилось по сути то дела!

Как только страница была благополучно водворена на место, то выполнение прерванной проги продолжается с той самой инструкции, которая вызвала #PF. А кстати, какая инструкция может вызвать #PF? Да в принципе любая, которая так или иначе обращается к памяти...

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

Проц всегда, где это возможно, облегчает себе жизнь. Вспомни про «теневую» часть сегментного регистра. Также и в случае со страничной адресацией – страницы, к которым проц чаще всего обращается кэшируются в процессоре, в области, которая называется буфер с ассоциативной выборкой (TLB - Table lookaside buffer). Т.е. не все такие страницы целиком, а только записи, которые необходимы для доступа к ним (см. ниже).

Несколько слов по поводу TLB. Начиная с P6 процев сущестувуют кэши специально для записей, описывающих код и данные, также разные кэши для 4Кб и для 4Мб страниц. Инструкция CPUID позволяет определить размер этих самых TLB в твоем проце. Чем они больше – тем быстрее соответственно будет работать проц. В отличии от теневой части сегментного регистра, куда мы не могли лезть руками и вообще не имели никакого доступа к ней, в TLB мы можем кое что изменять (естественно только в том случае, если мы на самом крутом уровне привилегий, на нулевом). Для этого существует команда INVLPG и др. приемы, на которых не стоит заострять внимания (если кому интересно в подробностях – пишите).

Итак, страничная организация непосредственно в проце управляется тремя флажками:

  1. Флаг PG (paging): бит 31 в регистре CR0. Появился в 386 проце.
  2. Флаг PSE (page size extensions): бит 4 в регистре CR4. Появлися в пнях.
  3. PAE (physical address extension) flag: бит 5 в регистре CR4. Появился в пентиум pro процах.

Теперь подробнее. Флаг PG разрешает страничную адресацию. Сразу после установки его в единицу страничная адресация включена.

Флаг PSE, если его установить, позволяет использовать страницы больших размеров (4Мб и 2Мб). Если сброшен – страницы имеют размер 4Кб.

Флаг PAE позволяет расширить физический адрес до 36 бит (стандартно он 32-х битный). Данный флаг можно использовать ТОЛЬКО в режиме страничной адресации. Узнать, поддерживает ли твой проц данное расширение можно по 17 биту в EDX после CPUID).

Кстати, использовать 36-разрядную адресацию можно как с помощью PAE-флага, так и с помощью PSE-флага, это два разных метода, мы их рассмотрим дальше.

Каталоги и таблицы страниц.

Ну все, хватит лирики, пора приступать к делу. При трансляции линейного адреса в физический (при включенной страничной адресации) процессор использует 4 структуры данных:

1. Каталог страниц – массив 32-битных записей (PDE – page- directory entry), к-рые хранятся в 4Кб странице. Напоминает таблицу дескрипторов, не так ли? А сколько 32-битных записей помещается в 4Кб? Правильно, 1024 штуки. Т.е. всего 1024 PDE- шки...

2. Таблица страниц – массив 32-битных записей (PTE – page-table entry), которые также все расположены в одной 4Кб странице. Т.е. PTE-шек тоже может быть всего 1024 штуки. Забегая вперед – для 2Мб и 4Мб страниц таблица страниц вообще никак не используется – все решают только PDE-шки.

3. Сама страница – 4Кб, 2Мб или 4Мб кусок памяти:)

4. Указатель на каталог страниц – массив 64-битных записей, каждая из которых указывает на каталог страниц. Эта структура данных используется процем только при использовании 36-битной адресации.

Все эти таблицы позволяют обращаться к 4Кб или к 4Мб страницам при 32-х битной адресации и к 4Кб, 2Мб или 4Мб страницам при 36-битной адресации. Смотри на таблицу, какие флаги на что влияют:

Непонятно тут может быть только одно – что за колонка PSE-36? Дело в том, что этот режим работы (PSE-36) появился только в третьих пнях, а доступен он или нет можно узнать посредством CPUID. Как видишь, при использовании PSE-36 механизма доступны только страницы размером 4Мб. Фактически таким макаром можно адресовать 64 Gb физического адресного пространства.

Конечно, на первый взгляд получается несколько туманно и путано, столько флажков, какие то разрядности, но на самом деле все довольно четко и логично, просто надо вникнуть, а потом задать вопросы).

Вообщем, расклад таков: при страничной организации существуют 3 способа адресации: 32-х разрядная, 36-разрядная с использованием флага PAE и 36-разрядная с использованием флага PSE.

Для начала рассмотрим самую простую и наглядную – 32-х разрядную адресацию. Все о чем пойдет дальше речь – справедливо только для нее.



Поделиться:


Последнее изменение этой страницы: 2016-06-22; просмотров: 274; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.226.34.148 (0.011 с.)