DOS-extender для компилятора Borland C++ 3.1
Рефераты >> Программирование и компьютеры >> DOS-extender для компилятора Borland C++ 3.1

Любая попытка программы обратиться к сегменту памяти, в дескрипторе которого бит P установлен в 0, приведёт к прерыванию.

Бит A называется битом обращения к сегменту и для всех наших программ должен быть установлен в 0.

Поле доступа дескриптора сегмента данных имеет битовые поля W и D. Поле W называется битом разрешения записи в сегмент. Если этот бит установлен в 1, наряду с чтением возможна и запись в данный сегмент. В противном случае при попытке чтения выполнение программы будет прервано.

Поле D задаёт направление расширения сегмента. Обычный сегмент данных расширяется в область старших адресов (расширение вверх). Если же в сегменте расположен стек, расширение происходит в обратном направлении - в область младших адресов (расширение вниз). Для сегментов, в которых организуются стеки, необходимо устанавливать поле D равным 1.

Рассмотрим, как таблица дескрипторов будет выглядеть на языке программирования C. (В дальнейшем где это только возможно будем применять язык С, а Ассемблер – только там, где это необходимо.):

typedef struct descriptor

{

word limit; // Предел (размер сегмента в байтах)

word base_lo; // Базовый адрес сегмента (младшее слово)

unsigned char base_hi; // Базовый адрес сегмента (старший байт)

unsigned char type_dpl; // Поле доступа дескриптора

unsigned reserved; // Зарезервированные 16 бит

} descriptor;

Данная структура описана в файле tos.h.

Инициализацию экземпляра такой структуры можно произвести при помощи функции, подобной функции init_gdt_descriptor, описанной в файле tos.c:

void init_gdt_descriptor(descriptor *descr,

unsigned long base,

word limit,

unsigned char type)

{

// Младшее слово базового адреса

descr->base_lo = (word)base;

// Старший байт базового адреса

descr->base_hi = (unsigned char)(base >> 16);

// Поле доступа дескриптора

descr->type_dpl = type;

// Предел

descr->limit = limit;

// Зарезервированное поле, должно быть

// сброшено в 0 всегда (для процессоров 286)

descr->reserved = 0;

}

Например, запись в третий по счёту элемент GDT информации о сегменте данных с сегментным адресом _DS и пределом 0xffff будет выглядеть так:

init_gdt_descriptor(&gdt[2], MK_LIN_ADDR(_DS, 0), 0xffffL,

TYPE_DATA_DESCR | SEG_PRESENT_BIT | SEG_WRITABLE);

Макрос MK_LIN_ADDR определен в файле tos.h и служит для преобразования адреса реального режима формата сегмент:смещение в физический адрес:

#define MK_LIN_ADDR(seg,off) (((unsigned long)(seg))<<4)+(word)(off)

Специальный регистр процессора 286 LDTR имеет длину 16 разрядов и содержит селектор дескриптора, описывающего текущую таблицу LDT.

В данном курсовом проекте я не использую регистр LDTR и не создаю таблицы LDT, в моем варианте достаточно обойтись только одним кольцом защиты (0) процессора и только таблицей GDT.

3.2 Переход в защищенный режим процессора 80286

При переходе в защищенный режим программа совершает следующие операции:

  • Подготовка в оперативной памяти глобальной таблицы дескрипторов GDT. В этой таблице создаются дескрипторы для всех сегментов, которые будут нужны программе сразу после того, как она переключится в защищённый режим.
  • Для обеспечения возможности возврата из защищённого режима в реальный записывает адрес возврата в реальный режим в область данных BIOS по адресу 0040h:0067h, а также пишет в CMOS-память в ячейку 0Fh код 5. Этот код обеспечит после выполнения сброса процессора передачу управления по адресу, подготовленному нами в области данных BIOS по адресу 0040h:0067h.
  • Запрещает все маскируемые и немаскируемые прерывания.
  • Открывает адресную линию A20 (попробуем оперировать блоками памяти выше 1 Мб).
  • Запоминает в оперативной памяти содержимое сегментных регистров, которые необходимо сохранить для возврата в реальный режим, в частности, указатель стека реального режима.
  • Программирует контроллер прерываний для работы в защищенном режиме.
  • Загружает регистры IDTR и GDTR.

Необходимые функции для этого реализованы в файлах tos.c и TOSSYST.ASM:

Подготовка GDT осуществляется при помощи описанных выше функции init_gdt_descriptor() и макроса MK_LIN_ADDR().

Остальные действия, необходимые для перехода в защищенный режим, описаны в функции protected_mode() модуля TOSSYST.ASM:

Обеспечение возможности возврата в реальный режим:

push ds ; готовим адрес возврата

mov ax,40h ; из защищённого режима

mov ds,ax

mov [WORD 67h],OFFSET shutdown_return

mov [WORD 69h],cs

pop ds

Запрет прерываний:

сli

in al, INT_MASK_PORT

and al, 0ffh

out INT_MASK_PORT, al

mov al,8f

out CMOS_PORT,al

Открытие линии A20 производится вызовом функции enable_a20(), описанной в файле TOSSYST.ASM:

PROC enable_a20 NEAR

mov al,A20_PORT

out STATUS_PORT,al

mov al,A20_ON

out KBD_PORT_A,al

ret

ENDP enable_a20

Запоминаем содержимое сегментных регистров SS и ES:

mov [real_ss],ss

mov [real_es],es

Программируем при помощи функции set_int_ctrlr(), описанной в файле TOSSYST.ASM каскад контроллеров прерываний (Master и Slave) для работы в защищенном режиме (описание работы прерываний в защищенном режиме приведено ниже):

mov dx,MASTER8259A

mov ah,20

call set_int_ctrlr

mov dx,SLAVE8259A

mov ah,28

call set_int_ctrlr

Загружаем регистры IDTR и GDTR:

lidt [FWORD idtr]

lgdt [QWORD gdt_ptr]

И, напоследок, переключаем процессор в защищенный режим:

mov ax, 0001h

lmsw ax

3.3 Возврат в реальный режим процессора.

Для того, чтобы вернуть процессор 80286 из защищённого режима в реальный, необходимо выполнить аппаратный сброс (отключение) процессора. Это реализуется в функции real_mode(), описанной в файле TOSSYST.ASM:

PROC _real_mode NEAR

; Сброс процессора

cli

mov [real_sp], sp

mov al, SHUT_DOWN

out STATUS_PORT, al

rmode_wait:

hlt

jmp rmode_wait

LABEL shutdown_return FAR

; Вернулись в реальный режим

mov ax, DGROUP

mov ds, ax

assume ds:DGROUP

mov ss,[real_ss]

mov sp,[real_sp]

; Размаскируем все прерывания

in al, INT_MASK_PORT

and al, 0

out INT_MASK_PORT, al

call disable_a20

mov ax, DGROUP

mov ds, ax

mov ss, ax

mov es, ax

mov ax,000dh

out CMOS_PORT,al

sti

ret

ENDP _real_mode

Функция disable_a20(), описанная в файле TOSSYST.ASM закрывает адресную линию A20:

PROC disable_a20 NEAR

push ax

mov al, A20_PORT

out STATUS_PORT, al

mov al ,A20_OFF

out KBD_PORT_A, al

pop ax

ret

ENDP disable_a20

3.4 Обработка прерываний в защищенном режиме.

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


Страница: