КаталогИндекс раздела
НазадОглавлениеВперед


4. Загрузка системы и распределение памяти

4.1. Основное распределение памяти

Как известно, адресное пространство микропроцессора 8086 имеет размер 1 Мбайт. Это адресное пространство распределяется таким образом, как показано на рис.4.1 (младшие адреса - внизу).


Рис.4.1 Распределение адресного пространства ПЭВМ
(все адреса шестнадцатиричные).

Адреса c 0000:0000 по 0000:03FF (1 Кбайт) занимает таблица векторов прерываний. Отметим, что векторы могут содержать адреса программ-обработчиков, адреса таблиц данных или быть свободными. По спецификациям DOS вектора с номерами от 0x60 по 0x67 свободны и могут заниматься программами пользователей. Однако, если пользователю необходимо использовать собственное прерывание, ему нельзя выбрать любой вектор из указанного диапазона без проверки. В этот момент в памяти ПЭВМ могут находиться какие-то резидентные программы (например, драйверы-русификаторы), которые могут использовать эти же вектора. Свободные векторы (а они могут найтись и вне специфицированной области) найти легко: эти векторы содержат нулевые адреса или константу NULL Турбо-Си.
Программа, приведенная ниже, выводит на экран таблицу векторов прерываний и определяет свободные векторы. Впоследствии мы укажем путь создания более совершенного варианта такой программы.


/*=                   ПРИМЕР 4.1.                   =*/
/*============= Анализ таблицы векторов =============*/
#include <dos.h>
#include <stdlib.h>
void *readvect(int in);
main() {
  void far *vect;  /* вектор */
  int intnum;      /* номер прерывания */
  int line, i;
  for (clrscr(),intnum=line=0;  intnum<l;256;  intnum++) {
    for (i=0;i<17;i+=16) {
      vect=readvect(intnum+i);
      printf("INT %02Xh - %Fp - ",intnum+i,vect);
      if (vect==NULL) printf("%-16s","Свободен");
      else printf("%-16s","Занят"); }
    if (i) {
      printf("\n");
      if (++line>15)
        { intnum+=16; line=0; getch(); clrscr(); }
      }
    }
}
/*==== Получение вектора ====*/
void *readvect(int in) {
 union REGS rr; struct SREGS sr;
  rr.h.ah=0x35; rr.h.al=in; intdosx(&rr,&rr,&sr);
  return(MK_FP(sr.es,rr.x.bx));
}

Адреса с 0040:0000 по 0040:00FF (256 байт) называются областью памяти BIOS. В некоторых описаниях - областью памяти ROM BIOS. Приставка ROM (Read Only Memory, т.е. ПЗУ) говорит не о том, что эта память защищена от чтения, а о том, что данные в этой области используются программами, находящимися в ПЗУ. С другой стороны, возможно, эта приставка предупреждает пользователя о том, что изменять данные в этой области памяти не следует, хотя ничем, кроме словесного предупреждения, эта память не защищена. Область памяти BIOS содержит данные, характеризующие состав, режим работы и текущее состояние оборудования ПЭВМ. Эти данные устанавливаются BIOS при загрузке и изменяются программами BIOS в процессе функционирования ПЭВМ. В дальнейшем мы познакомимся с размещением и использованием части этих данных. Доступ к этим данным может производиться либо через обращение к известным адресам памяти, либо (предпочтительнее) через прерывания BIOS. BIOS предоставляет нам ряд прерываний, с помощью которых мы можем корректно прочитать или записать информацию в этой области.
Адреса с 0050:0000 до 0050:FFFF - область памяти DOS, содержащая на фиксированных местах некоторые переменные DOS.
Далее вплоть до адреса 9000:FFFF (640 Кбайт) - область памяти, занимаемая компонентами DOS и распределяемая DOS для загружаемых программ (резидентных и нерезидентных).
Адресное пространство с A000:0000 по B000:FFFF носит название видеопамяти. Физически она расположена на плате дисплейного адаптера. Реально, в зависимости от типа адаптера, может иметься лишь часть этой области. Для монохромного адаптера MDA требуется только 4 Кбайт, начиная с адреса B000:0000. Для цветного - CGA - 16 Кбайт, начиная с B800:0000. Видеопамять для адаптеров EGA и VGA начинается с адреса B800:0000 в текстовом режиме и с A000:0000 - в графи- ческом.
Память в адресном пространстве с C000:0000 по F600:0000 не обязательно присутствует в ПЭВМ. В этой адресной области размещаются расширения ПЗУ. Мы можем проверить установленные на нашей ПЭВМ расширения ПЗУ при помощи программы, приведенной в примере 4.2. Эта программа читает первое слово из каждых 2 Кбайт, начиная с адреса C000:0000 в поисках маркера расширения ПЗУ: 0x55AA. Если такой маркер найден, то следующий байт содержит длину модуля ПЗУ, а следующие несколько десятков байт наша программа выводит на экран в символьном виде, обычно в этой области содержится текстовая информация о назначении модуля ПЗУ и о фирме-производителе.


/*=                   ПРИМЕР 4.2                     =*/
/*=============== Поиск расширений ПЗУ ===============*/
#include <dos.h>
main() {
  unsigned int  segm,off;      /* Части  адреса */
  unsigned int  byte=0xAA55;   /* Маркер   ПЗУ */
  clrscr();
  for (segm=0xc000;segm<0xffb0;segm+=0x40) {
    /* Перебор памяти от C000:0 с шагом 2 К */
    if (peek(segm,0)==byte) {
      /* Маркер найден */
      printf("Адрес ПЗУ = %04x",segm);
      printf(", Длина    модуля    =     %d*512     байт\n",
        peekb(segm,2));
      /* Распечатка части ПЗУ */
      for (off=3; off<200; off++)
        printf("%c",peekb(segm,off));
      getch();
      printf("\n\n");
      }
    }
}

Во всех проверенных нами машинах по адресу C000:0000 размещается ПЗУ дисплейного адаптера, а в машинах типа XT также по адресу C800:0000 - ПЗУ жесткого диска.
Адресное пространство с F600:0000 по FD00:0FFF предназначено для ПЗУ интерпретатора Бэйсика, имеющегося только на ПЭВМ производства фирмы IBM.
Наконец, от FE00:0000 и до конца адресного пространства расположено ПЗУ BIOS. BIOS в ПЗУ содержит программы, выполняющие следующие функции:

4.2. Загрузка системы

При включении питания микропроцессор 8086 начинает работу с передачи управления по адресу FFFF:0000 (этот адрес заносится в регистры CS:IP) - это аппаратная особенность микропроцессора. Этот адрес принадлежит ПЗУ BIOS, 5 байт по этому адресу содержат команду перехода на начало программы POST в ПЗУ (Power On Self Test - самопроверка при включении питания). Программа POST проверяет состав оборудования и формирует список оборудования в области памяти BIOS, выполняет тест ОЗУ (как правило, прохождение этого теста трассируется на экране терминала) и прочего оборудования ПЭВМ и инициализирует таблицу векторов прерываний в части прерываний, обслуживаемых BIOS. Также программа ищет в памяти расширения ПЗУ (как это делала наша программа 4.2) и вызывает их программы инициализации.
Затем BIOS начинает процедуру начальной загрузки. Начальный загрузчик опрашивает первое устройство гибких дисков, проверяя на нем наличие диска для начальной загрузки. Если диска там нет, программа обращается к ПЗУ, связанным с другими устройствами, которые могут содержать диски для начальной загрузки. Когда устройство загрузки найдено, BIOS читает с него блок начальной загрузки и передает на него управление. Блок начальной загрузки, размещенный на дорожке 0, секторе 1, стороны 0 первой доступной дискеты (или жесткого диска) обычно считывается в память по адресу 07C0:0000 и содержит загрузчик операционной системы и блок параметров, из которого загрузчик получает информацию о конфигурации системного диска. Загрузчик через таблицу векторов использует сервисные средства BIOS для загрузки в память остальной части системы. Загрузчик прежде всего устанавливает, что первые два файла в каталоге - IO.SYS и MSDOS.SYS (IBMBIO.COM и IBMDOS. COM для операционной системы PC DOS). Если это так, то оба файла считываются в оперативную память.
Файл IO.SYS состоит из модуля резидентных драйверов (BIOS DOS), модуля инициализации BIOS.DOS и модуля системной инициализации. В ходе инициализации BIOS DOS формируется список резидентных драйверов устройств в соответствии со списком оборудования, полученным при работе POST и изменяются некоторые векторы прерываний BIOS (т.е. BIOS DOS перехватывает обработку этих векторов у BIOS ПЗУ). После отработки модулей инициализации IO.SYS занимаемая ими память освобождается, и управление получает программа инициализации ядра DOS. Эта программа устанавливает векторы прерываний DOS и выполняет инициализацию резидентных драйверов. В ходе этой инициализации определяется максимальный размер сектора, используемого драйверами, и в соответствии с этим размером в памяти организуется буфер секторов. Затем выполняется обработка файла CONFIG.SYS. В соответствии с параметрами, заданными в CONFIG.SYS (или по умолчанию - если CONFIG.SYS отсутствует), формируются системные таблицы и загружаются устанавливаемые драйверы устройств. Наконец, открываются системные файлы (CON, PRN, AUX), загружается в память командный процессор COMMAND.COM, и управление передается его секции инициализации.

Имя командного процессора задается оператором SHELL в CONFIG.SYS, по умолчанию это COMMAND.COM. COMMAND.COM состоит из трех частей:

Таким образом, после окончания процесса загрузки область памяти, названная на рис.4.1 "DOS и транзитные программы" распределяется так, как показано на рис.4.2.


Рис.4.2 Область памяти "DOS и транзитные программы"

Вернемся к началу процесса загрузки. Как выполнить перезагрузку системы из своей программы? Прежде всего, определим, что перезагрузка может быть трех видов - "горячая", "теплая" и "холодная".
Прерывание BIOS 0x19 позволяет выполнить перезагрузку системы из программы. При этом перезагрузка начинается с действий, следующих за выполнением программы POST - начального загрузчика BIOS - и носит название "горячей" перезагрузки. Следующая программа, возможно, приведет к "горячей" перезагрузке системы:


/*=                   ПРИМЕР 4.3.                   =*/
/*========== Горячая перезагрузка системы ===========*/
#include <dos.h>
main() {
  /* 2-й и 3-й параметры вызова нулевые, т.к. для
  прерывания 0x19 никаких параметров не требуется */
  int86(0x19,00,00);
}

Вы обратили внимание на слово "возможно" в предыдущей фразе? Скорее всего, программа приведет к "зависанию" системы. Дело в том, что при "горячей" перезагрузке не переустанавливаются векторы прерываний BIOS, таким образом, если прерывания BIOS были к моменту выдачи INT 19H перехвачены какими-то резидентными программами, после перезагрузки системы эти векторы будут указывать неизвестно куда. Поэтому не следует возлагать больших надежд на "горячую" перезагрузку.
В "холодном" и "теплом" вариантах перезагрузка выполняется с самого начала - с выполнения программы POST. Различие между "холодным" и "теплым вариантами заключается в том, что в первом случае POST выполняется в полном объеме - как при нажатии кнопки RESET, а во втором из нее исключается тестирование оборудования и оперативной памяти - как при нажатии комбинации клавиш Ctrl+ Alt+Del. Для запуска перезагрузки надо просто передать управление по адресу FFFF:0000. Тип перезагрузки BIOS определяет из содержимого слова по адресу 0040:0072 - если там находится код 0x1234, выполняется "теплая" перезагрузка, иначе - "холодная". Программное выполнение такой перезагрузки представлено в примере 4.4.


/*=                    ПРИМЕР 4.4                     =*/
/*=== Вызов программы POST холодная/теплая загрузка ===*/
#include <dos.h>
main() {
void (* func)(); /* адрес функции */
unsigned int code=0x0a;
  /* Формируется адрес POST - F000:FFF0 */
  func=MK_FP(0xf000,0xfff0);
  while (code==0x0a) {
    printf
      ("\nУкажите вариант перезагрузки:  0 -  холодная;\n");
    printf(" 1 - теплая >"); switch(getche()) {
      case '0': code=0; break;
      case '1': code=0x1234; break;
      }
    }
  /* Запись признака типа перезагрузки в область  памяти  BIOS */
  poke(0x40,0x72,code);  /* Передается управление на POST */
  (*func)();
}

Следует, однако, иметь в виду, что указанное различие между "холодным" и "теплым" вариантами строго соблюдается в компьютерах производства фирмы IBM. В компьютерах, имеющих BIOS других производителей, "теплая" загрузка может включать в себя и тестирование - частичное или полное (в последнем случае она не будет отличаться от "холодной").

4.3. Файл CONFIG.SYS

Выше мы упомянули файл CONFIG.SYS, содержимое которого влияет на формирование системных таблиц и загрузку устанавливаемых драйверов. CONFIG.SYS является текстовым файлом, содержащим набор команд конфигурирования системы. Приведем краткий обзор команд конфигурирования:

BREAK - установка уровня проверки Ctrl+Break.
BUFFERS- установка числа буферов для дисковых операций.
COUNTRY- установка зависящего от страны формата даты и времени.
DEVICE- установка драйвера устройства.
DRIVPARM- установка параметров для дискового драйвера.
FCBS- установка числа Блоков Управления Файлами, одновременно открытых в режиме разделения.
FILES- установка числа описателей файлов в системе.
INSTALL- загрузка TSR-программ (DOS 4.0 и выше).
LASTDRIVE- установка числа дисковых идентификаторов.
SHELL- определение файла командного процессора и размера окружения.
SWITCHAR- установка символа переключения для командной строки.
SWITCHES- отмена расширенной клавиатуры.
STACKS- установка размеров стеков, используемых для обработки прерываний от оборудования


КаталогИндекс раздела
НазадОглавлениеВперед