Ну, начнем с исторических функций.
Давным-давно, когда даже Билл Гейтс говорил что 640 килобайт хватит всем,
но не у всех были эти 640 килобайт. :) в биосах существовала функция
определения количества базовой памяти.
|
int 12h Выходные параметры:
|
Сейчас уже вряд ли кому придет в голову, что базовой памяти может быть меньше
640 килобайт. но мало ли... ;)
Появлялись новые процессоры, и размеры памяти стали расти. в связи с чем
появилась функция определения количества расширенной памяти.
|
int 15h fn 88h Входные параметры:
|
Возможно из за архитектуры 286-х процессоров (которым размер шины адреса не
позволяет иметь больше чем 16 мегабайт памяти) эта функция часто имеет
аналогичное ограничение и результат в ax не может превышать 3с00h
(Что составляет 15Мб).
Но, опять таки, появились новые процессоры. 16 мегабайт стало мало.
Вследствие этого появилась еще одна функция BIOS:
|
int 15h fn e801h Входные параметры:
|
Не знаю, что означает сконфигурированная память. Так написано в описании.
Здесь производители BIOS видимо оказались неединодушны. Некоторые версии
в ax и bx возвращают 0, это значит что размер памяти следует определять
из cx, dx.
Но видимо и 4 гигабайт оказалось мало. В новых BIOS появилась еще одна функция.
|
int 15h fn e820h Входные параметры:
|
Эту функцию нужно вызывать в цикле до тех пор, пока не будет прочитана вся
карта памяти.
Формат структуры таков:
struct {
long long base;
long long length;
long type;
};
Поле type может содержать следующие значения:
Функции BIOS не работают в защищенном режиме, поэтому все эти операции необходимо производить еще до перехода в защищенный режим.
Помимо функций BIOS есть еще много других способов.
Самый простой - помереть память самому. :) Делается это из защищенного
режима, страничное преобразование должно быть выключено, адресная линия
A20 должна быть включена.
Можно мереть от нуля, но поскольку в первом мегабайте есть дыры
(видеопамять, биосы, просто дыры), удобнее делать это начиная с первого
мегабайта.
Вовсе не обязательно проверять каждый байт, достаточно проверять один байт
на какое-то определенное количество памяти. Определенным количеством памяти
можно посчитать мегабайт, но лучше (хотя и медленнее) за единицу памяти
принять одну страницу памяти (4к).
Во избежание неприятностей память лучше не разрушать, а восстанавливать в
первоначальном виде. делается это примерно так:
xchg [ebx], eax
xchg [ebx], eax
Если после этого в eax содержится то же значение, которое было до того,
значит память присутствует по данному адресу. Если возвратилось 0ffffffffh,
значит память отсутствует, если же что ни будь другое - то это может быть
ROM, хотя после мегабайта вы вряд ли встретите какой либо BIOS. В любом
случае если память по текущему адресу не обнаружена, значит, память
закончилась и дальше искать чревато... существуют еще различные типы памяти
(ACPI например) которую не стоит трогать.
Из защищенного режима можно воспользоваться содержимым CMOS, некоторые
ячейки в нем BIOS заполняет определенными при начальном тесте системы
значениями. Но здесь все не так однозначно как хотелось бы. Разные версии
BIOS могут хранить значения в разных местах.
Байты 30-31 принято считать стандартными, но они определяют только 64Мб
памяти. Не очень то подходят для использования.
Почти любое приложение пользуется динамически выделяемыми блоками памяти
(известная, наверное, всем функция malloc в c). Сейчас мы поговорим о том,
как это все работает.
Подходить к этому можно по разному, но принцип везде прослеживается один.
На каждый блок памяти необходимо иметь структуру, описывающую занятось
блока, его размер. В примитивной реализации это может выглядеть так, как
это сделано в DOS.
В ДОСе вся память на равных правах принадлежит всем запущенным программам.
Но чтобы операционная система могла как-то контролировать использование
памяти, в ДОСе применяются MCB (Memory Control Block). Формат этого блока
таков:
struct {
char Signature;
unsigned short OwnerId;
unsigned short SizeParas;
char Reserved[3];
char OwnerName[8];
};
Размер структуры 16 байт (1 параграф памяти) и эта структура непосредственно
предшествует описываемому блоку памяти.
Размер блока указывается в параграфах в поле SizeParas. Такая структура
вполне подходит для ограниченной по размерам памяти DOS, но для приложений
она не очень то применима. Разница состоит в том, что в случае ДОС, чтобы
найти блок свободной памяти (Такие блоки помечаются нулевым OwnerId),
необходимо пройти по всем блокам от начала цепочки, до тех пор, пока не
встретится свободный блок соответствующего размера. В ДОСе имеется функция,
с помощью которой можно получить адрес первого блока (Base MCB)
(int 21h, fn 52h).
Столь медленный поиск не страшен для DOS, у которого количество блоков
редко превышает несколько десятков, но в приложениях поиск по цепочке
блоков может быть достаточно долгой процедурой.
Поэтому в приложениях обычно применяется другой алгоритм, который
заключается в следующем. (Я рассмотрю наиболее быстрый алгоритм, вариантов,
конечно, может быть множество):
У каждого блока, как я уже говорил, есть два основных параметра: размер и
флаг занятости. Оба эти параметра размещаются в одном двойном слове памяти.
Поскольку как начало блока, так и его размер обычно выравниваются на
четное число байт, младшие биты размера остаются неиспользуемыми (всегда
равны нулю) и флаг занятости размещается в одном из них.
Этот параметр блока размещается перед началом и по окончанию блока.
Начальный параметр следующего блока соответственно будет размещен
непосредственно после конечного параметра предыдущего, что позволит
анализировать цепочку блоков с одинаковым успехом в обоих направлениях.
Свободные блоки памяти размещаются в списках в соответствии со своим
размером. Размер блоков в списках увеличивается в геометрической прогрессии.
К примеру, в первом списке хранятся блоки до 16 байт длиной, во втором до
32-х байт длиной и так далее. Такая система позволяет, зная размер
необходимого блока, сразу же выбирать из соответствующего списка подходящий
блок и не требует поиска по всем блокам. Для организации списков к блоку
добавляются несколько параметров (поскольку блок свободен, и его внутреннее
пространство может быть использовано для любых целей, эти параметры
размещаются в самом блоке). К этим параметрам относятся ссылка на следующий
свободный блок в списке, и номер списка в котором находится блок. (Это
позволяет ускорить удаление блока из списка).
Для выделения блока необходимого размера сперва проверяется список
соответствующего размера, в котором может потребоваться поиск блока. Если
соответствующий список пуст, то проверяется следующий список, в котором уже
не требуется проводить поиска, поскольку любой блок заведомо больше нужного
размера. Найденный пустой блок делится на две части, вторая - не нужная
часть оформляется как свободная и помещается в соответствующий список,
а первая часть оформляется как занятая и возвращается программе.
Из-за необходимости введения дополнительных параметров для свободных блоков
памяти минимальный размер блока не может быть меньше 8 байт. Даже если
пользователь захочет получить блок меньшего размера, выделится блок в 8
байт длиной.
При освобождении блока, если предыдущий или последующий блоки пусты, он
объединяется с ними в один блок и добавляется в список соответствующего
размера. Использованные окружающие блоки удаляются из тех списков, в
которых они были записаны ранее.
Для того, чтобы предотвратить попытку объединения первого блока памяти (при
его освобождении) с предшествующим ему, перед первым блоком ставится
параметр с флагом занятости. То же самое делается и для последнего блока
памяти, но только после него.
Не буду пока вдаваться в тонкости реализации всего этого, если вас заинтересовало, то в ближайших выпусках рассмотрим. А этот выпуск заканчиваю. Жду от вас с нетерпением отзывов, пожеланий. До скорых встреч.
Отправлено 2002-02-15 для 6542 подписчиков.
ведущий рассылки Dron
Сайт проекта
Архив Рассылки
При поддержке Kalashnikoff.ru
| (C)Москва, 2001. Авторское право принадлежит Валяеву А.Ю. Публичное размещение материала из рассылки, а также его использование полностью или частично в коммерческих или иных подобных целях без письменного согласия автора влечет ответственность за нарушение авторских прав. |
| http://subscribe.ru/
E-mail: ask@subscribe.ru |
Отписаться
Убрать рекламу |