В MS-DOS реализовано управление памятью без организации виртуального адресного пространства, но с распределением блоков переменной длины. Базовые механизмы ОС опираются только на средства реального режима процессоров x86, и лишь для работы с «верхней» памятью используются особенности адресации 286+ и переключение в защищенный/виртуальный режим.
Память в MS-DOS представляется как непрерывный массив, распределяемый отдельными блоками. Блоки могут начинаться только на границе параграфа, поэтому для задания блока достаточно его сегментного адреса. Блоки следуют непосредственно друг за другом и составляют связный список. Вся доступная для распределения память должна быть включена в эти блоки, в том числе и свободная. Последний блок в списке соответствует нераспределенному нефрагментированному остатку памяти.
Каждый блок предваряется управляющим блоком (MCB — Memory Control Block), который занимает ровно один параграф и содержит поля:
байт 0 – опознавательный маркер блока: 5Ah (‘Z’) – для последнего блока списка, 4Dh (‘M’) – для всех остальных;
байты 1..2 – сегментный адрес PSP программы – владельца блока (в MS-DOS адрес PSP играет роль PID – идентификатора загруженной программы);
байты 3..4 – размер блока в параграфах, при отсутствии «зазоров» между блоками в списке это значение является «относительной» ссылкой на следующий блок (размер самого MCB в этом поле не учитывается!);
байты 8..15 – имя программы – владельца блока.
Поля PID и имени владельца для пустых блоков ожидаются пустыми. Для используемых блоков корректность их значений не гарантируется: обычная их интерпретация справедлива в случаях, если блок был выделен стандартным способом обычной прикладной программе. Блоки, выделенные DOS для своих нужд, имеют PID = 0008h и имя «владельца», начинающееся с комбинаций “SD” (data) или “SC” (code). Внутри «системных» блоков памяти могут организовываться вложенные списки с аналогичными структурами суб-блоков и суб-MCB. Маркеры суб-MCB могут содержать значения: 'B' – дисковые буферы, 'D' – драйвер устройства, 'F' – системная таблица файлов, 'L' – данные логического диска, 'S' – внутренние стеки DOS; 'X' – кэш FCB и так далее (эта информация считается недокументированной).
Зная адрес одного из блоков, можно просканировать все последующие до конца списка. DOS хранит адрес первого блока в специальной структуре или DIB – DOS Info Block (она же List of Lists). Адрес DIB возвращает в регистрах ES:BX недокументированная функция int 21h AH = 52h. Слово по адресу ES:BX‑2 содержит сегментный адрес первого в списке MCB.
Помимо этого, в качестве стартовой точки можно использовать первый не принадлежащий системе блок памяти, выделенный прикладной программе, которая имеет PSP. Для этого выполняется сканирование параграфов до обнаружения первого содержащего действительный MCB. Признаки такого MCB:
– наличие маркера MCB;
– владельцем блока является он сам, то есть PID владельца указывает на следующий после MCB параграф;
– блок содержит PSP – начинается с команды int 20h.
Так как первой «нормально» загружаемой программой является обычно командный интерпретатор (как правило, COMMAND.COM), то можно также искать в MCB его имя.
Других структур для описания распределяемой памяти не предусмотрено, вся необходимая информация получается, в том числе и системой, путем сканирования списка MCB, поэтому любые изменения в ней отражаются на работе всей системы. Так, уменьшение значения в поле размера последнего MCB приводит к изменению объема памяти, контролируемой DOS, и появлению «невидимой» области.
В общем случае, ОС должна обеспечить: выделение блока памяти по запросу прикладной программы, освобождение блока, перераспределение ранее выделенного блока (изменение размера), а также учёт свободной и занятой памяти, дефрагментацию блоков и другие сервисные функции.
В MS-DOS предусмотрены три основные функции прерывания int 21h:
AH = 48h – выделение блока памяти. На входе: BX – размер блока в параграфах. На выходе: AX – сегментный адрес выделенного блока, BX – максимальный доступный размер этого блока.
AH = 49h – освобождение блока. На входе: ES – сегментный адрес блока.
AH = 4Ah – изменение размера ранее выделенного блока. На входе: ES – сегментный адрес блока, BX – новый размер блока в параграфах. На выходе: BX – максимальный доступный размер этого блока.
Все функции при возникновении ошибки устанавливают флаг CF и возвращают ее код в AX.
DOS выделяет только непрерывные блоки памяти, перемещение выделенных фрагментов, а также дефрагментация свободной памяти не предусмотрены, за исключением объединения пустых блоков в конце списка. После стандартного завершения программы выделенные ей блоки освобождаются автоматически, но только при условии, что их владелец в MCB был указан корректно. Дополнительные функции позволяют управлять стратегиями распределения памяти.
Контрольные вопросы
1. Организация памяти в MS-DOS.
2. Структура MCB блока.
4. Функции для создания, удаления и изменения размера блока.
5. Организация сложных динамических структур данных.
Варианты заданий
3.3.1. Создать двунаправленный список для хранения строк. Каждый элемент списка должен хранить указатель на блок с предыдущим элементом, указатель на блок со следующим элементом, указатель на блок, хранящий строку. Строки необходимо хранить в отдельных блоках памяти. Пользователю должны быть доступны следующие функции: добавить строку в начало списка, добавить строку в конец списка, удалить элемент списка с указанным номером, очистить список, показать содержимое списка (хранимые строки) на экране.
3.3.2. Создать динамический массив для хранения строк. Массив должен представлять собой указатели на блоки памяти, в которых хранятся строки. При добавлении элемента необходимо проверить, есть ли для него место. Если весь массив занят, его необходимо выделить заново, увеличив размер вдвое, и скопировать туда старое содержимое. Пользователю должны быть доступны следующие функции: добавить строку в конец массива, установить новую строку в определенный элемент массива (с указанным индексом), удалить строку с указанным индексом, очистить массив, показать содержимое массива (хранимые строки) на экране.
3.3.3. Создать двоичное дерево, хранящее числа. Каждый элемент дерева должен хранить число и «левую» и «правую» ссылки на нижестоящие элементы. Необходимо реализовать алгоритмы добавления числа в двоичное дерево и удаления числа из него. Пользователю должны быть доступны следующие функции: добавить число, удалить число, очистить дерево, показать содержимое дерева на экране. При выводе на экран показывать дерево в виде строки вида: содержимое родителя (содержимое левой ветви, содержимое правой ветви); для каждой из ветвей функция вывода должна быть вызвана рекурсивно.
3.3.4. Сформировать путем анализа списка MCB и вывести карту памяти, включая размер блоков и их владельцев.
3.3.5. Реализовать выделение и освобождение блоков памяти без обращений к функциям DOS.
3.3.6. Реализовать перераспределение блока памяти; в случае невозможности увеличить размер блока попытаться переместить его на новое место (текущее содержимое блока копируется).
3.3.7. Объединяет функции вариантов 4..6, дополняется интерактивным интерфейсом, позволяющим выбирать функции (повышенной сложности).
Лабораторная работа №4
Обработчики прерываний
Цели работы:
1) изучить поддержку прерываний и их использование;
2) научиться создавать и использовать собственные обработчики прерываний;
3) научиться создавать и отлаживать резидентные программы.