Рефераты. DOS-extender для компилятора Borland C++ 3.1 p> - реализовать защищенный режим процессора 80286,

- адресовать до 16 Мб памяти,

- обрабатывать прерывания реального режима DOS

- реализуем набор средств для создания параллельно выполняющихся потоков в среде DOS.

После разработки необходимых средств, напишем программу–пример с их использованием. Собственно это получится не просто программа, а некий прототип многозадачной операционной системы.

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

- Borland C++ 3.1

- Borland Turbo Assembler из поставки Borland C++ 3.1


3. Реализация работы программы в защищенном режиме процессора 80286.

3.1 Адресация защищенного режима процессора 80286.

Логический адрес в защищённом режиме (иногда используется термин
"виртуальный адрес") состоит из двух 16-разрядных компонент - селектора и смещения. Селектор записывается в те же сегментные регистры, что и сегментный адрес в реальном режиме. Однако преобразование логического адреса в физический выполняется не простым сложением со сдвигом, а при помощи специальных таблиц преобразования адресов.

В первом приближении можно считать, что для процессора i80286 селектор является индексом в таблице, содержащей базовые 24-разрядные физические адреса сегментов. В процессе преобразования логического адреса в физический процессор прибавляет к базовому 24-разрядному адресу 16-разрядное смещение, т.е. вторую компоненту логического адреса (Рис. 1).

Такая схема формирования физического адреса позволяет непосредственно адресовать 16 мегабайт памяти с помощью 16-разрядных компонент логического адреса.

Таблиц дескрипторов в системе обычно присутствует от одной до нескольких десятков. Но всегда существует так называемая таблица GDT
(Global Descriptor Table), в которой обычно хранится описание сегментов самой операционной системы защищенного режима 80286. Таблицы LDT (Local
Descriptor Table) создаются на каждый новый запускаемый процесс в операционной системе, и в них хранится описание сегментов только одной отдельной задачи.

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

Процессор 80286 имеет специальный 5-байтный регистр защищенного режима
GDTR, в котором старшие 3 байта содержат 24-разрядный физический адрес таблицы GDT, младшие два байта - длину таблицы GDT, уменьшенную на 1.

[pic]

Рис. 1. Схема преобразования логического адреса в физический в защищенном режиме процессора 80286.

Перед переходом в защищённый режим программа должна создать в оперативной памяти таблицу GDT и загрузить регистр GDTR при помощи специальной команды LGDT.

Каждый элемент таблицы дескрипторов имеет следующий формат:

[pic]

Общая его длина составляет 8 байт, в которых расположены следующие поля:

. поле базового адреса длиной 24 бита содержит физический адрес сегмента, описываемого данным дескриптором;

. поле предела содержит размер сегмента в байтах, уменьшенный на единицу;

. поле доступа описывает тип сегмента (сегмент кода, сегмент данных и др.);

. зарезервированное поле длиной 16 бит для процессора i80286 должно содержать нули, это поле используется процессорами i80386 и i80486

(там, в частности, хранится старший байт 32-разрядного базового адреса сегмента).

Поле доступа, занимающее в дескрипторе один байт (байт доступа) служит для классификации дескрипторов. На рис. 2 приведены форматы поля доступа для трёх типов дескрипторов - дескрипторов сегментов кода, сегментов данных и системных.
[pic]

Рис. 2. Форматы поля доступа дескриптора.

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

Биты P и A предназначены для организации виртуальной памяти. Их назначение будет описано в разделе, посвящённом виртуальной памяти. Сейчас отметим, что бит P называется битом присутствия сегмента в памяти. Для тех сегментов, которые находятся в физической памяти (мы будем иметь дело в основном с такими сегментами) этот бит должен быть установлен в 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))ss = ds; t->ip = (word)ip; // указатель команд t->sp = (word)sp; // смещение стека t->bp = (word)sp;
}

// -------------------------------------------------
// Функция инициализации дескриптора в таблице GDT
// -------------------------------------------------

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;
}

// -----------------------------------------------
// Инициализация всех таблиц и вход
// в защищённый режим
// -----------------------------------------------

void Init_And_Protected_Mode_Entry(void)
{ union REGS r;

// Инициализируем таблицу GDT, элементы с 1 по 5

init_gdt_descriptor(&gdt[1], MK_LIN_ADDR(_CS, 0),

0xffffL, TYPE_CODE_DESCR | SEG_PRESENT_BIT |
SEG_READABLE);

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

0xffffL, TYPE_DATA_DESCR | SEG_PRESENT_BIT |
SEG_WRITABLE);

init_gdt_descriptor(&gdt[3],
MK_LIN_ADDR(_DS, &task_1_tss),

(unsigned long)TSS_SIZE-1, TYPE_TSS_DESCR | SEG_PRESENT_BIT);

init_gdt_descriptor(&gdt[4],

MK_LIN_ADDR(_DS, &task_2_tss),

(unsigned long)TSS_SIZE-1, TYPE_TSS_DESCR |
SEG_PRESENT_BIT);

init_gdt_descriptor(&gdt[5],

MK_LIN_ADDR(_DS, &main_tss),

(unsigned long)TSS_SIZE-1, TYPE_TSS_DESCR |
SEG_PRESENT_BIT);


// Инициализируем TSS для задач TASK_1, TASK_2

init_tss(&task_1_tss, CODE_SELECTOR, DATA_SELECTOR, task_1_stack+ sizeof(task_1_stack), task1);

init_tss(&task_2_tss, CODE_SELECTOR, DATA_SELECTOR, task_2_stack+ sizeof(task_2_stack), task2);

// Инициализируем элемент 6 таблицы GDT -
// дескриптор для сегмента видеопамяти

// Определяем видеорежим r.h.ah = 15; int86(0x10, &r, &r);

// Инициализация для монохромного режима if (r.h.al == MONO_MODE) init_gdt_descriptor(&gdt[6], MONO_VID_MEM,

3999, TYPE_DATA_DESCR | SEG_PRESENT_BIT | SEG_WRITABLE);
// Инициализация для цветного режима else if (r.h.al == BW_80_MODE || r.h.al == COLOR_80_MODE) init_gdt_descriptor(&gdt[6], COLOR_VID_MEM,

3999, TYPE_DATA_DESCR | SEG_PRESENT_BIT | SEG_WRITABLE); else
{ printf("nИзвините, этот видеорежим недопустим."); exit(-1);
}

// Инициализация элементов 7 и 8 таблицы GDT init_gdt_descriptor(&gdt[7],

MK_LIN_ADDR(_DS, &idt),

(unsigned long)IDT_SIZE-1,

TYPE_DATA_DESCR | SEG_PRESENT_BIT | SEG_WRITABLE);

init_gdt_descriptor(&gdt[8],

MK_LIN_ADDR(_DS, &keyb_task_tss),

(unsigned long)TSS_SIZE-1,

TYPE_TSS_DESCR | SEG_PRESENT_BIT);

// Инициализация TSS для задачи KEYB_TASK init_tss(&keyb_task_tss, CODE_SELECTOR, DATA_SELECTOR, keyb_task_stack + sizeof(keyb_task_stack), keyb_task);

// Инициализация элемента 9 таблицы GDT init_gdt_descriptor(&gdt[9],

MK_LIN_ADDR(_DS, &keyb_tss),

(unsigned long)TSS_SIZE-1,

TYPE_TSS_DESCR | SEG_PRESENT_BIT);

// Инициализация TSS для задачи KEYB обработки ввода с клавиатуры init_tss(&keyb_tss, CODE_SELECTOR, DATA_SELECTOR, keyb_stack + sizeof(keyb_stack), Keyb_int);

// Инициализация элемента 10 таблицы GDT init_gdt_descriptor(&gdt[10],

MK_LIN_ADDR(_DS, &flipflop_tss),

(unsigned long)TSS_SIZE-1,

TYPE_TSS_DESCR | SEG_PRESENT_BIT);

// Инициализация TSS для задачи FLIP_TASK init_tss(&flipflop_tss, CODE_SELECTOR, DATA_SELECTOR, flipflop_stack + sizeof(flipflop_stack), flipflop_task);

// Загрузка регистра IDTR load_idtr(MK_LIN_ADDR(_DS, &idt), IDT_SIZE);

Страницы: 1, 2, 3, 4



2012 © Все права защищены
При использовании материалов активная ссылка на источник обязательна.