АЛМАТИНСКИЙ ИНСТИТУТ ЭНЕРГЕТИКИ И СВЯЗИ

Кафедра инженерной кибернетики

 

 

 

 

 

 

 

 

 

 

 

СИСТЕМНОЕ ПРОГРАММИРОВАНИЕ

Часть 2

Методические указания к выполнению лабораторных работ

 (для студентов специальностей

360140 Автоматизация и информатизация в системах управления,

050702 – Автоматизация и управление)

 

 

 

 

 

 

Алматы 2006


СОСТАВИТЕЛИ: Н.В.Сябина. Системное программирование. Часть 2. Методические указания к выполнению лабораторных работ (для студентов очной формы обучения специальностей 360140 – Автоматизация и информатизация в системах управления, 050702 – Автоматизация и управление). - Алматы: АИЭС, 2006.-  35 с.

 

   

 

Методические указания по дисциплине «Системное программирование» включают 9 лабораторных работ (в двух частях) и разработаны в помощь студентам, изучающим системное программирование, с  целью выработки практических навыков в следующих направлениях:

- применение языка программирования С как инструмента для системного программирования;

- программное управление аппаратными средствами ПЭВМ на низком уровне;

- использование внутренних структур данных операционной системы MS DOS для получения информации и оперативной настройки системы.

В каждой лабораторной работе предлагаются варианты заданий, методы и примеры решения задач, листинги программ, которые сопровождаются необходимыми комментариями, а также контрольные вопросы.

Методические указания предназначены для студентов специальности 360140 – Автоматизация и информатизация в системах управления. 

  Библиогр. –  10 назв.

 

 

 

 

 

 

    Рецензент: канд. техн. наук, доц. Ибраева Л.К.

 

 

 

 

    Печатается по плану издания Алматинского института энергетики

и связи на 2006 г.

 

 

 

 

 

 

© Алматинский институт энергетики и связи, 2006 г.


6 Лабораторная работа № 6. Проверка оборудования

 

Цель работы – получение практических навыков в определении конфигурации и основных характеристик компьютера.

Предварительно необходимо изучить следующие разделы: «Управление вводом-выводом в операционных системах»,  «Организация внешней памяти на магнитных дисках» [1, 6, 7, 8].

 

6.1 Постановка задачи

Для компьютера на своем рабочем месте определить:

- тип компьютера;

- конфигурацию оборудования;

- объем оперативной памяти;

- наличие и объем расширенной памяти;

- наличие дополнительных ПЗУ;

- версию операционной системы.

 

6.2 Пример решения задачи

6.2.2 Метод решения

6.2.2.1 Структура данных программы

Программа использует так называемый список оборудования — 2-байтное слово в области данных BIOS по адресу 0040:0010.

Назначение разрядов списка оборудования:

- 0 - установлен в 1, если есть НГМД;

- 1 - установлен в 1, если есть сопроцессор;

- 2,3 - число 16-Кбайтных блоков ОЗУ на системной плате;

- 4,5 - код видеоадаптера: 11 — MDA, 10 — CGA, 80 колонок, 01 — CGA, 40 колонок, 00 — другой;

- 6,7 - число НГМД-1 (если в разряде 0 единица);

- 8, 9 - канал ПДП;

- 9,10,11 - число последовательных портов RS-232;

- 12 - 1, если есть джойстик;

- 13 - 1, если есть последовательный принтер;

- 14,15 - число параллельных принтеров.

6.2.2.2 Структура программы

Программа состоит только из основной функции main(). Выделения фрагментов программы в отдельные процедуры не требуется, т. к. операций, многократно выполняемых во время работы программы, нет.

6.2.2.3 Описание переменных

Переменные, применяемые в программе:

- type_PC — байт типа компьютера, записанный в ПЗУ BIOS по адресу FF00:0FFE;

- a, b — переменные для определения объема extended-памяти ПЭВМ, a — младший байт, b — старший байт;

- konf_b — 2-байтное слово из области данных BIOS, которое содержит список оборудования;

- type — массив символьных строк, представляющих типы компьютера;

- typ1A — массив байт, содержащий коды типов дисплеев;

- types1A[] — массив строк, содержащий названия типов дисплеев;

- j — вспомогательная переменная, используемая для идентификации типа дисплея;

- seg — сегмент, в котором размещено дополнительное ПЗУ;

- mark — маркер ПЗУ;

- bufVGA[64] — буфер данных VGA, из которого (при наличии VGA) выбирается объем видеопамяти;

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

6.2.3 Описание алгоритма программы

Алгоритм основной программы разбит на пять частей.

Часть 1 предназначена для определения типа компьютера. Для этого считывается байт, записанный в ПЗУ BIOS по адресу FF00:0FFE. В зависимости от значения этого байта делается вывод о типе ПЭВМ. Так, например, компьютеру типа AT соответствует код 0xFC.

Часть 2 предназначена для определения конфигурации ПЭВМ. Для этого считывается из области данных BIOS список оборудования. Для определения количества дисководов (если бит 0 установлен в 1) необходимо выделить биты 6 и 7 (маска 00C0h) и сместить их вправо на 6 разрядов, а потом добавить 1.

Для определения количества 16-Кбайтных блоков ОЗУ на системной плате необходимо выделить биты 2 и 3 с помощью маски 000Ch, сместить вправо на 2 разряда и добавить 1.

Для определения количества последовательных портов RS-232 выделить с помощью маски 0Eh биты 9-11 и сместить вправо на 9 разрядов.

Для определения наличия математического сопроцессора проверить установку бита 1 маской 0002h.

Для определения наличия джойстика — бита 12 с помощью маски 1000h.

Определить количество параллельных принтеров можно, выделив биты 14 и 15 маской C000h и сместив их вправо на 14 разрядов.

Поскольку список оборудования содержит недостаточно информации о дисплейном адаптере, то для уточнения типа адаптера выполняются дополнительные действия. Видеоадаптер обслуживается прерыванием BIOS 10h. Для новых типов адаптеров список его функций расширяется. Эти новые функции и используются для определения типа адаптера. Функция 1Ah доступна только при наличии расширения BIOS, ориентированного на обслуживание VGA. В этом случае функция возвращает в регистре AL код 1Ah свою “визитную карточку”, а в BL — код активного видеоадаптера. В случае, если функция 1Ah поддерживается, выполняется обращение к функции 1Bh, которая заполняет 70-байтный блок информации  о состоянии, из которого выбирается объем видеопамяти. Если 1Ah не поддерживается, это означает, что VGA нет, в этом случае следует обратиться к функции 12h и получить информацию  о EGA. При наличии расширения, ориентированного на EGA, эта функция изменяет содержимое BL (перед обращением он должен быть 10h) на 0 (цветной режим) или на 1 (монохромный режим), а в BH возвращает объем видеопамяти. Если же ни 1Ah, ни 12h не поддерживаются, то список оборудования BIOS содержит достаточную информацию  о видеоадаптере и, выделив  биты 4, 5, можно сделать окончательный вывод об имеющемся типе адаптера.

В третьей части программы определяется объем оперативной памяти, наличие и объем extended-памяти. Объем оперативной памяти для AT может быть прочитан из регистров 15h (младший байт) и 16h (старший байт) CMOS-памяти или из области памяти BIOS по адресу 0040:0013 (2-байтное слово). Кроме того, в ПЭВМ может быть еще и дополнительная (expanded) память свыше 1 Мб. Ее объем можно получить из регистров 17h (младший байт) и 18h (старший байт) CMOS-памяти. Для чтения регистра CMOS-памяти необходимо записать в порт 70h байт номера регистра, а потом из порта 71h прочитать байт содержимого этого регистра.

В четвертой части программы определяется наличие и объем дополнительных ПЗУ. В адресном пространстве от C000:0000 по F600:0000 размещаются расширения ПЗУ (эта память не обязательно присутствует в ПЭВМ). Для определения наличия дополнительного ПЗУ следует считать первое слово из каждых 2 Кб, начиная с адреса C000:0000, в поисках маркера расширения ПЗУ: 55AAh. Если такой маркер найден, то следующий байт содержит длину модуля ПЗУ.

В пятой части программы определяется версия DOS, установленная на ПЭВМ. Для этого достаточно воспользоваться функцией DOS 30h, которая возвращает в регистре AL старшее число номера версии, а в регистре AH — младшее число.

6.2.4 Программа и результаты ее работы

Текст программы приведен в приложении А. В процессе работы программы на экран может быть выведена следующая информация:

Лабораторная работа N6

Проверка состава оборудования

Тип компьютера: AT

Конфигурация:

Дисководов ГМД: 2

Математич. сопроцессор: есть

Тип дисплейного адаптера: VGA, кол., анал., 256 Кбайт

Первичный блок памяти: 16 Кбайт

Портов RS232: 2

Джойстик: нет

Принтеров: 1

Объем оперативной памяти: 639 Кбайт

Объем extended-памяти: 384 Кбайт

Адрес ПЗУ = c000. Длина модуля = 24576 байт

Версия MS-DOS 6.20

 

6.3 Контрольные вопросы

6.3.1 Назовите основные концепции организации ввода-вывода в операционных системах.

6.3.2 Какие основные задачи возлагаются на супервизор ввода-вывода?

6.3.3 Какие существуют режимы управления вводом-выводом?

6.3.4 Перечислите основные системные таблицы ввода-вывода.

6.3.5 Что представляет собой синхронный ввод-вывод?

6.3.6 Чем асинхронный ввод-вывод отличается от синхронного?

6.3.7 Какие действия необходимо выполнить для определения типа видеоадаптера?

6.3.8 Что представляет собой BIOS? Какие функции она выполняет?

6.3.9 Что понимают под конфигурацией оборудования?

6.3.10 Что представляет собой список оборудования?

 

 

7 Лабораторная работа № 7. Главная загрузочная запись

 

Цель работы – получение практических навыков в работе с главной загрузочной записью жесткого диска.

Предварительно необходимо изучить следующие темы: «Функции файловой системы и иерархия данных», «Файловая система FAT», «Структура загрузочной записи DOS» [1, 6, 7, 8], «Сложные типы данных в С: структуры» [3, 5].

 

7.1 Постановка задачи

Прочитать и выполнить форматный вывод на экран главной загрузочной записи жесткого диска на своем рабочем месте.

 

7.2 Пример решения задачи

7.2.1 Структура программы

Программа состоит из основной программы main(), которая реализует все действия для чтения главной загрузочной записи.

7.2.2 Описание переменных

7.2.2.1 Переменные:

- x, y — экpанные кооpдинаты;

- head — номеp головки (0);

- Sect_Trk — номеp доpожки и сектоpа (0,1);

- ndrive=0 — номеp логического диска;

- EndList — указатель на подпись.

7.2.2.2 Структуры

а) struct Part {                  /* структура элемента раздела*/

byte ActFlag;                  /* признак активного раздела */

/* физический адрес начала раздела */

byte Begin_Hd;              /* # головки */

word Begin_SecTrk;       /* # секторы и дорожки */

byte SysCode;                 /* код системы */

/* физический адрес конца раздела */

byte End_Hd;                 /* # головки */

word End_SecTrk;          /* # секторы и дорожки */

dword RelSec;                    /* # секторы */

dword Size; }                 /* количество секторов */

 

б) struct MBR {                 /* структура главной загрузочной записи.*/

char LoadCode[0x1be];  /* пpогpамма загрузки */

struct Part rt[4];              /* 4 элемента pазделов */

word EndFlag;     }          /* подпись MBR */

 

7.2.3 Описание алгоритма программы

Программа демонстрирует разделение логического диска.

Начальный адрес для чтения задан: 0,0,1. При помощи прерывания 0x13 программа считывает сектор по заданному адресу, далее происходит поэлементный анализ таблицы разделов, пока не встретится признак конца таблицы или раздел нулевого размера. Значения полей элемента таблицы выводятся на экран. Манипуляции, которые описываются макросами TRK и SECT, обеспечивают распаковку номера дорожки и сектора. Если в поле SysCode содержится признак расширенного раздела, то устанавливается новый дисковый адрес, считывается новый сектор и анализируется новая таблица.

7.2.4 Программа и результаты ее работы

Текст программы приведен в приложении Б. В процессе работы программы на экран выводится информация вида:

Лабораторная работа N7

Главная загрузочная запись

Разделы жесткого диска:

Лог.диск -----> C Ext E Ext G

Признак ------> 80H 00H 00H 00H 00H

Код системы --> 1 5 4 5 0

Начало: гол.--> 1 0 1 0 1

дор.--> 0 121 121 724 724

сект.-> 1 1 1 1 1

Конец: гол.--> 4 4 4 4 4

дор. -> 120 975 723 975 975

сект.-> 17 17 17 17 17

Нач.сектор ---> 17 10285 17 51255 17

Размер -------> 10268 72675 51238 21420 21403

Нажмите любую клавишу...

 

7.3 Контрольные вопросы

7.3.1 Опишите структуру магнитного диска (разбиение на разделы).

7.3.2 Как в общем случае осуществляется загрузка операционной системы после включения компьютера?

7.3.3 Что понимается под начальным, системным и внесистемным загрузчиками? Где они располагаются?

7.3.4 Что представляет собой файловая система? Какие файловые системы применяются на ПЭВМ?

7.3.5 Объясните общие принципы устройства файловой системы FAT.

7.3.6 Сравните файловые системы FAT16 и FAT32.

7.3.7 Из каких компонентов состоит системная область логического диска?

7.3.8 Что представляет собой таблица размещения файлов?

7.3.9 Каким образом хранится и обновляется таблица FAT?

7.3.10 Опишите структуру загрузочной записи DOS.

 

 

8 Лабораторная работа № 8. Дисковые структуры данных DOS

 

Цель работы – получение практических навыков в работе с таблицей размещения файлов.

Предварительно необходимо изучить следующие темы: «Файловая система FAT», «Таблица размещения файлов» [1, 6, 7, 8], «Указатели» [3, 5].

 

8.1 Постановка задачи

Определить номера всех кластеров диска, которые занимает заданный преподавателем файл в текущем каталоге.

 

8.2 Пример решения задачи

8.2.1 Структура программы

Программа состоит из главной функции main() и 11 вспомогательных функций:

- void Read_Mbr(void) — функция чтения MBR и поиска требуемого раздела;

- void Read_Boot(void) — функция чтения boot-сектора;

- void Get_First(void) — функция определения абсолютного номера сектора начала логического диска;

- void Read_Fat(void)функция чтения FAT;

- void Read_13(void *mem) — функция чтения сектора с помощью прерывания 13;

- void Sect_to_Daddr(dword sect) — функция формирования физического дискового адреса из номера сектора;

- dword Clust_to_Sect(word clust) — функция определения номера сектора по номеру кластера;

- word Next_Clust(word clust) — функция выборки следующего кластера из FAT;

- char *Get_Name(char *s, char *d) — функция выделения следующего элемента из строки задания;

- int Find_Name() — функция поиска имени в каталоге;

- void End_of_Job(int n) — функция выдачи сообщений или аварийного завершения.

8.2.2 Описание переменных

8.2.2.1 В программе описаны структуры вида:

- физический дисковый адрес

struct DADDR {

byte h;             /* головка */

word s,            /* сектор */

t,                    /* дорожка */

ts;                   /* упакованные сектор и дорожка */

} ;

- структура элемента раздела

struct PART {

byte Boot,                   /* признак активного раздела*/

/* физический адрес начала раздела */

Begin_Hd;                   /* # головки */

word Begin_SecTrk;   /* # секторы и дорожки */

byte SysCode,                /* код системы */

/* физический адрес конца раздела */

End_Hd;                     /* # головки */

word End_SecTrk;      /* # секторы и дорожки */

dword RelSec,                /* # секторы*/

Size;                            /* количество секторов */

} ;

- стpуктуpа главной загрузочной записи

struct MBR {

char LoadCode[0x1be];     /* программа загрузки */

struct PART rt[4];          /* 4 элемента разделов */

word EndFlag;               /* подпись MBR */

} ;

- структура загрузочной записи логического диска

struct BootRec {

byte jmp[3], ident[8];

word SectSize;

byte ClustSize;

word ResSect;

byte FatCnt;

word RootSize, TotSecs;

byte Media;

word FatSize, TrkSecs, HeadCnt;

word HidnSecL, HidnSecH;

dword LongTotSecs;

byte Drive, reserved1, DOS4_flag;

dword VolNum; char VolLabel[11], FatForm[8];

} ;

- структура элемента каталога

struct Dir_Item {

char fname[11];     /* имя файла */

byte attr;                 /* атрибут */

byte reserved[10];

word time;              /* время */

word date;              /* дата */

word cl;                  /* номер 1-го кластера */

dword size;             /* размер файла */

} ;

8.2.2.2 Переменные, глобальные для всей программы:

- part — текущий элемент раздела;

- buff1[512] — буфер MBR и boot;

- *mbr — указатель на таблицу разделов;

- *boot — указатель на корневую запись;

- buff2[512] — буфер каталога и текста;

- *dir — указатель на часть каталога;

- *text — указатель на текстовый буфер;

- *fat — указатель на FAT;

- job[81] — строка-задание;

- jobptr — текущий указатель в job;

- cname[12] — текущее имя для поиска;

- Fdisk — физический номер диска;

- caddr — текущий дисковый адрес;

- sect — текущий номер сектора;

- clust — текущий номер кластера;

- fat16 — признак формата FAT;

- fsize — размер файла;

- dirnum — номер элемента в каталоге;

- FirstSect — абсолютный номер сектора начала;

- rootdir=1 — признак корневого каталога или подкаталога (1/0);

- lastsect — последний сектор при чтении;

- fatalloc=0 — признак выделения памяти.

8.2.3 Описание алгоритма программы

Функция main запрашивает имя файла, потом обрабатывает его, и если все нормально, то запускает вспомогательные функции, необходимые для просмотра FAT заданного файла.

Функция Read_Mbr выполняет выборку элемента таблицы разделов для заданного диска.

Функция Read_Boot считывает boot-сектор логического диска, причем для гибкого диска адрес этого сектора назначается — 0, 0, 1, а для жесткого — выбирается из part.

Функция Get_First определяет абсолютный номер начального сектора логического диска и сохраняет его переменной First_Sect. Это значение вычисляется из физического адреса начала, который берется из полей Begin_Hd, Begin_SecTrk элемента таблицы разделов.

Функция Read_Fat считывает в память FAT целиком, адрес начала FAT на диске и ее размер определяются из ранее прочитанного boot-сектора.

Функция Read_13 читает один сектор с помощью прерывания BIOS.

Функция Sect_to_Daddr преобразует номер логического сектора в физический адрес.

Функция Clust_to_Sect преобразует номер кластера в номер сектора.

Функция Next_Clust определяет номер следующего кластера, анализируя FAT. Для последнего кластера (и для корневого каталога) эта функция возвращает нулевое значение.

Функция Get_Name предназначена для лексического разбора задания, она выделяет из задания очередное слово и переназначает jobptr. Пустое (NULL) значение jobptr — свидетельство об исчерпании задания.

Функция Find_Name выполняет поиск имени в каталоге. Здесь cname — требуемое имя, функция возвращает индекс найденного элемента в массиве dir или (-1).

Функция End_of_Job выполняет выдачу на экран различных сообщений при ошибках или при завершении программы.

8.2.4 Программа и результаты ее работы

Текст программы приведен в приложении В. В процессе работы программы на экран выводится следующая информация:

 

Лабораторная работа N8

Дисковые структуры данных DOS.

Файл D:\ TC\ TC.EXE в FAT занимает такие кластеры:

Нажимайте любую клавишу, пока не появится <КОНЕЦ ФАЙЛА>.

-<НАЧАЛО ФАЙЛА>

8L->2410--->2411--->2412--->2413--->2414--->2415--->2416--->2417-

-->2418--->2419--->241a--->241b--->241c--->241d--->241e--->241f-

-->2420--->2421--->2422--->2423--->2424--->2425--->2426--->2427-

-->2428--->2429--->242a--->242b--->242c--->242d--->242e--->242f-

-->2430--->2431--->2432--->2433--->2434--->2435--->2436--->2437-

-->2438--->2439--->243a--->243b--->243c--->243d--->243e--->243f-

-->2440--->2441--->2442--->2443--->2444--->2445--->2446--->2447-

-->2448--->2449--->244a--->244b--->244c--->244d--->244e--->244f-

-->2450--->2451--->2452--->2453--->2454--->2455--->2456--->2457-

-->2458--->2459--->245a--->245b--->245c--->245d--->245e--->245f-

-->2460--->2461--->2462--->2463--->2464--->2465--->2466--->2467-

-->2468--->2469--->246a--->246b--->246c--->246d--->246e--->246f-

-->2470--->2471--->2472--->2473--->2474--->2475--->2476--->2477-

-->2478--->2479--->247a--->247b--->247c--->247d--->247e--->247f-

-->2480--->2481--->2482--->2483--->2484--->2485--->2486--->2487-

-->2488--->2489--->248a--->248b--->248c--->248d--->248e--->248f-

-->2490--->2491--->2492--->2493--->2494--->2495--->2496--->2497-

-->2498--->2499--->249a--->249b--->249c--->249d---><КОНЕЦ ФАЙЛА>

Количество кластеров в файле: 142

Нажмите любую клавишу...

 

8.3 Контрольные вопросы

8.3.1 Какая информация указывается в таблице размещения данных?

8.3.2 Что содержит область данных?

8.3.3 Что представляет собой кластер?

8.3.4 Отчего зависит размер кластера?

8.3.5 Какой смысл имеет логическое разбиение области данных на кластеры?

8.3.6 Что понимается под фрагментацией файлов?

8.3.7 Какие проблемы могут возникнуть в связи с большой фрагментацией?

8.3.8 Что представляет собой структура элемента каталога?

8.3.9 В каком месте на диске размещается сектор, содержащий системный загрузчик DOS, каков его физический адрес?

8.3.10 Какие известные программы используются для работы с загрузочной записью DOS?

 

 


9 Лабораторная работа № 9. Управление программами

 

Цель работы – изучение принципов управления программами в MS DOS и приобретение практических навыков работы с префиксом программного сегмента и его полями.

Предварительно необходимо изучить следующие темы: «Сегментный способ организации виртуальной памяти», «Реальный и защищенный режимы работы процессора», «Сегменты» [1, 6, 7, 8].

 

9.1 Постановка задачи

Разработать программу, производящую форматный вывод на печать своего префикса программного сегмента.

 

9.2 Пример решения задачи

9.2.1 Структура программы

Программа состоит из основной программы и двух функций:

- void get_DOS_version_h(void) — функция, возвращающая в глобальной переменной dos_ver старшее число номера версии DOS.

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

9.2.2 Описание переменных, глобальных для всей программы:

- p_psp — указатель на структуру struct PSP,

- pid — сегментный адрес PSP;

- dos_ver — старшее число номера версии DOS;

- i — вспомогательная переменная, используемая для просмотра таблицы файлов задачи (JFT), которая представляет собой массив из 20 элементов (возможно, что их число отлично от 20, поэтому размер массива определяется из поля JFT_size);

- l — переменная, используемая для вывода содержимого сегмента окружения DOS и определения числа строк вызова (для версии DOS 3.0 и выше);

- s — переменная, которая вначале используется как указатель на таблицу файлов задачи, затем на строки сегмента окружения и строки вызова;

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

9.2.3 Описание алгоритма программы

Программа производит распечатку основных полей своего PSP. Для этого префикс программного сегмента представим в виде следующей структуры:

struct psp {                       /* формат PSP */

byte ret_op[2];                 /* команда INT 20h */

word end_of_mem;           /* вершина доступной памяти*/

byte reserved1;

byte old_call_dos[5];        /* старый вызов DOS */

void *term_ptr;                 /* адрес завершения */

void *ctrlbrk_ptr;             /* адрес обработчика Ctrl+Break */

void *criterr_ptr;              /* адрес обработчика крит.ошибок */

word father_psp;              /* PID родителя */

byte JFT[20];                   /* таблица файлов программы */

word env_seg;                  /* адрес окружения */

void *stack_ptr;                /* адрес стека */

word JFT_size;                 /* размер таблицы файлов */

byte *JFT_ptr;                /* адрес таблицы файлов */

byte reserved2[24];

byte new_call_dos[3];      /* новый вызов DOS */

} *p_psp;

Поле ret_op используется для возможного завершения программы по команде RET 0, поле old_call_dos содержит команду вызова диспетчера функций DOS. Обращение к этому полю в программе может использоваться вместо команды INT 21h, но в современных версиях DOS для этих целей лучше обращаться к полю new_call _dos.

Поле end_of_mem содержит сегментный адрес конца доступной памяти в системе. В три поля (term_ptr, ctrlbrk_ptr, criterr_ptr) при загрузке программы DOS копирует содержимое векторов прерываний: 22h, 23h, 24, представляющее собой адреса обработчиков: завершения программы, комбинации клавиш Ctrl+Break, критической ошибки — соответственно. Предполагается, что программа может свободно перенаправить эти векторы на собственные обработчики соответствующих ситуаций, но от забот по восстановлению векторов программа избавляется, так как при ее завершении DOS сама восстанавливает векторы из соответствующих полей PSP завершаемой программы. Для аналогичных целей предназначено и поле stack_ptr — в нем сохраняется (а при завершении — из него восстанавливается) адрес стека, использовавшегося до вызова программы. Поле, именуемое father_psp, содержит сегментный адрес PSP родителя — программы, запустившей данную программу, обычно родителем является COMMAND.COM.

При загрузке программы DOS, кроме программного сегмента, создает для нее еще и сегмент окружения. Сегмент окружения содержит ASCIIZ-строки, задающие значения некоторых глобальных переменных, эти значения могут устанавливаться командой DOS SET, они доступны командным файлам и через PSP программам. Набор строк окружения заканчивается пустой ASCIIZ-строкой (нулем). В DOS 3.0 и выше за ним следует еще 2-байтное число строк вызова (обычно 1) и далее — строка (или строки) вызова программы. Обычно в первую (до строк вызова) часть порождаемой программы копируется содержимое окружения программы-родителя. Программа имеет доступ к своему сегменту окружения через поле env_seg PSP, содержащее сегментный адрес окружения.

Поле JFT (Job File Table — таблица файлов задачи) представляет собой массив из 20 однобайтных элементов. При открытии программой файла DOS формирует для него блок-описатель в системной таблице файлов и помещает ссылку на него (его номер) в свободный элемент JFT. Дескриптор файла, возвращаемый программе DOS при открытии файла, является номером элемента в JFT. При запуске программы первые пять элементов, создаваемой для нее JFT, содержат ссылки на системные файлы, остальные свободны. При обработке JFT DOS использует не прямое обращение к полю JFT PSP, а косвенное — через поле JFT_ptr, а в качестве ограничителя размера JFT — не константу 20, а значение поля JFT_size PSP.

Для написания программы, осуществляющей форматный вывод своего префикса программного сегмента, сначала необходимо определить версию DOS с помощью функции get_DOS_version_h() и получить адрес PSP (с помощью функции addr_PSP()).

Функция get_DOS_version_h() определяет старшее число номера версии DOS, используя для этого функцию DOS 30h (прерывание 21h), которая возвращает в регистре AL старшее число номера версии, а в регистре AH — младшее число. Нас интересует только значение регистра AL.

Функция addr_PSP() возвращает сегментный адрес PSP путем использования функции DOS 62h:

Вход: AH = 62h

Выход: BX = сегментный адрес PSP текущего процесса

9.2.4 Программа и результаты ее работы

Текст программы приведен в приложении Г. В процессе работы программы на экран была выведена следующая информация:

Лабораторная работа N9

Управление программами

Адрес PID = 0BA0

Команды:

--------

Завершение — int 20h: CD 20

Старый вызов DOS: 9A F0 FE 1D F0

Новый вызов DOS: CD 21 CB

Адреса:

-------

Конец памяти: 9FC0:0000

Обработчик завершения: 0AFA:02B1

Обработчик Ctrl+Break: 0AFA:014A

Обработчик критич.ошибки: 0AFA:0155

Стек: 0E04:0F94

Родитель: 0AFA

 

Таблица файлов: 0BA0:0018 (20) — в этом же PSP

1 1 1 0 2 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1

Окружение DOS: 0A1E

CONFIG=STD

COMSPEC=C:\ DOS\ COMMAND.COM

PROMPT=$p$g

PATH=D:\ WIN;C:\ ;C:\ DOS;C:\ ARH;C:\ NC;C:\ BAT;D:\ TP;

D:\ TP7;D:\ BC\ BIN

TEMP=d:\ ~TMP

Число строк вызова: 1

D:\ TC\ TC_LAB9.EXE

 

9.3 Контрольные вопросы

9.3.1 Что такое сегмент?

9.3.2 Назовите известные регистры сегментов.

9.3.3 Для чего предназначен регистр сегмента кодов?

9.3.4 Что представляет собой префикс программного сегмента?

9.3.5 Что представляет собой механизм сегментной адресации?

9.3.6 Как определить физический адрес команды?

9.3.7 Что представляет собой дескриптор сегмента?

9.3.8 Какие сегментные регистры называют селекторами сегментов?

9.3.9 Что понимается под сегментным способом организации виртуальной памяти?

9.3.10 Что такое сегмент состояния задачи?

 

 


Приложение A

Листинг программы и комментарии к лабораторной работе № 6

 

/******************** Проверка состава оборудования**************/

#include <dos.h>

#include <conio.h>

#include <stdio.h>

/*************************************************************/

void main()

{

unsigned char type_PC,       /* Тип компьютера*/

a,b;                 /* Переменные для определения характеристик

памяти ПЭВМ*/

unsigned int konf_b;             /* Байт конфигурации из BIOS*/

char *type[]={"AT", "PCjr", "XT", "IBM PC", "unknown"};

unsigned char typ1A[]={0,1,2,4,5,6,7,8,10,11,12,0xff};

char *types1A[]={"нет дисплея","MDA, моно","CGA, цв.",

       "EGA, цв.","EGA, моно","PGA, цв.",

       "VGA, моно, анал.","VGA, кол., анал.",

       "MCGA, кол., цифр.","MCGA, моно, анал."

       "MCGA, кол., анал.","неизвестный тип",

       "непредусмотренный код"};

unsigned int j;                      /* Вспомогательная переменная*/

unsigned int seg;                  /* Сегмент ПЗУ*/

unsigned int mark=0xAA55; /* Маркер ПЗУ*/

unsigned char bufVGA[64]; /* Буфер данных VGA*/

union REGS rr;

struct SREGS sr;

textbackground(0);

clrscr();

textattr(0x0a);

cprintf("Лабораторная работа №6");

cprintf("\n Проверка состава оборудования");

/* Определение типа компьютера*/

type_PC=peekb(0xF000,0xFFFE);

if((type_PC-=0xFC)>4)

type_PC=4;

textattr(0x0b);

cprintf("\nТип компьютера:");

textattr(0x0f);

cprintf("%s\n\r",type[type_PC]);

/* Конфигурация*/

konf_b=peek(0x40,0x10); /* Чтение байта оборудования из памяти BIOS*/

textattr(0x0b);

cprintf("Конфигурация:\n\r");

textattr(0x0e);

cprintf("Дисководов ГМД:");

textattr(0x0f);

if(konf_b&0x0001)

cprintf("%d\n\r",((konf_b&0x00C0)>>6)+1);

else

cprintf("нет\n\r");

textattr(0x0e);

cprintf("Математич.сопроцессор:");

textattr(0x0f);

if(konf_b&0x0002)

cprintf("есть\n\r");

else

cprintf("нет\n\r");

textattr(0x0e);

cprintf("Тип дисплейного адаптера:");

textattr(0x0f);

/* Определение активного адаптера*/

/* Предполагается наличие VGA*/

rr.h.ah=0x1a;

rr.h.al=0;

int86(0x10,&rr,&rr);

if(rr.h.al==0x1a)         /* Поддерживается функция 1Ah прерывания 10h*/

{

for(j=0; j<12; j++)

if(rr.h.bl==typ1A[j])

break;

cprintf("%s",types1A[j]);

if(j>0 &&j<12)

{

rr.h.ah=0x1b;

rr.x.bx=0;

sr.es=FP_SEG(bufVGA);

rr.x.di=FP_OFF(bufVGA);

int86x(0x10,&rr,&rr,&sr);

cprintf(",%d Kb\n\r",((int)bufVGA[49]+1)*64);

}

else

cprintf("\n\r");

}

else                           /* Предполагается наличие EGA*/

{                                  

rr.h.ah=0x12;

rr.h.bl=0x10;

int86(0x10,&rr,&rr);

if(rr.h.bl!=0x10)           /* Поддерживается функция 12h прерывания 10h*/

{cprintf("EGA");

if(rr.h.bh)

cprintf(" моно");

else

cprintf(" кол.");

cprintf(", %d Kb\n\r",((int)rr.h.bl+1)*64);

}

else                       /* CGA или  MDA */

{switch(konf_b&0x0030)

{case 0: cprintf("EGA/VGA\n\r");break;

case 0x10: cprintf("CGA,40\n\r");break;

case 0x20: cprintf("CGA,80\n\r");break;

case 0x30: cprintf("MDA");break;}

}

}

/* Блоки ОЗУ на системной плате*/

textattr(0x0e);

cprintf("\n\r Первичный блок памяти: ");

textattr(0x0f);

switch(konf_b&0x000C)

{

case 0: cprintf("16 Kb\n\r");break;

case 4: cprintf("32 Kb\n\r");break;

case 8: cprintf("48 Kb\n\r");break;

case 12: cprintf("64 Kb или больше\n\r");break;

}

/* Количество последовательных портов RS-232*/

textattr(0x0e);

cprintf("  Портов  RS232:     ");

textattr(0x0f);

cprintf("%d\n\r",(konf_b&0x0E00)>>9);

/* Наличие джойстика*/

textattr(0x0e);

cprintf("  Джойстик:     ");

textattr(0x0f);

if(konf_b&0x1000)

cprintf("est\n\r");

else

cprintf("нет\n\r");

/* Количество параллельных принтеров*/

textattr(0x0e);

cprintf("Принтеров:    ");

textattr(0x0f);

cprintf("%d\n\n\r",(konf_b&0xC000)>>14);

/* Объем оперативной памяти*/

textattr(0x0e);

cprintf("Объем оперативной памяти: ");

textattr(0x0f);

cprintf("%d Kb \n\r",peek(0x40,0x13));

textattr(0x0e);

outportb(0x70,0x17);

a=inport(0x71);

outportb(0x70,0x18);

b=inport(0x71);

cprintf("Объем extended-памяти:  ");

textattr(0x0f);

cprintf("%d Kb \n\n\r",(b<<8)|a);

/* Наличие дополнительных ПЗУ*/

for(seg=0xC000; seg<0xFFB0;seg+=0x40)

/* Просмотр памяти от С000:0 с шагом 2 К*/

if(peek(seg,0)==mark)         /* Маркер найден*/

{textattr(0x0a);

cprintf("Адрес ПЗУ=");

textattr(0x0f);

cprintf("%04x",seg);

textattr(0x0a);

cprintf(", Длина модуля = ");

textattr(0x0f);

cprintf("%d",512*peekb(seg,2));

textattr(0x0a);

cprintf(" байт\n\r",peekb(seg,2));}

/* Определение версии операционной системы*/

rr.h.ah=0x30;

intdos(&rr,&rr);

textattr(0x0c);

cprintf("\n\rВерсия MS-DOS ");

textattr(0x0f);

cprintf("%d.%d\n\r",rr.h.al,rr.h.ah);

textattr(0x0a);

gotoxy(30,24);

cprintf("Нажмите любую клавишу");

textattr(0x07);

getch();

clrscr();

}

Приложение Б

Листинг программы и комментарии к лабораторной работе № 7

 

/****************Главная загрузочная запись***************/

#include <dos.h>

#include <stdio.h>

#include <conio.h>

#include <stdlib.h>

/* типы данных*/

#define byte unsigned char

#define word unsigned int

#define dword unsigned long

void read_MBR(void);                         /* чтение MBR*/

/* получение из упакованного SecTrk # сектора */

#define SECT(x) x&0x3f

/* получение из упакованного SecTrk # дорожки */

#define TRK(x) (x>>8)|((x<<2)&0x300)

/* структура элемента раздела*/

struct Part {

byte ActFlag;

byte Begin_Hd;

word Begin_SecTrk;

byte SysCode;

byte End_Hd;

word End_SecTrk;

dword RelSec;

dword Size;};

/* структура главной загрузочной записи*/

struct MBR {

char LoadCode[0x1be];

struct Part rt[4];

word EngFlag;

} mbr;

/* дополнительные переменные*/

int x=10,y;                       /* экранные координаты*/

byte head=0;                    /* номер головки (0)*/

word Sect_Trk=1;            /* номер дорожки и сектора (0,1) */

int ndrive=0;                    /* номер логического диска*/

word *EndList;                /* указатель на подпись*/

union REGS rr;               

struct SREGS sr;

word i;

/********************************************************/

main() {

textbackground(0);

clrscr(); textattr(0x0a);

cprintf("         Лабораторная работа №7");

gotoxy(1,2);

cprintf("       Главная загрузочная запись");

textattr(12);

gotoxy(30,4);

cprintf("Разделы жесткого диска:\n");

gotoxy(1,6);

textattr(11);

cprintf("Лог. диск ----> \n\r");

cprintf("Признак -----> \n\r");

cprintf("Код системы -> \n\r");

cprintf("Начало: гол..--> \n\r");

cprintf("         дор.--> \n\r");

cprintf("         сектt.-> \n\r");

cprintf("Конец: гол.--> \n\r");

cprintf("       дор.--> \n\r");

cprintf("       сект.-> \n\r");

cprintf("Нач.сектор--> \n\r");

cprintf("Размер ------> \n\r");

textcolor(11);

NEXT:

read_MBR();

for(EndList=(word *)&mbr.rt[(i=0)];

(*EndList!=0xaa55)&&(mbr.rt[i].Size>0L);

EndList=(word *)&mbr.rt[++i])

/* координаты курсора*/

{ y=6;

x+=7;

gotoxy(x,y++);

if (mbr.rt[i].SysCode==5)

{textattr(13);

cprintf("Ext  ");}

else

textattr(12);

cprintf("%-7c",'C'+ndrive++);

gotoxy(x,y++); textattr(14);

cprintf("%02xH   ",mbr.rt[i].ActFlag);

gotoxy(x,y++); textattr(15);

cprintf("%-7d",mbr.rt[i].SysCode);

gotoxy(x,y++); textattr(14);

cprintf("%-7d",mbr.rt[i].Begin_Hd);

gotoxy(x,y++); textattr(15);

cprintf("%-7u",TRK(mbr.rt[i].Begin_SecTrk));

gotoxy(x,y++); textattr(14);

cprintf("%-7u",SECT(mbr.rt[i].Begin_SecTrk));

gotoxy(x,y++); textattr(15);

cprintf("%-7d",mbr.rt[i].End_Hd);

gotoxy(x,y++); textattr(14);

cprintf("%-7u",TRK(mbr.rt[i].End_SecTrk));

gotoxy(x,y++); textattr(15);

cprintf("%-7u",SECT(mbr.rt[i].End_SecTrk));

gotoxy(x,y++); textattr(14);

cprintf("%-7lu",mbr.rt[i].RelSec);

gotoxy(x,y++); textattr(15);

cprintf("%-7lu",mbr.rt[i].Size);

if(mbr.rt[i].SysCode==5){

/* если код системы 5, раздел содержит свою таблицу разделов; определяется ее дисковый адрес и новая таблица считывается в память */

head=mbr.rt[i].Begin_Hd;

Sect_Trk=mbr.rt[i].Begin_SecTrk;

goto NEXT;}}

gotoxy(x,y++);

textattr(10+128);

gotoxy(29,18);

cprintf("Нажмите любую клавишу...");

getch();

return 0;}

/* чтение MBR*/

void read_MBR(void)

{rr.h.ah=2;                          /* чтение*/

rr.h.al=1;                             /* секторов 1*/

rr.h.dl=0x80;                           /* жесткий диск*/

rr.h.dh=head;                      /* головка*/

rr.x.cx=Sect_Trk;                 /* дорожка , сектор*/

sr.es=FP_SEG(&mbr);            /* адрес буфера в ОП*/

rr.x.bx=FP_OFF(&mbr);

int86x(0x13,&rr,&rr,&sr);

/* проверка ошибок чтения*/

if(rr.x.cflag) {

printf("Ошибка чтения: %x.  ",rr.h.ah);

printf("Нажмите любую клавишу...\n\7");

getch();

exit(1);}

}


Приложение В

Листинг программы и комментарии к лабораторной работе № 8

 

/**********************Дисковые структуры данных DOS***********/

#include <dos.h>

#include <string.h>

#include <stdlib.h>

#include <stdio.h>

#include <conio.h>

#include <ctype.h>

/* Типы и структуры данных */

#define byte unsigned char

#define word unsigned int

#define dword unsigned long

#define daddr struct DADDR

struct DADDR {         /* физический дисковый адрес */

byte h;

word s, t, ts;} ;

struct PART {         /* структура элемента раздела */

byte Boot, Begin_Hd;

word Begin_SecTrk;

byte SysCode, End_Hd;

word End_SecTrk;

dword RelSec, Size; } ;

struct MBR {          /* структура главной загрузочной записи */

char LoadCode[0x1be];

struct PART rt[4];

word EndFlag; } ;

struct BootRec {          /* структура корневой записи */

byte jmp[3], ident[8];

word SectSize;

byte ClustSize;

word ResSect;

byte FatCnt;

word RootSize, TotSecs;

byte Media;

word FatSize, TrkSecs, HeadCnt;

word HidnSecL, HidnSecH;

dword LongTotSecs;

byte Drive, reserved1, DOS4_flag;

dword VolNum;

char VolLabel[11], FatForm[8]; } ;

struct Dir_Item {            /* структура элемента директории */

char fname[11];

byte attr;

char reserved[10];

word time, date, cl;

dword size; } ;

/* Описания функций */

void Read_Mbr(void);

/* Чтение MBR и поиск требуемого раздела */

void Read_Boot(void);       /* Чтение boot-сектора */

void Get_First(void);      /* Определение абсолютного номера сектора

начала логического диска */

void Read_Fat(void);         /* Чтение FAT */

void Read_13(void *mem);

/* Чтение сектора с помощью прерывания 13 */

void Sect_to_Daddr(dword sect);

/* Формирование физического дискового адреса из # сектора */

dword Clust_to_Sect(word clust);

/* Вычисление номера сектора из номера кластера */

word Next_Clust(word clust);

/* Выборка следующего кластера из FAT */

char *Get_Name(char *s, char *d);

/* Выделение следующего элемента из строки-задания */

int Find_Name();           /* Поиск имени в каталоге */

void End_of_Job(int n);         /* Завершение (при n=0-5 — аварийное) */

struct PART part;           /* текущий элемент раздела */

byte buff1[512];         /* буфер MBR и boot */

struct MBR *mbr;           /* указатель на таблицу разделов */

struct BootRec *boot;     /* указатель на корневую запись */

byte buff2[512];         /* буфер каталога и текста */

struct Dir_Item *dir;      /* указатель на часть каталога */

char *text;              /* указатель на текстовый буфер */

byte *fat;                /* указатель на FAT */

char job[81];          /* строка-задание */

char *jobptr;          /* текущий указатель в job */

char cname[12];            /* текущее имя для поиска */

byte Fdisk;              /* физический номер диска */

daddr caddr;          /* текущий дисковый адрес */

dword sect;             /* текущий номер сектора */

word clust;             /* текущий номер кластера */

byte fat16;              /* признак формату FAT */

dword fsize;            /* размер файла */

int dirnum;             /* номер элемента в каталоге */

dword FirstSect;             /* абс.сектор начала */

byte rootdir=1;            /* признак корневого каталога или подкаталога (1/0) */

word lastsect;         /* последний сектор при чтении */

byte fatalloc=0;          /* признак выделения памяти */

void main() {

int n,i;

textattr(14);

clrscr();

/* ввод имени файла */

cprintf(" Просмотр таблицы FAT. ");

cprintf("Укажите полное имя файла -->");

scanf("%s",job);

/* перевод в верхний регистр */

strupr(job);

/* проверка правильности идентификатора диска */

if ((!isalpha(job[0]))||(job[1]!=':')||(job[2]!='\\')) {

printf("%c%c%c -",job[0],job[1],job[2]);

End_of_Job(0); }

textattr(10);

clrscr();

printf(" Лабораторная работа N8");

printf(" Дисковые структуры данных DOS.");

textattr(14);

cprintf("Файл %s в FAT занимает такие кластеры :\ n",job);

jobptr=job+3;

if (job[0]>'A') {

/* для жесткого диска — физический номер и чтение MBR */

Fdisk=0x80;

Read_Mbr(); }

else                

/* для гибкого диска — физический номер */

Fdisk=job[0]-'A';

Read_Boot();             /* чтение boot-сектора */

Read_Fat();               /* чтение FAT */

dir=(struct Dir_Item *)buff2;

do {                   

if (!rootdir) clust=dir[dirnum].cl; /* начальный кластер */

/* выделение следующего элемента из строки-задания */

jobptr=Get_Name(jobptr,cname);

do {                        /* пока не достигнут последний кластер */

if (rootdir) {                /* корневой каталог */

/* нач. сектор корневого кат. и количество секторов */

sect=boot->ResSect+boot->FatSize*boot->FatCnt;

lastsect=boot->RootSize*32/boot->SectSize+sect;}

else {                  /* подкаталог */

sect=Clust_to_Sect(clust);

lastsect=boot->ClustSize+sect;}

/*посекторное чтение корневого каталога или одного кластера подкаталога */

for (; sect<lastsect; sect++) {

Sect_to_Daddr(sect);

Read_13(dir);

/* поиск имени в прочитанном секторе */

if ((dirnum=Find_Name())>=0) goto FIND;}}

/* до последнего кластера подкаталога */

while (clust==Next_Clust(clust));

/* весь каталог просмотрен, а имя не найдено — ошибка */

printf("%s -",cname);

if (jobptr==NULL) End_of_Job(4);

else End_of_Job(5);

FIND:                    /* имя найдено */

rootdir=0;}

while (jobptr!=NULL);

/* найдено имя файла, из каталога получаем 1-й кластер */

clust=dir[dirnum].cl;

textattr(7);

gotoxy(10,4);

cprintf("Нажимайте любую клавишу ");

cprintf(" пока  не появится <КОНЕЦ ФАЙЛА>.");

textattr(12);

gotoxy(1,5);

cprintf("-<НАЧАЛО ФАЙЛА>");

gotoxy(1,6);

cprintf("L->");

i=0;

do {

i++;

if((i%10)==0) getch();

textattr(14+16);

cprintf("%4x",clust);

textattr(2);

cprintf("--->");}

while (clust==Next_Clust(clust));

textattr(12);

cprintf("<КОНЕЦ ФАЙЛА>\ n");

gotoxy(1,wherey());

textattr(15+3*16);

cprintf("Количество кластеров в файле: %u ",i);

End_of_Job(7);}

/* Чтение MBR и поиск нужного раздела */

void Read_Mbr(void) {

int i;

char ndrive;

word *EndList;

caddr.h=0;

caddr.ts=1;

ndrive='C';

mbr=(struct MBR *)buff1;

NEXT: Read_13(buff1);

for (EndList=(word *)&mbr->rt[(i=0)];

(*EndList!=0xaa55)&&(mbr->rt[i].Size>0L);

EndList=(word *)&mbr->rt[++i]) {

if (mbr->rt[i].SysCode==5) {

caddr.h=mbr->rt[i].Begin_Hd;

caddr.ts=mbr->rt[i].Begin_SecTrk;

goto NEXT;}

if (ndrive==job[0]) {

movmem(&mbr->rt[i],&part,sizeof(struct PART));

return;}

else ndrive++;}

/* требуемый раздел не найден */

printf("%c: -",job[0]);

End_of_Job(1);}

/* Чтение boot-сектора */

void Read_Boot(void) {

if (Fdisk<0x80) {

caddr.h=0;

caddr.ts=1;}

else {

caddr.h=part.Begin_Hd;

caddr.ts=part.Begin_SecTrk;}

Read_13(buff1);

boot=(struct BootRec *)buff1;

Get_First();}

/* Чтение FAT */

void Read_Fat(void) {

dword s, ls;

byte *f;

fat=(byte *)malloc(boot->FatSize*boot->SectSize);

if (fat==NULL) {

printf("Размещение FAT -");

End_of_Job(3);}

fatalloc=1;

s=boot->ResSect;

ls=s+boot->FatSize;

for (f=fat; s<ls; s++) {

Sect_to_Daddr(s);

Read_13(f);

f+=boot->SectSize;}

/* установление формата FAT */

if (Fdisk>=0x80)

if (part.SysCode==1) fat16=0;

else fat16=1;

else fat16=0;}

/* Чтение сектора при помощи прерывания 13 */

void Read_13(void *mem) {

/* mem — адреса в ОП */

union REGS rr;

struct SREGS sr;

rr.h.ah=2;

rr.h.al=1;

rr.h.dl=Fdisk;

rr.h.dh=caddr.h;

rr.x.cx=caddr.ts;

sr.es=FP_SEG(mem);

rr.x.bx=FP_OFF(mem);

int86x(0x13,&rr,&rr,&sr);

/* Проверка ошибок чтения */

if (rr.x.cflag&1) {

printf("%u -",rr.h.ah);

End_of_Job(2);}}

/* Определение абс.номера сектора начала лог.диска */

void Get_First(void) {

word s, t;

if (Fdisk<0x80) FirstSect=0;

else {

/* формирование # сектора из физич. дискового адреса */

t=(part.Begin_SecTrk>>8)|((part.Begin_SecTrk<<2)&0x300);

s=part.Begin_SecTrk&0x3f;

FirstSect=(((dword)t*boot->HeadCnt)+part.Begin_Hd)*

boot->TrkSecs+s-1;}}

/* Формирование физического дискового адреса из # сектора */

void Sect_to_Daddr(dword sect) {

/* sect — номер сектора, caddr — адрес на диске */

dword s;

if (Fdisk>=0x80) sect+=FirstSect;

caddr.s=sect%boot->TrkSecs+1;

s=sect/boot->TrkSecs;

caddr.h=s%boot->HeadCnt;

caddr.t=s/boot->HeadCnt;

caddr.ts=(caddr.t<<8)|caddr.s|((caddr.t&0x300)>>2); }

/* Вычисление номера сектора из номера кластера */

dword Clust_to_Sect(word clust) {

/* clust — номер кластера, возвращает номер сектора */

dword ds, s;

ds=boot->ResSect+boot->FatSize*boot->FatCnt+

boot->RootSize*32/boot->SectSize;

s=ds+(clust-2)*boot->ClustSize;

return(s);}

/* Выборка следующего кластера из FAT */

word Next_Clust(word clust) {

/* clust — номер кластера, возвращает номер следующего кластера

или 0 — если следующего нет */

word m, s;

if (rootdir) return(0);

if (!fat16) {

m=(clust*3)/2;

s=*(word *)(fat+m);

if(clust%2)              /* нечетный элемент */

s>>=4;

else                 /* четный элемент */

s=s&0x0fff;

if (s>0x0fef) return(0);

else return(s);}

else {

m=clust*2;

s=*(word *)(fat+m);

if (s>0xffef) return(0);

else return(s);}}

/* Выделение следующего элемента из строки-задания */

char *Get_Name(char *s, char *d) {

/* s — строка задания, d — выделенный элемент, возвращает указатель на новое начало строки задания. */

char *p,*r;

int i;

for(i=0;i<11;d[i++]=' ');

d[11]='\0';

if ((p=strchr(s,'\\'))==NULL) {

/* последний элемент строки — имя файла, перезапись имени */

for(r=s,i=0; (i<8)&&*r&&(*r!='.'); i++,r++) *(d+i)=*r;

/* перезапись расширения */

if (*r) for(i=0,r++; (i<3)&&*r; i++,r++) *(d+8+i)=*r;

return(NULL);}

else {

/* следующий элемент — имя подкаталога */

*p='\ 0';

for(r=s,i=0; (i<11)&&*r; i++,r++) *(d+i)=*r;

return(p+1);}}

/* Поиск имени в каталоге */

int Find_Name() {

int j;

for (j=0; j<boot->SectSize/sizeof(struct Dir_Item); j++) {

if (dir[j].fname[0]=='\0') {

/* конец использованных элементов каталога; cname — найденное имя; возвращает индекс найденного элемента в массиве dir или (-1) */

printf("%s -",cname);

if (jobptr==NULL) End_of_Job(4);

else End_of_Job(5);}

if ((byte)dir[j].fname[0]!=0xe5) {

if (memcmp(dir[j].fname,cname,11)==0) {

if (jobptr==NULL)

if ( !(dir[j].attr&0x18) ) return(j);

else

if (dir[j].attr&0x10) return(j);}}}

return(-1);}

/* Завершение (при n=0-5 — аварийное) */

void End_of_Job(int n) {

/* n — номер сообщения */

static char *msg[] = {

"неправильный идентификатор диска",

"логический диск отсутствует",

"ошибка чтения",

"нехватка памяти",

"подкаталог не найден",

"файл не найден",

"непредусмотренный конец файла",

" " } ;

/* освобождение памяти */

if (fatalloc) free(fat);

/* выдача сообщения */

textattr(12+128);

cprintf(" %s\ n",msg[n]);

gotoxy(28,wherey());

cprintf(" Нажмите любую клавишу...\ n");

textattr(7);

getch(); exit(0);}


Приложение Г

Листинг программы и комментарии к лабораторной работе № 9

 

/********************Управление программами*******************/

#include <dos.h>

#include <conio.h>

/* Типы данных */

#define byte unsigned char

#define word unsigned int

/* Описание функций */

void get_DOS_version_h(void);       /* Определение версии DOS */

void addr_PSP (void);                     /* Получение адреса PSP */

struct psp {                                      /* формат PSP */

byte ret_op[2];                                 /* команда INT 20h */

word end_of_mem;                          /* предел доступной памяти */

byte reserved1;

byte old_call_dos[5];                       /* старый вызов DOS */

void *term_ptr;                                /* адрес завершения */

void *ctrlbrk_ptr;                             /* адрес обработчика Ctrl+Break */

void *criterr_ptr;                             /* адрес обработчика крит.ошибок */

word father_psp;                             /* PID родителя */

byte JFT[20];                                  /* таблица файлов программы */

word env_seg;                                 /* адрес окружения */

void *stack_ptr;                               /* адрес стека */

word JFT_size;                                /* размер таблицы файлов */

byte *JFT_ptr;                                 /* адрес таблицы файлов */

byte reserved2[24];

byte new_call_dos[3];                     /* новый вызов DOS */

} *p_psp;

word pid;                                         /* сегм.адрес PSP */

int dos_ver, i, l, j;                             /* версия DOS */

char *s;

union REGS rr;

void main(){

textbackground(0);

clrscr();

textattr(0x0a);

cprintf(" Лабораторная работа N9");

cprintf(" Управление программами "); cprintf("---------------");

textcolor(11);

get_DOS_version_h();

addr_PSP();

cprintf("\ n\ n Адрес PID = %04X\ n\ n\ r",pid);        /* распечатка PSP */

p_psp=(struct psp *)MK_FP(pid,0);

textcolor(10);

cprintf("Команды:\ n\ r");

textcolor(14); cprintf(" Завершение — int 20h:");

textcolor(12);

cprintf(" %02X %02X\ n\ r",p_psp->ret_op[0],p_psp->ret_op[1]);

textcolor(14); cprintf(" Старый вызов DOS: ");

textcolor(12);

for (i=0;i<5;cprintf("%02X ",p_psp->old_call_dos[i++]));

textcolor(14);

cprintf("\ n\ r Новый вызов DOS: ");

textcolor(12);

for(i=0;i<3;cprintf("%02X ",p_psp->new_call_dos[i++]));

textcolor(10);

cprintf("\ n\ n\ rАдреса:\ n\ r"); cprintf("-------\ n\ r");

textcolor(14);

cprintf(" Конец памяти: ");

textcolor(12);

cprintf("%04X:0000\ n\ r",p_psp->end_of_mem);

textcolor(14);

cprintf(" Обработчик завершения: ");

textcolor(12);

cprintf("%Fp\ n\ r",p_psp->term_ptr);

textcolor(14);

cprintf(" Обработчик Ctrl+Break: ");

textcolor(12);

cprintf("%Fp\ n\ r",p_psp->ctrlbrk_ptr);

textcolor(14);

cprintf(" Обработчик критич.ошибки: ");

textcolor(12);

cprintf("%Fp\ n\ r",p_psp->criterr_ptr);

textcolor(14);

cprintf(" Стек: ");

textcolor(12);

cprintf("%Fp\ n\ n\ r",p_psp->stack_ptr);

textcolor(14);

cprintf("\ n\ rРодитель: ");

textcolor(12);

cprintf("%04X ",p_psp->father_psp);

textcolor(0x8b);

cprintf("\ n\ n\ rНажмите любую клавишу ...\ n\ r\ 7");

getch();clrscr();

textattr(0x0a);

/* Распечатка таблицы файлов */

s=p_psp->JFT_ptr;

textcolor(10);

cprintf("\ n\ n\ rТаблица файлов: ");

textcolor(12);

cprintf("%Fp (%d) ",s,p_psp->JFT_size);

textcolor(11);

if (s==(byte *)p_psp+0x18)

cprintf(" — в этом же PSP");

cprintf("\ n\ r");

for (i=0; ++i<=p_psp->JFT_size; cprintf("%d ",*(s++)));

textcolor(10);

cprintf("\ n\ n\ rОкружение DOS: ");

textcolor(12);

cprintf("%04X\ n\ r",p_psp->env_seg);

s=(char *)MK_FP(p_psp->env_seg,0);

textcolor(11);

while(l==strlen(s))

{cprintf(" %s\ n\ r",s);

s+=l+1;}

if (dos_ver>2) {

/* для DOS 3.0 и выше можно получить строку вызова */

s++;

l=*((int *)s);

textcolor(10);

cprintf("\ n\ rЧисло строк вызова: ");

textcolor(12); cprintf("%d\ n\ r",l);

s+=2;

textcolor(11);

for(i=0; i<l; i++)

{cprintf("%s\ n\ r",s);

s+=strlen(s)+1;}}

textattr(0x8b);

cprintf("\ n\ n\ n\ n\ rНажмите любую клавишу ...\ 7");

textattr(0x07); cprintf("\ n\ r");

getch(); clrscr();}

/* Определение версии DOS */

void get_DOS_version_h(void) {

rr.h.ah=0x30;

intdos(&rr,&rr);

dos_ver=rr.h.al;}

/* Получение адреса PSP */

void addr_PSP (void)

{ rr.h.ah=0x62;

intdos(&rr,&rr);

pid=rr.x.bx;}


Библиография

 

1. Гордеев А.В., Молчанов А.Ю. Системное программное обеспечение. – СПб.: Питер, 2002.

2  . Фельдман С.К. Системное программирование на персональном компьютере. - М.: ЗАО «Новый издательский дом», 2004.

3. Архангельский А.Я. C++ Builder 6. Справочное пособие. Книга 1. Язык С++. – М.: Бином-Пресс, 2002.

4. Архангельский А.Я. C++ Builder 6. Справочное пособие. Книга 2. Классы и компоненты. – М.: Бином-Пресс, 2002.

5. Ашарина И.В. Основы программирования на языках С и С++.- М.: Горячая линия - Телеком, 2002.

6. Иртегов Д.В. Введение в операционные системы. – СПб.: БХВ-Петербург, 2002.

7. Таненбаум Э. Современные операционные системы. -  СПб.: Питер, 2002.

8. Гордеев В.А. Операционные системы. – СПб.: Питер, 2004.

9. Пирогов В.Ю. ASSEMBLER. Учебный курс. - М.: Издательство Нолидж, 2001.

10. Зубков С. В. Assembler для DOS, Windows и UNIX.  - М.: ДМК Пресс; СПб.: Питер, 2004.

 

 

 

Содержание

 

6 Лабораторная работа №6. Проверка оборудования.......................... 3

7 Лабораторная работа №7. Главная загрузочная запись..................... 6

8 Лабораторная работа №8. Дисковые структуры данных DOS.......... 8

9 Лабораторная работа №9. Управление программами....................... 13

Приложение А....................................................................................... 17

Приложение Б........................................................................................ 21

Приложение В....................................................................................... 24

Приложение Г........................................................................................ 32

Библиография........................................................................................ 35

 

 

 

 

 

 

 

 

 

 

Дополнительный план 2006 г., поз. 4

 

 

Наталья Валерьевна Сябина

 

 

 

 

 

 

 

 

СИСТЕМНОЕ ПРОГРАММИРОВАНИЕ

Часть 2

Методические указания к выполнению лабораторных работ

 (для студентов очной формы обучения специальностей

360140Автоматизация и информатизация в системах управления,

050702 – Автоматизация и управление)

 

 

 

 

 

 

 

Редактор             Ж.М.Сыздыкова

 

 

 

 

 

 

Подписано в печать __. __. __.                                     Формат 60х84  1/ 16

Тираж  75 экз.                          Бумага типографская №1

Объем ___ уч.-изд. л.                      Заказ _____. Цена    тг.

 

 

 

 

Копировально-множительное бюро

 Алматинского института энергетики и связи

050013, Алматы, Байтурсынова, 126