Все для программиста

Реализация многозадачности в RealMode


Загрузка задачи.

В реальном режиме мы имеем 640Kb памяти - 10 сегментов по 64Kb. В первый сегмент нам лучше пока не соваться - эта область BIOS. Для простоты предположим, что каждая задача нашей ОС - это COM файл MS-DOS.

COM-программы содержат единственный сегмент (или, во всяком случае, не содержат явных ссылок на другие сегменты). Образ COM-файла считывается с диска и помещается в память, начиная с PSP:0100. Заметим, что COM-программа может использовать множественные сегменты, но она должна сама вычислять сегментные адреса, используя PSP как базу.

COM-программы предпочтительнее EXE-программ, когда дело касается небольших ассемблерных утилит. Они быстрее загружаются, ибо не требуется перемещения сегментов, и занимают меньше места на диске, поскольку заголовок EXE и сегмент стека отсутствуют в загрузочном модуле.

В MS-DOS после загрузки двоичного образа:

Наша задача при загрузке файла проделать те-же самые действия, что-бы программы ни коим образом не догадывалась об отстутствии ее родной ОС.

Переключение задач.

Предположим, что каждая COM-программа занимает в памяти один сегмент. Обычно это выглядит следующим образом:

18.2 раза в секунду приходит аппаратное прерывание, и процессор отвлекается на выполнение некоторой процедуры - восьмого прерывания (int 08h). При этом он сохраняет в стеке регистр флагов (PUSHF), и регистры указывающие на текущую команду (CS:IP) (PUSH CS, PUSH IP). Всего 6 байт. После окончания аппаратного прерывания эти регистры восстанавливаются и основная программа продолжает свое выполнение.

Наша задача, в время выполнения прервания подменять стек таким образом, что-бы после восстановления регистров выполнялась другая программа, находящаяяся в памяти.

Структура дескрипторов задачи.

При наилучшем раскладе возможна загрузка восьми задач - 640Kb/64Kb=10, то есть всего имеем десять сегментов - один под переменные DOS, и один под ядро, вот и остается только восемь.

Для каждой из восьми возможных задач и для ядра, заводим структуру:

task8          DB ?                     ;¦  char id; (255 - no task)
               DD ?                     ;¦  void far * pointer;
               DW 255 DUP(?)            ;-  unsigned int stack[255]; }

id - идентификатор задачи, если загружена, то ее номер, 255 - если не загружена и 254 - если приостановлена.

pointer - Точка входа в задачу.

stack[255] - В это место будем сохранять некоторые регистры задачи при переключении, кроме того здесь будет хранится указатель на стек задачи, где сохранены остальные регистры, ну и еще что-нибуть - если понадобится.

<< Начало