Федеральное агентство по науке и образованию

Тверской государственный технический университет

Кафедра ЭВМ

Переключение в защищенный режим и возврат в реальный режим. Страничная адресация.

Методические указания к лабораторной работе по курсу

«Организация ЭВМ, комплексов и систем»

для студентов специальности 23.01

«Вычислительные машины, комплексы, системы и сети»

Тверь

2009 г


Методическое указание разработано в соответствии с рабочей программой по дисциплине «Организация ЭВМ, комплексов и систем» для студентов специальности 23.01. Предназначено для оказания помощи студентам в подготовке к выполнению лабораторных работ по данной дисциплине.

Составили: к. т.н.

студент

© Тверской государственный технический университет

Оглавление

1. Введение - 4

1.1. Основы защищённого режима. 4

1.2. Адресация памяти в защищённом режиме. 5

2. Структуры данных защищённого режима - 7

2.1. Дескриптор сегмента - 7

2.2. Селектор сегмента - 9

2.3. Глобальная дескрипторная таблица - 10

3. Пример программы защищённого режима - 11

3.1. Подготовка таблицы глобальных дескрипторов GDT - 11

3.2. Инициализация необходимых дескрипторов в GDT - 13

3.3. Загрузка в регистр gdtr адреса и размера таблицы GDT - 14

3.4. Запрет обработки аппаратных прерываний - 14

3.5. Переключение микропроцессора в защищенный режим - 15

3.6. Организация работы в защищённом режиме - 16

3.7. Подготовка к возврату в реальный режим - 17

3.8. Переключение микропроцессора в реальный режим - 18

3.9. Разрешение прерываний - 18

НЕ нашли? Не то? Что вы ищете?

3.10. Стандартное для MS-DOS завершение работы программы - 19

4. Страничная организация памяти - 19

4.1. Подготовка каталога страниц - 21

4.2. Подготовка таблицы страниц - 22

4.3. Загрузка регистра CR3- 23

4.4. Включение страничного преобразования - 23

5. Литература - 25

6. Листинг программы-- 26

1.  Введение

1.1.  Основы защищённого режима.

Микропроцессоры Pentium, так же, как и его предшественники (начиная с 80268), могут работать в двух режимах: реального адреса и виртуального защищенного адреса. Обычно эти режимы называют просто реальным и защищенным. В реальном режиме 32-разрядные микропроцессоры функционируют фактически так же, как МП 86 с повышенным быстродействием и расширенным набором команд. Многие весьма привлекательные возможности микропроцессоров принципиально не реализуются в реальном режиме, который введен лишь для обеспечения совместимости с предыдущими моделями процессоров.

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

Сюда можно отнести:

·  Увеличение адресуемого пространства до 4 Гбайт;

·  Возможность работать в виртуальном адресном пространстве, превышающем максимально возможный объем физической памяти и составляющем огромную величину 64 Тбайт;

·  Организация многозадачного режима с параллельным выполнением нескольких программ (процессов);

·  Страничная организация памяти, повышающая уровень защиты задач;

1.2.  Адресация памяти в защищённом режиме.

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

Для обращения к памяти используется пара 16-разрядных регистров: сегментный регистр и смещение.

        В сегментном регистре находится адрес сегмента. Сегмент - это область памяти размером в 64 Кб, которая должна начинаться на границе параграфа или, другими словами, на 16-байтной границе, то есть сегмент может начинаться только по адресу 0, 16, 32, 48 и т. д. Адресное пространство процессора 8086 равно одному мегабайту - это адреса в диапазоне от 00000h до FFFFFh. Информация об адресе содержится в старших четырёх шестнадцатеричных разрядах - их и хранят в сегментном регистре. Другими словами, можно взять значение из сегментного регистра, умножить его наh) и получится адрес начала сегмента.

        Для указания конкретного адреса внутри сегмента используется второй 16-разрядный регистр, так называемое смещение. Использование пары регистров сегмент:смещение обеспечивает доступ ко всему мегабайту адресного пространства.

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

физический_адрес = сегмент * 10h + смещение.


        Теперь давайте рассмотрим схему образования адреса в защищённом режиме, как это происходит в процессоре iэто базовая модель для любого Pentium-а).


        Адрес памяти в 32-разрядном процессоре является также 32-разрядным. Это значит, что адресное пространство для такого процессора равно 4 Гббайт).
        Адресация памяти также производится через сегмент и смещение в сегменте, для чего используется пара регистров, но для описания сегмента используется специальная структура – дескриптор сегмента, который хранит:

·  32-разрядный адрес начала сегмента (база);

·  20-разрядный предел сегмента (предел = размер - 1);

·  Номер уровня привилегий сегмента;

·  Тип сегмента (код, стек, данные или системный объект);

·  Права доступа к сегменту

·  Атрибуты сегменты

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

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

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

        Процессор измеряет размер сегмента двумя типами величин: либо байтами, либо страницами. Страница - это блок памяти размером в 4Кб.
        В описании сегмента можно указать, в каких единицах измеряется сегмент и тогда можно получить два типа сегментов с максимальными размерами:

·  в 1Мб байт ) или

·  в 4Гб страниц = 2 20 * 4Кб = 2 20 * 2 12 = 2 32 байт )

        Эта способность измерять сегмент либо байтами, либо страницами, называется гранулярностью.

        Значение предела сегмента может быть любым, от 0 до 2, гранулярность устанавливается по усмотрению программиста и может быть либо байтная, либо страничная. Всё это позволяет определять сегменты размером до 4Гб.

2.  Структуры данных защищённого режима

2.1.  Дескриптор сегмента

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

Сегмент определяется в виде структуры данных, которая называется дескриптор. Размер дескриптора - 8 байт.

        Ниже приведен формат дескриптора:

Адрес сегмента - также называется базовым адресом, - 32-разрядный адрес области памяти, с которой начинается сегмент.

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

Бит A (Acessed) - бит доступа в сегмент. Этот бит показывает, был ли произведен доступ к сегменту, описываемому этим дескриптором, или нет

Тип сегмента - трёхбитовое поле, определяющее тип сегмента

Тип

Назначение сегмента

000

Сегмент данных, только для чтения

001

Сегмент данных с разрешением чтения и записи

010

Не определено

011

Сегмент стека с разрешением чтения и записи

100

Сегмент кода с разрешением только выполнения из него

101

Сегмент кода с разрешением выполнения и чтения из него

110

Подчинённый сегмент кода с разрешением только выполнения из него

111

Подчинённый сегмент кода с разрешением выполнения и чтения из него

Бит S (System) - определяет системный объект. Если этот бит установлен, то дескриптор определяет сегмент кода или данных, а если сброшен, то системный объект (например, сегмент состояния задачи, локальную дескрипторную таблицу, шлюз).

Поле DPL (Descriptor Privilege Level) - Уровень привилегий, который имеет объект, описываемый данным дескриптором. Это двухбитовое поле, в него при создании дескриптора записывают значения от 0 до 3, определяющее уровень привилегий.
Бит P (Present) - Присутствие сегмента в памяти. Если этот бит установлен, то сегмент есть в памяти, если сброшен, то его нет

Бит U (User) - Бит пользователя. Этот бит процессор не использует и позволяет программе использовать его в своих целях.

Бит X - Зарезервированный бит. Intel не рекомендует использовать этот бит, так как он может понадобится в более поздних моделях процессоров.

Бит D (Default size) - Размер операндов по умолчанию. Если бит сброшен, то процессор использует объект, описываемый данным дескриптором, как 16-разрядный, если бит установлен - то как 32-разрядный.

Бит G (Granularity) - Гранулярность сегмента, т. е. единицы измерения его размера. Если бит G=0, то сегмент имеет байтную гранулярность, иначе - страничную (одна страница - это 4Кб).

2.2.  Селектор сегмента

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

        Селектор имеет следующий формат:

·  Двухбитовое поле RPL (Requested Privilege Level) содержит номер уровня привилегий, которое имеет текущая программа.

·  Бит TI (Table Indicator) определяет таблицу, из которой выбирается нужный дескриптор. Если бит TI = 0, то обращение производится к глобальной дескрипторной таблице GDT (она одна на всю систему), если TI = 1 - то к текущей локальной дескрипторной таблице LDT (таких может быть много).

·  Index - это собственной номер дескриптора, от 0 до 8191.

В программе мы будем использовать только глобальную дескрипторную таблицу и нулевой уровень привилегий, поэтому младшие три бита будут равны 0

2.3.  Глобальная дескрипторная таблица

Прежде, чем процессор перейдёт в защищённый режим, должна быть определена глобальная дескрипторная таблица GDT (Global Descriptor Table), так как все сегменты и прочие системные объекты должны быть описаны в дескрипторной таблице. Адрес GDT храниться в специальном регистре процессора GDTR.

Формат регистра GDTR:

Адрес начала GDT - это тот адрес, по которому вы разместили GDT.
Предел таблицы GDT - это максимальное смещение относительно её начала.

        Например, вы создаёте GDT, состоящую из 3-х дескрипторов - для сегментов кода, стека и данных. Общее число дескрипторов будет равно четырём, потому что первым по счёту будет идти нулевой дескриптор, а за ним уже остальные три:

Смещение от начала GDT

Назначение дескриптора

0

Нулевой

8

Сегмент кода

16

Сегмент стека

24

Сегмент данных

        Размер GDT в данном случае будет равен 32 байтам, следовательно, предельное смещение в таблице будет равно 31 - это и есть предел GDT.

3.  Пример программы защищённого режима

Для перевода процессора в режим защищённых адресов необходимо выполнить ряд действий:

1.  Подготовка в оперативной памяти таблицы глобальных дескрипторов GDT.

2.  Инициализация необходимых дескрипторов в таблице GDT.

3.  Загрузка в регистр gdtr адреса и размера таблицы GDT.

4.  Запрет обработки аппаратных прерываний.

5.  Переключение микропроцессора в защищенный режим.

6.  Организация работы в защищенном режиме:

·  настроить сегментные регистры;

·  выполнить содержательную работу программы; в нашем случае мы выводим строку в видеобуфер;

·  подготовиться к возврату в реальный режим;

·  запретить аппаратные прерывания.

7.  Настройка сегментных регистров для работы в реальном режиме.

8.  Переключение микропроцессора в реальный режим.

9.  Разрешение прерываний.

10.  Стандартное для MS-DOS завершение работы программы.

Рассмотрим каждый этап подробнее:

3.1.  Подготовка таблицы глобальных дескрипторов GDT

В нашей программе достаточно определить одну дескрипторную таблицу – GDT. Таблицу LDT есть смысл применять, когда в системе работают несколько задач и необходимо изо­лировать их друг от друга.

Дескриптор сегмента удобно представить в виде структуры:

descr struc

limit dw 0

base_1 dw 0

base_2 db 0

AR db 0

attr db 0

base_3 db 0

ends

Поля структуры соответствуют формату дескриптора.

Дескрипторную таблицу представим в виде сегмента, который содержит массив структур типа descr.

gdt_segment segment para public 'data' use32

null_descr descr <0,0,0,0,0,0> ;нулевой дескриптор 0h

data32_descr descr <0,0,0,b,0,0> ; дескриптор ; сегмента данных защищённого режима 8h

code32_descr descr <0,0,0,b,0,0> ; дескриптор ; сегмента кода защищённого режима 10h

vbuf32_descr descr <0,0,0,b,0,0> ; дескриптор ; видеобуфера защищённого режима 18h

code16_descr descr <0,0,0,b,0,0> ; дескриптор ; кода реального режима 20h

data16_descr descr <0,0,0,b,0,0> ; дескриптор ; данных реального режима 28h

gdt_size = $-null_descr-1 ; размер таблицы GDT

point_gdt gdtr <gdt_size,0> ; псевдодескриптор для команды lgdt

gdt_segment ends

3.2.  Инициализация необходимых дескрипторов в GDT

Для заполнения поля адреса и предела в дескрипторе сегмента удобнее использовать макрос:

load_descr macro descriptor, seg_address, seg_size

mov descriptor. limit, seg_size

xor eax, eax

mov ax,seg_address ; адрес сегмента в ах

shl eax,4 ; сдвигом на 4 разряда получим ;физический 20-разрядный адрес сегмента

mov descriptor.base_1,ax

rol eax,16 ; получаем оставшуюся часть адреса

mov descriptor. base_2,al

endm

Заполнение полей дескрипторов:

load_descr data32_descr, data, data_size

load_descr code32_descr,0,0FFFFh ; 0FFFF – ;младшие разряды поля предел, старшие разряды установим ;в поле attr

load_descr vbuf32_descr,0,0FFFFh

load_descr code16_descr, rm_code,0FFFFh

load_descr data16_descr,0,0FFFFh

Поле attr структуры descr заполним командой mov:

mov data32_descr.attr,b ; устанавливаем биты ; G и D в 1, для 32-х разрядной адресации

mov code32_descr.attr,b ; старшие 4 разряда ; пределасегмента = 1111b

mov vbuf32_descr. attr,b

3.3.  Загрузка в регистр gdtr адреса и размера таблицы GDT

Адрес и размер сформированной таблицы GDT нужно поместить в регистр gdtr.

Для загрузки именно этого регистра в системе команд микропроцессора есть специ­альная команда:

lgdt адрес_48-битного_поля (Load GDT register) — загрузить регистр gdtr. Команда lgdt загружает системный регистр gdtr содержимым 6-байтового поля, адрес которого указан в качестве операнда.

Из описания команды следует, что вначале необходимо сформировать поле из шести байт со структурой, аналогичной формату регистра gdtr, а затем указать адрес этого поля в качестве операнда команды lgdt.

Структура для описания псевдодескриптора gdtr:

gdtr struc

limit dw 0

adress dd 0

ends

Вычисляем физический адрес GDT и загружаем регистр gdtr :

xor eax, eax

mov ax, gdt_segment

shl eax,4

mov point_gdt. adress, eax ; сохраняем полученный ; адрес в структуре gdtr – point_gdt

lgdt point_gdt ; загружаем регистр gdtr

3.4.  Запрет обработки аппаратных прерываний

Обработка прерываний в защищенном режиме принципиально отличается от обработки прерываний в реальном ре­жиме. Поэтому, как только микропроцессор переключится в защищенный режим, первое же прерывание от таймера, которое происходит 18,2 раза в секунду, «подвесит» компьютер. Пока не будем обрабатывать прерывания, поэтому их надо запретить.

;запрещаем прерывания:

cli ;маскируемые

mov al,80h ;немаскируемые

out 70h, al

3.5.  Переключение микропроцессора в защищенный режим

Для перевода процессора в защищённый режим необходимо установить бит pe в регистре управления cr0:

mov eax,cr0 ; получаем содержимое cr0

or al,1 ; устанавливаем бит pe

mov cr0,eax ; загружаем в регистр cr0 новое ; значение

Также необходимо вычислить адрес точки входа в защищённый режим:

xor eax,eax

mov ax,pm_code ; адрес сегмента кода ; защищённого режима

shl eax,4 ; получаем физический адрес

add eax,offset pm_entry_point ; добавляем ; к адресу смещение метки pm_entry_point

; сохраняем полученный адрес в переменной ;protected_mode

mov dword ptr protected_mode, eax

Настройка сегментных регистров:

В защищённом режиме необходимо загрузить в сегментные регистры селекторы соответствующих сегментов в таблице GDT. Регистр cs в защищённом режиме программно недоступен, поэтому загрузить в него селектор сегмента кода можно при помощи моделирования команды дальнего перехода far jmp на метку protected_mode. Команды ближнего перехода изменяют только содержимое eip\ip, а команды дальнего пе­рехода — оба регистра cs и eip\ip. Исходя из этого получаем:

db 66h ;префикс замены разрядности ; операнда

db 0EAh ;машинный код команды ; far jmp

protected_mode dd ? ;смещение метки перехода в ; сегменте команд

dw 10h ;селектор дескриптора ; сегмента кода в таблице GDT

Теперь загрузим селекторы остальных сегментов:

mov ax,8h ; селектор сегмента данных

mov ds,ax

mov ax,18h ; селектор видеобуфера

mov es, ax

3.6.  Организация работы в защищённом режиме

Здесь мы просто выводим две строки, используя механизм страничной адресации, который рассмотрим в следующем разделе. Вывод строки в видеобуфер оформим в виде макроса:

print_str macro message,msg_len,atr

local outstr

mov cx,msg_len ;длина сообщения

mov esi,offset message ;адрес строки ;сообщения

mov ah,atr ;атрибут выводимых символов

outstr:

mov al,[si]

mov es:[edi],ax ; в es:[edi] должны ; указывать на видеобуфер

inc si

inc edi

inc edi

loop outstr

endm

3.7.  Подготовка к возврату в реальный режим

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

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

· предел должен быть равен 64 К = 0ffffh;

·  бит G - 0 (значение размера в поле предела) — это значение в байтах;

·  байт атрибута равен = 92h;

·  базовый адрес значения не имеет.

Следовательно, перед переходом в реальный режим нужно сформировать эти значения в соответствующих дескрипторах и сделать актуальными эти изменения в теневых регистрах, для чего нужно перезагрузить сегментные регистры. После этого можно переходить в реальный режим. В программе все эти действия могут выглядеть так:

;переход в сегмент rm_code на метку real_mode

db 0EAh

dd offset real_mode

dw 20h ; селектор дескриптора сегмента кода ; реального режима!!!

mov ax,28h ; селектор дескриптора сегмента ;данных для реального режима!!!

mov ds, ax

mov es, ax

;загрузить в регистр cs адрес rm_code

db 0EAh

dw offset next

dw rm_code

3.8.  Переключение микропроцессора в реальный режим

Для перевода процессора в защищённый режим необходимо сбросить бит pe в регистре управления cr0:

mov eax,cr0 ; получаем содержимое cr0

and al,0FEh ; сбрасываем бит pe

mov cr0,eax ; загружаем в регистр cr0 новое ; значение

3.9.  Разрешение прерываний

Теперь можно разрешить прерывания.

sti

xor al,al

out 70h,al

3.10.  Стандартное для MS-DOS завершение работы программы

;окончание работы программы:

mov ax,4c00h

int 21h

4.  Страничная организация памяти

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

Смысл в использовании линейных и физических адресов появляется, когда программа включает в процессоре механизм трансляции страниц. Страница - это 4Кб-область памяти. Всё адресное пространство разбивается на страницы. Получается 220 страниц (т. е. 1048576 или 1М), которые полностью покрывают 32-разрядное адресное пространство.

Механизм страничного преобразования:

Структура элемента каталога страниц

Структура элемента таблицы страниц

Для включения механизма страничного преобразования необходимо выполнить ряд действий:

1.  Подготовить каталог страниц

2.  Заполнить таблицу страниц

3.  Адрес каталога страниц поместить в регистр CR3

4.  Включить страничное преобразование (установка бита 31 в регистре СR0)

4.1.  Подготовка каталога страниц

Каталог страниц – это набор 32 – разрядных записей (элементов). Начало каталога страниц в оперативной памяти будет располагаться по адресу 1МБ (100000h).

В нашем примере единственное, что мы делаем – выводим на экран заданную строку. При этом используется один единственный адрес –0B8000h. Следовательно, в данном примере для демонстрации возможностей страничной адресации достаточно заполнить лишь один элемент каталога страниц :

mov edi,100000h ;начало каталога страниц (1Мб)

mov eax,101007h ;единственный значащий элемент

stosd

mov ecx,1023 ; остальные 1023 элемента

xor eax,eax

rep stosd ; заполним нулями

Элемент 101007h означает, что страница присутствует в оперативной памяти (бит Р), доступна для чтения – записи (бит R/W) и доступна с любого уровня привилегий (бит U/S). А 1010000h = 1МБ + 4Кб, а 4КБ – потому что сам каталог занимает столько.

4.2.  Подготовка таблицы страниц

Заполним таблицу страниц:

mov eax,h ; первая запись - адрес ; нулевой страницы равен 0

mov ecx,1024 ; количество страниц в таблице

fill_page_table:

stosd ; запишем первый элемент

add eax,1000h ; добавим 4 Кб

loop fill_page_table ; заполним всю таблицу ; страниц

Первая запись таблицы ссылается на страницу с адресом 0h (h), длинна страницы равна 4 Кб. Далее мы еще создаем 1023 записи таблицы страниц, которые ссылаются на адреса, вычисляемые по формуле:

Адрес страницы n=4Кб+n*4Кб, где n меняется от 1 до 1023. Последняя запись страницы (запись с номером 1023) ссылается на страницу с адресом = 4Кб+1023*4Кб = 4Мб.

4.3.  Загрузка регистра CR3

mov eax,h ; базовый адрес = 1 Мб

mov cr3,eax ; cr3 хранит базовый адрес каталога страниц

4.4.  Включение страничного преобразования

mov eax, cr0

bts eax,31 ; установка31 бита регистра eax

mov cr0,eax ; обновление регистра cr0

Изменяем физический адрес страницы 12000h на 0B8000h:

mov eax,000B8007h

mov es:h+012h*4,eax

Если страничное преобразование выключено то линейный адрес равен ES (0000h) + смещение (равное 101000h + 12h*4) = 101048h. Далее процессор, видя, что включена страничная адресация, начинает преобразовывать линейный адрес в физический адрес по правилам страничного преобразоания:

Старшие 10 бит (b)=00hномер записи в каталоге страниц

Средние 10 бит (b)=101hномер записи в таблице страниц

Младшие 12 бит ()=048h – смещение в странице

Нулевая запись каталога страниц указывает на начало нашей таблицы страниц. В сформированной нами таблице страниц получается, что запись с номером 101h отображена на адрес 101000h. И в результате мы имеем физический адрес (выставляемый процессором на шину): 101000h + 048h = 101048h.

Физический адрес совпал с линейным, только потому что мы сформировали такую таблицу страниц.

У нас получилось так, что запись с номером h) ссылается на 1 Мб (256*4Кб), а запись h) на 1 Мб + 4 Кб (1010000), значит она ссылается на саму таблицу страниц. Таким образом, если мы будем записывать по адресу – запись 257 + смещение, то мы будем изменять значение записей таблицы страниц. Причем чтобы изменить нужную запись, нам надо сформировать смещение равно n*4, где n – номер одной из 1024-ёх записей, а 4 – так как размер одной записи равен 4 байта (или 32 бита).

Например, в нашем случае - мы берем запись каталога страниц (на него ссылается регистр CR0) с номером ноль (00h), она ссылается на определенную нами в таблицу страниц. В таблице страниц мы берем запись номер h), она ссылается на адрес памяти равный 1 Мб + 4 Кб (1010000h). Далее мы прибавляем к этому адресу смещение 012h*4 и записываем уже по адресу 1010000h + 012h*4 регистр EAX (000В8000h). Итак, получилось, что мы записали в запись с номером 18(12h) таблицы страниц значение 0В8000h. Теперь она ссылается на область видеобуфера.

Выводим строку в видеобуфер:

mov edi,0B8000h ; стандартный адрес ;видеобуфера

print_str msg1,msg_length1,0Ah

Так как включён механизм страничной трансляции, то:

старшие 10 битов: 0b = 0

средние 10 битов:b = B8h

младшие 12 битов: 0b = 0

Нулевая запись в каталоге страниц указывает на нашу таблицу страниц. Запись номер В8h содержит адрес 0B8000h (Начало видеобуфера)

Смещение – 0 (см. младшие 12 битов) к началу страницы 0B8000h не нужно ничего прибавлять.

Физический адрес = 0B8000h

mov edi,0120A0h ; теперь адрес 12000h ;отображён на физический адрес 0B8000

print_str msg2,msg_length2,0Ch

Аналогично:

старшие 10 битов: 0b = 0

средние 10 битов:b = 12h

младшие 12 битов: 0b = A0h

Только запись с номером 12h в таблице страниц теперь отображена на адрес В8000h. И получилось так, что мы выводим строку по адресу видеобуфера (0B800h) + смещение A0h (чтобы на экрани выводимые строки не накладывались друг на друга)

5.  Литература

1.  , Язык ассемблера: уроки программирования. – Диалог-МИФИ, 2001. – с. 640.

2.  Assembler для DOS, Windows и UNIX. – М.: ДМК Пресс, 2000.

3.  http://sasm. *****/ - Защищённый режим процессора с архитектурой IA-32

6.  Листинг программы

;

; TASM:

; tasm /m p_mode,,,

; tlink /3 p_mode

;

.586P ;разрешение инструкций Pentium

.model large

;Структура для описания дескриптора сегмента:

descr struc

limit dw 0

base_1 dw 0

base_2 db 0

AR db 0

attr db 0

base_3 db 0

ends

;Макрос инициализации дескрипторов:

load_descr macro descriptor, seg_address, seg_size

mov descriptor. limit, seg_size

xor eax, eax

mov ax, seg_address

shl eax,4

mov descriptor. base_1,ax

rol eax,16

mov descriptor. base_2,al

endm

;Макрос вывода строки в видеобуффер:

print_str macro message, msg_len, atr

local outstr

mov cx, msg_len ;длина сообщения

mov esi, offset message ;адрес строки сообщения

mov ah, atr ;атрибут выводимых символов

outstr:

mov al,[si]

mov es:[edi],ax

inc si

inc edi

inc edi

loop outstr

endm

;Структура для описания псевдодескриптора gdtr:

gdtr struc

limit dw 0

adress dd 0

ends

;Сегмент стека реального режима:

stk segment stack 'stack' use16

db 256 dup (0)

stk ends

;Таблица глобальных дескрипторов:

gdt_segment segment para public 'data' use32

null_descr descr <0,0,0,0,0,0> ; нулевой ;дескриптор 0h

data32_descr descr <0,0,0,b,0,0> ; дескриптор ;сегмента данных защищённого режима 8h

code32_descr descr <0,0,0,b,0,0> ; дескриптор ;сегмента кода защищённого режима 10h

vbuf32_descr descr <0,0,0,b,0,0> ; дескриптор ;видеобуфера защищённого режима 18h

code16_descr descr <0,0,0,b,0,0> ; дескриптор ;кода реального режима 20h

data16_descr descr <0,0,0,b,0,0> ; дескриптор ;данных реального режима 28h

gdt_size = $-null_descr-1 ; размер таблицы GDT

point_gdt gdtr <gdt_size,0> ; псевдодескриптор для ;команды lgdt

gdt_segment ends

;Сегмент данных защищённого режима :

data segment para public 'data' use32

msg1 db "Welcome to"

msg_length1 = $-msg1

msg2 db "Protected mode!!!"

msg_length2 = $-msg2

crlf db 0Ah,0Dh,'$'

data_size=$-msg1-1

data ends

;Сегмент кода реального режима:

rm_code segment para public 'code' use16

assume cs:rm_code, ss:stk

main proc

mov ax, stk

mov ss, ax

mov ax,03h ; Установка текстового режима ;80x25 и

int 10h ; очистка экрана

; открываем линию А20 для 32-х битной адресации:

in al,92h

or al,2

out 92h, al

;заполняем таблицу глобальных дескрипторов:

assume ds:gdt_segment

mov ax, gdt_segment

mov ds, ax

load_descr data32_descr, data, data_size

load_descr code32_descr,0,0FFFFh

load_descr vbuf32_descr,0,0FFFFh

load_descr code16_descr, rm_code,0FFFFh

load_descr data16_descr,0,0FFFFh

mov data32_descr. attr,b

mov code32_descr. attr,b

mov vbuf32_descr. attr,b

;вычисляем адрес точки входа в защищённый режим:

xor eax, eax

mov ax, pm_code

shl eax,4

add eax, offset pm_entry_point

mov dword ptr protected_mode, eax

;загружаем регистр gdtr:

xor eax, eax

mov ax, gdt_segment

shl eax,4

mov point_gdt. adress, eax

lgdt point_gdt

;запрещаем прерывания:

cli ;маскируемые

mov al,80h ;немаскируемые

out 70h, al

;переключение в защищенный режим:

mov eax, cr0

or al,1

mov cr0,eax

;настройка сегментных регистров:

;загрузка селектора сегмента кода в регистр cs:

db 66h ;префикс ;замены разрядности операнда

db 0EAh ; машинный код команды ;far jmp

protected_mode dd? ;смещение метки перехода в ;сегменте команд

dw 10h ;селектор сегмента кода в ;таблице GDT

real_mode:

;переключение в реальный режим режим:

mov eax, cr0

and al,0FEh

mov cr0,eax

;загрузить в регистр cs адрес rm_code

db 0EAh

dw offset next

dw rm_code

next:

mov ax, data

mov ds, ax

mov ax, stk

mov ss, ax

;разрешаем прерывания:

sti

xor al, al

out 70h, al

; перевод строки и возврат каретки:

mov ah,9

lea dx, crlf

int 21h

;окончание работы программы:

mov ax,4c00h

int 21h

main endp

rm_code ends

; Сегмент кода защищённого режима:

pm_code segment para public 'code' use32

assume cs:pm_code

pm_entry_point:

; загрузка селекторов для сегмента данных и видеобуфера:

mov ax,8h

mov ds, ax

mov ax,18h

mov es, ax

; Работаем в защищенном режиме:

; заполняем каталог страниц:

mov edi,100000h ; начало каталога страниц (1Мб)

mov eax,101007h ; единственный значащий ;элемент

stosd

mov ecx,1023 ; остальные 1023 элемента

xor eax, eax

rep stosd ; заполним нулями

; заполняем таблицу страниц:

mov eax,h ; первая запись - адрес нулевой страницы равен 0

mov ecx,1024 ; количество страниц в ;таблице

fill_page_table:

stosd ; запишем первый элемент

add eax,1000h ; добавим 4 Кб

loop fill_page_table ; заполним всю таблицу страниц

mov eax,h ; базовый адрес = 1 Мб

mov cr3,eax ; cr3 хранит базовый адрес ;каталога страниц

; включить страничную адресацию:

mov eax, cr0

bts eax,31

mov cr0,eax

; изменяем физический адрес страницы 12000h на 0B8000h:

mov eax,000B8007h

mov es:h+012h*4,eax

; выводим строку в видеобуфер:

mov edi,0B8000h ; стандартный адресс ;видеобуфера

print_str msg1,msg_length1,0Ah

mov edi,0120A0h ; теперь адрес 12000h ;отображён на физический адрес 0B8000

print_str msg2,msg_length2,0Ch

; выключить страничную адресацию:

mov eax, cr0

btc eax,31

mov cr0,eax

;Выход из защищённого режима:

;формирование дескрипторов для реального режима:

;загрузка теневых дескрипторов:

mov ax,28h

mov ds, ax

mov es, ax

;переход в сегмент rm_code на метку real_mode

db 0EAh

dd offset real_mode

dw 20h

pm_code ends

end main