- •Программирование эвм
- •Int 21h ;кодом возврата 0 прерывания 21h
- •Работа с битами
- •Порядок выполнения работы
- •Устройства ввода-вывода
- •Ввод исходных данных с клавиатуры и вывод результатов на дисплей
- •Inc di ;смещение в видеопамяти на следующий символ
- •Порядок выполнения работы
- •Контрольные задания
- •Система команд процессора
- •Способы адресации
- •Влияние команд на регистр флагов
- •Расширенные регистры и типы данных процессоров x86
- •Система команд процессоров ia-32 и Intel 64
- •Int 21h ;системного прерывания 21h
- •Использование дальней подпрограммы
- •X dw 0aabBh, 0abbAh, 0baaBh, 0bbaAh ;исходные данные
- •Использование подпрограмм для ввода-вывода
- •Порядок выполнения работы
- •Контрольные задания
- •Дескрипторы
- •Порядок работы процессора в защищенном режиме
- •Использование дальней подпрограммы в защищенном режиме
- •Использование idt. Ввод данных с клавиатуры в защищенном режиме
- •Порядок выполнения работы
Порядок работы процессора в защищенном режиме
Глобальная (GDT) и локальная (LDT) таблицы дескрипторов
При работе в защищенном режиме все обращения к памяти происходят через глобальную таблицу дескрипторов (Global Descriptor Table, GDT) или (опционально) через локальную таблицу дескрипторов (Local Descriptor Table, LDT).
Глобальная и локальная таблицы дескрипторов содержат структуры, называемые дескрипторами сегментов. Дескриптор IA-32 имеет размер в восемь байт. Он содержит базовый (начальный) адрес сегмента, его тип, дополнительные свойства (разрядность адресов и операндов, единицу измерения величины сегмента, лимит), права доступа, информацию об использовании сегмента. Каждый дескриптор имеет связанный с ним селектор. Размер селектора — 16 бит. Он содержит индекс (номер) дескриптора в таблице, флаг, определяющий, где находится дескриптор, в локальной или глобальной таблице, а также права доступа. Линейный базовый адрес глобальной таблицы дескрипторов и ее размер содержатся в регистре глобальной таблицы дескрипторов (Global Descriptor Table Register, GDTR), локальной таблицы дескрипторов — в регистре локальной таблицы дескрипторов (Local Descriptor Table Register, LDTR). GDT может быть только одна, обычно в ней находятся описания сегментов операционной системы. LDT может быть любое количество: ни одной, одна на множество задач или по одной на каждую задачу. Они содержат описания сегментов программ, работающих под управлением операционной системы, т.е. отдельных задач. В каждый момент времени процессор может использовать только одну таблицу LDT.
Размер GDT, уменьшенный на единицу, называется пределом таблицы GDT (GDT limit). Он используется для проверки правильности задаваемых программой селекторов. Поле индекса селектора должно содержать ссылки только на существующие элементы таблицы GDT, в противном случае произойдет прерывание. Зная размер GDT, процессор блокирует использование селекторов со значениями поля индекса, выходящими за рамки разрешенных для таблицы GDT. Аналогичный механизм используется и для проверки селекторов, ссылающихся на LDT.
Для доступа к байту внутри сегмента необходимы селектор сегмента и смещение данного байта внутри сегмента. Процессор по значению селектора определяет соответствующий дескриптор, из которого берет базу сегмента — линейный начальный адрес сегмента (адрес первого байта сегмента), прибавляет к нему смещение искомого байта и получает его линейный адрес, который в случае использования только сегментирования (отключенной страничной адресации) является и физическим. Этот механизм используется для доступа к любому действительному сегменту кода, данных или стека при условии, что сегмент доступен из текущего уровня привилегий (current privilege level, CPL), с которым работает процессор. CPL определяется как уровень привилегий текущего исполняемого сегмента кода.
Обработка прерываний. Таблица дескрипторов прерываний (IDT)
Внешние прерывания, программные прерывания, исключения обрабатываются с использованием таблицы дескрипторов прерываний (Interrupt Descriptor Table, IDT). Исключение — это событие, которое происходит, если команда вызывает ошибку. Например, попытка деления на ноль генерирует исключение. Однако есть исключения, например, контрольные точки, которые происходят при других условиях. IDT содержит множество дескрипторов различных шлюзов: прерываний, ловушек и задач — которые предоставляют доступ к обработчикам прерываний и исключений. Так же как и GDT, IDT не является сегментом. Линейный базовый адрес и лимит IDT содержатся в регистре таблицы дескрипторов прерываний (Interrupt Descriptor Table Register).
Для вызова обработчика процессор должен вначале получить номер прерывания от внутренней логики, внешнего контроллера прерываний или программы посредством команд INT, INTO, INT 3 или BOUND.
Номер прерывания представляет собой индекс соответствующего дескриптора в IDT. Если это дескриптор шлюза задачи, то доступ к обработчику осуществляется через переключение задач. Если это дескриптор шлюза прерывания или ловушки, то вызов обработчика аналогичен вызову подпрограммы. Процессор читает из шлюза прерывания селектор сегмента кода, в котором находится обработчик прерывания и смещение обработчика прерывания от начала этого сегмента. По селектору он находит дескриптор, из которого извлекает базу сегмента и, таким образом, определяет полный логический адрес обработчика.
Повышение надежности функционирования системы в защищенном режиме
Функционирование системы в защищенном режиме значительно повышает ее надежность.
Во-первых, повышение надежности обусловлено возможностью задания необходимого размера сегмента и контролем адресации памяти вне пределов сегментов.
Во-вторых, байт доступа дескриптора сегмента кода содержит бит разрешения чтения сегмента (бит 1). Если этот бит установлен в 1, программа может считывать содержимое сегмента кода. В противном случае процессор может только выполнять этот код, т. е. программа не может модифицировать сегмент кода. Это означает невозможность создания самомодифицирующихся программ для защищенного режима. Впрочем, возможность модификации кода остается. Для сегмента кода можно создать еще один, алиасный дескриптор, в котором этот сегмент отмечен как сегмент данных. Для него можно разрешить запись, установив тот же самый бит 1, и модифицировать код программы во время ее выполнения.
Процессор при обращении к памяти в защищенном режиме проверяет соблюдение всех необходимых условий: возможность доступа к сегменту по уровню привилегий, не превысил ли адрес предел сегмента, можно ли вообще обращаться к данному сегменту в данной ситуации. И если процессор обнаруживает нарушение какого-либо условия, то генерирует исключение и тем самым обеспечивает защиту (режим называется защищенным) и, следовательно, повышение надежности.
Переключение процессора между реальным и защищенным режимами
Переключение процессора из реального в защищенный режим и обратно осуществляется программно. Для того чтобы перейти в защищенный режим, необходимо выполнить следующие действия:
-
подготовить глобальную таблицу дескрипторов;
-
подготовить при необходимости другие системные структуры данных, например таблицу дескрипторов прерываний;
-
включить адресную линию А20;
-
загрузить регистр глобальной таблицы дескрипторов и при необходимости другие системные регистры, например регистр таблицы дескрипторов прерываний;
-
запретить маскируемые прерывания;
-
переключиться в защищенный режим установкой бита 0 в CR0;
-
осуществить переход на первую команду защищенного режима, загрузив CS селектором соответствующего сегмента кода, IP нужным смещением;
-
загрузить при необходимости другие сегментные регистры;
-
разрешить при необходимости прерывания.
Для возврата из защищенного режима в реальный необходимо:
-
запретить маскируемые прерывания;
-
осуществить переход в точку возврата, загрузив в CS селектор сегмента кода реального режима, а в IP смещение точки возврата в соответствующем сегменте;
-
переключиться в реальный режим сбросом бита 0 в CR0;
-
загрузить CS базой сегмента кода реального режима;
-
выполнить необходимую инициализацию;
-
разрешить прерывания.
Примеры программ
Программа "Hello from PM"
В данном примере происходит переключение процессора в защищенный режим, вывод сообщения "Hello from PM" в защищенном режиме и возврат в реальный режим.
Запускать программу необходимо в MS-DOS или подобной операционной системе. Поскольку программа загружается операционной системой, заполнение полей базы сегментов в дескрипторах необходимо осуществить уже в процессе работы программы в реальном режиме перед переключением в защищенный режим. Поля лимита сегментов для простоты не рассчитываются, а устанавливаются в максимальное значение.
;PM1Hello.asm
;пpогpамма выводит сообщение "Hello from PM" в защищенном pежиме
;tasm /m PM1Hello.asm
;tlink /3 PM1Hello.obj
.386p ;чтобы можно было использовать системные команды IA-32
;сегмент стека
SSeg segment stack use16
db 100h dup(?)
SSeg ends
;сегмент кода, котоpый начинает выполняться после запуска пpогpаммы в pеальном pежиме
CSeg16 segment use16
assume CS:CSeg16, DS:CSeg32, SS:SSeg
;точка входа в программу, инициализация DS
start: push CSeg32
pop ds
;включается адресная линия A20
in al, 92h
or al, 2
out 92h, al
;рассчитываются и заполняются поля базы дескрипторов сегментов
xor eax, eax
mov ax, cs
shl eax, 4
mov word ptr CS16Dsc+2, ax
shr eax, 16
mov byte ptr CS16Dsc+4, al
mov ax, CSeg32
shl eax, 4
push eax
mov word ptr CS32Dsc+2, ax
mov word ptr DS32Dsc+2, ax
shr eax, 16
mov byte ptr CS32Dsc+4, al
mov byte ptr DS32Dsc+4, al
;рассчитывается линейный адрес начала GDT (база GDT),
;заполняется соответствующее поле переменной gdtr
pop eax
add eax,offset GDT
mov dword ptr gdtr+2, eax
;загружается регистр GDTR значением одноименной переменной
lgdt fword ptr gdtr
;запрещаются маскируемые прерывания
cli
;устанавливается бит PE - процессор с этого момента в защищенном режиме
mov eax, cr0
or al, 1
mov cr0, eax
;JMP в код защищенного режима
db 66h
db 0EAh
dd offset PMentry
dw CS32Sel
;точка возврата из кода защищенного режима, сбрасывается бит PE,
;процессор в реальном режиме
RMret: mov eax, cr0
and al, 0FEh
mov cr0, eax
db 0EAh
dw $+4
dw CSeg16
;разрешаются маскируемые прерывания
sti
mov ah, 0
int 16h
;завершение работы программы
mov ah, 4Ch
int 21h
CSeg16 ends
;сегмент кода защищенного режима
CSeg32 segment use32
assume cs:CSeg32
;сообщение, выводимое в защищенном режиме
msg db 'H',7,'e',7,'l',7,'l',7,'o',7,' ',7,'f'
db 7,'r',7,'o',7,'m',7,' ',7,'P',7,'M',7
msg_l = $-msg ;длина сообщения
rest_scr = (80*25*2-msg_l)/4 ;остаток экрана
;Глобальная таблица дескрипторов
GDT label byte
db 8 dup(0) ;дескриптор 0
CS16Dsc db 0FFh,0FFh,0,0,0,10011010b,0,0 ;дескриптор 1
CS32Dsc db 0FFh,0FFh,0,0,0,10011010b,11001111b,0 ;дескриптор 2
DS32Dsc db 0FFh,0FFh,0,0,0,10010010b,11001111b,0 ;дескриптор 3
VSegDsc db 0FFh,0FFh,0,80h,0Bh,10010010b,11001111b,0 ;дескриптор 4 (Video)
GDT_l = $-GDT ;длина GDT
;переменная, значение которой загружается в GDTR
gdtr dw GDT_l-1 ;лимит GDT
dd ? ;база GDT
CS16Sel equ 0000000000001000b ;селектор дескриптора 1
CS32Sel equ 0000000000010000b ;селектор дескриптора 2
DS32Sel equ 0000000000011000b ;селектор дескриптора 3
VSegSel equ 0000000000100000b ;селектор дескриптора 4
;точка входа в код защищенного режима
PMentry:
;инициализация сегментных регистров
mov ax, DS32Sel
mov ds, ax
mov ax, VSegSel
mov es, ax
;инициализация указателя на сообщение
mov esi, offset msg
;инициализация указателя на начало видеопамяти
xor edi, edi
;инициализация счетчика длиной сообщения
mov ecx, msg_l
;вывод сообщения
rep movsb
;заполнение оставшейся части экрана пробелами
mov eax, 07200720h
mov ecx, rest_scr
rep stosd
;JMP в код реального режима
db 0EAh
dd offset RMret
dw CS16Sel
CSeg32 ends
end start