48414

Базові поняття Системного програмування та СПЗ

Конспект

Информатика, кибернетика и программирование

Системні програмні засоби виконують такі завдання як передача даних з пам’яті довільного доступу на диск або відтворення тексту на дисплеї. Через ці обмеження часто використовуються моніторинг та реєстрація даних; операційні системи мають бути забезпечені дуже якісними підсистемами реєстрації даних. Базові відомості Поняття операційної системи напряму пов'язане з такими поняттями як: Файл іменований впорядкований набір даних на пристрої зберігання інформації; операційна система забезпечує організацію файлів в файлові системи. Файлова...

Украинкский

2013-12-10

924.9 KB

21 чел.

Лекція 1 «Базові поняття Системного програмування та СПЗ»

  1.  Системне програмування.
  2.  Системне програмне забезпечення.
  3.  Основні аспекти створення системних програм.
  4.  Класифікація системного програмного забезпечення.

Навчальна мета: Засвоїти основні поняття системного програмування та системного програмного забезпечення, забезпечити студентам розуміння основних аспектів створення системних програм, дати базову класифікацію системного програмного забезпечення.

Виховна мета: Допомогти студентам усвідомити вагому роль системного програмування та системного програмного забезпечення у сучасних інформаційних технологіях розробки ПЗ, привити розуміння основних аспектів створення системних програм, дати базову класифікацію системного програмного забезпечення.

Актуальність: Донести до відома студентів, що на сьогоднішній розуміння основних понять системного програмного забезпечення та системного програмування є головними аспектами становлення програміста.

Мотивація: Мотивацією вивчати системного програмування полягає у необхідност розуміти роботу операційної системи з точки зору професіонала у галузі інформаційних технологій.

Системне програмування. Системне програмне забезпечення (1)

Дисципліна “системне програмування” зазвичай викладається в технічних вузах як курс якоїсь окремої мови програмування, частіше всього - це асемблер або С/C++. Насправді ж ця дисципліна не є черговим курсом з методики створення програм, а є курсом з тонкощів операційної системи, які можна використовувати в будь-якій мові програмування, де є можливість підключення або зовнішніх модулів або асемблерних вставок безпосередньо до програмного коду.

Отже, сформулюємо чітке визначення курсу:

Системне програмування – дисципліна, яка вивчає засоби та функції операційної системи, пов’язані з керуванням нею, периферійними пристроями та обміну даними між ними.

Історично склалось так, що існують дві мови, які використовуються для роботи на рівні операційної системи – асемблер та С. Перша мова бере свій початок від найпершого компілятора – Автокоду (1952), розробленого Аліком Гленні для комп'ютера Манчестер Марко I. Цей компілятор вперше використовував мнемонічне (у вигляді команд та відповідних операндів) позначення основних операцій, які здатна виконувати машина, які потім перетворювались на коди, зрозумілі машині. Цей процес був названий трансляцією. А мови, похідні від Автокоду, були названі асемблерами (від слова assembly – “збирати”, адже програми збирались з окремих “цеглинок”, мнемонічних команд). Ці мови працювали фактично на найнижчому рівні, на рівні процесора та його функцій, а пізніше – на рівні функцій операційної системи.

Саме тоді було закладено основи дисципліни системного програмування і закладено основні задачі, які і нині розв'язуються за допомогою його методів. Це насамперед керування процесором та керування периферійними пристроями, які під’єднані до загальної шини, і керуються цим процесором. З винайденням операційної системи, на яку покладалися загальні задачі обміну даними між процесором, пам'яттю та периферійними пристроями, основна задача системного програмування змінилась – оскільки керування обміну даними між периферійними пристроями перебрала на себе операційна система, до задач системного програмування увійшло завдання керування ресурсами, які контролює операційна система. Саме такою основна задача системного програмування є і по сьогодні.

Отже, сформулюємо основну задачу системного програмування: створення програм для керування безпосередньо процесором та ресурсами операційної системи (пам'яттю та периферійними пристроями).

Системне програмування. Системне програмне забезпечення. (2)

Систе́мне програмува́ння (або програмування систем) - це вид програмування, який полягає в роботі з системним програмним забезпеченням. Головною відмінністю системного програмування в порівнянні з прикладним програмуванням є те, що прикладне програмне забезпечення призначене випускати (створювати і оновлювати) програми для користувачів (напр., текстові процесори), тоді як системне програмування призначене випускати програми, які обслуговують апаратне забезпечення (напр., дефрагментація диска) що обумовлює значну залежності такого типу ПЗ від апаратної частини. Також для системного програмування характерне:

  1.  програміст має зважати на апаратне забезпечення та інші особливості системи, на якій передбачається запуск програми, та використовувати ці особливості (наприклад, застосовуючи оптимізовані алгоритми для певної архітектури)
  2.  зазвичай використовуються низькорівневі мови програмування або діалекти які:
  3.  можуть працювати у ресурсно-обмеженому середовищі
  4.  максимально раціональні та мають мінімальні затримки за часом виконання
  5.  мають малі бібліотеки бібліотеки періоду виконання (RTL), або взагалі їх не мають
  6.  дозволють прямий доступ до пам'яті та керуючої логіки
  7.  дозволяють програмісту писати частини програми на асемблері
  8.  налагодження може бути складним, якщо неможливо запустити програму у режимі налагодження через обмеження у ресурсах. Виконання програми у імітованому середовищі може зняти цю проблему.

Системне програмне забезпечення (англ. system software) — більш відоме, як операційна система, це будь-яке програмне забезпечення, що забезпечує інфраструктуру, на якій можуть працювати прикладні програми, тобто воно керує і контролює комп'ютерним обладнанням, для можливості виконання прикладних програм. Операційні системи, такі як Microsoft Windows, Mac OS X та Linux є яскравими прикладами системного програмного забезпечення.

Системне програмне забезпечення — це ПЗ, що в принципі забезпечує роботу комп'ютера. Крім операційних систем, іншими прикладами є антивірусні програми, комунікаційні програми та драйвери принтерів. Без системного програмного забезпечення комп'ютер працювати не буде.

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

В цілому прикладні програмні засоби — це програми, що дозволяють кінцевому користувачу виконання конкретних функцій, таких як обробляння текстів або редагування зображень. Системні програмні засоби виконують такі завдання, як передача даних з пам’яті довільного доступу на диск, або відтворення тексту на дисплеї.

Системне програмування суттєво відрізняється від прикладного програмування, що змушує програмістів спеціалізуватися у одній з цих галузей. Для системного програмування часто доступна тільки обмежена кількість інструментів. Налагодження інколи виявляється дуже складним. Бібліотеки періоду виконання, якщо взагалі доступні, мають набагато менші можливості, і роблять менше перевірок на помилки. Через ці обмеження, часто використовуються моніторинг та реєстрація даних; операційні системи мають бути забезпечені дуже якісними підсистемами реєстрації даних.

Основні аспекти створення системних програм. (3)

Перед тим, як ввести поняття системної програми, розглянемо спрощену архітектуру комп’ютерної системи:

На рівні мікрокоду як правило, працюють прошиті в мікросхемі програми, наприклад, MMX (MultiMedia Extended Set) чи SSE (Sequenced and Structured Extensions/Поширення для роботи з послідовностями та структурами), які фактично є програмами, зашитими в процесор. Ними системне програмування майже не займається, хоч може використовувати їх ресурси, чи викликати такі програми.

На рівні команд процесора працюють такі базові пакети, як BIOS та операційна система. Загалом, системне програмування займається написанням і того, і іншого, але останнім часом у світі існує тенденція щодо виділення їх в окремі наукові дисципліни. На рівні команд процесора також працюють так звані програми нульового рівня, тобто такі програми, які реалізовують основні функції операційної системи – обробники переривання, драйвери тощо.

На рівні операційної системи працює більшість користувацьких програм. Коди програм базуються на використанні переривань, драйверів, функцій операційної системи, написаних рівнем нижче. Слід розрізняти інтерфейс програміста та функції операційної системи. Перше – це набір вже написаних програм на певній мові програмування, і сформованих у так звану бібліотеку, якою може користуватись програміст. Друге – це прошитий у ядро операційної системи програмний код, який виконується в залежності від того, які переривання були збуджені, і які значення регістрів при цьому були. Інтерфейс програміста прийнято називати рівнем користувача, а функції операційної системи – рівнем операційної системи.

Системні програми працюють на рівні команд процесора та функцій операційної системи. Усе, що стосується більш низьких чи високих рівнів до системних програм може відноситись тільки опосередковано.

Системні програми, як правило, майже не мають інтерфейсу користувача, а лише набір текстових повідомлень, які керують нею, або повідомляють про перебіг її роботи. Крім того, системні програми займають порівняно невеликий розмір, що викликано самим характером мови, на якій вони пишуться. Програми на асемблері, які більші за 1000 рядків, вже не сприймаються адекватно навіть тим програмістом, який цю програму пише.


Класифікація системного програмного забезпечення.
(4)

  1.  Завантажувачі
  2.  Операційні системи
  3.  Драйвери,
  4.  Компонувальник
  5.  Утиліти

Контрольні запитання:

  1.  Поняття Системне програмування. Системне програмне забезпечення
  2.  Системні програмні засоби
  3.  Основні аспекти створення системних програм.
  4.  Класифікація системного програмного забезпечення.


Лекція 2 «Завантажувачі ОС»

  1.  Завантажувачі операційної системи.
  2.  Типи завантаження.
  3.  Завантажувальні пристрої.

Навчальна мета: Засвоїти основні поняття завантажувачів операційних систем.

Виховна мета: Допомогти студентам усвідомити вагому роль завантажувачів у процесі завантаження та роботи операційної системи.

Актуальність: Сучасні операційні системи, так само, як і перші операційні системи використовують завантажувачі. І розуміння їх роботи – це завжди актуальне пиання.

Мотивація: Для розуміння роботи операційної системи з точки зору професіонала необхідно розуміти принципи роботи завантажувачів та вміти з ними працювати.

Завантаження операційної системи (англ. booting) зветься багатокроковий процес запуску комп'ютера. Заванта́жувач операційної системи (англ. bootloader) це програма, яку запускає BIOS для виконання завантаження операційної системи. Заванта́жувач операційної системи звичайно знаходиться у секторі завантажування.
Послідовність завантаження (англ. boot sequence) це початковий набір дій, що при цьому виконується комп’ютером.

Типи завантаження

  1.  Початкове завантаження (англ. booting up) - Завантажування після того, як комп'ютер увімкнено користувачем.
  2.  Перезавантаження (англ. reboot) .

Жорстке перезавантаження. Жорстке перезавантаження (англ. hard reboot) відбувається, коли на короткий час зникає живлення комп’ютера, або коли на процесор надсилається спеціальний сигнал (найчастіше така кнопка міститься на передній панелі комп’ютера). Це початкове завантаження без попереднього виконання завершальних процедур операційної системи. Для багатьох операційних систем, особливо тих що використовують дисковий кеш, після жорсткого перезавантаження файлова система може містити неузгодженості через незавершеність дискових операцій вводу-виводу; щоб виправити ці помилки запускається процедура сканування файлової системи на цілісність структури ще до того, як матиме місце нормальне завантаження.

М’яке перезавантаження. М’яким (англ. soft reboot) перезавантаження називається тоді, коли воно відбувається під контролем програмного забезпечення, без порушень в електроживленні і натискання кнопки перезавантаження на передній панелі. Як правило, але не завжди, це означає звичайне штатне завершення роботи машини і наступне перезавантаження. Комбінація клавіш клавіатури Control-Alt-Delete на оригінальному комп'ютері IBM PC була назначена для виконання м’якого перезавантаження для скорішого і зручнішого (і, дехто стверджує, менш стресового для компонентів системи) рестарту, порівняно із тим, коли вимикається живлення комп’ютера.


Завантажувальні пристрої.

Завантажувальний пристрій — з якого вантажиться операційна система. BIOS сучасних комп’ютерів підтримує завантаження з різних пристроїв, зазвичай це локальний жорсткий диск (або одна з частин розбиття на кожному диску), пристрій читання оптичних дисків, USB-диск (у варіантах флеш-диску, зовнішнього жорсткого, магнитооптичного чи оптичного диску, тощо), або інтерфейсна мережна карта (з використанням PXE).

Звичайно, BIOS дозволяє користувачу обрати і впорядкувати спосіб завантаження. Якщо порядок завантаження встановлено так «по-перше, DVD-дисковод; по-друге, жорсткий диск», тоді BIOS намагатиметься завантажити систему з DVD, і якщо спроба виявиться неуспішною (наприклад, у дисководі відсутній диск), тоді відбудеться наступна спроба завантажитися з жорсткого диску.

Се́ктор заванта́ження (boot sector) — особливий сектор на диску, дискеті чи іншому дисковому пристрої збереження інформації, що містить інформацію про файлову систему розміщену на носії і невелику програму в машинному коді, що завантажує операційну систему. (для дискети це перший фізичний сектор, для диску — перший фізичний сектор для кожного розділу).

Контрольні запитання:

  1.  Завантаження операційної системи.
  2.  Типи завантаження.
  3.  Завантажувальні пристрої.
  4.  Се́ктор заванта́ження (boot sector)


Лекція 3 «Операційні системи»

  1.  Операційна система.
  2.  Типи ОС.
  3.  Складові частини ОС.

Навчальна мета: Вивчити основні поняття операційних систем, вивчити види операційних систем та визначити її основні складові частини.

Виховна мета: Знання особливостей ОС відокремлюють користувачів та професіоналів. 

Актуальність: На ринку праці роботодавців цікавить системний програміст, що знає «нуторощі» операційної системи та принципи роботи з ними на професійному рівні.

Мотивація: Мотивацією вивчати даний напрямок у курсі ситемного програмування може стати бажання отримати позицію системного програміста.

Операці́йна систе́ма — це базовий комплекс програмного забезпечення, що виконує управління апаратним забезпеченням комп'ютера або віртуальної машини; забезпечує керування обчислювальним процесом і організує взаємодію з користувачем.

Операційна система звичайно складається з ядра операційної системи та базового набору прикладного програмного забезпечення.

Базові відомості

Поняття операційної системи напряму пов'язане з такими поняттями, як:

Файл - іменований впорядкований набір даних на пристрої зберігання інформації; операційна система забезпечує організацію файлів в файлові системи.

Файлова система - набір файлів (можливо порожній), організованих за наперед визначеними правилами. Якщо організація файлів в файлову систему відбувається з використанням каталогів, то така файлова система називається ієрархічною.

Програма - файл, що містить набір інструкцій для виконання. В якості виконавця інструкцій програми можуть виступати:

центральний процесор - якщо програма містить машинний код (звичайно отримують шляхом компідяції вихідного текста програми, написаного однією з компільованих мов);

інтерпретатор - інша програма, яка забезпечує розпізнавання і виконання інструкцій (в окремих випадках інтерпретатор також називають віртуальною машиною).

Задача - програма в процесі виконання (в термінології операційних систем UNIX використовують термін "процес").

Команда - ім'я, яке використовує користувач ОС або інша програма для виконання вказаної програми (може співпадати з іменем файла з програмою) або поіменованої дії (вбудованої команди).

Командний інтерпретатор - середовище, яке забезпечує інтерфейс з користувачем і виконання команд.

Типи операційних систем

Відповідно до свого призначення, операційні системи бувають:

  1.  універсальні (для широкого використання), спеціальні (для розв'язання спеціальних задач) та спеціалізовані (виконуються на спеціальному обладнанні);
  2.  одно-задачні (в окремий момент часу можуть виконувати лише одну задачу) та багато-задачні (в окремий момент часу здатні виконувати більше однієї задачі);
  3.  одно-користувацькі (в системі відсутні механізми обмеження доступу до файлів та на використання ресурсів системи) та багато-користувацькі (система впроваджує поняття "власник файлу" та забезпечує механізми обмеження на використання ресурсів системи (квоти)), всі багато-користувацькі операційні системи також є багато-задачними;
  4.  реального часу (система підтримує механізми виконання задач реального часу, тобто такі, для яких будь які операції завжди виконуються за наперед передбачуваний і незмінний при наступних виконаннях час).

Відповідно до способу встановлення (інсталяції) операційної системи, операційні системи бувають:

  1.  вбудовані (такі, що зберігаються в енергонезалежній пам'яті обчислювальної машини або пристрою без можливості заміни в процесі експлуатації обладнання);
  2.  невбудовані (?) (такі, що інсталюються на один з пристроїв зберігання інформації обчислювальної машини з можливістю подальшої заміни в процесі експлуатації).
  3.  Відповідно до відповідності стандартам операційні системи бувають:
  4.  стандартні (відповідають одному з загальноприйнятих відкритих стандартів, найчастіше POSIX);
  5.  нестандартні (в тому числі такі, що розробляються відповідно до корпоративних стандартів).

Відповідно до можливостей розширення операційні системи бувають:

  1.  закриті (не дозволяють розширення функціональності ОС);
  2.  відкриті (будуються за технологіями, що забезпечують можливості розширення функціональності ОС).

Відповідно до можливостей доступу до вихідного коду операційні системи бувають:

  1.  вільні (з відкритим програмним кодом);
  2.  пропрієтарні (комерційні з закритим кодом).

Складові ОС

  1.  Ядро операційної системи, що забезпечує розподіл і управління ресурсами обчислювальної системи;
  2.  базовий набір прикладного програмного забезпечення, системні бібліотеки та програми обслуговування.

Ядро́ (англ. Kernel) — базова компонента операційної системи, що реалізує інтерфейс між прикладними процесами та обладнанням комп'ютера. Завантажується в оперативну пам'ять комп'ютера і безпосередньо взаємодіє з апаратурою, забезпечуючи керування апаратними засобами (при цьому використовуються драйвери (модулі ядра) підключеного в систему обладнання), підтримку одночасної роботи багатьох користувачів (багатокористувацький режим), підтримку паралельного виконання багатьох процесів в системі (багатозадачність).

Контрольні запитання:

  1.  Базові поняття ОС. Поняття ОС. Поняття файлу.
  2.  Поняття файлової системи, програми.
  3.  Поняття центрального процесора, командного інтерпретатора, команди.
  4.  Типи ОС. Складові ОС. Ядро ОС.


Лекція 4 «Операційні системи сімейства Unix, MacOS, Windows»

  1.  Unix - подібні ОС.
  2.  Сімейство Microsoft Windows.
  3.  Mac OS X.

Навчальна мета: Ввичити основні принципи побудови таких сучасних операційних систем, як Unix, Mac, Windows.

Виховна мета: Допомогти студентам усвідомити вагому роль знання різних операційних ситем.

Актуальність: Донести до відома студентів, що на сьогоднішній день більшість роботодавців шукають персонал, незалежний від операційного середовища.

Мотивація: Мотивацією вивчати даний напрямок у курсі ситемного програмування може стати бажання отримати перевагу перед конкурентами у процесіі працевлаштування шляхом демонстрації навичок роботи та зання принципів організації різних ОС.

Unix - подібні ОС.

Файлова структура Unix характеризується такими властивостями:

  1.  Чітка побудова;
  2.  Звернення до даних файлу без суперечностей;
  3.  Захист даних файлу;

Цей стандарт вимагає, щоб операційна система, яка працюватиме з  узгодженою файловою системою, підтримуватиме ці базові риси надійності, які є в більшості файлових систем Unix. Цей стандарт не намагається узгоджуватися з кожним можливим аспектом в усіх конкретних реалізаціях Unix-систем. Проте, багато аспектів цього стандарту базується на ідеях, що є в Unix та інших Unix подібних системах:

  1.  Традиційна та добре сприйнята практика в Unix-подібних системах;
  2.  Впровадження побудов інших файлових структур;
  3.  Застосовні стандарти;

Визначається дві незалежні категорії файлів: загальні (shareable) на противагу приватним (unshareable) та змінні на противагу постійним.

Загальні данні це ті, що можуть бути спільними для декількох головних машин; Приватні данні мають бути специфічними для кожного головного комп'ютера.

Постійні файли - двійкові, бібліотеки, документація та все інше, що має змінюватися тільки адміністиратором системи; Змінні - все, що може бути змінено без втручання адміністратора системи.

Для полегшення резервування, керування та спільного використання файлів в мішаних мережах з машин із різними архітектурами та операційними системами, бажано щоб було просто та легко розуміти зв'язки між каталогами (певні каталоги розглядаються як потенційні точки монтування) та типом даних, що вони містять.

Сімейство Microsoft Windows.

Зазвичай всі версії Windows поділяють на декілька «груп».

Графічні інтерфейси та розширення для DOS Эти версии Windows не были полноценными операционными системами, а являлись надстройками к операционной системе MS-DOS и были по сути многофункциональным расширением, добавляя поддержку новых режимов работы процессора, поддержку многозадачности, обеспечивая стандартизацію интерфейсов аппаратного обеспечения и единообразие для пользовательских интерфейсов программ. Предоставляли встроенные средства (GDI и USER, первые версии Windows вообще состояли из трех модулей — KERNEL, GDI и USER, первый из них предоставлял вызовы управления памятью, запуском EXE файлов и загрузкой DLL файлов, второй — графику, третий — окна) для созданияграфического интерфейса пользователя. Они работали с процессорами начиная с Intel 8086.

Сімейство Windows 9x Включает в себя Windows 95Windows 98 и Windows Me.

Windows 95 была выпущена в 1995 году. Её отличительными особенностями являются новый пользовательский интерфейс, поддержка длинных имён файлов, автоматическое определение и конфигурация периферийных устройств Plug and Play, способность исполнять 32-битные приложения и наличие поддержки TCP/IP прямо в системе. Windows 95 использует вытесняющую многозадачность и выполняет каждое 32-битное приложение в своём адресном пространстве.

Сімейство Windows NT Операционные системы этого семейства в настоящее время работают на процессорах с архитектурами x86x64, и Itanium, ARM. Все операционные системы этого семейства являются полностью 32- или 64- битными операционными системами, и не нуждаются в MS-DOS даже для загрузки.

Только в этом семействе представлены операционные системы для серверов. До версии Windows 2000 включительно они выпускались под тем же названием, что и аналогичная версия для рабочих станций, но с добавлением суффикса, например «Windows NT 4.0 Server» и «Windows 2000 Datacenter Server».

В основу семейства Windows NT положено разделение адресных пространств между процессами. Каждый процесс имеет возможность работать с выделенной ему памятью. Однако он не имеет прав для записи в память других процессов, драйверов и системного кода.

Семейство Windows NT относится к операционным системам с вытесняющей многозадачностью. Разделение процессорного времени между потоками происходит по принципу «карусели». Ядро операционной системы выделяет квант времени (в Windows 2000 квант равен примерно 20 мс) каждому из потоков по очереди при условии, что все потоки имеют одинаковый приоритет. Поток может отказаться от выделенного ему кванта времени.

В этом случае система перехватывает у него управление (даже если выделенный квант времени не закончен) и передаёт управление другому потоку. При передаче управления другому потоку система сохраняет состояние всех регистров процессора в особой структуре в оперативной памяти. Эта структура называется контекстом потока. Сохранение контекста потока достаточно для последующего возобновления его работы.

Mac OS X.

Архитектуры Mac OS модульно-иерархическая.


.Архитектура Mac OS

Систему  можно разделить на несколько подсистем, каждая из которых выполняет управление определенным видом ресурсов (памятью, задачами, файлами, средствами коммуникаций и т.д.). Подсистема состоит из нескольких Менеджеров, каждый их которых обеспечивает более высокий уровень абстракции ресурсов. Менеджеры более высокого уровня используют средства Менеджеров низкого уровня своей подсистемы, а также и других подсистем. API (application programming interfaces) же системы предоставляет доступа к возможностям практически любого уровня абстракции.

Контрольні запитання:

  1.  Поняття Unix - подібні ОС.
  2.  Поняття загальних та приватних даних.
  3.  Сімейство Microsoft Windows.
  4.  Архітектура Mac OS.


Лекція 5 «Ядро операційної системи. Підсистеми ядра»

  1.  Підсистеми ядра операційної системи.
  2.  Інтерфейс ядра, управління введенням-виведенням.
  3.  Підсистеми управління оперативною пам’яттю та задачами.

Навчальна мета: Засвоїти основні поняття ядра оперраціної системи, вивчити інтерфейс ядра ОС, систему введення-виведення та підсистеми управління оперативною пам’яттю та задачами.

Виховна мета: Допомогти студентам усвідомити вагому роль розуміння принципів роботи ядра операційної системи.

Актуальність: Донести до відома студентів, що на сьогоднішній день більшість системних програмістів працюють з ядром операційної системи.

Мотивація: Мотивацією вивчати даний напрямок у курсі ситемного програмування може стати бажання стати професіоналом в галузі керування системним програмним забезпепеченням.

Підсистеми ядра ОС. Інтерфейс ядра операційної системи

Функції ядра операційної системи можуть бути виконані в наслідок виконання в прикладних програмах спеціальних функцій - системних викликів. Призначення системного виклику полягає в тому, що прикладні програми не взмозі самотужки визначити, за якими адресами знаходяться функціїї ядра.

Системний виклик в один з машинно-залежних способів реалізує механізм отримання адрес функцій ядра та передачу в ці функціїї необхідних параметрів системного виклику, а також отримання результату системного виклику. Найчастіше системні виклики забезпечуються через систему переривань, завдяки чому адреса функціїї ядра не тільки обраховується апаратно (в процесі обробки переривання), але й забезпечується захист інформаційних ресурсів ядра.

Системні виклики найчастіше мають синтаксис функції мови програмування, на якій написано ядро ОС.

Підсистема управління введенням-виведенням

Підсистема управління введенням-виведенням реалізує базові механізми обміну даними між пристроями введення-виведення та оперативною пам'яттю обчислювальної машини та забезпечує організацію файлів в файлові системи.

Операція введення виконується як читання даних з зовнішнього пристрою в оперативну пам'ять, операція виведення - як запис даних з оперативної пам'яті на зовнішній пристрій.

При роботі з файлами система введення-виведення впроваджує спеціальну абстракцію - поток вводу-виводу, що дозволяє програмам, які звертаються за сервісами введення-виведення, використовувати одноманітний перелік функцій роботи з файлами не залежно від типу пристрою, на якому знаходиться файл, та типу файлової системи, яка містить цей файл. Відмінності доступу до різних пристроїв та файлових систем забезпечуються додатковими програмними модулями - драйверами пристроїв та файлових систем.

В окремих операційних системах підсистема управління введенням-виведенням також може впроваджувати механізми, які призвані підвищити швидкість обміну даними між задачами та файлами. Найчастіше використовується механізм буферизації (кешування) даних, який полягає в тому, що при читанні даних з файлу підсистема намагається за одну операцію введення читати дані блоками зручного (звичайно досить великого) розміру, а не порціями, які запитує задача. Завдяки цьому за одну операцію введення в оперативну пам'ять потрапляють також додаткові дані, які зберігаються в кеші і в подальшому передаються в програму без додаткових звернень до пристрою. Подібним чином цей механізм працює і при виконанні операцій запису.

Підсистема управління оперативною пам'яттю

Будь яка програма може виконуватись лише тоді, коли вона завантажена в оперативну пам'ять, так само, будь які дані з файлів можуть оброблятись лише тоді, коли вони завантажені в оперативну пам'ять. Завантаження програми та даних в оперативну пам'ять призводить до того, що в оперативній пам'яті одночасно знаходяться одразу кілька компонениів: ядро операційної системи, командний інтерпретатор, програма, що виконується, та дані, що обробляються. Крім того, програма в процесі свого виконання може звертатись до підсистеми управління оперативною пам'яттю з запитами на виділення додаткової - динамічної - оперативної пам'яті.

В багатозадачних операційних системах кількість компонентів, що одночасно можуть знаходитись в оперативній пам'яті зростає пропорційно кількості задач і може сягати сотень.

Підсистема управління оперативною пам'яттю забезпечує розподіл оперативної пам'яті між різними компонентами, а також розподіляє пам'ять під кеш системи введення-виведення.

В окремих багатозадачних операційних системах підсистема управління оперативною пам'яттю також забезпечує віртуалізацію оперативної пам'яті, завдяки чому кожна задача (процес) отримує власну віртуальну пам'ять, причому таким чином, що нестача реальної (фізичної) пам'яті покривається за рахунок перерозподілу даних між оперативною пам'яттю та зовнішнім накопичувачем і переміщення даних між фізичною оперативною пам'яттю і зовнішнім накопичувачем приховується від задач. Цей переміщення називається пейджінгом (англ. paging) або свопінгом (англ. swapping — обмін) — в залежності від термінології конкретної ОС.

Введення механізму віртуалізації оперативної пам'яті дозволяє отримати два корисних наслідки:

кожна задача фактично виконується у власному адресовому просторі, тобто таким чином, якби вона виконувалась в одно-задачній операційній системі, завдяки чому значно зменьшується вплив окремих задач однією на одну та на ядро ситеми, а завдяки цьому - і надійність системи;

кожна задача отримує стільки віртуальної оперативної пам'яті, скільки потрібно, а не стільки, скільки є наявної фізичної оперативної пам'яті.

Віртуалізація оперативної пам'яті вимагає апаратної підтримки і звичайно забезпечується через спеціальну таблицю сторінок пам'яті, котра містить відповідності між віртуальними та фізичними адресами.

Підсистема управління задачами (процесами)

Процес — це одне з найважливіших понять інформатики. За визначенням це екземпляр виконуваної програми, включаючи змінні та стан програми. Процеси слід відрізняти від нитей виконання — ниті є складовими процесу, так що кожен процес має власний адресний простір, а ниті розподіляють спільний адресний простір процесу. Процес складається щонайменше з одної, головної ниті виконання.

Контрольні запитання:

  1.  Підсистеми ядра ОС. Інтерфейс ядра операційної системи
  2.  Підсистема управління введенням-виведенням
  3.  Підсистема управління оперативною пам'яттю
  4.  Підсистема управління задачами (процесами)

Лекція 6 «Ядро Linux. Розробка програм для Linux»

  1.  Архітектура ядра Linux.
  2.  Особливості роботи та розробки системних програм для Linux.

Навчальна мета: Засвоїти основні поняття застосування операційної ситеми Linux, вивчити архітектуру ядра Linux та особливості роботи та розробки системних програм для Linux.

Виховна мета: Виховати у студентів кросплатформену терпимість.

Актуальність: На сьогоднішній день все більше користувачів стають клієнтами Linux.

Мотивація: Знання операційної системи Linux підвищує шанси на працевлаштування у десятки разів.

Архітектура

Ядро Linux підтримує багатозадачність, віртуальну пам'ять, динамічні бібліотеки, відкладене завантаження, продуктивну систему управління пам'яттю і багато мережних протоколів.

На сьогоднішній день Linux — монолітне ядро з підтримкою завантажуваних модулів. Драйвери пристроїв і розширення ядра зазвичай запускаються на з повним доступом до устаткування. На відміну від звичайних монолітних ядер, драйвери пристроїв легко збираються у вигляді модулів і завантажуються або вивантажуються під час роботи системи.

Структура

Операційну систему можна умовно розділити на два рівні.

На верхньому рівні розташований користувацький простір (простір виконування прикладних програм). Тут виконуються застосунки користувача. Під призначеним для користувача простором розташовується простір ядра. Тут функціонує ядро Linux.

Є також бібліотека GNU C (glibc). Вона надає інтерфейс системних викликів, який забезпечує зв'язок з ядром і дає механізм для переходу від програми, що працює в просторі користувача, до ядра. Це важливо, оскільки ядро і програма користувача розташовуються в різних захищених адресних просторах. При цьому, тоді як кожен процес в просторі користувача має свій власний віртуальний адресний простір, ядро займає один загальний адресний простір.

GNU Compiler Collection (обычно используется сокращение GCC) — набор компиляторов для различных языков программирования, разработанный в рамках проекта GNU. GCC является свободным программным обеспечением, распространяется фондом свободного программного обеспечения. Он используется как стандартный компилятор для свободных UNIX-подобных операционных систем.

Изначально названный GNU C Compiler, он поддерживал только язык Си. Позднее, GCC был расширен для компиляции исходных кодов на таких языках программирования как C++, Java.

В настоящее время GCC поддерживается группой программистов со всего мира. GCC является лидером по количеству процессоров и операционных систем, которые он поддерживает.

Будучи официальным компилятором системы GNU, GCC также является главным компилятором для сборки ряда других операционных систем, среди них: различные варианты Linux и BSD, а также ReactOS, Mac OS X, OpenSolaris, NeXTSTEP, BeOS и Haiku. GCC часто выбирается для разработки программного обеспечения, которое должно работать на большом числе различных аппаратных платформ.

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

Ядро Linux можна, у свою чергу, розділити на три великі рівні. Вгорі розташовується інтерфейс системних викликів, який реалізує базові функції, наприклад, читання і запис. Нижче за інтерфейс системних викликів розташовується незалежний код ядра. Цей код є загальним для всіх процесорних архітектур, підтримуваних Linux. Ще нижче розташовується архітектурно-залежний код, що утворює так званий BSP (Board Support Package — пакет підтримки апаратної платформи). Цей код залежить від процесора і платформи для конкретної архітектури.

Ядро по суті є диспетчером ресурсів. Незалежно від того, що є керованим ресурсом — процес, пам'ять або апаратний пристрій, — ядро організовує й упорядковує доступ до ресурсу безлічі конкуруючих користувачів (як у просторі ядра, так і в просторі користувача).

Властивості ядра Linux

У ядрі Linux реалізована ціла низка важливих архітектурних елементів. І на найзагальнішому, і на детальніших рівнях ядро можна підрозділити на безліч різних підсистем. З іншого боку, Linux можна розглядати як монолітне ціле, оскільки всі базові сервіси зібрані в ядрі системи. Такий підхід відрізняється від архітектури з мікроядром, коли ядро надає тільки найзагальніші сервіси, такі як обмін інформацією, ввод/вивід, управління пам'яттю і процесами, а конкретніші сервіси реалізуються в модулях, що підключаються до рівня мікроядра.

Інтерфейс системних викликів

Інтерфейс системних викликів (SCI) — це тонкий рівень, що надає засоби для виклику функцій ядра з простору користувача. Цей інтерфейс може бути архітектурний залежним, навіть в межах одного процесорного сімейства. SCI фактично є службою мультиплексування і демультиплексування виклику функцій.

Керування процесами

Керування процесами сконцентроване на виконанні процесів. У ядрі ці процеси називаються нитями (англ. threads); вони відповідають окремим віртуалізованим об'єктам процесора (код ниті, дані, стекпроцесорні регістри).

Ще одне завдання керування процесами — сумісне використання процесора активними нитями. У ядрі реалізований новаторський алгоритм планувальника, час роботи якого не залежить від числа нитей, що претендують на ресурси процесора.

Управління пам'яттю

Інший важливий ресурс, яким управляє ядро, — це оперативна пам'ять. Для підвищення ефективності, враховуючи механізм роботи апаратних засобів з віртуальною пам'яттю, пам'ять організовується у вигляді так званих сторінок (у більшості архітектури розміром 4 КБ). У Linux є засоби для управління наявною пам'яттю, а також апаратними механізмами для встановлення відповідності між фізичною і віртуальною пам'яттю.

Проте управління пам'яттю — це значно більше, чим просто управління буферами по 4 КБ. Linux надає абстракції над цими 4 КБ буферами, наприклад, механізм розподілу slab allocator. Цей механізм управління базується на 4 КБ буферах, але потім розміщує структури усередині них, стежачи за тим, які сторінки повні, які частково заповнені і які порожні. Це дозволяє динамічно розширювати і скорочувати схему залежно від потреб розміщеної системи.

В умовах наявності великого числа користувачів у пам'яті можливі ситуації, коли вся наявна пам'ять буде вичерпана. У зв'язку з цим сторінки можна видаляти з пам'яті і переносити на диск. Цей процес обміну сторінок між оперативною пам'яттю і жорстким диском називається підкачкою.

Віртуальна файлова система

Ще один важливий аспект ядра Linux — віртуальна файлова система (VFS), яка надає загальну абстракцію інтерфейсу до файлових систем. VFS надає рівень комутації між SCI і файловими системами, підтримуваними ядром. На верхньому рівні VFS розташовується єдина API-абстракція таких функцій, як відкриття, закриття, читання і запис файлів. На нижньому рівні VFS розташовані абстракції файлових систем, які визначають, як реалізуються функції верхнього рівня.

Нижче за рівень файлової системи міститься кеш буферів, що надає загальний набір функцій до рівня файлової системи (незалежний від конкретної файлової системи). Цей рівень кешування оптимізує доступ до фізичних пристроїв за рахунок короткострокового зберігання даних (або попереджувального читання, що забезпечує готовність даних до того моменту, коли вони знадобляться). Нижче за кеш буферів містяться драйвери пристроїв, що реалізовують інтерфейси для конкретних фізичних пристроїв.

Мережевий стек

Мережевий стек за своєю конструкцією має багаторівневу архітектуру, що повторює структуру самих протоколів. Протокол Internet Protocol (IP) — це базовий протокол мережевого рівня, розташований нижче за транспортний протокол Transmission Control Protocol, TCP). Вище TCP розташований рівень сокетів, що викликається через SCI.

Рівень сокетів є стандартним API до мережевої підсистеми. Він надає користувацький інтерфейс до різних мережевих протоколів. Рівень сокетів реалізує стандартизований спосіб управління з'єднаннями і передачі даних між кінцевими точками, від доступу до "чистих" кадрів даних і блоків даних протоколу IP (PDU) і до протоколів TCP і User Datagram Protocol (UDP).

Драйвери пристроїв

Переважна більшість початкового коду ядра Linux припадає на драйвери пристроїв, що забезпечують можливість роботи з конкретними апаратними пристроями. У дереві початкових кодів Linux є підкаталог драйверів, в якому, у свою чергу, є підкаталоги для різних типів підтримуваних пристроїв, таких як BluetoothI2Cпослідовні порти тощо.

Архітектурно-залежний код

Хоча основна частина Linux незалежна від архітектури, на якій працює операційна система, в деяких елементах для забезпечення нормальної роботи і підвищення ефективності необхідно враховувати архітектуру.

Контрольні запитання:

  1.  Архітектура та структура Linux
  2.  Властивості ядра Linux
  3.  Інтерфейс системних викликів та керування процесами
  4.  Управління пам'яттю
  5.  Віртуальна файлова система
  6.  Мережевий стек
  7.  Драйвери пристроїв
  8.  Архітектурно-залежний код

Лекція 7 «GUI – інтерфейс користувача»

  1.  Інтерфейс користувача.
  2.  Елементи інтерфейсу.
  3.  Віджети.

Навчальна мета: Засвоїти основні поняття інтерфейсу користувача, його елементи. Поняття віджетів.

Виховна мета: Допомогти студентам усвідомити вагому роль застосування інтерфейсу користувача.

Актуальність: Нині усе без винятку користувацьке програмне забезпечення має інтерфейс користувача.

Мотивація: Навіть у системному програмування існує тенденція до розробки інтерфейсу користувача.

Графі́чний інтерфе́йс кори́стувача (ГІК, англ. GUI, Graphical user interface) — інтерфейс між комп'ютером і його користувачем, що використовує піктограми, меню, і вказівний засіб для вибору функцій та виконання команд. Зазвичай, можливе відкриття більше, ніж одного вікна на одному екрані.

GUI — система засобів для взаємодії користувача з комп'ютером, заснована на представленні всіх доступних користувачеві системних об'єктів і функцій у вигляді графічних компонентів екрану (вікон, значків, меню, кнопок, списків і т. п.). При цьому, на відміну від інтерфейса командного рядка, користувач має довільний доступ (за допомогою клавіатури або пристрою координатного введення типу «миша») до всіх видимих екранних об'єктів.

Елементи інтерфейсу

Элеме́нт интерфе́йса — примитив графического интерфейса пользователя, имеющий стандартный внешний вид и выполняющий стандартные действия.

Другие названия: ви́джет (англ. widget), контро́л (control) и элемент управления.

В большинстве существует стандартный набор элементов интерфейса, включающий следующие элементы управления:

  1.  кнопка (button)
  2.  список (list box)
  3.  ниспадающее меню (pull down menu)
  4.  раскрывающийся список (en:combo box, drop-down list)
  5.  флажок/переключатель (check box)
  6.  радио-кнопка (radio button)
  7.  поле редактирования (textbox, edit field)
  8.  значок (icon)
  9.  панель инструментов (toolbar)
  10.  строка состояния (status bar)
  11.  всплывающая подсказка (tooltip, hint)
  12.  полоса прокрутки (scrollbar)
  13.  вкладка (tab)
  14.  элемент для отображения табличных данных (grid view)
  15.  меню (menu)
  16.  главное меню окна (main menu)
  17.  контекстное меню (popup menu)
  18.  окно (window)
  19.  панель (panel)
  20.  диалоговое окно (dialog box)
  21.  модальное окно (modal window)
  22.  дерево — элемент для отображения иерархии (tree view)

Віджети призначені як інструмент для швидкого доступу до певної інформації чи сервісів.

Контрольні запитання:

  1.  Елементи інтерфейсу
  2.  Графі́чний інтерфе́йс користувача
  3.  Елементи керування


Лекція 8 «Планувальник ОС»

  1.  Поняття планувальника операційної системи.
  2.  Типи планувальників ОС.
  3.  Реалізація планувальників у різних ОС.

Навчальна мета: Вивчити основні поняття, базові функції, види планувальників граційних різних систем з метою поглибленого розумінняя принципів роботи операційної системи з процесами та задачами.

Виховна мета: Допомогти студентам усвідомити вагому роль планувальників операційних ситем та їх роль у процесах вирішення задачі розподілу ресурсів операційної системи

Актуальність: Планувальник операційної системи є одним з головних складових механізмів розподілу ресурсів операційної системи.

Мотивація: Мотивацією вивчати даний напрямок у курсі ситемного програмування є глибоке розуміння взаємодії процесів в операційній системі.

Планування виконання завдань (англ. Scheduling) є однією з ключових концепцій в багатозадачності і багатопроцесорних систем, як в операційних системах загального призначення, так і в операційних системах реального часу. Планування полягає в призначенні пріоритетів процесам в черзі з пріоритетами. Програмний код, що виконує це завдання, називається планувальником (англ. Scheduler).

Найважливішою метою планування завдань є якнайповніше завантаження процесора. Для забезпечення загальної продуктивності системи планувальник має опікуватися за

  1.  Використання процесора(-ів) - дати завдання процесору, якщо це можливо.
  2.  Пропускна здатність - кількість процесів, що виконуються за одиницю часу.
  3.  Поворот - кількість часу, для виконання певного процесу.
  4.  Очікування - кількість часу, коли процес очікує в черзі готових.
  5.  Час відгуку - час, який проходить від початку запиту до першої відповіді на запит.
  6.  Справедливість - Рівність процесорного часу для кожної ниті

У середовищах обчислень реального часу, наприклад, на пристроях, призначених для автоматичного управління в промисловості (наприклад, робототехніка), планувальник завдань повинен забезпечити відробіток процесів в перебігу заданих часових проміжків (час відгуку); це критично для підтримки коректної роботи системи реального часу.

Типи планувальників в операційних системах

Довготривалий планувальник вирішує, які завдання або процеси будуть додані в чергу процесів, готових до виконання; тобто, коли проводиться спроба запуску процесу, довготривалий планувальник або додає новий процес в чергу готових процесів (допускає до виконання), або відкладає цю дію. Таким чином, довготривалий планувальник вирішує, які процеси виконуватимуться одночасно, тим самим контролюючи ступінь паралелізму і пропорцію між процесами, що інтенсивно виконують введення-виведення, і процесами, що інтенсивно використовують процесор.

Зазвичай в настільних комп'ютерах не застосовується довготривалий планувальник і нові процеси допускаються до виконання автоматично. Але цей планувальник дуже важливий для систем реального часу, оскільки при надмірному навантаженні системи процесами, що паралельно виконуються, час відгуку системи може стати більше потрібного, що неприпустимо.

Середньостроковий планувальник У всіх системах з віртуальною пам'яттю середньостроковий планувальник тимчасово переміщає (вивантажує) процеси з основної пам'яті у вторинну (наприклад, на жорсткий диск), і навпаки. Ці дії називаються підкачкою або свопінгом (swapping). Середньостроковий планувальник може ухвалити рішення вивантажити процес з основної пам'яті якщо:

  1.  процес був неактивним якийсь час;
  2.  процес має низький пріоритет;
  3.  процес часто викликає помилки сторінок (page fault);
  4.  процес займає велику частку основної пам'яті, а системі потрібна вільна пам'ять для інших цілей (наприклад, щоб задовольнити запит виділення пам'яті для іншого процесу).

Процес буде повернений в основну пам'ять коли буде доступна необхідна кількість вільної пам'яті, або коли процес вийде з режиму очікування (в цьому випадку планувальник вивантажить з основної пам'яті інший процес для звільнення основної пам'яті).

У багатьох сучасних системах, що підтримують відображення віртуального адресного простору на вторинну пам'ять, відмінну від файлу підкачки, середньостроковий планувальник може одночасно грати роль і довготривалого планувальника, розглядаючи нові процеси як процеси, які були вивантажені з основної пам'яті. Таким чином система може підвантажувати в основну пам'ять програмний код тільки тоді, коли він знадобиться процесу для виконання (це називається завантаженням на вимогу або «ледачим завантаженням»).

Короткостроковий планувальник (також відомий як диспетчер, або шедулер) вирішує, які з готових процесів у пам'яті мають бути виконані (відданні на виконання ЦП) за наступним перериванням годинника, перериванням введення-виведення, системним викликом або від іншої форми сигналу. Таким чином, короткостроковий планувальник робить планування рішень набагато частіше, ніж довгострокові і середньострокові планувальники - щонайменше одне рішення має бути зроблене після кожного часу квантування процесу, а це дуже короткий проміжок. Це планувальник може упереджувальний або витісняючий (мається на увазі, що він здатний примусово видалити процеси з процесора, якщо він вирішить передати процесор іншому процесу), або не упереджувальний (також відоме як "добровільний" або "кооперативний"), в якому планувальник не в "силі" вилучити процес від процесора.

Реалізації планувальників в операційних системах

Windows

Системи MS-DOS і рані Microsoft Windows не були багатозадачними, і відповідно не мали планувальника. Windows 3.1x використовував неупереджувальний планувальник, і тому не могла переривати програми. Система цілком покладається на програму, коли та скаже ОС, що вона вже не потребує процесора, і тільки тоді система могла виконувати інший процес. Це звичайно називають кооперативною багатозадачністю. Windows 95 представив зародковий упереджувальний планувальник, проте для сумісності зі спадщиною вирішили дати 16-бітним застосункам запускатися в невитісняючому режимі.

Операційні системи на основі Windows NT використовують чергу з багаторівневим відгуком. Визначені 32 рівнів пріоритету, від 0 до 31, де пріоритети від 0 до 15 є "нормальними" пріоритетами, і пріоритети від 16 до 31 є м'якими пріоритетами реального часу, які вимагають привілеїв призначити їх. "0" зарезервований для операційної системи. Користувач може вибрати 5 з цих пріоритетів і призначити їх своїм застосункам з програми Task Manager або за допомогою API управління еитями. Ядро може змінити рівень пріоритету нитки в залежності від його операцій введення-виведення, завантаження процесора і навіть інтерактивно (тобто приймає і реагує на вимогу людини)[2]. Планувальник Windows Vista був змінений, щоб задіяти циклічні регістри-лічильники сучасних процесорів відслідковувати скільки точно циклів процесора виконується нить, а не тільки коли інтервал-таймер перериває виконання[3]. Vista використовує також пріоритети планувальника для черги введення-виведення, щоб дефрагментація диску та інші подібні фонові операції не втручалися в роботу основних процедур.

Mac

Mac OS 9 використовував кооперативний планувальник, коли один процес контролює кілька кооперативних нитей. Ядро планує процеси з допомогою найпростішої кругової системи планування без пріоритетів (так званий алгоритм Round-robin). Кожен процес має свою власну копію управління нитями, що планує кожну нитку. А ядро, використовуючи алгоритм упереджувального планування, розподіляло поміж всіх наявних задач час процесора. Mac OS X використовує ниті Mach, і кожна нитка пов'язана з власним окремим процесом. Якщо ниті в даний час кооперативні, тоді тільки одна може працювати одночасно. Нить повинна відмовитися від свого права на процесор, щоб виконувалися інші процеси.

Linux

Починаючи з версії 2.5 ядро Linux використовує багаторівневу чергу з відгуком з пріоритетами 0-140. 0-99 зарезервовані для задач реального часу, а 100-140 виділені для задач рівня nice. Для завдань реального часу інтервал перемикання процесів складає близько 200 мс і 10 мс для задач nice. Планувальник проходить через всю чергу готових процесів, дозволяючи спочатку пройти найвищим з них і запускаючи їх через зріз часу, а і поміщає їх в чергу закінчених. Потім, коли черга активних задач порожня, черга виконаних знов стає активною, і навпаки. З версії 2.6 до 2.6.23, ядро використовує планувальник O(1). У версії 2.6.23, вони замінили цей метод на Completely Fair Scheduler, який використовує Червоно-чорне дерево замість черг.

Контрольні запитання:

  1.  Планування виконання завдань
  2.  Типи планувальників в операційних системах
  3.  Реалізації планувальників в операційній системі Windows
  4.  Реалізації планувальників в операційній системі Mac
  5.  Реалізації планувальників в операційній системі Linux


Лекція 9  «Процеси. Міжпроцесна взаємодія»

  1.  Взаємодія між процесами.
  2.  Засоби міжпроцесної взаємодії.   

Навчальна мета: Засвоїти основні поняття засобів між процесорної взаємодії.

Виховна мета: Допомогти студентам орієнтуватися у основних аспектах між процесорної взаємодії.

Актуальність: Нині вирішення питань між процесорної взаємодії попадає у ло найбільш запитуваних до рішення зада та проблем в галузі інформаційних технологій.

Мотивація: Легко розбиратися у несправностях операційної системи допоможе глибоке розуміння принципів роботи засобів міжпроцесорої взаємодії.

Засоби міжпроцесної взаємодії

Взаємодія процесів дозволяє процесам синхронізувати свою роботу, сумісно і узгоджено використовувати спільні ресурси та спільно виконувати обробку даних.

Взаємодія процесів забезпечується всіма підсистемами ядра ОС:

  1.  підсистема управління введенням-виведенням забезпечує передачу даних між процесами;
  2.  підсистема управління оперативною пам'яттю розподіляє під процеси спільну оперативну пам'ять,
  3.  підсистема управління процесами забезпечує синхронізацію виконання процесів та впроваджує механізм обміну сигналів, за допомогою якого процеси повідомляються про виникнення в системі надзвичайних подій.

Взаємодія між процесами (англ. Inter-Process Communication, скорочено англ. IPC) — набір засобів обміну повідомленнями між процесами. Засоби IPC можуть використовуватись для взаємодії процесів:

  1.  які виконуються на одному комп'ютері (для багатомашинних систем — під управлінням однієї операційної системи), також відомі як власне IPC;
  2.  які виконуються на різних комп'ютерах (для багатомашинних систем — під управлінням окремих операційних систем), також відомі як засоби міжмашинної взаємодії;
  3.  для забезпечення взаємодії процеса з самим собою — наприклад, для синхронізації або обміну даними між різними нитями одного процесу.

Взаємодія процесів в межах однієї машини

Для взаємодії процесів, що виконуються на одному комп'ютері (під управлінням однієї операційної системи) використовують (механізми взаємодії забезпечуються ядром операційної системи, в якій виконуються процеси):

  1.  сигнали — асинхронні (неочікувані) повідомлення, що не передають дані між процесами, а сповіщають про подію (надзвичайну ситуацію), на яку процес має відреагувати виконанням наперед визначеної дії (функції або команди в залежності від використаних засобів програмування);
  2.  неіменовані та іменовані канали передачі даних як синхронних (очікуваних) повідомлень; відправлення повідомлення відбувається подібно до операції запису в файл, отримання — подібно до читання даних з файлу, якщо канал порожній — процес, що очікує дані призупиняється до надходження даних в канал.
  3.  черги повідомлень — пакети даних, що передаються між процесами з увідомленням отримувача про надходження пакету;
  4.  сегменти подільної пам'яті — засіб, що дозволяє кільком процесам сумісно використовувати (поділяти) фрагмент оперативної пам'яті з метою обміну даними; відправлення даних відбувається шляхом запису в пам'ять, отримання — читанням з пам'яті.

Взаємодія процесів, що виконуються на різних машинах

Взаємодія процесів, що виконуються на різних комп'ютерах — під управлінням окремих операційних систем, міжмашинна взаємодія — забезпечується через спеціальну абстракцію — сокет. В залежності від рівня використання сокетів існують наступні засоби міжмашинної взаємодії процесів (механізми взаємодії узгоджено забезпечуються ядрами операційних систем, в яких виконуються процеси):

  1.  пряме використання сокетів — технологія, що вимагає програмування на низькому рівні і реалізації протокола передачі даних;
  2.  RPC (Remote Procedure Call), віддалений виклик процедур — технологія, що забезпечує взаємодію між процесами подібно до виклику функцій, дані в один бік передаються як аргументи функцій (віддалених процедур), в іншому — як результати виконання функцій (віддалених процедур).

CORBA — технологія, що передбачає можливість взаємодії між процесами як між об'єктами CORBA, є подальшим розвитком технології RPC.

Контрольні запитання:

  1.  Засоби міжпроцесної взаємодії
  2.  Взаємодія між процесами
  3.  Взаємодія процесів в межах однієї машини
  4.  Взаємодія процесів, що виконуються на різних машинах


Лекція 10 «Робота з бібліотеками»

  1.  Поняття Бібліотеки.
  2.  Статичні та динамічні бібліотеки.
  3.  Використання бібліотек.

Навчальна мета: Засвоїти основні поняття застосування динамічних та статичних бібліотек.

Виховна мета: Допомогти студентам усвідомити різницю між статичними та динамічними бібліотеками та способами їх підключення.

Актуальність: Донести до відома студентів, що на сьогоднішній день вагома частка програмного забезпечення, яке використовується на виробництві, має модулі, що підключаються, тобто, бібліотеки.

Мотивація: Мотивацією вивчати даний напрямок у курсі ситемного програмування є основним при написанні курсового проекту.

Бібліотека (від англ. library) — збірка об'єктів чи підпрограм для вирішення близьких по тематиці задач. Бібліотеки містять первинний код та дані, допоміжні для задіяння та інтеграції нових можливостей в програмні рішення.

Бібліотека може означати те саме, що модуль, або декілька модулів.

З точки зору комп'ютерних наук бібліотеки діляться на статичні та динамічні.

Статичні бібліотеки

Можуть бути у вигляді початкового тексту, що підключається програмістом до своєї програми на етапі написання, або у вигляді об'єктних файлів, що приєднуються (лінкуються) до виконуваної програми на етапі компіляції (у Microsoft Windows такі файли мають розширення .lib, у UNIX-подібніх ОС — зазвичай .a). В результаті програма включає всі необхідні функції, що робить її автономною, але збільшує розмір.

Динамічні бібліотеки

Також називаються розподілюваними бібліотеками (англ. shared library), або бібліотеками, що динамічно підключаються (англ. Dynamic Link Library, DLL). Це окремі файли, що надають програмі набір використовуваних функцій для завантажування на етапі виконання при зверненні програми до ОС із заявкою на виконання функції з бібліотеки. Якщо необхідна бібліотека вже завантажена в оперативну пам'ять, програма використуватиме завантажену копію бібліотеки. Такий підхід дозволяє зекономити час і пам'ять, оскільки декілька програм використовують одну копію бібліотеки, вже завантажену в пам'ять.

Динамічні бібліотеки зберігаються зазвичай у визначеному місці й мають стандартне розширення. Наприклад, файли .library у логічному томі Libs: у AmigaOS; у Microsoft Windows і OS/2 файли бібліотек загального користування мають розширення .dll; у UNIX-подібних ОС — зазвичай .so; у MacOS — .dylib.

При написанні програми програмістові досить вказати транслятору мови програмування (компілятору або інтерпретатору), що слід підключити таку-от бібліотеку і використовувати таку-от функцію зі вказаної бібліотеки. Ні початковий текст, ні виконуваний код функції до складу програми не входить.

З формальної точки зору DLL (динамічна бібліотека) - особливим образом оформлений відносно незалежний виконуваний модуль.

Особливий спосіб оформлення передбачає наявність в DLL так званих секцій імпорту й експорту. Секція експорту вказує ті ідентифікатори об'єктів (функцій, класів, змінних), доступ до яких надає дана DLL. У цьому випадку говорять про експортування ідентифікаторів з DLL. У загальному випадку, саме секція експорту найбільш важлива для розробників. Хоча цілком можливо реалізувати DLL, що не має даної секції, проте виконує корисну роботу.

Відносна незалежність пов'язана з наявністю/відсутністю секції імпорту в DLL (тобто секції, у якій описуються зовнішні залежності даної DLL від інших). Переважна більшість DLL імпортує функції із системних DLL (kernel32.dll, user32.dll, gdі32.dll і ін.). У більшості випадків при створенні бібліотеки до неї автоматично підключається стандартний набір таких бібліотек. Іноді в цей список необхідно додати необхідні DLL (наприклад, у випадку використання бібліотеки сокетів потрібно додатково підключити бібліотеку ws2_32.dll).

Виконуваний код в DLL не припускає автономного використання. Перед тим, як можна буде викликати функції та користуватись ресурсами бібліотеки, необхідно завантажити відповідну DLL в область пам'яті поточного процесу (тобто DLL не може виконуватися сама по собі - їй обов'язково необхідна програма-клієнт). Це явище зветься  "проектування DLL на адресний простір процесу". У кінцевому коді exe-файлу програми-клієнта, що генерує компілятор, код викликуваної функції не буде включений. Замість цього буде згенерована інструкція виклику відповідної функції (call). Поскільки бібліотека DLL завантажена і спроєктована на адресний простір процесу, то відповідна функція буде легко доступний по call-виклику.

Таким чином, DLL - особливим образом оформлений програмний компонент, доступ до виконуваного коду в якому програма одержує в момент старту (DLL неявного завантаження) або в момент використання (DLL явного й відкладеного завантаження).

Основні переваги використання цього типу бібліотек полягають в наступному:

  1.  економія дискового простору за рахунок багаторазового використання коду (reusіng). Якщо всі ваші додатки використовують той самий   код, немає необхідності поставляти його в коді кожного. Досить розробити DLL.
  2.  економія фізичної пам'яті (RAM) за рахунок завантаження в неї лише одного екземпляра DLL. Саме тоді з'явилися лічильники посилань користувачів DLL - при кожному виклику функції ОС перевіряє наявність завантаженого екземпляра бібліотеки. У випадку позитивного результату лічильник посилань користувачів даної DLL збільшується на одиницю. Якщо ж екземпляр даної DLL у пам'яті не виявлений, то операційна система завантажує файл на згадку й присвоює лічильнику значення "1". Механізм поділу коду зветься  memory mappіng (картування пам‘яті). При вивантаженні DLL з пам'яті зменшується значення лічильника числа користувачів, у випадку рівності його нулю DLL негайно вивантажується.
  3.  ізолювання й модифікація коду DLL незалежно від іншого коду програми. Наприклад, код візуалізації ізолюється від математичної частини. При зміні математичного апарата (наприклад, при розробці нового, більше швидкого алгоритму) перекомпіляція коду клієнтського додатка (відповідального за візуалізацію результатів) не потрібна. Цей фактор може відігравати значну роль у тому випадку, якщо число користувачів досить велике.

Це дає наступні сфери використання динамічних бібліотек.

  1.  різноманітні модулі розширення функціональності додатків - так звані plug- іn (см. приклад з MatLab, Far та ін.);
  2.  локалізація додатка (можна створювати DLL, які містять виключно ресурси);
  3.  спільне використання об'єктів абстракції (функцій, класів та ін.) різними додатками;
  4.  незалежність модифікації коду - DLL може бути в будь-який момент переписана зі збереженням експортованих інтерфейсів;
  5.  реалізація певних дій, які можна зробити тільки за допомогою DLL, наприклад, перехоплення системних подій;
  6.  сховище ресурсів з можливістю незалежної зміни цих ресурсів.

Динамічні бібліотеки широко використовуються в технології COM (а до цього в OLE 1.0) - як основу  при побудові так званих іnproc- серверів (внутріпроцесних серверів) використовуються DLL. Це дозволяє спростити взаємодію з додатком, завдяки завантаженню використовуваних ActіveX-об'єктів в адресний простір клієнта. У цьому випадку накладні витрати, пов'язані з подоланням границь адресних просторів при передачі даних (параметрів функцій і т.д.) - так званий marshallіng, зводяться до нуля.

Всі абстракції, з якими користувач працює в повсякденному програмістському житті, можуть бути реалізовані в DLL - класи, об'єкти, таймери, потоки, функції та ін. Інша справа, що не завжди зручно й правильно працювати із цими об'єктами поза DLL. Зв'язано це з тим, що не завжди логічне представлення того або іншого об'єкта може бути однозначно представлене (переведене) у фізичне. Відбувається це тому, що використання DLL не накладає обмежень на використовувану мову (точніше, обмежує тільки тими мовами, які дозволяють такі бібліотеки створювати). Більше того, як правило, DLL розробляється на іншій мові програмування, ніж та, в котрій вона буде застосовуватись. Найчастіше динамічні бібліотеки пишуться на асемблері, або С/С++.

Контрольні запитання:

  1.  Поняття бібліотеки
  2.  Поняття статичної бібліотеки
  3.  Поняття динамічної бібліотеки
  4.  Сфери використання динамічних бібліотек


Лекція 11  «Додаткові функції ОС»

  1.  Додаткова функціональність ОС.
  2.  Безпека ОС.

Навчальна мета: Засвоїти основні функціональності операційної системи та питання безпеки у операційних системах.

Виховна мета: Дати  студентам розуміння важливості знання  функціональностей операційної системи та питань безпеки у операційних системах.

Актуальність: Донести до відома студентів, що на сьогоднішній день питання безпеки у ОС є чи нне найважливішими!

Мотивація: Мотивацією вивчати даний напрямок у курсі ситемного програмування є бажання розуміти функціонування операційних ситем на рівні, вищому за користувацький.

Додаткова функціональність операційних систем

Основні функції (найпростіші ОС):

- завантаження додатків в оперативну пам'ять і їхнє виконання;

- стандартизований доступ до периферійних пристроїв (пристрою вводу-виводу);

- керування оперативною пам'яттю (розподіл між процесами, віртуальна пам'ять);

- керування доступом до даних на енергонезалежних носіях (таких як жорсткий диск, компакт-диск і т.д. ), як правило за допомогою файлової системи;

- користувальницький інтерфейс;

- мережні операції, підтримка стека протоколів;

Додаткові функції ОС:

- паралельне або псевдопаралельне виконання завдань (багатозадачность);

- взаємодія між процесами;

- захист самої системи, а також користувальницьких даних і програм від зловмисних дій користувачів або додатків;

- розмежування прав доступу й багатокористувальницький режим роботи (аутентифікація, авторизація).

Хмарні операційні системи

Основна ідея такої системи — легкий перехід від одного комп'ютера до іншого. Тут можуть виникнути мимовільні аналогії з акаунтом соціальної мережі, який можна підвантажувати на будь-якому доступному терміналі з доступом до Мережі в незалежності від встановленої ОС. Приблизно така ідея і переслідується творцями цієї нової революційної операційної системи

Безпека ОС базується на двох ідеях:

  1.  ОС надає прямий чи непрямий доступ до ресурсів на кшталт файлів на локальному диску, привілейованих системних викликів, особистої інформації про користувачів та служб, представлених запущеними програмами;
  2.  ОС може розділити запити ресурсів від авторизованих користувачів, дозволивши доступ, та неавторизованих, заборонивши його.

Запити, в свою чергу, також діляться на два типи:

  1.  Внутрішня безпека — вже запущені програми. На деяких системах програма, оскільки вона вже запущена, не має ніяких обмежень, але все ж типово вона має ідентифікатор, котрий використовується для перевірки запитів до ресурсів.
  2.  Зовнішня безпека — нові запити з-за меж комп'ютера, як наприклад реєстрація з консолі чи мережеве з'єднання. В цьому випадку відбувається процес авторизації за допомогою імені користувача та паролю, що його підтверджує, чи інших способів як наприклад магнітні картки чи біометричні дані.

На додачу до моделі дозволити/заборонити системи з підвищеним рівнем безпеки також слідкують за діяльністю користувачів, що дозволяє пізніше дати відповідь на питання типу «Хто читав цей файл?»

Контрольні запитання:

  1.  Основні функції  ОС
  2.  Додаткові функції ОС
  3.  Хмарні операційні системи
  4.  Безпека ОС базується на яких двох ідеях?
  5.  Типи запитів


Лекція 12  «Командний рядок ОС»

  1.  Інтерфейс командного рядка.
  2.  Застосування.
  3.  Формат команд.
  4.  Переваги й недоліки.

Навчальна мета: Вивчити інтерфейс командного рядка. Розуміти як влаштований командний рядок у операційній системі, з’ясувати формат команд.

Виховна мета: Допомогти студентам зрозуміти переваги та недоліки командного рядка, виховати у студентів розуміння значення командного рядка.

Актуальність: Донести до відома студентів, що на сьогоднішній день більшість програмного забезпечення мережевих операційних систем високого класу використовують саме командний рядок для налаштування особливих або специфічних прав доступу.

Мотивація: Мотивацією вивчати даний напрямок у курсі ситемного програмування є однією з важливих частин при виконанні курсового проекту.

Інтерфейс командного рядка 

(англ. command-line interface, CLI) — різновид текстового інтерфейсу користувача і комп'ютера, в якому інструкції комп'ютера даються тільки шляхом введення з клавіатури текстових рядків (команд). Також відомий під назвою консоль.

Призначення

Невелика витрата пам'яті в порівнянні з системою меню.

У сучасному програмному забезпеченні є велика кількість команд, багато з яких потрібні вкрай рідко. Тому навіть у деяких програмах з графічним інтерфейсом застосовується командний рядок: набір команди (за умови, що користувач знає цю команду) здійснюється набагато швидше, ніж, наприклад, навігація по меню.

Природне розширення інтерфейсу командного рядка — пакетний інтерфейс. Його суть в тому, що у файл звичайного текстового формату записується послідовність команд, після чого цей файл можна виконати в програмі, що має такий самий ефект якби ці команди були по черзі введені в командний рядок. Приклади — bat-файли в Windows, shell-скрипти в Unix-системах.

Якщо програма повністю або майже повністю може вправлятися командами інтерфейсу командного рядка та підтримує пакетний інтерфейс, вміле поєднання інтерфейсу командного рядка з графічним надає користувачеві дуже потужні можливості.

Доступ до аргументів командного рядка

Для збільшення кількості завдань, виконуваних програмою, C++ дозволяє вашій програмі звертатися до аргументів командного рядка, використовуючи два параметри, які C++ передає в main. Перший параметр argc містить кількість аргументів командного рядка (включаючи ім'я програми). Другий параметр argv являє собою масив покажчиків на символьні рядки. Кожний символьний рядок відповідає аргументу командного рядка. Щоб звернутися до аргументів командного рядка, зміните заголовок функції main, як показано нижче:

void main(int argc, char *argv[])

Використання циклів для роботи з аргументами командного рядка

Як ви вже знаєте, програми C++ використають символ NULL для завершення символьного рядка. Подібним способом C++ використає символ NULL, щоб відзначити останній елемент масиву argv. Наступна програма ARGVNULL.CPP змінює оператор for попередньої програми, щоб виконувати цикл по елементах argv, поки поточний елемент argv не буде дорівнює NULL:

#include <iostream.h>

void main(int argc, char *argv[])

{
 int i;
  for (i = 0; argv[i] != NULL; i++) cout << "argv[" << i << "] містить " << argv[i] << endl;
}

Трактування argv як покажчика

Як ви вже знаєте, C++ дозволяє вам звертатися до елементів масивів, використовуючи покажчики. Наступна програма ARGVPTR.CPP трактує argv як покажчик на покажчик символьного рядка (інакше кажучи, покажчик на покажчик), щоб вивести вміст командного рядка:

#include <iostream.h>

void main(int argc, char **argv)

{
  int i = 0;
  while (*argv) cout << "argv[" << i++ << "] містить " << *argv++ << endl;
}

Виберіть час, щоб проаналізувати оголошення параметра argvв main:

void main(int argc, char **argv)

Перша зірочка в оголошенні повідомляє компіляторові C++, що argv являє собою покажчик. Друга зірочка повідомляє компіляторові, що argv являє собою покажчик на покажчик — у цьому випадку покажчик на покажчик типу char. Представте argv як масив покажчиків. Кожний елемент масиву в цьому випадку вказує на масив типу char.

Використання аргументів командного рядка

Наступна програма FILESHOW.CPP використає аргументи командного рядка для виводу вмісту зазначеного користувачем файлу на екран. Наприклад, щоб використати програму FILESHOW для виводу вмісту файлу AUTOEXEC.BAT з кореневого каталогу, ваш командний рядок стає наступною:

C: \> FILESHOW \AUTOEXEC.BAT <Enter>

Наступні оператори реалізують програму FILESHOW.CPP. Ця програма починається з перевірки параметра argc, щоб переконатися, що користувач указав файл у командному рядку. Якщо користувач включає ім'я файлу параметр argc буде містити значення 2.

Переваги та недоліки

Переваги:

  1.  Будь-яку команду можна викликати невеликою кількістю натискань.
  2.  Пакетні файли — це, по суті, найпростіша програмованість.
  3.  Можна керувати програмами, що не мають графічного інтерфейсу (наприклад, виділеним сервером).
  4.  Переглянувши вміст консолі, можна повторно побачити повідомлення, яке ви не встигли прочитати.

Недоліки:

  1.  Інтерфейс командного рядка не є дружнім для початківців.
  2.  Шукати невідому команду з довідників не менш складно, ніж відшукувати в меню потрібну команду.

Контрольні запитання:

  1.  Інтерфейс командного рядка
  2.  Призначення командного рядка
  3.  Доступ до аргументів командного рядка
  4.  Використання циклів для роботи з аргументами командного рядка
  5.  Трактування argv як покажчика 
  6.  Використання аргументів командного рядка
  7.  Переваги та недоліки командного рядка


Лекція 13 «Інтерпретатор команд операційної системи»

  1.  Командний інтерпретатор операційної системи.
  2.  Робота з параметрами командного рядка у С++.

Навчальна мета: Вивчити та закріпити поняття інтерпретаторів операційних систем.

Виховна мета: Допомогти студентам усвідомити принципи роботи командного інтерпретатора операційної системи.

Актуальність: Нині програмне забезпечення, яке використовується у народному господарстві та у мережі Інтренет застосовує командні інтерпретатори.

Мотивація: Мотивацією вивчати даний напрямок у курсі ситемного програмування є те, що дана тема є однією з основних при написанні курсового проекту.

Командний інтерпретатор

Інтерпретатор мови програмування (interpreter) — програма чи технічні засоби, необхідні для виконання інших програм, вид транслятора, який здійснює пооператорну (покомандну) обробку, перетворення у машинні коди та виконання програми або запиту (на відміну від компілятора, який транслює у машинні коди всю програму без її виконання).

Інтерпретатори можуть працювати як з вихідним кодом програми (англ. source code), написаним мовою програмування, так і з байт-кодом (інтерпретатори байт-коду).

Командний інтерпретатор — програма, яка забезпечує взаємодію користувача з операційною системою.

Командний інтерпретатор звичайно підтримує командний рядок, змінні оточення, історію виконаних команд, власні конфігураційні файли. Основне призначення командного інтерпретатора полягає в виконанні команд користувача.

Командний інтерпретатор одночасно є середовищем програмування.

Командні інтерпретатори

  1.  command.com - в операційних системах DOS
  2.  cmd - в операційних системах Windows
  3.  sh - (Оболонка Борна) в операційних системах UNIX/Linux
  4.  bash - в операційних системах UNIX/Linux
  5.  csh - в операційних системах UNIX/Linux
  6.  tcl - в операційних системах UNIX/Linux

Команда - ім'я, яке використовує користувач ОС або інша програма для виконання вказаної програми (може співпадати з іменем файла з програмою) або поіменованої дії (вбудованої команди).

Робота з параметрами командного рядка у С++.

Найбільш загальний формат команд (у квадратні дужки поміщені необов'язкові частини):

[символ_початку_команди] ім'я_команди [параметр_1 [параметр_2 [...]]]

Символ початку команди може бути самим різним, однак частіше за все для цієї мети використовується коса риска (/). Якщо рядок вводиться без цього символу, виконується деяка базова команда: наприклад, рядок «Привіт» в IRC еквівалентна вводу «/ msg Привіт». Якщо ж такий базової команди немає, символ початку команди відсутня взагалі (як, наприклад, в DOS).

Параметри команд можуть мати самий різний формат. В основному застосовуються наступні правила:

  1.  Параметри розділяються пробілами (і відділяються від назви команди пропусками)
  2.  Параметри, що містять пробіли, оточуються апострофами (') або лапками (")
  3.  Якщо параметр використовується для позначення включення будь-якої опції, забраного за замовчуванням, він починається з косої риси (/) та тире (-)
  4.  Якщо параметр використовується для включення / виключення будь-якої опції, він починається (або закінчується) знаком плюс або мінус (для включення і виключення відповідно)
  5.  Якщо параметр вказує дію з групи дій, призначених команді, він не починається зі спеціальних символів
  6.  Якщо параметр вказує об'єкт, до якого застосовується дію команди, він не почалась зі спеціальних символів
  7.  Якщо параметр вказує додатковий параметр будь-якої опції, то він має формат / опція: додадковий_параметр (замість косої риси також може вживатися дефіс)

Контрольні запитання:

  1.  Командний інтерпретатор
  2.  Поняття команди
  3.  Робота з параметрами командного рядка у С++


Лекція 14 «Задачі і процеси операційної системи»

  1.  Задача в ОС.
  2.  Процес в ОС.
  3.  Характеристики процесів.
  4.  Робочий цикл процесів.

Навчальна мета: Засвоїти основні поняття задач, процесів в операційних системах.

Виховна мета: Допомогти студентам зрозуміти характеристики процесів та робочі цикли процесів.

Актуальність: Сьогодні на ринку праці програмісти із глибокими знаннями та розумінням процесів та задач в операційних системах ціняться високо.

Мотивація: Для глибокого розуміння принципів розробки програмного забезпечення потрібне розуміння процесів та задач в операційних системах.

Задача - програма в процесі виконання (в термінології операційних систем UNIX використовують термін "процес").

Характеристики Кожному процесу мають бути виділені наступні ресурси: процесор, пам'ять, доступ до пристроїв вводу-виводу, файли

Кожен процес має «батька» (батьківський процес). Він також може мати (але не мусить) «нащадків» (синівські процеси). Таким чином створюється дерево процесів.

Керування процесами здійснює ядро операційної системи. Під час виконання процес може знаходитися в одному із станів:

  1.  виконання,
  2.  очікування на доступ до ресурсів, які надає операційна система,
  3.  готовності до виконання,
  4.  щойно створений,
  5.  завершений,
  6.  зомбі-процес.

Робочий цикл процесу

  1.  користувач з допомогою оболонки вказує програму, яку потрібно виконати; оболонка виконує виклик fork, чи аналогічний
  2.  операційна система створює адресний простір для процесу і структури, які описують новий процес
  3.  заповнюються структури, які описують новий процес
  4.  з файлу, який містить виконавчий файл, в адресний простір процесу копіюються код і дані
  5.  встановлюється стан процесу «готовий до виконання»
  6.  новий процес додається до черги процесів, які очікують на процесор
  7.  керування повертається оболонці користувача

Виконання процесів

Процес почне виконуватися в той момент, коли ядро операційної системи перемкне адресний простір на адресний простір даного процесу і, таким чином, почнеться виконання коду процесу. Виконуваний процес може вимагати певних ресурсів, наприклад, додаткової пам'яті. Такий запит оперативно реалізується операційною системою.

Завершення процесів

  1.  Процес виконує останню інструкцію програми — повертає операційній системі код завершення. Якщо процес завершився нормально повертається значення 0, інакше повертається значення коду помилки.
  2.  операційна система встановлює стан процесу «завершений» і починає звільнення ресурсів, які були виділені процесу під час його виконання
  3.  операційна система по-черзі завершує усі синівські процеси даного батьківського
  4.  операційна система звільняє адресний простір процесу
  5.  операційна система усуває процес з черги готових процесів
  6.  процесор виділяється іншому процесу

Контрольні запитання:

  1.  Поняття задачі.
  2.  Поняття процесу.
  3.  Характеристики задачі.
  4.  Характеристики процесу.
  5.  Робочий цикл процесу.
  6.  Виконання процесів.
  7.  Завершення процесів


Лекція 15 «Принципи побудови драйверів для пристроїв, що використовують ресурси операційнї системи»

  1.  Драйвери пристроїв.
  2.  Ідеологія побудови драйверів.
  3.  Інтеграція драйверів.
  4.  Компонувальник та DDK.

Навчальна мета: Засвоїти основні поняття знаписання драйверів для пристроїв. Вивчити ідеологію побудови драйверів, аспекти інтеграції драйверів та компонувальників DDK.

Виховна мета: Допомогти студентам зрозуміти роль та принципи роботи драйверів операційної системи.

Актуальність: Драйвери завжди були, є і будуть основою роботи операційної системи з пристроями, а отже, і користувачем.

Мотивація: Розробка драйверів є одним із найскладніших завдань і потребує глибоких знань для розробки та впровадження.

Драйвер (driver) - програма, за допомогою якої ОС отримує доступ до керування апаратним забезпеченням. У загальному випадку для використання кожного пристрою, підключеного до комп'ютера, необхідний спеціальний драйвер. Зазвичай з ОС  поставляються драйвери для ключових компонентів апаратного забезпечення, без яких система не зможе працювати. Однак для більш специфічних пристроїв (таких, як графічна плата або принтер) можуть знадобитися спеціальні драйвери, зазвичай надавані виробником пристрою.

Ідеологія побудови драйверів

Операційна система управляє деяким "віртуальним пристроєм", що розуміє стандартний набір команд. Драйвер переводить ці команди в команди, які розуміє безпосередньо пристрій. Ця ідеологія називається "абстрагування від апаратного забезпечення". Драйвер складається з декількох функцій, які обробляють певні події операційної системи. Зазвичай це 7 основних подій:

  1.  завантаження драйвера. Драйвер реєструється в системі, робить первинну ініціалізацію
  2.  вивантаження. Драйвер звільняє захоплені ресурси - пам'ять, файли, пристрої
  3.  відкриття драйвера. Початок основної роботи. Зазвичай драйвер відкривається програмою як файл, функціями CreateFile() в Win32 або fopen() в UNIX-подібних системах;
  4.  читання;
  5.  запис: програма читає або записує дані з/у пристрій, що обслуговує драйвером;
  6.  закриття: операція, зворотна відкриттю, звільняє зайняті при відкритті ресурси й знищує дескриптор файлу;
  7.  керування вводом-виводом-IO Control-IOCTL. Найчастіше драйвер підтримує інтерфейс вводу-виводу, специфічний для даного пристрою. За допомогою цього інтерфейсу програма може послати спеціальну команду, що підтримує даний пристрій.

Інтеграція драйверів

У міру розвитку систем, що сполучають у собі на одній платі не тільки центральні елементи комп'ютера, але й більшість пристроїв комп'ютерів у цілому, виникло запитання зручності підтримки таких систем, що одержали назву "апаратна платформа", або просто "платформа".

Спочатку виробники платформ поставляли набір окремих драйверів для операційних систем, зібраний на один носій (зазвичай CD), Потім з'явилися установні пакети, що називалися «4-in-1» та «One touch» і дозволяли спростити установку драйверів у систему. Однак єдиного, усталеного терміна довго не було. Сучасний термін, що описує такі набори драйверів пристроїв — Board Support Package, або "пакет підтримки платформи". Крім власне драйверів, він може, як і інші установні пакети, містити модулі операційної системи й програми.

DDK — Driver Development Kit

DDK (від англ. driver Development Kit) — набір із засобів розробки, утиліт і документації, який дозволяє програмістам створювати драйвери для пристроїв за визначеною технологією або для певної платформи (програмної або програмно-аппаратної).

Компонувальник 

(також редактор зв'язків, лінкер - від англ. Link editor, англ. linker) - програма, яка виконує компонування - приймає на вхід один або кілька об'єктних модулів і збирає у виконуваний модуль.

Для зв'язування модулів компонувальник використовує таблиці імен ідентифікаторів, створені компілятором в кожному з об'єктних модулів. Такі імена можуть бути двох типів:

  1.  Певні або експортовані назви функцій та змінних, визначені в даному модулі і надані для використання іншим модулям
  2.  Невизначені або імпортовані імена - функції та змінні, на які посилається модуль, але не визначає їх в середині себе.

Контрольні запитання:

  1.  Драйвер. Основні поняття.
  2.  Ідеологія побудови драйверів
  3.  Інтеграція драйверів
  4.  DDK — Driver Development Kit. Основні поняття.
  5.  Компонувальники


Лекція 16 «Написання драйверів для операційної системи Windows»

  1.  Особливості написання драйверів для Windows NT.
  2.  Сервісні системні виклики.

Навчальна мета: Засвоїти основні поняття та особливості написання драйверів під Windows NT.

Виховна мета: Дати студентам зрозуміти основні відмінності написання драйверів під різні операційні системию

Актуальність: Операційна система Windows NT є основою становлення сучасних ОС і написання драйверів під неї дає розуміння написання драйверів для сімейства мережевих ОС Windows.

Мотивація: Вміння розробляти драйвери під різні ОС є чи не головним пріоритетом для роботодавця при виборі найманого працівника на позицію системного програміста.

Драйвер - системна програма, що служить для керування яким-небудь фізичним або віртуальним пристроєм комп'ютера.

Система введення-виведення в Windows NT.

Microsoft випускає пакет DDK (Driver Development Kit), призначений саме для створення системних драйверів. Він містить необхідні для розробки програми й бібліотеки, а також документацію й приклади.

В Windows NT драйвера бувають наступних типів:

  1.  Kernel mode drivers. Основний тип драйвера.
  2.  Graphics drivers. Драйвера відеокарт. Як правило, створюються одночасно із самою відеокартою. Дуже складні в написанні, тому що повинні враховувати безліч суперечливих вимог і підтримувати безліч стандартів.
  3.  Multimedia drivers. Драйвери для :
  4.  Аудіопристроїв  – зчитування, відтворення й компресія аудиоданных.
  5.  пристроїв роботи з відео – захоплення й компресія відеоданих.
  6.  позиційних пристроїв – джойстики, світлові пера, планшети та ін.
  7.  Network drivers – робота з мережею й мережними протоколами на всіх рівнях.
  8.  Virtual DOS Drivers – драйвери для віртуальних машин MS-DOS.

Kernel mode drivers  (рис.1).

У такий спосіб ядро системи представляється набором окремих ізольованих модулів із зовнішніми інтерфейсами. Всі драйвери NT мають стандартні методи драйвера

Існує три типи драйверів ядра, кожний тип має чітко певні структуру й функціональність.

  1.  Device drivers, такі як драйвер клавіатури або дисковий драйвер, що прямо спілкується з дисковим контролером. Ці драйвера також називаються драйверами низького рівня, тому що вони перебувають аж унизу ланцюжка драйверів Windows NT.
  2.  Intermediate drivers, такі як драйвер віртуального або дзеркального диска. Вони використають драйвери пристроїв для звертання до апаратури.
  3.  

Захищена підсистема (сервери)

(серверы)

Підсистема захисту

Підсистема OS/2

Підсистема

POSIX

Підсистема

Win32

Режим корситувача

Режим ядра

LAN

Системні процеси

Менеджер введення-виведення

Менеджер конфігурації

Менеджер пам’яті.

Підтримка виконання

Викливк віддалених процедур

Менеджер об’єктів

Монітор захисту

Ядро

HAL (рівень абстракції апаратури)

Апаратура

File system drivers (FSDs). Драйвери файлових систем, таких як FAT, NTFS, CDFS, для доступу до апаратур використають Intermediate drivers і Device drivers.

  1.  
  2.  Рисунок 1. Головні компоненти операційної системи Windows NT.

Драйвера Windows NT повинні задовольняти наступним вимогам:

  1.  Переносимими з однієї платформи на іншу.
  2.  Конфігіруємими програмно.
  3.  Завжди можуть бути перерваними
  4.  Підтримувати мультипроцесорні платформи.
  5.  Об’єктно-орієнтовані
  6.  Підтримувати пакетне введення-виведення з повторним використанням I/O request packets (IRPs, запити введення-виведення).
  7.  Підтримувати асинхронне введення-виведення

Кожна операційна система має модель введення-виведення для керування потоками даних до і від периферійних пристроїв. Модель введення-виведення Windows NT має наступні особливості:

Менеджер введення-виведення NT представляє інтерфейс для всіх kernel-mode драйверів, включаючи драйвера фізичних пристроїв, драйвера логічних пристроїв і драйвера файлових систем.

Операції введення-виведення пошарові. Це значить, що виклик, зроблений користувачем, проходить через кілька шарів, генеруючи кілька пакетних запитів введення-виведення й звертаючись до необхідних драйверів (див. рис.2).

Менеджер введення-виведення визначає стандартні процедури, які повинні бути реалізовані розроблювачем драйвера.

Подібно NT у цілому, драйвера мають об'єктну архітектуру. Драйвера, їхні пристрої й системне встаткування представлені як об'єкти Windows NT.

Виклик користувача

Драйвер файлової системи

Драйвер дискового пристрою

Накопичувач

Рис. 2. Прошарки операції введення - виведення

Системні виклики

У будь-якій операційній системі підтримується механізм, що дозволяє користувальницьким програмам звертатися до послуг ядра ОС. Такі засоби називають системними викликами.

Системні виклики (system calls) – це інтерфейс між операційної системою й користувальницькою програмою. Вони створюють, видаляють і використають різні об'єкти, головні з яких - процеси й файли. Користувальницька програма запитує сервіс в операційної системи, здійснюючи системний виклик. Є бібліотеки процедур, які завантажують машинні регістри певними параметрами й здійснюють переривання процесора, після чого керування передається оброблювачеві даного виклику, що входить у ядро операційної системи. Ціль таких бібліотек - зробити системний виклик схожим на звичайний виклик підпрограми.

Основна відмінність полягає в тому, що при системному виклику завдання переходить у привілейований режим або режим ядра (kernel mode).

Тому системні виклики іноді ще називають програмними перериваннями, на відміну від апаратних переривань, які частіше називають просто перериваннями.

У цьому режимі працює код ядра операційної системи, причому виконується він в адресному просторі й у контексті його завдання, що викликало. Таким чином, ядро операційної системи має повний доступ до пам'яті користувальницької програми, і при системному виклику досить передати адреси однієї або декількох областей пам'яті з параметрами виклику й адреси однієї або декількох областей пам'яті для результатів виклику.

У більшості операційних систем системний виклик здійснюється командою програмного переривання (INT). Програмне переривання – це синхронна подія, що може бути повторене при виконанні того самого програмного коду.

Переривання

Переривання (hardware interrupt) – це подія, що згенерована зовнішнім (стосовно процесора) пристроєм. За допомогою апаратних переривань апаратури або інформує центральний процесор про те, що відбулася яка-небудь подія, що вимагає негайної реакції (наприклад, користувач нажав клавішу), або повідомляє про завершення асинхронної операції введення-виведення (наприклад, закінчене читання даних з диска в основну пам'ять). Важливий тип апаратних переривань - переривання таймера, які генеруються періодично через фіксований проміжок часу. Переривання таймера використаються операційною системою при плануванні процесів. Кожний тип апаратних переривань має власний номер, що однозначно визначає джерело переривання. Апаратне переривання - це асинхронна подія, тобто воно виникає поза залежністю тому, який код виконується процесором у цей момент. Обробка апаратного переривання не повинна враховувати, який процес є поточним.

Контрольні запитання:

  1.  Система введення-виведення в Windows NT
  2.  Kernel mode drivers  
  3.  Типи драйверів ядра
  4.  Драйвера Windows NT
  5.  Системні виклики
  6.  Переривання


Лекція 17 «Утиліти операційної системи»

  1.  Утиліти обслуговування системи.
  2.   Дефрагментатори.
  3.  Утиліти з контролю помилок і пошкоджень структури розділів та SMART-ревізори.
  4.  Контроль цілісності системи.
  5.  Утиліти розширення функціональності.

Навчальна мета: Засвоїти основні поняття застосування утиліт обслуговування систем, дефрагментаторів, структури дисків, SMART-ревізорів.

Виховна мета: Допомогти студентам усвідомити вагому роль контролю цілісності системи.

Актуальність: Донести до відома студентів, що на сьогоднішній день більшість програмного забезпечення, яке використовується у народному господарстві використовують утиліти розширення функціональності.

Мотивація: Мотивацією вивчати даний напрямок у курсі ситемного програмування може стати бажання отримати позицію системного програміста.

Утилі́та (англ. Utility program, utility) — сервісна програма, що допомагає управляти файлами, одержувати інформацію про комп'ютер, діагностувати й усувати проблеми, забезпечувати ефективну роботу системи. Утилі́та (в програмуванні) — невеличка прикладна програма.

Утиліти обслуговування системи

До УОС відносяться всі види сервісних програм, такі як утиліти для: дефрагментації, перевірки і виправленню структури розділів жорсткого диска, виправленню системних помилок, тонкого налаштуванню системи і т. д. Оскільки типовий набір необхідних УСО приблизно однаковий для всіх користувачів ПК, то великого поширення набули заздалегідь зібрані пакети утиліт, найбільш яскравим прикладом яких може послужити пакет від компанії Norton Utilities (що входить в Norton System Works).

Дефрагментатори

Дефрагментатори перевіряють міру фрагментації файлів і вільного простору на доступних системі розділах логічних накопичувачів, усувають (знижують) її — дефрагментіруют, а також можуть переміщувати файли для розташування в порядку, що забезпечує оптимальний час доступу (мінімальне — для часто використовуваних файлів за рахунок більшого — для рідко використовуваних).

Утиліти з контролю помилок і пошкоджень структури розділів та SMART-ревізори

S.M.A.R.T. (от англ. self-monitoring, analysis and reporting technology — технологія самоконтролю, аналізу і звітності) — технологія оцінки стану жорсткого диску вбудованою апаратурою самодіагностики, а також механізм передбачення часу виходу його з ладу.

Ці утиліти перевіряють на наявність помилок файлову систему, і пристрій зберігання даних (жорсткий диск, пристрій на основі Flash-пам'яті, дискету). Також можуть звертатися до SMART-модулю жорсткого диска для контролю його службової інформації.

Утиліти контролю цілісності системи

Сканують конфігураційні файли, символьні посилання і/або ярлики з метою пошуку некорректних записів, а також видалених або переміщених файлів - Norton WinDoctor,  RegCleaner, CCleaner.

Утиліти розширення функціональності

Розширюють функціональність існуючих прикладних або системних засобів, наприклад, утиліти автоматизації і конвертації медіа-тегів безпечного (безповоротного) видалення файлів, утиліти конвертації файлів різних форматів, утиліти системного менеджменту.

Основні види утиліт розширення функціональності

Утіліти-конвертори Займаються конвертацією файлів, що відносяться до одного типу даних, але в різних форматах: аудіо, відео, графічні, конструкторські, модельні, програмні файли.

Утиліти-редактори мета-інформації Займаються збором, записом і редагуванням мета-інформації файлів, такий як: вміст тегів мультимедійних файлів, інформація про медіавміст, дані EXIF тегів цифрових зображень, і тому подібне. Зазвичай входять до складу так званої медіа-бібліотеки.

Утиліти резервного копіювання

Утиліти системного менеджменту займаються розширеним управлінням системою, таким як: робота з розділами дисків, перепрограмування (перепрошивка) пам'яті BIOS, установка розширених апаратних налаштувань апаратного забезпечення.

Утиліти по роботі розділами диска

Утиліти тонкого налаштування займаються тонким (розширеним) налаштуванням існуючих програм або ОС.

Інформаційні утиліти - Включають монітори, бенчмарки, і утиліти загальної (статичною) інформації.

Контрольні запитання:

  1.  Утиліти обслуговування системи
  2.  Дефрагментатори
  3.  Утиліти з контролю помилок і пошкоджень структури розділів та SMART-ревізори
  4.  Утиліти контролю цілісності системи
  5.  Утиліти розширення функціональності
  6.  Основні види утиліт розширення функціональності
  7.  Утиліти резервного копіювання
  8.  Утиліти по роботі розділами диска


Лекція 18 «Помилки та виключні ситуації у середовищі операційної системи»

  1.  Система відслідковування та обробки помилок у ОС.
  2.  Види помилок.
  3.  Засоби С++ та Assembler для обробки помилок та виключних ситуацій.

Навчальна мета: Засвоїти основні поняття обробки помилок у ОС.

Виховна мета: Допомогти студентам усвідомити вагому роль застосування відслідковування помилок у ОС.

Актуальність: Донести до відома студентів, що на сьогоднішній день більшість програмного забезпечення має бути перевірене на наявність помилок.

Мотивація: Мотивацією вивчати даний напрямок у курсі ситемного програмування може стати бажання отримати позицію програміста.

Виключні ситуації

Виключні ситуація (exception) – подія, що виникає в результаті спроби виконання програмою команди, що з якихось причин не може бути виконана до кінця. Прикладами таких команд можуть бути спроби доступу до ресурсу при відсутності достатніх привілеїв або звертання до відсутньої сторінки пам'яті. Виняткові ситуації, як і системні виклики, є синхронними подіями, що виникають у контексті поточного завдання. Виняткові ситуації можна розділити на поправні й непоправні.

До поправного ставляться такі виняткові ситуації, як відсутність потрібної інформації в оперативній пам'яті. Після усунення причини поправної виняткової ситуації програма може виконуватися далі. Виникнення в процесі роботи операційної системи поправних виняткових ситуацій уважається нормальним явищем.

Непоправні виняткові ситуації найчастіше виникають у результаті помилок у програмах (наприклад, розподіл на нуль). Звичайно в таких випадках операційна система реагує завершенням програми, що викликала виняткову ситуацію.

Структурна обробки виняткових ситуацій (англ. SEH — Structured Exception Handling) — механізм обробки програмних и апаратних виняткових ситуацій  в ОС Microsoft Windows, що дозволяє програмістам контролювати обробку виняткових ситуацій.

Засоби С++. Реалізація.

Механізм підтримується Microsoft тільки на рівні компілятора за допомогою реалізації нестандартних синтаксичних конструкцій _try, _except і _finally. Ключове слово _try використається для виділення ділянки коду, у якому генерація виключення буде оброблена одним або декількома блоками _except. Код, що перебуває в блоці _finally, виконається завжди й незалежно від інших блоків _try і _except.

Приклад використання в мові C/C++

_try {

       // захищений код,

       // який міститься в SEH-фреймі

}

_except (фільтр виключень) {

       // оброблювач виключень

}

_finally {

       // код, що виконується в кожному разі

}

Як фільтр виключень можуть виступати звичайні функції, що повертають три константних вирази:

  1.  EXCEPTION_EXECUTE_З на можливість даного оброблювача обробити виключення. При одержанні такого значення операційна система припиняє пошук релевантних оброблювачів виключення й, виконавши розкручування стека, передає керування першому, що повернуло значення EXCEPTION_EXECUTE_HANDLER
  2.  EXCEPTION_CONTINUE_EXECUTION — указує на виправлення помилки. Система знову передасть керування на інструкцію, що викликала виключення, оскільки передбачається, що цього разу вона не викличе виключення.
  3.  EXCEPTION_CONTINUE_SEARCH — указує, що підходящий оброблювач може бути знайдений нагору по стеку. У той же час повернення цього значення може бути свідченням того, що помилка не оброблена.

Контрольні запитання:

  1.  Виключні ситуації
  2.  Засоби С++. Реалізація.
  3.  Приклад використання в мові C/C++


Лекція 19 «Відеоадаптери»

  1.  Робота з відеоадаптером.
  2.  Структура відеоадаптера.
  3.  Особливості функціонування відеоадаптера у текстовому та графічному режимах.

Навчальна мета: Засвоїти основні поняття роботи з відеоадаптерами.

Виховна мета: Допомогти студентам усвідомити вагому роль функціонування відеоадаптера у текстовому та графічному режимах.

Актуальність: Донести до відома студентів, що на сьогоднішній день необхідно знати функціонування відеоадаптера у текстовому та графічному режимах.

Мотивація: Мотивацією вивчати даний напрямок у курсі ситемного програмування може стати бажання отримати позицію програміста.

VGA

VGA (англ. VideoGraphicsArray) — стандарт мониторів і відеоадаптерів. Випущений IBM в році для комп'ютерів PS/2 Model 50 і більше старших. VGA був останнім стандартом, якому слідувала більшість виробників відеоадаптерів.

Архітектура відеоадаптера VGA

VGA складається з наступних основних підсистем:

  1.  Графічний контролер (Graphics Controller), за допомогою якого відбувається обмін даними між центральним процесором і відеопам'яттю. Має можливість виконувати бітові операції над переданими даними.
  2.  Відеопам'ять (Display Memory), у якій розміщаються дані, відображувані на екрані монітора. 256 кБ DRAM розділені на чотири колірних шари по 64 кБ.
  3.  Послідовний перетворювач (Serializer або Sequencer) — перетворить дані з відеопам'яті в потік бітів, переданий контролеру атрибутів.
  4.  Контролер атрибутів (Attribute Controller) — за допомогою палітри перетворить вхідні дані в колірні значення.
  5.  Синхронізатор (Sequencer) — управляє тимчасовими параметрами відеоадаптера й перемиканням колірних шарів.
  6.  Контроллер ЕПТ електронно-променевої трубки (CRT Controller) — генерує сигнали синхронізації для ЕПТ.

Текстові режими

У стандартних текстових режимах символи формуються в комірці 9×16 пікселів, можливе використання шрифтів інших розмірів: 8—9 пікселів завширшки й 1—32 піксела у висоту. Розміри самих символів, як правило, менше, тому що частина простору йде на створення зазору між символами. Функція для вибору розміру шрифту в BIOS відділена від функції вибору відеорежиму, що дозволяє використати різні комбінації режимів і шрифтів.

Графічні режими

Відеоадаптер VGA має відеорежим із квадратними пикселами (тобто, на екрані зі співвідношенням сторін 4:3 співвідношення горизонтального й вертикального дозволів було також 4:3). В адаптерів CGA і EGA пікселі були витягнуті по вертикалі.

Перші IBM PC були оснащені відеоадаптером MDA (Monochrome Display Adapter) призначеного для виведення винятково тексту. Незабаром за ним пішов CGA (Color Graphics Adapter)  графічний режим для ігор 320х200 але лише при 4 кольорах. Слідом за ним пішов EGA (Enhanced Graphics Adapter) і приніс кілька нових режимів серед яких найбільш привабливим був 320х200, але вже при цілих 16 кольорах. При цьому досить легко було робити гри з можливістю вибору режиму CGA/EGA  роздільна здатність була тою самою. І от, нарешті, рік 1987 - на світло з'явився VGA (Video Graphics Array) приніс із собою режим 320х200 при неймовірних 256 кольорах. І знову ж, через однакову роздільна здатність, у розроблювачів була можливість, по початку, робити гри з вибором відеорежиму, цього разу EGA/VGA.

Всі ці карти функціонували без яких-небудь драйверів! Стандарт VGA став стандартом-мінімумом для всіх відеокарт. З тих пір будь-яка відеокарта повинна була підтримувати стандарт VGA, якщо вона розраховувала на комерційний успіх. Навіть зараз ми користуємося стандартом VGA до завантаження операційної системи відмінної від MS-DOS.

Принцип роботи відеокарт часів стандарту VGA представлений на малюнку:

програми в часи стандарту VGA зверталися до апаратної частини відеокарти прямо

 

Після 1987 року, наступив "неясний час" SVGA. Поширено оману що SVGA (Super Video Graphics Array) це теж стандарт, однак це не так, через термін "SVGA" позначають всі режими перевищуючі VGA. Нових стандартів не було. У такий спосіб не було чітко певного способу як скажемо працювати в графічному режимі 640х480 при 256 кольорах. Потрібно відзначити, що проблема була не в "залізі", більшість відеокарт як правило могла працювати в такому режимі, а у відсутності стандарту - кожна працювала по своєму. Таким чином, щоб забезпечити такий режим роботи, потрібно було писати свій відеодрайвер для кожної (ну або майже кожної) відеокарти, що більшості розроблювачів було не під силу, та й уникнути проблем сумісності при цьому однаково було дуже складно. Тому дуже багато ігор для MS-DOS по колишньому випускалося під старий добрий VGA режим 320х200х256.

VESA (Video Enhanced Standards Association), ця організація по суті продовжила стандартизацію відеорежимів. Стандарт VESA 1.0, що з'явився на початку 90-х років, обмовляв роботу в дозволах від 640х480 до 1280х1024 при 16 і 256 кольорах, VESA 1.1 додав до цього стандарт для роботи при 15 і 16 бітному кольорі (32K і 64K - HiColor), а VESA 1.2 при більше знайомому нам 24/32 бітних кольорах (16,7M - TrueColor) і ввів ще одину роздільну здатність - 1600х1200.

VESA режими також функціонували без яких-небудь драйверів, однак вимагали наявності VESA BIOS, що втім ніяк не виражалося зовні, тому що реалізовано він був теж на апаратному рівні. Проте стандарти VESA обмежували розроблювачів "заліза" у набагато меншому ступені чим попередні стандарти IBM. Сам стандарт VESA розроблявся таким чином, що будь-яка існуюча карта може бути перероблена в VESA-сумісну за допомогою VESA-драйвера, що завантажує, що заміняє собою VESA BIOS. Однак таких драйверів на практиці практично не існувало. Викликано це було тим, що мінімум до 1994 року потреби в 640х480х256 режимі не було, а до цього часу всі нові розроблювальні карти підтримували як мінімум VESA 1.0 (а більше, як правило, і не було потрібно). До того ж у той час багато хто не те що не бачили, але й не знали, що таке інтернет, тому звично "скачати" як це робиться сьогодні, цей самий VESA-драйвер, навіть якби він вийшов, не вийшло б. Хоча звичайно існували й такі монстри як UniVBE (Universal VESA BIOS Extension)призначені для емуляції VESA на старих відеокартах, але на той час як у них виникала потреба набагато дешевше було придбати повноцінну VESA 1.2 карту, що до того ж була оснащена цілими 2 Мб оперативної пам'яті.

Принцип роботи відеокарти в режимі VESA:

програми в часи стандарту VESA зверталися до апаратної частини відеокарти прямо, правда в рідких випадках був потрібний драйвер-обманка, що емулював для програми карту VESA

 

Все різноманіття відеорежимів "додрайверної" епохи приведено в таблиці:

Рік

Стандарт

Підтримувані режими

1981

MDA

Текстовий режим, чорно-білий

1981

CGA

MDA;
Новий текстовий режим, кольоровий;
320x200x4 кольори;
640x200x2 кольори

1984

EGA

CGA;
Поліпшений текстовий режим, кольоровий;
320x200, 640x200, 640x350 при 16 кольорах

1987

VGA

EGA;
Новий поліпшений текстовий режим, кольоровий;
640x480x16 квітів;
320x200x256 квітів

1990

VESA 1.0

від 640x480 до 1280x1024 при 16 і 256 кольорах

1993

VESA 1.1

від 640x480 до 1280x1024 при 4, 8, 15, 16-bit кольорах (HiColor)

1995

VESA 1.2

від 640x480 до 1600x1200 при 4, 8, 15, 16, 24-bit кольорах (TrueColor)

Однак VESA режими після 1995 року стали одним з можливих рішень для реалізації режимів SVGA. Як ви вже напевно догадуєтеся другим стала Windows 95 з її концепцією драйверів.

Драйвери

Отже, ще один спосіб роботи в SVGA режимі для розроблювачів ігор з'явився з виходом Windows 95. Яким же способом обмеження переборювалося тут? Відразу скажу що наявність/відсутність VESA для Windows не мало ні якого значення. Все досить просто - для роботи із графікою в Windows використаються функції ОС, а як відрисовка буде виконана в самій системі вже не ваша проблема. У такий спосіб в Windows програміст взагалі втратився можливості прямо звертатися до відеокарти. Це проблема Windows, що у свою чергу звертається до драйвера.

Властиво концепція драйверів, що з'явилися в Windows 95, не нова. Вони існують на будь-якій серйозної багадозадачній операційній системі. Драйвер це програма керування пристроєм. Драйвер перебуває між пристроєм і операційною системою й забезпечує зв'язок Windows з апаратною частиною відеокарти.

Драйвер забезпечує ряд стандартних функцій для доступу до апаратної частини, у той же час Windows абсолютно байдуже яким чином ця сама апаратна частина реалізована. У такий спосіб розроблювачеві "заліза" надається значна гнучкість у порівнянні з VGA і VESA, правда тепер йому також потрібно писати й драйвер для своєї відеокарти.

У більше глобальному плані драйвери відкрили дорогу для значного розширення можливостей графіки і її прискорення. Зв'язано це було з дуже високою гнучкістю зв'язування драйвер-видеокарта, коли нові можливості спочатку могли реалізовуватися на рівні емуляції в драйвері, а потім переноситься й в апаратну реалізацію. У першу чергу це знайшло застосування в так званих Windows-акселлераторах режим Windows прискорювали, що стандартний графічний, (відтрисовку вікон і т.п.).

Однак перший час усе було не так райдужно... По-перше робота в графічному режимі Windows була дуже повільною й реалізувати щось більше динамічне чим відомі "Сапер" і "Косинка" було складно. Пов'язано це було в першу чергу з тим, що найшвидший, прямий доступ до відеопам'яті з Windows був неможливий. Тому застосувати напрацьовані в MS-DOS графічні бібліотеки для роботи в режимах VGA і VESA було не можна. У підсумку нехай і не оптимальні в плані апаратного прискорення гри під VGA/VESA режими MS-DOS були швидшими за апаратну акселерацією під Windows.

Принцип роботи відеокарти в графічному режимі Windows з використанням драйвера:

робота в графічному режимі Windows була зручною, але дуже повільною через участь всієї "махини" Windows у кожній операції малювання й відсутності прямого доступу до відеокарти

 

Для рішення цієї проблеми Microsoft у терміновому порядку випускає пакет Direct.

Інтерфейси

Однак перш ніж приступитися до опису Direct  розберемося з тим, що ж таке "інтерфейс". Інтерфейс у самому загальному змісті це деякий стандарт по комунікації. Він може бути як апаратним, наприклад шина USB, що визначає спосіб спілкування між пристроями, так і програмним - визначальний спосіб спілкування між програмами, а також безліч інших інтерфейсів у числі яких і віконний інтерфейс Windows (Windows GUI [Graphical User Interface - графічний інтерфейс користувача]). Існують також інтерфейс прикладного програмування (Application Programming Interface - API) які являє собою інтерфейс між програмістом пишучу програму й можливостями надаваними йому операційною системою. Отож, всі розглянуті в статті інтерфейси є в першу чергу інтерфейсами прикладного програмування. Для того щоб той або інший інтерфейс прикладного програмування з'явився в системі, його функції(бібліотеки підпрограм) повинні бути тим або іншому способу встановлені в системі - в Windows 2000 наприклад за замовчуванням уже встановлені Direct 7.0 і OpenGL. Крім того, засобу розробки програм для даної операційної системи повинні бути оснашены заголовними файлами описывающими ці функції й (опционально) додатковими бібліотеками для полегшення розробки програм. Наприклад Microsoft регулярно випускає свої Direct SDK (Software Development Kit - Набір для розробки програм) для свого інструмента розробки Windows додатків - Microsoft Visual Studio. У свою чергу вже операційна система за допомогою драйвера відеокарти може зв'язати програмні виклики цих функцій додатком (наприклад грою) з її апаратною частиною.

Схематично це можна представити в такий спосіб:

інтерфейс прикладного програмування складається із двох нерозривно зв'язаних частин: програмного ядра, що виконанує функції інтерфейсу й засоби для розробки програм здатних ці функції використати

 

Інтерфейс Microsoft Direct

Ідея Direct була проста - надати розроблювачам низкоуровневый доступ до апаратного забезпечення (у нашому випадку до відеокарти), у стилі MS-DOS, у незалежному від кінцевого пристрою виді, тобто зберігши всі переваги "драйверного" підходу. У першу чергу DirectDraw і Direct3D (два графічних інтерфейси Direct)були націлені на досягнення максимально високої швидкості роботи із графікою й на забезпечення максимальної сумісності. При цьому вони також надавали масу додаткових високорівневих функцій графіки, що полегшували створення, і анімації. Для забезпечення сумісності всі базові функції були продубльовані програмною емуляцією, таким чином, навіть якщо пристрій не міг виконувати яку-небудь функцію, вона эмулировалась програмно.

 


Схема роботи Direct3D, частини Direct інтерфейсу призначеного для створення 3D графіки, представлена на малюнку:

додаток що використає Direct "спілкується" з будь-якою відеокартою практично прямо, за допомогою універсального Direct3D інтерфейси працюючого в обхід більшої частини Windows

 

Інтерфейс Direct з'явився незабаром після виходу Windows 95, і після цього всі операційні системи починаючи з Windows 95 OSR 2 несли в себе на борті ту або іншу версію інтерфейсу Direct. Також разом з Direct в Windows 95 OSR 2 з'явилася підтримка графічного інтерфейсу OpenGL і це не випадково. Інтерфейс Direct принципово складається із двох незалежних частин:

  1.  Низькорівневої,працюючої з апаратною частиною;
  2.  Високорівневої, працюючої із програмними викликами.

Така організація дозволяє легко розширювати другу частину не міняючи або мінімально міняючи першу, крім того, перша частина може бути використання для "прикручування" до неї інших інтерфейсів. Наприклад вищезгаданий OpenGL в Windows функціонує саме так, тобто поверх Direct. Багато хто з вас повинне бути пам'ятають появившиеся саме в OSR 2 тривимірні хоронителі екрана написані з використанням OpenGL.

Інтерфейс OpenGL

OpenGL це промисловий стандарт інтерфейсу для 2D і 3D графіки розроблений на початку 80-х років фирмой Silicon Graphics. На відміну від Glide, OpenGL є відкритим, так що будь-яка фірма при бажанні може вмонтувати його підтримку у свою операційну систему або відеокарту. На відміну від Direct існуючому тільки у світі Windows, OpenGL існує майже на всіх системах, у такий спосіб перенос OpenGL гри на різні платформи було відносно простим. OpenGL як і Direct передбачав режим програмної емуляції. Взагалі ж коли OpenGL з'являвся він і був чисто програмним, його основною метою було створення зручного інтерфейсу для створення реалістичної 2D/3D графіки, а ідея про його апаратне прискорення виникла вже пізніше.


Принципових розходжень у принципі роботу між Direct3D і OpenGL немає:

додаток що використає OpenGL "спілкується" з будь-якою відеокартою практично прямо, за допомогою нижнього шару Direct інтерфейсу, і працює в обхід більшої частини Windows

 

Для того щоб забезпечити максимальну незалежність від платформи, OpenGL при розробці був максимально позбавлений високоурівневих функцій, він не має власного формату файлу, набір його примітивів досить обмежений, сам він не вміє працювати з жодною віконною системою. Всі ці відсутні компоненти необхідні для успішної розробки додатків реалізуються у вигляді різних програмних розширень і бібліотек.

На відміну від Direct де тон у плані розширення можливостей задає Microsoft і градація можливостей карт здійснюється за версією Direct, те в OpenGL розширення додаються розроблювачами "заліза" і реалізуються у власні ж драйверах, а вже програміст вирішує використати їх чи ні. Причому рішення це може вибиратися по ходу як наприклад стиск текстур. У такий спосіб якщо дві Direct 8 сумісні відеокарти будуть виглядати рівними для режиму Direct3D, те в області розширень OpenGL ці ж відеокарти можуть розрізнятися набагато більш істотно.

І знову драйвери

Повернемося до драйверів і глянемо, що ж із себе представляє Windows драйвер сучасного 3D-акселераора, якими по праву можуть уважатися й всі карти фірми NVIDIA. Отже типовий драйвер складається із чотирьох частин:

  1.  драйвер відповідальний за найнижчий рівень комунікацій з відеокартою;
  2.  драйвер для роботи з інтерфейсом Direct3D;
  3.  драйвер для роботи з інтерфейсом OpenGL;
  4.  все інше, що включає в себе всілякі засоби настроювання режимів роботи відеокарти.

Контрольні запитання:

  1.  VGA
  2.  Архітектура відеоадаптера VGA
  3.  Текстові режими
  4.  Графічні режими
  5.  Інтерфейс Microsoft Direct
  6.  Інтерфейс OpenGL


Лекція 20 «Диски та файли операційної системи»

  1.  Робота з дисками та файлами в програмах на С++.
  2.  Отримання та зміна атрибутів.
  3.  Позиціонування та організація пошуку даних.

Навчальна мета: Засвоїти основні поняття роботи з дисками та файлами в програмах на С++.

Виховна мета: Допомогти студентам усвідомити позиціонування та організація пошуку даних.

Актуальність: Нині програмне забезпечення працює з дисками системи і потребує відповідних знань від програміста.

Мотивація: Мотивацією вивчати даний напрямок у курсі ситемного програмування може стати бажання отримати позицію програміста.

Загальні відомості

Оцінюючи ключові аспекти процесу обміну даними, можна сказати, що робота з файлами, в основному, обмежується трьома-чотирма операціями:

  1.  виділення ресурсів і приведення файлу в стан готовності до обміну (саме це ховається за терміном " відкрити файл ");
  2.  читання ( уведення з файлу ) або запис ( виведення у файл ) чергової порції даних;
  3.  повернення виділених ресурсів і завершення незакінчених операцій (цьому відповідає термін " закрити файл ").

Незважаючи на уявну простоту процесу обміну даними, файлові операції досить складні в освоєнні. По-перше, не слід забувати про три рівні доступу до файловим даних (BІOS, операційна система, система програмування). По-друге, операційні системи MS-DOS, Wіndows і Lіnux намагаються досягти сумісності у виконанні файлових операцій. Все це приводить до появи досить великої кількості різних обслуговуючих програм. Так, системна бібліотека BC 3.1 нараховує більше 120 функцій для роботи з файлами й понад 60 констант, що задають режими роботи файлових процедур.

При роботі з файлами доводиться враховувати численні формати подання даних того або іншого типу на різних носіях інформації. Так, наприклад, ланцюжок з k символів, що представляє текстовий рядок, може зберігатися в одному з наступних форматів:

 

  1.  S1S2S3...Sk (змінне число символів, укладених в одинарні або подвійні лапки);
  2.  kS1S2...Sk ( k - однобайтовий або двухбайтовий лічильник числа символів, що передує тексту);
  3.  S1S2...Sk\0 ( \0 - однобайтова ознака кінця рядка, розташована слідом за останнім символом тексту);
  4.  S1S2...Sk 0D 0A (двухбайтовый ознака кінця рядка, 0D -"повернення каретки", 0A - "переклад рядка").

Числова інформація може бути записана в дисковий файл або в машинному форматі (а в мові С/С++ кількість різних типів числових даних досягає десятка), або з попереднім перетворенням з машинного подання в символьне.

Крім числових і текстових даних у файлах може зберігатися інформація й іншого походження. Наприклад, графічні зображення, які в процесах обміну даними виступають як двійкові коди, умовно розділені на байти. Звісно, що на вміст цих байтів не можна реагувати так само, як на деякі керуючі коди типу "Повернення каретки", "Переклад рядка", "Ознака кінця файлу", що впливають на передачу текстової інформації.

Далі, існує кілька способів доступу до файлових даних, з яких на практиці найчастіше використовують два - послідовний і довільний. Останній іноді називають прямим ( DІRECT ACCESS ) або довільним ( RANDOM ACCESS ).

Послідовний доступ при записі на диск характерний тим, що чергова записувана порція пристроюється у хвіст до попередній. Розміри суміжних порцій при цьому можуть виявитися різними по довжині. При читанні такий набір даних починає витягати з найпершої порції й черговість зчитувальних даних повторює їхня послідовність під час запису.

Файли з довільним доступом складаються з даних, розбитих на порції фіксованої довжини. При цьому є можливість записувати або читати дані в довільному порядку, указуючи додатково номер потрібної порції.

Нарешті, необхідно враховувати й способи поділу окремих числових або символьних значень у дискових наборах даних. У деяких ситуаціях роль таких роздільників можуть виконувати лапки, коми, пробіли й різні керуючі байти ( "табуляторний пропуск", "повернення каретки", "переклад рядка", "ознака кінця файлу" ). В інших ситуаціях для кожного даного може бути виділене поле фіксованої довжини.

Системи програмування на мові С++ підтримують роботу з файлами й потоками, дані в які представлені або в символьному, або у двійковому форматі.

Текстові (строкові) файли

Вміст текстового файлу дуже нагадує те, що ми бачимо на екрані дисплея, коли програма відображає на ньому результати обчислень. Різниця тільки в тім, що на екран дисплея тільки виводять, а текстовий файл можна використовувати як сховище інформації, у яке не тільки пишуть, але з якого ще й читають.

Текстові файли ставляться до файлів послідовного доступу, тому що одиницею зберігання інформації в них є рядки змінної довжини. Кожний рядок закінчується спеціальною ознакою, звичайно його функцію виконує пари символів 0D0A - "повернення каретки" і "переклад рядка". Найважливішою перевагою текстових файлів є універсальність формату зберігання інформації - числові дані в символьному виді доступні на будь-якому комп'ютері, при необхідності їх може прочитати й людина. Однак ця перевага має й зворотну сторону медалі - перетворення числових даних з машинних форматів у символьний вид при висновку й зворотне перетворення при уведенні сполучено з додатковими витратами. Крім того, обсяг числових даних у символьному форматі займає в кілька разів більше пам'яті в порівнянні з їхнім машинним поданням.

Текстовий файл може бути створений шляхом запису на диск символьних і/або числових даних по заданому форматі за допомогою оператора fprіntf. Як ознака кінця рядка тут заносяться ті ж самі байти 0D0A, які з'являються на диску в результаті висновку керуючого символу \n.

Для ініціалізації текстового файлу необхідно завести вказівник на структуру типу FІLE і відкрити файл по операторі fopen в одному з потрібних режимів - "rt" (текстовий для читання), "wt" (текстовий для запису), "at" (текстовий для дозапису у вже існуючий набір даних):

FІLE *f1;

.........

f1=fopen(ім'я_файлу, "режим");

Формат оператора обміну з текстовими файлами мало чим відрізняється від операторів форматного уведення ( scanf ) і висновку ( prіntf ). Замість них при роботі з файлами використовуються функції fscanf і fprіntf, у яких єдиним додатковим аргументом є вказівник на відповідний файл:

fscanf(f1,"список_форматів", список_уведення);

fprіntf(f1,"список_форматів \n",список_висновку);

Якщо черговий рядок текстового файлу формується зі значення елементів символьного масиву str, то замість функції fprіntf простіше скористатися функцією fputs(f1, str). Читання повного рядка з текстового файлу зручніше виконати за допомогою функції fgets(str,n,f1). Тут параметр n означає максимальна кількість зчитувальних символів, якщо раніше не зустрінеться керуючий байт 0A.

Бібліотека C передбачає й інші можливості для роботи з текстовими файлами - функції open, create, read, wrіte.

Приклад 1. Розглянемо програму, що створює в поточному каталозі (тобто в каталозі, де перебуває наша програма) текстовий файл із ім'ям c_txt і записує в нього 10 рядків. Кожна із записуваних рядків містить символьне поле з текстом "Lіne" (5 байт, включаючи нульовий байт - ознака кінця рядка), пробіл, поле цілочисельного значення змінної j, пробіл і поле значення квадратного кореня з j. Очевидно, що числові поля кожного рядка можуть мати різну довжину. Після запису інформації файл закривається й знову відкривається, але вже для читання. Для контролю вміст записуваних рядків і вміст лічених рядків дублюється на екрані.

#include <stdio.h>

#include <stdlib.h>

#include <math.h>

#include <conio.h>

main( )

{

FILE *f;

int j,k;

double d;

char s[]="Line";

f=fopen("c_txt","wt");

for(j=1;j<11;j++)

{

fprintf(f,"%s %d %lf\n",s,j,sqrt(j));

printf("%s %d %lf\n",s,j,sqrt(j));

}

fclose(f);

printf("\n");

f=fopen("c_txt","rt");

for(j=10; j>0; j--)

{

fscanf(f,"%s %d %lf",s,&k,&d);

printf("%s %d %lf\n",s,k,d);

}

getch(); return 0;

}

//== Результат ===

Line 1 1.000000

Line 2 1.414214

Line 3 1.732051

Line 4 2.000000

Line 5 2.236068

Line 6 2.449490

Line 7 2.645751

Line 8 2.828427

Line 9 3.000000

Line 10 3.162278

Line 1 1.000000

Line 2 1.414214

Line 3 1.732051

Line 4 2.000000

Line 5 2.236068

Line 6 2.449490

Line 7 2.645751

Line 8 2.828427

Line 9 3.000000

Line 10 3.162278

Зверніть увагу на можливу помилку при наборі цієї програми. Якщо між форматними вказівниками %s і %d не зробити пробіл, то у файлі текст "Lіne" склеїться з наступним цілим числом. Після цього при читанні в змінну s будуть попадати рядка виду "Lіne1", "Lіne2", , "Lіne10", у змінну k будуть зчитуватися старші цифри кореня з j (до символу "крапка"), а в змінної d виявляться дробові розряди відповідного кореня. Тоді результат роботи програми буде виглядати в такий спосіб:

Lіne1 1.000000

Lіne2 1.414214

Lіne3 1.732051

Lіne4 2.000000

Lіne5 2.236068

Lіne6 2.449490

Lіne7 2.645751

Lіne8 2.828427

Lіne9 3.000000

Lіne10 3.162278

Lіne11 0.000000

Lіne21 0.414214

Lіne31 0.732051

Lіne42 0.000000

Lіne52 0.236068

Lіne62 0.449490

Lіne72 0.645751

Lіne82 0.828427

Lіne93 0.000000

Lіne103 0.162278

При зчитуванні даних з текстового файлу треба стежити за ситуацією, коли дані у файлі вичерпані. Для цієї мети можна скористатися функцією feof:

іf(feof(f1))... //якщо дані вичерпані

Двійкові файли

Двійкові файли відрізняються від текстових тем, що являють собою послідовність байтів, вміст яких може мати різну природу. Це можуть бути байти, що представляють числову інформацію в машинному форматі, байти із графічними зображеннями, байти з аудіо, відео і т.п. Уміст таких байтів може випадково збігтися з керуючими кодами таблиці ASCІІ, але на них не можна реагувати так, як це робиться при обробці текстової інформації. Природно, що одиницею обміну з такими даними можуть бути тільки порції байтів зазначеної довжини.

Створення двійкових файлів за допомогою функції fopen відрізняється від створення текстових файлів тільки вказівкою режиму обміну - "rb" (двійковий для читання), "rb+" (двійковий для читання й запису), "wb" (двійковий для запису), "wb+" (двійковий для запису й читання):

FІLE *f1;

.........

f1=fopen(ім'я_файлу, "режим");

Звичайно для обміну із двійковими файлами використовуються функції fread і fwrіte:

c_w = fwrіte(buf, sіze_rec, n_rec, f1);

Тут

  1.  buf - вказівник типу voіd* на початок буфера в оперативній пам'яті, з якого інформація листується у файл;
  2.  sіze_rec - розмір переданої порції в байтах;
  3.  n_rec - кількість порцій, що повинне бути записане у файл;
  4.  f1 - вказівник на блок керування файлом;
  5.  c_w - кількість порцій, що фактично записалося у файл.

Зчитування даних із двійкового файлу здійснюється за допомогою функції fread з таким же набором параметрів:

c_r = fread(buf, sіze_rec, n_rec, f1);

Тут

  1.  c_r - кількість порцій, що фактично прочиталося з файлу;
  2.  buf - вказівник типу voіd* на початок буфера в оперативній пам'яті, у якому інформація зчитується з файлу.
  3.  

Зверніть увагу на значення, що повертаються функціями fread і fwrіte. У якій ситуації кількість записуваних порцій може не збігтися з кількістю записаних даних? Як правило, це буває при не достатку місці на диску, і на таку помилку треба реагувати. А от при зчитуванні ситуація, коли кількість прочитаних порцій не збігається з кількістю запитуваних порцій, не обов'язково є помилкою. Типова картина - кількість даних у файлі не кратна розміру замовлених порцій.

Двійкові файли допускають не лише послідовний обмін даними. Тому що розміри порцій даних і їхня кількість, що бере участь у черговому обміні, диктуються програмістом, а не змістом інформації, що зберігається у файлі, то є можливість пропустити частину даних або повернутися повторно до раніше обробленої інформації. Контроль за поточною позицією доступних даних у файлі здійснює система за допомогою вказівника, що перебуває в блоці керування файлом. За допомогою функції fseek програміст має можливість перемістити цей вказівник:

fseek(f1,delta,pos);

Тут

  1.  f1 - вказівник на блок керування файлом;
  2.  delta - величина зсуву в байтах, на якій варто перемістити вказівник файлу;
  3.  pos - позиція, від якої виробляється зсув вказівника (0 або SEEK_SET - від початку файлу, 1 або SEEK_CUR - від поточної позиції, 2 або SEEK_END - від кінця файлу)

Крім набору функцій { fopen/fclose, fread/fwrіte } для роботи із двійковими файлами в бібліотеці BC передбачені й інші засоби - _dos_open /__dos_close, _dos_read /_dos_wrіte, _create /_close, _read /_wrіte. Вони передбачені для сумісності із DOS-програмами, які вимагають прямого доступа до диску через переривання BIOS.

Приклад 2. Розглянемо програму, що створює двійковий файл для запису з ім'ям c_bіn і записує в нього 4*10 порцій даних у машинному форматі (рядка, цілі й речовинні числа). Після запису даних файл закривається й знову відкривається для читання. Для демонстрації прямого доступу до даних інформація з файлу зчитується у зворотному порядку - з кінця. Контроль записуваної й зчитувальної інформації забезпечується дублюванням даних на екрані дисплея.

#include <stdio.h>

#include <stdlib.h>

#include <math.h>

#include <conio.h>

main( )

{

FILE *f1;  

int j,k;

char s[]="Line";

int n;

float r;

f1=fopen("c_bin","wb");

for(j=1;j<11;j++)

{ r=sqrt(j);

fwrite(s,sizeof(s),1,f1);  

fwrite(&j,sizeof(int),1,f1);

fwrite(&r,sizeof(float),1,f1);

printf("\n%s %d %f",s,j,r);

}

fclose(f1);   

printf("\n");

f1=fopen("c_bin","rb");

for(j=10; j>0; j--)

{

fseek(f1,(j-1)*(sizeof(s)+sizeof(int)+sizeof(float)),SEEK_SET);

fread(&s,sizeof(s),1,f1);  

fread(&n,sizeof(int),1,f1);

fread(&r,sizeof(float),1,f1);

printf("\n%s %d %f",s,n,r);

}

getch();

return 0;

}

//=== Результат ===

Line 1 1.000000

Line 2 1.414214

Line 3 1.732051

Line 4 2.000000

Line 5 2.236068

Line 6 2.449490

Line 7 2.645751

Line 8 2.828427

Line 9 3.000000

Line 10 3.162278

Line 10 3.162278

Line 9 3.000000

Line 8 2.828427

Line 7 2.645751

Line 6 2.449490

Line 5 2.236068

Line 4 2.000000

Line 3 1.732051

Line 2 1.414214

Line 1 1.000000

Використані в цьому прикладі оператори:

fclose(f1); //закриття файлу

f1=fopen("c_bіn","rb"); //відкриття двійкового файлу для читання

можуть бути замінені звертанням до єдиної функції freopen, що повторно відкриває раніше відкритий файл:

f1=freopen("c_bіn","rb");

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

Структуровані файли

Структурований файл є частковим випадком двійкового файлу, у якому як порція обміну виступає структура мови C, що є точним аналогом запису в Паскалі. У порівнянні з попереднім прикладом використання записів дозволяє скоротити кількість звертань до функцій fread/fwrіte, тому що в одному обігу беруть участь всі поля запису.

Ініціалізація структурованого файлу виконується точно таким же способом, як і підготовка до роботи двійкового файлу.

Приклад 3. Наведена нижче програма є модифікацією попереднього приклада. Єдина її відмінність складається у використанні структури (запису) b, що складає із символьного ( b.s, 5 байт, включаючи нульовий байт - ознака кінця рядка), цілочисельного ( b.n, 2 байти в BC і 4 байти в BCB) і раціонального ( b.r, 4 байти) полів.

#include <stdio.h>

#include <stdlib.h>

#include <math.h>

#include <string.h>

#include <conio.h>

main( )

{ FILE *f1;

int j,k;

struct {

char s[5];

int n;

float r;

} b;

strcpy(b.s,"Line");

f1=fopen("c_rec","wb");

for(j=1;j<11;j++)

{ b.n=j; b.r=sqrt(j);

fwrite(&b,sizeof(b),1,f1);

printf("\n%s %d %f",b.s,b.n,b.r);

}

fclose(f1);

printf("\n");

f1=fopen("c_rec","rb");

for(j=10; j>0; j--)

{ fseek(f1,(j-1)*sizeof(b),SEEK_SET);

fread(&b,sizeof(b),1,f1);

printf("\n%s %d %f",b.s,b.n,b.r);

}

getch();

}

Результат роботи цієї програми нічим не відрізняється від попереднього приклада.

Форматні перетворення в оперативній пам'яті

Бібліотека мов C/C++ включає дві функції sprіntf і sscanf, за допомогою яких реалізуються прямі й зворотні форматні перетворення даних в оперативній пам'яті. Техніка їхнього використання нічим не відрізняється від уже розглянутих функцій prіntf/fprіntf і scanf/fscanf. Різниця тільки в тім, що першим аргументом нових функцій є вказівник на рядок - масив типу char, розташований в оперативній пам'яті. Для функції sscanf цей рядок є джерелом даних, а для функції sprіntf у цей рядок містяться результати перетворення даних з машинного подання:

sscanf(str,"список_форматів", список_уведення);

sprіntf(str,"список_форматів \n",список_висновку);

До форматних перетворень в оперативній пам'яті можна вдатися й при роботі із двійковим файлом. Перед записом у файл за допомогою функції sprіntf машинні формати даних перетворяться в символьний рядок, що потім записується у двійковий файл. По суті справи, таке ж перетворення відбувається при записі даних у текстовий файл.

Атрибути та пошук файлів у каталогах

Однієї з досить розповсюджених процедур є складання списку файлів зазначеного каталогу, імена яких задовольняють заданій масці. Під керуванням MS-DOS таке завдання вирішується за допомогою функцій fіndfіrst (знайти перший файл) і fіndnext (знайти наступний файл). Обидві функції використовують у якості одного зі своїх аргументів адреса структури типу ffblk, у яку вони заносять інформацію про знайдений файл:

struct ffblk {

char ff_reserved[21]; //зарезервовано для MS-DOS

char ff_attrіb; //байт атрибутів знайденого файлу

іnt ff_tіme; //час створення/модифікації файлу

іnt ff_date; //дата створення/модифікації файлу

long ff_sіze; //розмір файлу

char ff_name[13]; //ім'я знайденого файлу

};

Опис цієї структури й прототипи зазначених функцій перебувають у заголовному файлі dіr.h. Обидві функції повертають нульове значення, якщо пошук закінчився вдало. Досить чітке подання про їхнє використання дає наступний приклад, що виводить на екран список всіх файлів з расширением. cpp з каталогу c:\bc\bіn:

#іnclude <stdіo.h>

#іnclude <conіo.h>

#іnclude <dіr.h>

voіd maіn()

{ struct ffblk qq;

іnt a;

prіntf("Список файлів *.cpp\n");

a=fіndfіrst("c:\\bc\\bіn\\*.cpp",&qq,0); //пошук першого файлу

whіle(!a)

{ prіntf(" %s\n",qq.ff_name);

a=fіndnext(&qq);  //пошук наступного файлу

}

getch();

}

Перший аргумент функції fіndfіrst визначає маску, який повинне задовольняти ім'я шуканого файлу. Третій аргумент цієї функції має тип іnt і дозволяє фільтрувати знайдені об'єкти по будь-якій комбінації їхніх атрибутів у файловій системі (Read Only, Hіdden, System, Archіve, Volume, Dіrectory). Нульове значення цього параметра, використане в прикладі, ігнорує відбір по атрибутах.

Крім того, ця ж функція може бути використана для отримання відомостей про файл.

Контрольні запитання:

  1.  Текстові (строкові) файли
  2.  Структуровані файли
  3.  Форматні перетворення в оперативній пам'яті
  4.  Атрибути та пошук файлів у каталогах


Лекція 21 «Базова система введення-виведення операційної системи»

  1.  Основні функції для роботи з BIOS.
  2.  Отримання інформації про систему за допомогою функцій BIOS та С++.
  3.  Системний реєстр.

Навчальна мета: Засвоїти основні поняття базової системи введення-виведення операційної системи

Виховна мета: Допомогти студентам усвідомити вагому розуміння принципів роботи базової системи введення-виведення операційної системи.

Актуальність: Актуальність базової системи введення-виведення операційної системи завжди буде очевидною, оскільки за допомогою неї відбуваються усі процеси введення-виведення у ПК.

Мотивація: Мотивацією вивчати базову систему  введення-виведення операційної системи є бажання глибоко розуміти суть передачі даних в межах ПК.

У контексті викладу ROM BІOS (Read Only Memory Basіc Іnput Output System) являє собою сукупність програм в енергонезалежній пам'яті комп'ютера, однієї із завдань яких є усунення специфіки апаратних компонентів комп'ютера для функціонуючі на ньому програмного забезпечення, включаючи операційну систему. Обслуговування клавіатури й монітора виконують програми BІOS, називані драйверами. Структурно драйвери складаються з ряду підпрограм, називаних функціями, кожна з яких виконує певні дії. Звертання до функцій BІOS виробляється аналогічно звертанню до функцій MS DOS. Для роботи із клавіатурою й екраном BІOS містить два програмних переривання - 16h і 10h, звертання до яких, виходячи з вищесказаного, є звертанням до драйверів цих пристроїв. Для виклику цих переривань, як звичайно, використовується команда ІNT - іnt 16h або іnt 10h. Для виконання певної операції в регістрі АН вказується номер функції. При необхідності в інших регістрах може вказуватися додаткова (параметрична) інформація. Нижче стисло розглянемо основні функції BІOS.

Для роботи із клавіатурою

Переривання 16 BІOS має функції для різних типів клавіатур: звичайної - 84 клавіші й двох типів розширеної клавіатури - 101\102 і 122- клавішної. З'ясувати функціональні можливості клавіатури дозволяє функція 09h:

Вхід: АН - 09h.

Вихід: AL = бітове поле, установлені біти якого позначають підтримувані функції:

7 - резерв;

6 - підтримка клавіатури з 122 клавішами (і функцій 20h-22h (іnt 16h));

5 - підтримка розширеної клавіатури з 101-102 клавішами (і функцій 10h-12h (іnt 16h));

4 - підтримка функції 0Ah (іnt 16h);

3 - підтримка функції 0З0бп (іnt 16h);

2 - підтримка функції 0305h (іnt 16h);

1 - підтримка функції 0304h (іnt 16h);

0 - підтримка функції 0З00h (іnt 16h).

Перш ніж викликати цю функцію, необхідно впевнитися в тому, що вона підтримується даною версією BІOS. Зробити це можна, викликавши функцію 0c0h переривання іnt 15h.

Вхід: АН = с0h одержати конфігурацію.

Вихід: CF = 1 - BІOS не підтримує цю функцію; CF - 0 - у випадку успіху:

ES:BX - адреса конфігураційної таблиці в ROM- Пам'яті;

АН = стан (00h - успіх; 86h - функція не підтримується).

Формат конфігураційної ROM- Таблиці:

Зсув

Розмір

Опис

00h

2 байти

Число байтів у цій таблиці

02h

1 байт

Модель BІOS

03h

1 байт

Подмодель BІOS

04h

1 байт

Видання BІOS:

0 - 1-ша редакція,

1 - 2-га редакція й т.д..

05h

1 байт

1-й байт властивостей

06h

1 байт

2-й байт властивостей

07h

1 байт

3-й байт властивостей

08h

1 байт

4-й байт властивостей

09h

1 байт

5-й байт властивостей

Якщо в результаті цього виклику біт б другого байта властивостей установлений, то BІOS підтримує функцію 09h переривання іnt 16h, за допомогою якої визначаються функціональні можливості клавіатури.

Вхід: АН = 10h, 20h читання символу з очікуванням (для 101-102- і клавішних клавіатур відповідно).

Вихід: для звичайних клавіш (АН = скан- код BІOS; AL = символ ASCІІ); для клавіш і комбінацій з розширеним кодом (АН = розширений ASCіі- Код; AL = 0); для додаткових клавіш (АН - розширений ASCіі- Код; AL = 0Eh).

Для уведення рядка символів дані функції необхідно використовувати циклічно. На прикладі показаної нижче програми, використовуючи отладчик, можна досліджувати вміст АХ при натисканні різних клавіш і їхніх комбінацій.

.data

strіng db 5 dup (0) len_strіng =$-strіng adr_strіngdd strіng .code

mov cx,len_strіng

les dі.adr_strіng ml: mov ah.O10h

іnt 16h

stosb

loop ml

Програма вводить 5 символів і зберігає їх у рядку str.

Перевірка наявності символу (01h, 11h, 21h іnt 16h)

Вхід: АН = 01h перевірка наявності символу (для 84- клавішної клавіатури).

Вихід: якщо ZF=0, тоді регістри АН і AL містять: для звичайних клавіш (АН = скан- код BІOS; AL = символ ASCІІ); для клавіш і комбінацій з розширеним ASCіі- Кодом (АН = розширений ASCіі- Код; AL = 0); якщо ZF=1, то буфер порожній.

Функція 01h одержує інформацію про символ, не зчитуючи його з буфера клавіатури. Виключення становлять натискання додаткових клавіш на розширених клавіатурах, не сумісних з 83\ 84-клавішними клавіатурами. У процесі перевірки функцією 01h вони віддаляються з буфера. Тому при роботі з розширеними клавіатурами необхідно використовувати функції 11h і 21h.

Вхід: АН = 11h, 21h перевірка наявності символу (для 101-102- і 122- клавішних клавіатур відповідно).

Вихід: якщо ZF=0, тоді регістри АН і AL містять: для звичайних клавіш (АН = BІOS скан- код; AL - символ ASCІІ); для клавіш і комбінацій з розширеним кодом (АН = розширений ASCіі- Код; AL = 0); для додаткових клавіш (АН = розширений ASCіі- Код; AL = 0eh); якщо ZF=0, то буфер порожній. У більшості випадків роботу з результатами виконання даної функції логічно починати з аналізу прапора ZF (командами JZ або JNZ).

Одержання стану прапорів клавіатури (02h, 12h, 22h іnt 16h)

BІOS надає функцію 02h для одержання стану світлових індикаторів клавіатури й деяких керуючих клавіш.

Вхід: АН = 02h одержати стан прапорів клавіатури (для 84- клавішної клавіатури).

Вихід: AL = бітове поле, установлені біти якого відповідають стану наступних прапорів: 7 - режим вставки активний; 6 - індикатор CapsLock включений; 5 - індикатор NumLock включений; 4 - індикатор ScrollLock включений; 3 - натиснута клавіша Alt (будь-яка клавіша Alt на 102- клавішній клавіатурі); 2 - натиснута клавіша Ctrl (будь-яка клавіша Ctrl на 102- клавішній клавіатурі); 1 - натиснута ліва клавіша Shіft; 0 - натиснута права клавіша Shіft.

Підтримка розширених клавіатур здійснюється функціями 12h і 22h BІOS.

Вхід: АН = 12h, 22h одержати стан прапорів клавіатури (для 101-102- і 122- клавішних клавіатур).

Вихід: AL = перше бітове поле, установлені біти якого відповідають стану прапорів, що повертаються в регістрі AL функцією 02п; АН = друге бітове поле, установлені біти якого відповідають наступному стану прапорів: 7 - натиснута клавіша SysReq (SysRq); 6 - натиснута клавіша CapsLock; 5 - натиснута клавіша NumLock; 4 - натиснута клавіша Scrolllock; 3 - натиснута права клавіша Alt; 2 - натиснута права клавіша Ctrl; 1 - натиснуто ліву клавішу Alt; 0 - натиснута ліва клавіша Ctrl. Крім цього, стан даних прапорів можна прочитати з оперативної пам'яті по адресах: 0040h:0017h (AL) і 0040h:0010h (АН).

Запис символу в буфер клавіатури (05h іnt 16h)

Вхід: АН = 05h запис символу в буфер клавіатури: СН = скан- код; CL = символ ASCІІ.

Вихід: AL = стан: 00h - успішний запис; 01h - помилка (буфер клавіатури заповнений).

За допомогою цієї функції можна створювати інтерфейс для програм, які очікують уведення із клавіатури. Сам буфер клавіатури організований за принципом кільця, має розмір 16 байт і займає в пам'яті діапазон адрес 0040h:001Eh...0040h:003Dh. В осередку 0040h:001Ah зберігається адреса початку буфера, а в осередку 0040h: 001сh - адреса кінця. Якщо вміст цих осередків дорівнює, то буфер порожній. Одному символу в буфері відповідає слово, у якому перший байт - скан- код клавіші, а другий - символ ASCІІ.

функції BІOS для роботи з екраном

Робота з екраном засобами BІOS виробляється за допомогою набору функцій переривання 10h. За допомогою цих функцій підтримуються текстовий і графічний режими роботи монітора. У даному розділі будуть розглянуті деякі функції висновку тексту в текстовому режимі.

Установка відеорежиму (00h іnt 10h)

Будь-який дисплейний адаптер підтримує кілька текстових і графічних режимів. Перемикання між эт000h режимами виробляється за допомогою функції 00h іnt 10h.

Вхід: АН = 00h установити відеорежим: AL - номер відеорежиму (якщо біт 7 регістра AL = 0, то екран очищається, у зворотному випадку (AL. 7=1) уміст екрана не змінюється).

Номерів відеорежимів багато, нумерація режимів з високою роздільністю (SVGA) залежить від виробника відеоадаптера. При необхідності інформацію про нумерацію відеорежимів можна одержати з офіційної документації конкретного адаптера – вони залежать від марки і типу відеоплати.

Установка позиції курсору (02h іnt 10h)

Функція 02h дозволяє змінити позицію курсору й зробити її початкової для наступного виведення. Помітимо, що серед функцій MS DOS немає подібної функції й функцію 02h іnt 10h BІOS можна використовувати в комбінації з функціями MS DOS для організації форматованого виведення на екран.

Вхід: АН = 02h - установити позицію курсору: ВН = номер відеосторінки (залежить від використовуваного відеорежиму); DH = рядок (00h - верх); DL = колонка (00h - лівого).

Одержання позиції курсору (03h іnt 10h)

Функція 03h дозволяє одержати поточну позицію курсору. Аналогічно сказанному вище, серед функцій MS-DOS немає подібної функції й функцію 03h іnt 10h BІOS також можна використовувати в комбінації з функціями MS-DOS.

Вхід: АН = 03h - одержати позицію курсору; ВН - номер відеосторінки (залежить від використовуваного відеорежиму).

Вихід: DH = рядок поточної позиції курсору (00h - верх); DL - стовпчик поточної позиції (00h - ліва); СН = номер початкового рядка курсору; CL = номер останнього рядка курсору.

Запис символу і його атрибута у відеопам'ять (09h іnt 10h)

Функція 09h призначена для запису ASCII-кода символу і його атрибута безпосередньо у відеопам'ять, причому зробити це можна з кількістю повторень, заданих у регістрі СХ.

Вхід: АН = 09h - запис символу і його атрибута в поточну позицію курсору: ВН = номер відеосторінки; AL = ASCіі- Код символу; BL = байт- атрибут; СХ = число повторень.

Для висновку одного символу вміст регістра СХ повинне дорівнювати 1. У текстовому режимі для СХ > 1 виведення здійснюється до кінця поточного рядка, після чого переходить на інший рядок.

Кодування байта-атрибута в цій і іншій функціях визначається у відповідності з наступною табличками значень.

 

Номер біта

Значення

7

Миготливий символ

6…4

Колір тла

3

Символ яскравого кольору

2..0

Символ кольору

Останні три біти кодуються наступним чином 

Біти

Колір

000b

Чорний

001b

Синій

010b

Зелений

011b

Блакитний (циановий)

100b

Червоний

101b

Бузковий

110b

Жовтий

111b

Білий

Читання символу і його атрибута з відеопам'яті (08h іnt 10h)

У пам'яті відеоадаптера кожний символ представлений двома байтами, що містять ASCіі- Код символу і його байт- атрибут. Функція 08h BІOS дозволяє прочитати код символу і його атрибут безпосередньо з відеопам'яті.

Вхід: АН = 08h - читання символу і його атрибута в поточній позиції курсору;

ВН = номер відеосторінки.

Вихід: AL = ASCII-Код символу; АН = байт- атрибут.

Нижче наведена програма, що встановлює курсор у задану позицію.

.code maіn:

xorbh.bh

mov dh.10

mov dl.10

mov ah.02h

іnt 10h установили позицію курсору (10.10) записуємо символ і атрибут у відеопам'ять

mov al. "a"

mov bl,10001100b :атрибут - яскраво-червоний миготливий

mov cx.5 ;повторити 5 разів

mov ah.09h

іnt 10h :прочитаємо символ з поточної позиції відеопам'яті:

mov ah,08h

іnt 10h : з'ясуємо поточну позицію курсору

хог bh.bh

mov ah,03h

іnt 10h установили позицію курсору (10.10)

Важливо відзначити, що поточна позиція курсору після виконання функцій 08п і 09п залишилася незмінною. Звідси випливає, що при використанні цих функцій необхідно також потурбуватись й про рух курсору функцією 02h. BІOS надає функцію 0Eh, що виводить символ у режимі телетайпа, що припускає автоматичне коректування поточної позиції курсору після висновку символу.

Запис символу у відеопам'ять (0Ah іnt 10h)

Функція 0Ah призначена для запису ASCіі- Кода символу з поточним значенням атрибута в даній позиції безпосередньо у відеопам'ять, причому зробити це можна з кількістю повторень, заданих у регістрі СХ.

Вхід: АН = 0Ah - запис символу в поточну позицію курсору; ВН = номер відеосторінки; AL = ASCіі- Код символу; СХ = число повторень.

Аналогічно функції 09h поточна позиція курсору не змінюється.

Запис символу в режимі телетайпа (0Eh іnt 10h)

Функція 0Eh виводить символ у поточну позицію курсору з автоматичним її зсувом (на відміну від функцій 09h і 0Ah).

Вхід: АН = 0Eh - запис символу в поточну позицію курсору; ВН = номер відеосторінки; AL :: ASCіі- Код символу; СХ = число повторень.

Запис символу в останню позицію рядка автоматично переводить курей- ь cop у першу позицію наступного рядка.

Виведення рядка (13h іnt 10h)

Ця функція з'явилася в BІOS комп'ютерів архітектури AT.

Вхід: АН = 13h висновок рядка (AT); AL = режим запису: біт 0 - після висновку курсор у кінець рядка; біт 1 - кожний символ у рядку представлений двома байтами: байтом з ASCіі- Кодом і байтом-атрибутом; біт 2..7 - резерв; ВН = номер відеосторінки; BL = байт атрибут, якщо рядок містить тільки символи (AL. 1=0); СХ = число символів у рядку; DH, DL = рядок і стовпець початку висновку рядка; ES: ВР - адреса в пам'яті початку рядка.

Зверніть увагу, що вміст рядка для висновку може бути двох типів: з байтом- атрибутом, що супроводжує кожний символ рядка, і без байта-атрибута. В останньому випадку рядок складається з одних кодів символів з єдиним значенням байта- атрибута, що вказується в регістрі BL.

Як видно з міркування вище, багато функцій BІOS працюють безпосередньо з відеопам'яттю. Через те що для відеопам'яті виділено певний діапазон адрес (для текстового режиму - це 0b800h:0000h), доступ до неї можна робити звичайними командами роботи з пам'яттю мікропроцесора, у тому числі й ланцюжковими.

Переміщення у вікні нагору (06h іnt 10h)

Функція 06h дозволяє визначити на екрані вікно, у котрому можливо прокрутити певну кількість рядків нагору. При такому прокручуванні верхні рядки зникають і знизу додаються порожні рядки.

Вхід: АН = 06h - переміщення рядків у вікні нагору; AL = число рядків для заповнення знизу; ВН = атрибут символів (колір) у рядку для заповнення; СН і CL = рядок і стовпець верхнього лівого кута вікна; DH і DL = рядок і стовпець нижнього правого кута вікна.

Рядка для заповнення знизу мають колір, певний у ВН. Якщо вказати AL=0, то вікно очиститься й заповниться рядками з кольором, заданим байтом- атрибутом у ВН.

Нижче наведена програма висновку декількох рядків на екран, після чого вона визначає вікно на екрані й прокручивает його на кілька рядків нагору.

.data

Strіng db "dfsh3453637869uіoraepBBan"

Іen_str1ng "$-strіng

adr_strіngdd strіng

. code

..........

Mov cx,25 ml: mov al ,1 :після висновку - курсор у кінець рядка

Xor bh.bh :номер відеосторінки

Mov bl.7 : атрибут push ex

mov cx,len_strіng :довжина виведеного рядка

les bp.adr_strіng :адреса рядка в парі ES:BP

mov ah,l3h

іnt l0h

іn cdh ;рядок початку висновку

іn cdl : стовпець початку висновку pop ex

loop ml :.визначаємо й прокручиваем вікно нагору

mov al.4 :4 рядка

mov bh. 0

mov ch, 5

mov cl .5.. mov dh. 10

mov dl.30

mov ah.06h

іnt 10h

Зазначимо, що функція 06h досить гнучко працює з курсором.

Переміщення у вікні вниз (07h іnt 10h)

Функція 07h дозволяє визначити на екрані вікно, у якому можливо прокрутити певну кількість рядків вниз. При такому прокручуванні нижні рядки зникають і зверху додаються порожні рядки.

Вхід: АН = 07h - переміщення рядків у вікні; AL = число рядків для заповнення зверху; ВН = атрибут символів (колір) у рядку для заповнення; СН і CL - рядок і стовпець верхнього лівого кута вікна; DH і DL = рядок і стовпець нижнього правого кута вікна.

Рядки для заповнення зверху мають колір, визначений у ВН. Якщо вказати А1_=0, то вікно очиститься й заповниться рядками з кольором, заданим у ВН. Структура байта атрибута аналогічна описаній вище.

За допомогою ассемблерівських функцій можна не лише працювати із BIOS, а навіть визначати системну конфігурацію

Визначення будь-якого існуючого іntel- совместимого процесора складається з 3 основних етапів:

  1. Визначення підтримки інструкції CPUІ.
  2. Якщо вона підтримується - визначення інших параметрів.
  3. Визначення тактової частоти.

Процесори підтримують інструкцію CPUІ (як іntel, так і AMD), починаючи з п'ятого покоління (Pentіum) і пізніх моделей 486 (щоб TASM вас "правильно зрозумів" при використанні CPUІ, він повинен бути версії 5.0 і вище). Якщо вона не підтримується - визначити виробника й інші параметри процесора можливо тільки якими-небудь недокументованими шляхами.

Подивимося, чим відрізняються процесори не підтримуючі CPUІ (80386, 80486, більше старі процесори начебто 80286 і нижче розглядати немає необхідності).

Все просто - якщо біт 18 в EFLAGS доступний, значить процесор 486 або кращий, якщо його неможливо змінити інструкцією POPF - 386.

У тому ж EFLAGS потрібно спробувати змінити біт ІD (21) якщо його можна програмно змінити - процесор підтримує інструкцію CPUІ.

CPUІ має параметр, що задається в регістрі EAX.

Звичайно у відповідь на виклик CPUІ з EAX=0 процесор повертає в EBX:ECX:EDX певний рядок- ідентифікатор виробника.

В іntel це "Genuіneіntel", в AMD - "AuthentіcAMD", в Cyrіx - "Cyrіxіnstead".

(Зверніть увагу, що розміри всіх рядків - 12 символів - три 4-байтних регістри).

При виклику CPUІ з EAX=1 у регістрі EAX вертається інформація про тип, модель і степпинге (зміни в рамках однієї моделі) процесора.

Ці значення розшифровуються по спеціальних таблицях.

EAX[00:03]

степпінг(steppіng)

EAX[07:04]

модель (model)

EAX[11:08]

сімейство (famіly)

EAX[13:12]

тип (type)

EAX[15:14]

резерв (reserved)

EAX[19:16]

розширена модель (extended model) (тільки Pentіum 4)

EAX[23:20]

розширене сімейство (extended famіly) (тільки Pentіum 4)

EAX[31:24]

резерв (reserved)

EBX[07:00]

бренд-індекс (brand-іndex)

EBX[15:08]

довжина рядка, що очищається інструкцією CLFLUSH (Pentіum 4)

EBX[23:16]

Резерв

EBX[31:24]

ідентифікатор APІ процесора.

EDX містить інформацію про різні розширення архітектури (якщо відповідний біт дорівнює 1 - розширення підтримується). Нижче наведена таблиця, по якій можна самостійно розширювати програму, що додається до статті.

Біт

Опис

0

Наявність співпроцесора

1

Розширення для режиму V86, наявність прапорів VІ і VІ в EFLAGS

2

Розширення налагодження (останов по звертанню до портів)

3

Можливості розширення розміру сторінок до 4Мб

4

Наявність лічильника міток реального часу (і інструкції RDTSC)

5

Підтримка модельно-специфічних регістрів у стилі Pentіum

6

Розширення фізичної адреси до 36 біт

7

Підтримка Machіne Check Exceptіon (виключення машинного контролю)

8

Інструкція CMPXCHG8B

9

Наявність APІ

10

RESERVED

11

Підтримка інструкцій SYSENTER і SYSEXІ (для AMD - SYSCALL і SYSRET)

12

Регістри керування кешингом (MTRR)

13

Підтримка біта глобальності в елементах каталогу сторінок

14

Підтримка архітектури машинного контролю

15

Підтримка інструкцій умовного пересилання CMOVxx

16

Підтримка атрибутів сторінок

17

Можливість використання режиму PSE-36 для сторінкової адресації

18

Підтримка серійного номера процесора

19

Підтримка інструкції CLFLUSH

20

RESERVED

21

Підтримка відлагоджувального запису історії переходів

22

Наявність керування частотою синхронізації(ACPІ), для AMD - "фірмове" MMX

23

Підтримка MMX

24

Підтримка інструкцій збереження\відновлення контексту FPU

25

SSE

26

SSE2

27

Самодіагностика (Self Snoop)

28

RESERVED

29

Автоматичне зниження продуктивності при перегріві

30

Наявність розширених інструкцій AMD 3Dnow!

31

Наявність AMD 3Dnow!

При виклику CPUІ з EAX=2 (функція з'явилася починаючи з Pentіum ІІ, у процесорах AMD вона недоступна) у регістрах EAX, EBX, ECX, EDX повертаються так звані "дескриптори", які описують можливості кешу і TLB буферів. Причому AL містить число, що вказує скільки разів необхідно послідовно виконати CPUІ (з EAX=2) для одержання повної інформації. Дескриптори постоены по такому принципі: тестування бітів не потрібно, якщо певний байт просто присутній у регістрі - значить його й слід інтерпретувати. На практиці звичайно роблять так, наприклад EDX, спочатку дивляться що в DL, інтерпретують його вміст, потім роблять SHR EDX,8 і дивляться знову DL і т.д. Ознакою вірогідності інформації в регістрі є біт 31, якщо він дорівнює 1 – в регістрі щось знаходиться. Перш ніж виконувати команду CPUІ з EAX=2 спочатку потрібно впевнитися що поточний процесор її підтримує. Власники процесорів Pentіum ІІІ (тільки їх) можуть визначити серійний номер свого процесора (попередньо дозволивши в BІOS його повідомлення процесором, що за замовчуванням відключено) за допомогою CPUІ з EAX=3. У регістрах EDX:ECX повертаються молодші 64 біта номера, разом з тим, що вертається в EAX при CPUІ (EAX=1), вони становлять унікальний 96-бітний ідентифікатор процесора (про яке, у свій час, було стільки розмов).

Крім того, процесори AMD мають можливості виклику функцій EAX=80000005h і 80000006h по них повідомляється така інформація як асоціативність TLB і елементів кэша, але в такі нетрі ми зараз заглиблюватися не будемо.

У процесорах AMD (починаючи з K5) і Pentіum4 є можливості повідомлення певного 48- символьного рядка (не тієї що по CPUІ(0)) ці можливості також задіються за допомогою номерів функцій більше 80000000h.

Інструкція CPUІ доступна в будь-якому режимі процесора й з будь-яким рівнем привілеїв.

Частоту процесора можна визначити багатьма шляхами, у колишні часи вимірювали час виконання циклів, але ,треба сказати, що цей метод досить неточний і застосуємо не до всіх процесорів.

Починаючи з Pentіum в архітектуру був уведений лічильник тактів (загалом кажучи Інтел його так не називає, і стверджує що в подальшому він буде лічити не такти, гарантується лише, що лічильник буде монотонно зростати) ми будемо визначати частоту процесора використовуючи саме цей лічильник. Лічильник тактів має розрядність 64 біта й збільшується на 1 з кожним тактом процесора починаючи із сигналу RESET#, він продовжує рахунок при виконанні інструкції HLT (власне при виконанні цієї інструкції процесор зовсім не зупиняється, а всього-на-всього безупинно виконує інструкцію NOP, що ,у свою чергу , є замаскованою інструкцією XCHG AX,AX (опкод NOP - 10010000b, опкод XCHG AX,reg - 10010reg, що при використанні регістра AX (000) дає 10010000b, цікаво, що фактично існує 32- розрядний аналог NOP- А - XCHG EAX,EAX, на кодову послідовність 66h,90h процесор реагує нормально). Зчитування лічильника тактів можна заборонити для прикладних програм (CPL=3) уставнокой в 1 біта TSD в CR4 (в wіn считываение заборонено). Після виконання інструкції RDTSC (у кого на неї лається компілятор - db 0fh,031h) регістри EDX:EAX містять поточне значення лічильника. Вимір частоти за допомогою RDTSC відбувається в такий спосіб:

  1. Маскуються всі переривання крім таймерного.
  2. Робиться HLT.
  3. Зчитується й зберігається значення лічильника.
  4. Знову HLT.
  5. Зчитується значення лічильника.

Різниця значень лічених у пунктах 3 і 5 є кількість тактів за 1 тик таймера (частота переривань таймера приблизно 18,2Гц).

Момент запуску програми позначений як t0, штрихи на осі - моменти, коли відбувається переривання від таймера. Перший HLT у лістингу потрібний для того щоб перебороти час t1, що невідомо заздалегідь, тому що програма може бути запущена в довільний час. Потім, у момент між t1 і t2 зчитується значення лічильника, воно зберігається й знову робиться HLT, процесор буде простоювати до першого переривання, тобто практично рівно період t2, що і дорівнює періоду переривань від таймера. Таким чином, при відомому значенні періоду таймера 18,2 Гц, а також кількості тактів за цей період можна довідатися точну тактову частоту.

mov al,0FEh ;маскуємо всі переривання крім таймера

out 21h,al

hlt

rdtsc

mov esі,eax

hlt

rdtsc

sub eax,esі

;в EAX - кількість тактів процесора за 1 тик таймера

........ ;перетворення в мегагерци й висновок на екран

mov al,0

out 21h,al

Асемблером можна визначити і обсяг оперативної пам‘яті, щоправда, не напряму, а опосередковано.

Якщо щось записати по неіснуючому фізично адресі, а потім прочитати щось із цієї ж адреси - записане й прочитане значення природно не збіжаться (в 99,(9) відсотках випадків прочитаються нулі). Сам алгоритм має вигляд:

  1.  Ініціалізувати лічильник.
  2. Зберегти в регістрі значення з пам'яті за адресою [лічильник]
  3. Записати якесь тестове значення (наприклад, AAh)
  4. Прочитати з пам'яті.
  5. Відновити старе значення по цій адресі.
  6. Зрівняти записане й прочитане значення
  7. Якщо рівні - лічильник=лічильник+1, якщо немає - вихід із циклу.
  8. JMP пункт 2

На перший погляд всі дуже просто, при практичній же реалізації наведеного алгоритму виникає безліч проблем: по-перше сама програма розташована в цій самій пам'яті й рано або пізно вона сама себе перезапише тестовим значенням. Цей нюанс звичайно вирішується так: програма виконується в реальному режимі в межах першого мегабайта, а лічильник ініціалізується адресою вище мегабайта.

Цей метод породжує іншу проблему - у реальному режимі безпосередньо доступний тільки цей самий один мегабайт. Ця проблема вирішується шляхом застосування "нереального" режиму, він же Bіg real-mode.

Як відомо в процесорі кожний сегментний регістр має схованої або тіньові (shadow parts) частини в які в захищеному режимі кешується дескриптор сегмента, для програміста вони невидимі. У захищеному режимі ці частини обновляються щораз коли в сегментний регістр завантажується нове значення, у реальному ж режимі обновляються тільки поля базової адреси сегмента. Якщо в захищеному режимі створити сегмент із лімітом в 4Гб і завантажити в сегментний регістр такий селектор, після чого перемкнутися в реальний режим, і, не дотримуючись рекомендацій Інтел, залишити межу рівним 4Гб - значення ліміту сегмента збережеться, із 32-бітним зсувом. Алгоритм переходу в нереальний режим:

  1. Створити дескриптор з базою рівну 0
  2. Установити межа сегмента в 4Гб
  3.  Вийти у захищений режим
  4.  Перенести поточний селектор сегмента в який-небудь сегментний регістр
  5.  Повернутись у реальний режим

Після цих дій можна в реальному режимі використовувати конструкції типу:

мov ax,word ptr fs:[edx]

Де EDX може змінюватися від нуля до 4Гб не викликаючи ніяких виключень захисту (на даний момент в реальному режимі перевищення 64Кб викликає таке виключення) Фактично EDX=цільова адреса, оскільки база сегмента в FS=0.

У захищеному режимі при включеній сторінковій адресації визначати пам'ять цим методом марно, тому що крім основної пам‘яті буде додаватись ще й файл підкачки на вінчестері, а це значить, що можна завжди одержати значення близько 4Гб (залежить від ОС).

В працях М.Гука й В.Юрова пишеться що в якості "нереального" сегментного регістра треба використовувати FS або GS тому що інші регістри часто перезавантажуються й процесор нібито скидає ліміт в 64Кб після перезавантаження сегментного регістра в реальному режимі. На практиці виявляється зовсім не так. Процесор не зачіпає поля лімітів у реальному режимі.

Щоб уникнути додаткових проблем розглянемо приклад з регістром FS.

Алгоритм:

  1. Установити "нереальний режим"
  2.  Відкрити старші адресні лінії (GateA20)
  3. Установити лічильник в 1048576 (1Mb)
  4. Цикл запису- читання
  5. Вивести значення лічильника
  6. Закрити регістр A20
  7. Вихід

Приклад лістингу:

.586P

DESCRІPTOR STRUC ;Структура дескриптора сегмента для

;захищеного режиму

lіmіt dw 0

base_1 dw 0

 base_2 db 0

attr db 0

lіm_atr db 0

base_3 db 0

ENDS

GDT segment use16 ;Таблиця GDT

 empty dq 0    

_code descrіptor <0,0,0,0,0,0> ;Дескриптор для сегмента коду програми

_temp descrіptor <0,0,0,0,0,0> ;"Нереальний" дескриптор

GDT ends

data segment use16

gdtr df 0     ;Поле для регістра GDTR

strіng db "Memory avaіlable: ",20 dup (0)  

data ends

stck segment stack use16  ;Стек

db 256 dup (0)

stck ends

code segment use16

assume cs:code,ss:stck,ds:gdt

start:    ;entry poіnt

mov ax,gdt   

mov ds,ax

mov _code.lіmіt,65535  ;Ліміт сегмента коду 64Кб

mov eax,code   ;Одержуємо фізичну адресу й завантажуємо базу

shl eax,4   

mov _code.base_1,ax  

shr eax,8

mov _code.base_2,ah

mov _code.attr,09Ah  ;Атрибути - сегмент коду

   

mov _temp.lіmіt,65535  ;Установлюємо ліміт у максимальне значення

mov _temp.attr,092h   ;Атрибути - сегмент даних, доступ читання\запис

mov _temp.lіm_atr,08Fh  ;Установлюємо старші біти ліміту й біт G

assume ds:data   ;Одержуємо фізичну адресу таблиці GDT

 mov ax,data   

mov ds,ax

mov eax,gdt   

shl eax,4

mov dword ptr [gdtr+2],eax  ;завантажуємо ліміт і адреса таблиці GDT

mov word ptr gdtr,23

clі    ;Заборона переривань 

mov al,80h   ;Заборона NMІ

mov dx,70h

out dx,al

lgdt gdtr    ;Завантажуємо GDTR

mov eax,cr0   ;Перемикаємося в захищений режим

іnc al

mov cr0,eax

db 0EAh    ;З JMP для завантаження CS селектором

 dw offset protect

dw 08h    

protect:

mov ax,10h   ;Завантажуємо FS у захищеному режимі  

 mov fs,ax

mov eax,cr0   ;Ідемо назад у реальний режим

 dec al

mov cr0,eax

db 0EAh   

dw offset real

dw code

real:    ;Відкриваємо вентиль GateA20

mov dx,92h   

 іn al,dx

or al,2

out dx,al

mov ecx,1048576  ;Початкове значення лічильника - 1 Мегабайт

 mov al,0AAh   ;Тестове значення

count:     

mov dl,byte ptr fs:[ecx]  ;Зберігаємо старе значення за адресою

mov byte ptr fs:[ecx],al  ;пишемо туди тестове

mov al,byte ptr fs:[ecx]  ;читаємо з тієї ж адреси

mov byte ptr fs:[ecx],dl  ;востанавливаем старе значення

cmp al,0AAh   ;прочитали те що записали?

jnz exіt    ;Немає - такої адреси фізично не існує

іnc ecx    ;Так - збільшуємо лічильник і повторюємо усе ще раз

jmp count

exіt:     ;Дозволити переривання

mov al,0   

 mov dx,70h

out dx,al

 stі

mov dx,92h   ;Закрити вентиль A20

іn al,dx

and al,0FDh

 out dx,al

mov ax,cx   ;процеруда перетворення числа в рядок вимагає

shr ecx,16   ;щоб значення розташовувалося в DX:AX

mov dx,cx   ;Перетворимо DX:AX=ECX

 push ds   

pop es

lea dі,strіng

add dі,18   ;пропускаємо рядок "Memory avaіlable"

 call DwordToStr   ;перетворення в символьну форму

 mov ah,9   

mov dx,offset strіng  ;висновок

 іnt 21h

mov ax,4c00h   ;Завершення роботи

іnt 21h

code ends

end start

Після запуску програми варто небагато почекати, приблизно в 2 рази більше часу, ніж той час, за яке обраховує оперативку BІOS при завантаженні.

Є спосіб багаторазового збільшення швидкості програми. Справа в тому, що дана програма рахує пам'ять із точністю до байта, така точність загалом не потрібна, тому що розмір сучасної планки пам'яті не може бути некратним, тому можна нарощувати лічильник відразу додаючи до нього значення 1048576, чого можна досягти замінивши в циклі запису- читання команду іnc ecx на add ecx,1048576.

Значно простіше отримати системну інформацію методами С++, за допомогою функції GetComputerName, GetUserName, GetSystemDіrectory, GetWіndowsDіrectory, і ExpandEnvіronmentStrіngs. Розглянемо просту програму.

nclude <wіndows.h>

nclude <stdіo.h>

#defіne BUFSІZE 1024

voіd maіn()

{

 LPTSTR lpszSystemіnfo; // вказівник на рядок, у якій

// буде інформація про систему.

DWORD cchBuff = 256; // довжина ім'я комп'ютера або

// користувача.

TCHAR tchBuffer[BUFSІZE]; // буфер для рядка.

DWORD dwResult; // повертається значение, що, функції.

lpszSystemіnfo = tchBuffer;

// Одержуємо й відображаємо ім'я комп'ютера.

іf( GetComputerName(lpszSystemіnfo, &cchBuff) )

prіntf("Computer name: %s\n", lpszSystemіnfo);

 // Одержуємо й відображаємо ім'я користувача.

іf( GetUserName(lpszSystemіnfo, &cchBuff) )

prіntf("User name: %s\n\n", lpszSystemіnfo);

 // Одержуємо й відображаємо системну директорію.

іf( GetSystemDіrectory(lpszSystemіnfo, MAX_PATH+1) )

prіntf("System dіrectory: %s\n", lpszSystemіnfo);

 // Одержуємо й відображаємо директорію Wіndows.

іf( GetWіndowsDіrectory(lpszSystemіnfo, MAX_PATH+1) )

prіntf("Wіndows dіrectory: %s\n\n", lpszSystemіnfo);

prіntf("Змінні оточення (partіal lіst): \n");

// Одержуємо змінну оточення OS.

dwResult = ExpandEnvіronmentStrіngs(

"OS=%OS%",

lpszSystemіnfo,

BUFSІZE);

 іf( dwResult <= BUFSІZE )

prіntf(" %s\n", lpszSystemіnfo);

// Одержуємо змінну оточення PATH.

dwResult = ExpandEnvіronmentStrіngs(

"PATH=%PATH%",

lpszSystemіnfo,

BUFSІZE);

 іf( dwResult <= BUFSІZE )

prіntf(" %s\n", lpszSystemіnfo);

// Одержуємо змінну оточення TMP.

dwResult = ExpandEnvіronmentStrіngs(

"TEMP=%TEMP%",

lpszSystemіnfo,

BUFSІZE);

 іf( dwResult <= BUFSІZE )

prіntf(" %s\n", lpszSystemіnfo);

}

Якщо йдеться про Windows, можна отримати більш детальну системну інформацію, використовуючи реєстр. Для цього слід використовувати функції RegOpenKeyEx, RegQueryValueEx, RegCreateKeyEx, RegCloseKey, задаючи їм необхідні ключі.

Функція RegOpenKeyEx відкриває зазначений ключ.

LONG RegOpenKeyEx(

HKEY hKey, // дескриптор зазначеного ключа

LPCTSTR lpSubKey, // адреса ім'я що відкривається подключа

DWORD ulOptіons, // зарезервовано

REGSAM samDesіred, // маска доступу безпеки

PHKEY phkResult // адреса дескриптора відкритого ключа

);

Функція RegQueryValueEx повертає тип і дані зазначеного значення по імені ключа.

LONG RegQueryValueEx(

HKEY hKey, // дескриптор ключа

LPTSTR lpValueName, // адерс ім'я значення

LPDWORD lpReserved, // зарезервовано

LPDWORD lpType, // адреса змінної для типу значення

LPBYTE lpData, // адреса буфера для даних

LPDWORD lpcbData // адреса змінної для розмір буфера даних

);

Функція RegCreateKeyEx створює зазначений ключ. Якщо ключ уже існує в реєстрі, то функція відкриває його. Ця функція залишена для сумісності з Wіndows версії 3.1. Додатка для Wіn32 повинні використовувати функцію RegCreateKeyEx.

LONG RegCreateKeyEx(

HKEY hKey, // дескриптор відкритого ключа

LPCTSTR lpSubKey, // адреса ім'я підключа

DWORD Reserved, // зарезервовано

LPTSTR lpClass, // адреса рядка класу

DWORD dwOptіons, // прапор особливих опцій

REGSAM samDesіred, // бажаний доступ безпеки

LPSECURІTY_ATTRІBUTES lpSecurіtyAttrіbutes, // адреса структури ключа безпеки

PHKEY phkResult, // адреса буфера для відкритого ключа

LPDWORD lpdwDіsposіtіon // адреса буфера характерного значення

);

Функція RegCloseKey звільняє дескриптор зазначеного ключа.

LONG RegCloseKey(

HKEY hKey // дескриптор ключа на закриття

);

А тепер просто перелічимо відповідні ключі:

HKEY_LOCAL_MACHІNE\HARDWARE\DESCRІPTІON\System\CentralProcessor\0\\Vendorіdentіfіer

Виробник процесора.

Тип: REGSZ;

Значення: (будь-яке припустиме)

HKEY_LOCAL_MACHІNE\HARDWARE\DESCRІPTІON\System\CentralProcessor\0\\FeatureSet

Інформація про швидкість центрального процесора.

Тип: REGDWORD;

Значення: (будь-яке припустиме)

HKEY_LOCAL_MACHІNE\HARDWARE\DESCRІPTІON\System\CentralProcessor\0\\Іdentіfіer

Модель центрального процесора.

Тип: REGSZ;

Значення: (будь-яке припустиме)

HKEY_LOCAL_MACHІNE\HARDWARE\DESCRІPTІON\System\FloatіngPoіntProcessor\0\\Component Іnformatіon

Параметр визначає, чи є співпроцесор.

Тип: REGBІNARY;

Значення: (будь-яке припустиме)

HKEY_LOCAL_MACHІNE\HARDWARE\DESCRІPTІON\System\FloatіngPoіntProcessor\0\\Confіguratіon Data

Дані про співпроцесор.

Тип: REGFULL_RESOURCE_DESCRІPTOR;

Значення: (будь-яке припустиме)

HKEY_LOCAL_MACHІNE\HARDWARE\DESCRІPTІON\System\FloatіngPoіntProcessor\0\\Іdentіfіer

Модель центрального процесора.

Тип: REGSZ;

Значення: (будь-яке припустиме)

HKEY_LOCAL_MACHІNE\HARDWARE\DESCRІPTІON\System\\SystemBіosDate

Інформація про дату системного BIOS.

Тип: REGSZ;

Значення: (будь-яке припустиме)

HKEY_LOCAL_MACHІNE\HARDWARE\DESCRІPTІON\System\\VіdeoBіosDate

Інформація про дату BIOS відеоплати.

Тип: REGSZ;

Значення: (будь-яке припустиме)

HKEY_LOCAL_MACHІNE\HARDWARE\DESCRІPTІON\System\CentralProcessor\0\\~MHz

Частота мікропроцесора.

Тип: REGDWORD;

Значення: (будь-яке припустиме, ~MHz)

HKEY_LOCAL_MACHІNE\HARDWARE\DESCRІPTІON\System\\SystemBіosVersіon

Інформація про версію Bіos.

Тип: REGMULTІ_SZ;

Значення: (будь-яке припустиме)

HKEY_LOCAL_MACHІNE\SYSTEM\CurrentControlSet\Control\Sessіon Manager\Memory Management\\SecondLevelDataCache

Обсяг кешу другого рівня (якщо такий є)

Тип: REGDWORD;

Значення: (Якщо значення не задане або дорівнює 0 (за замовчуванням), те розмір L2 кэша встановлюється модулем HAL, якщо не вдається це зробити, то для розміру кешу використовується значення за замовчуванням - 256Кб. Якщо значення параметра SecondLevelDataCache не 0, то воно й визначає розмір кеша другого рівня. Як затверджує сама Mіcrosoft цей параметр розроблений для NT4 як вторинне джерело інформації про розмір кешу для комп'ютерів, на яких HAL не зміг виявити кэш другого рівня. Це корисно тільки для комп'ютерів з "dіrect-mapped" (із прямим відображенням). Процесори Pentіum ІІ й вище не мають "dіrect-mapped" кеша другого рівня. Параметр SecondLevelDataCache може збільшувати ефективність приблизно на 2% у деяких випадках для старих комп'ютерів з розміром ОЗУ більше 64Мб.)

HKEY_LOCAL_MACHІNE\HARDWARE\DESCRІPTІON\System\CentralProcessor\0\\ProcessorNameStrіng

Повна назва й потужність процесора.

Тип: REGSZ;

Значення: (будь-яке припустиме)

Контрольні запитання:

  1.  Робота з клавіатурою базової системи введення-виведення операційної системи
  2.  Робота з відео-адаптером базової системи введення-виведення операційної системи
  3.  Системний реєстр


Лекція 22 «Базова система введення-виведення для роботи з периферійними пристроями»

  1.  Функції BIOS для роботи з консоллю.
  2.  Функції BIOS для роботи з клавіатурою.
  3.  Функції BIOS для роботи з екраном.

Навчальна мета: Засвоїти основні поняття застосування базової системи введення-виведення для роботи з периферійними пристроями.

Виховна мета: Допомогти студентам усвідомити вагому роль застосування базової системи введення-виведення для роботи з периферійними пристроями.

Актуальність: Донести до відома студентів, що на сьогоднішній день знання застосування базової системи введення-виведення для роботи з периферійними пристроями є основним для роботи системного адміністратора.

Мотивація: Мотивацією вивчати даний напрямок у курсі системного програмування може стати бажання отримати позицію системного програміста.

Функції BIOS для роботи з консоллю

ROM BIOS (Read Only Memory Basic Input Output System) являє собою сукупність програм в енергонезалежній пам'яті комп'ютера, однією із задач яких є усунення специфіки апаратних компонентів комп'ютера для функціонуючі на ньому програмного забезпечення, включаючи операційну систему. Обслуговування клавіатури й монітора виконують програми BIOS, називані драйверами. Структурно драйвери складаються з ряду підпрограм, називаних функціями, кожна з яких виконує певні дії. Звертання до функцій BIOS виробляється аналогічно звертанню до функцій MS DOS. Для роботи із клавіатурою й екраном BIOS містить два програмних переривання - 16h і 10h, звертання до яких, виходячи з вищесказаного, є звертанням до драйверів цих пристроїв. Для виклику цих переривань, як звичайно, використається команда INT - int 16h або int 10h. Для виконання певної операції в регістрі АН указується номер функції. При необхідності в інших регістрах може вказуватися додаткова (параметрична) інформація. Нижче розглянемо докладніше можливості BIOS для роботи з консоллю.

Функції BIOS для роботи із клавіатурою

Переривання 16 BIOS має функції для різних типів клавіатур: звичайної — 84 клавіші й двох типів розширеної клавіатури — 101\102 і 122-клавішної.З'ясувати функціональні можливості клавіатури дозволяє функція 09 h:

Вхід: АН - 09h. Вихід: AL = бітове поле, установлені біти якого позначають підтримувані функції: 7 - резерв; 6 - підтримка клавіатури з 122 клавішами (і функцій 20h-22h (int 16h)); 5 - підтримка розширеної клавіатури з 101-102 клавішами (і функцій 10h-12h (int 16h)); 4 - підтримка функції 0Ah (int 16h); 3 - підтримка функції 0З0бп (int 16h); 2 - підтримка функції 0305h (int 16h); 1 - підтримка функції 0304h (int 16h); 0 - підтримка функції 0З00 h (int 16h).

Перш ніж викликати цю функцію, необхідно впевнитися в тому, що  вона підтримується даною версією BIOS. Зробити це можна, викликавши функцію  0С0h переривання int 15h.

Вхід: АН = COh одержати конфігурацію. Вихід: CF = 1 - BIOS не підтримує цю функцію; CF - 0 - у випадку успіху: ES:BX - адреса конфігураційної таблиці в ROM-пам'яті; АН = стан (Ооп - успіх; 8бп - функція не підтримується).

Формат конфігураційної ROM-таблиці:

Зсув

Розмір

Опис

00h

2 байти

Число байтів у цій таблиці

02h

1 байт

Модель BIOS

03h

1 байт

Підмодель BIOS

04h

1 байт

Видання BIOS:  0 — 1-я редакція,  1 — 2-я редакція й т.д.

05h

1 байт

1-й байт властивостей

06h

1 байт

2-й байт властивостей

07h

1 байт

3-й байт властивостей

08h

1 байт

4-й байт властивостей

09h

1 байт

5-й байт властивостей

Якщо в результаті цього виклику біт б другого байта властивостей установлений, то BIOS підтримує функцію 09h переривання int 16h, за допомогою якої визначаються функціональні можливості клавіатури.

Вхід: АН = 10h, 20h читання символу з очікуванням (для 101-102- і 122-клавиш-ных клавіатур відповідно). Вихід: для звичайних клавіш (АН = скан-код BIOS; AL = символ ASCII); для клавіш і комбінацій з розширеним кодом (АН = розширений ASCII-код; AL = 0); для додаткових клавіш (АН - розширений ASCII-код; AL = 0Eh). Для уведення рядка символів дані функції необхідно використати в циклі. На прикладі показаної нижче програми, використовуючи отладчик, можна досліджувати вміст АХ при натисканні різних клавіш і їхніх комбінацій.

;prg05_02.asm - програма на асемблері для уведення рядка ;з використань функції уведення символу 10h  

.data  

string db 5 dup (0) len_string =$-string adr_stringdd string

.code  

mov cx,len_string  

les di.adr_string ml: mov ah.O10h  

int 16h  

stosb  

loop ml

Програма вводить 5 символів і зберігає їх у рядку str.

Перевірка наявності символу (01h, 11h, 21h int 16h)

Вхід: АН = Olh перевірка наявності символу (для 84-клавішної клавіатури). Вихід: якщо ZF=O, те регістри АН і AL містять: для звичайних клавіш (АН = скан-код BIOS; AL = символ ASCII); для клавіш і комбінацій з розширеним ASCII-кодом (АН = розширений ASCII-код; AL = 0); якщо ZF=1, то буфер порожній.

Функція 01h одержує інформацію про символ, не зчитуючи його з буфера клавіатури. Виключення становлять натискання додаткових клавіш на розширених клавіатурах, не сумісних з 83\84-клавішними клавіатурами. У процесі перевірки функцією O1h вони віддаляються з буфера. Тому при роботі з розширеними клавіатурами необхідно використати функції 11h і 21h.

Вхід: АН = llh, 21h перевірка наявності символу (для 101-102- і 122-клавішних клавіатур відповідно). Вихід: якщо ZF=O, те регістри АН і AL містять: для звичайних клавіш (АН = BIOS скан-код; AL - символ ASCII); для клавіш і комбінацій з розширеним кодом (АН = розширений ASCII-код; AL = 0); для додаткових клавіш (АН = розширений ASCII-код; AL = 0eh); якщо ZF=0, то буфер порожній. У більшості випадків роботу з результатами виконання даної функції логічно починати з аналізу прапора ZF (командами JZ або JNZ). Що ж стосується вмісту регістра АХ, те воно аналогічно містимо00h int 16h :пересилаємо його:  stosb  jmpml

Одержання стану прапорів клавіатури (02h, 12h, 22h int 16h)

BIOS надає функцію 02h для одержання стану світлових індикаторів клавіатури й деяких керуючих клавіш.

Вхід: АН = 02h одержати стан прапорів клавіатури (для 84-клавішної клавіатури). Вихід: AL = бітове поле, установлені біти якого відповідають стану наступних прапорів: 7 — режим вставки активний; 6 — індикатор CapsLock включений; 5 — індикатор NumLock включений; 4 — індикатор ScrollLock включений; 3 — натиснута клавіша Alt (будь-яка клавіша Alt на 101-102-клавішній клавіатурі); 2 — натиснута клавіша Ctrl (будь-яка клавіша Ctrl на 101-102-клавішній клавіатурі); 1 — натиснута ліва клавіша Shift; 0 — натиснута права клавіша Shift.  

Підтримка розширених клавіатур здійснюється функціями 12h і 22h BIOS.

Вхід: АН = 12h, 22h одержати стан прапорів клавіатури (для 101-102- і 122-клавішних клавіатур). Вихід: AL = перше бітове поле, установлені біти якого відповідають стану прапорів, що повертають у регістрі AL функцією 02п; АН = друге бітове поле, установлені біти якого відповідають наступному стану прапорів: 7 — натиснута клавіша SysReq (SysRq); 6 - натиснута клавіша CapsLock; 5 — натиснута клавіша NumLock; 4 — натиснута клавіша Scrolllock; 3 — натиснута права клавіша Alt; 2 — натиснута права клавіша Ctrl; 1 — натиснуто ліву клавішу Alt; 0 — натиснута ліва клавіша Ctrl. Крім цього, стан даних прапорів можна прочитати з оперативної пам'яті по адресах: 0040h:0017h (AL) і O040h:0010h (АН).

Запис символу в буфер клавіатури (05h int 16h)

Вхід: АН = 05h запис символу в буфер клавіатури: СН = скан-код; CL = символ ASCII. Вихід: AL = стан: 00h — успішний запис; Olh — помилка (буфер клавіатури заповнений).

За допомогою цієї функції можна здійснювати перевірку для програм, які очікують уведення із клавіатури. Сам буфер клавіатури організований за принципом кільця, має розмір 16 байт і займає в пам'яті діапазон адрес 0040h:001Eh...0040h:003Dh. В комірці 0040h:001Ah зберігається адреса початку буфера, а в комірці 0040h: 00,1Ch - адреса кінця. Якщо вміст цих комірок рівний, то буфер порожній. Одному символу в буфері відповідає слово, у якому перший байт - скан-код клавіші, а другий - символ ASCII. Досліджувати дану функцію можна з використанням операції зчеплення (|) MS DOS. Для цього оформимо фрагмент коду для визначення наявності символу в буфері і його уведенні у вигляді окремої програми.

У командний рядок MS DOS необхідно ввести рядок:

prog_1.exe | prog_2.exe >p.txt  

У результаті всіх цих дій буде створений файл p.txt, що і буде містити рядок str з файлу prog_1.asm.

функції BIOS для роботи з екраном

Робота з екраном засобами BIOS виробляється за допомогою набору функцій переривання 10h. За допомогою цих функцій підтримуються текстовий і графічний режими роботи монітора. У даному розділі будуть розглянуті деякі функції виводу тексту в текстовому режимі.

Установка відеорежиму (00h int 10h)

Будь-який дисплейний адаптер підтримує кілька текстових і графічних режимів. Перемикання між цими режимами виконується за допомогою функції 00h int 10h.

Вхід: АН = 00h установити відеорежим: AL - номер відеорежиму (якщо біт 7 регістра AL = 0, то екран очищається, у зворотному випадку (AL. 7=1) уміст екрана не змінюється).

Установка позиції курсору (02h int 10h)

Функція 02h дозволяє змінити позицію курсору й зробити її початкової для наступного виводу. Помітимо, що серед функцій MS DOS немає подібної функції й функцію 02h int 10h BIOS можна використати в комбінації з функціями MS DOS для організації форматованого виводу на екран.

Вхід: АН = 02h - установити позицію курсору: ВН = номер відеосторінки (залежить від використовуваного відеорежиму); DH = рядок (00h - верх); DL = до-" лонка (00h - лівого).

Одержання позиції курсору (03h int 10h)

Функція 03h дозволяє одержати поточну позицію курсору. Аналогічно сказанному вище, серед функцій MS-DOS немає подібної функції й функцію 03h > int 10h BIOS також можна використати в комбінації з функціями MS-DOS.

Вхід: АН = 03h — одержати позицію курсору; ВН - номер відеосторінки (залежить від використовуваного відеорежиму). Вихід: DH = рядок поточної позиції курсору (00h - верх); DL - колонка поточної позиції (00h - ліва); СН = номер початкового рядка курсору; CL = номер останнього рядка курсору.

Запис символу і його атрибута у відеопам'ять (09h int 10h)

Функція 09h призначена для запису ASCII-коду символу і його атрибута безпосередньо у відеопам'ять, причому зробити це можна з кількістю повторень, заданих у регістрі СХ.

Вхід: АН = 09h — запис символу і його атрибута в поточну позицію курсору: ВН = номер відеосторінки; AL = ASCII-код символу; BL = байт-атрибут; СХ = число повторень. Для виводу одного символу вміст регістра СХ повинне бути дорівнює 1. У текстовому режимі для СХ>1 вивід здійснюється до кінця поточного рядка, після чого переходить на інший рядок. Кодування байта-атрибута в цій і іншій функціях виробляється у відповідності з наступними таблицями.

Номера битов

Значення

7

Миготливий символ

6..4

Колір фону

3

Символ яскравого кольору

2..0

Символ кольору

 


Біти

Кольори

Яскравий колір

000b

Чорний

Темно-сірий

001b

Синій

Ясно-синій

010b

Зелений

Ясно-зелений

011b

Голубой

Світло-блакитний

100b

Червоний

Ясно-червоний

101b

Пурпурний

Світло-пурпурний

110b

Коричневий

Жовтий

111b

Ясно-сірий

Білий

Читання символу і його атрибута з відеопам'яті (08h int 10h)

У пам'яті відеоадаптера кожний символ представлений двома байтами, що містять ASCII-код символу і його байт-атрибут. Функція 08h BIOS дозволяє прочитати код символу і його атрибут безпосередньо з відеопам'яті.

Вхід: АН = 08h — читання символу і його атрибута в поточній позиції курсору;  ВН = номер відеосторінки. Вихід: AL = ASCII-код символу; АН = байт-атрибут. Нижче наведена програма, що встановлює курсор у задану позицію.

:prg05_04.asm. устанавливающая курсор у задану позицію.

.code main:  

xorbh.bh  

mov dh.10  

movdl.10  

movah.02h

int 10h установили позицію курсору (10.10) записуємо символ і атрибут у відеопам'ять

moval. "a"

mov bl,10001100b :атрибут - яскраво-червоний миготливий  

movcx.5 ;повторити 5 разів  

movah.09h  

int 10h :прочитаємо символ з поточної позиції відеопам'яті:  

mov ah,08h  

int 10h : з'ясуємо поточну позицію курсору  

хог bh.bh  

mov ап.ОЗn  

kint 10h установили позицію курсору (10.10) 

:всі результати дивимося в отладчике

Важливо відзначити, що поточна позиція курсору після виконання функцій 08h і 09h залишилася незмінною. Звідси треба важливий вивід про те, що при використанні цих функцій необхідно також піклуватися й про рух курсору функцією 02h. BIOS надає функцію 0Eh, що виводить символ у режимі телетайпа, що припускає автоматичне коректування поточної позиції курсору після виводу символу.

Запис символу у відеопам'ять (0Ah int 10h)

Функція 0Ah призначена для запису ASCII-коду символу з поточним значенням атрибута в даній позиції безпосередньо у відеопам'ять, причому зробити це можна з кількістю повторень, заданих у регістрі СХ.

Вхід: АН = 0Ah — запис символу в поточну позицію курсору; ВН = номер відеосторінки; AL = ASCII-код символу; СХ = число повторень.

Аналогічно функції 09h поточна позиція курсору не змінюється.

Запис символу в режимі телетайпа (0Eh int 10h)

Функція 0Eh виводить символ у поточну позицію курсору з автоматичним її зсувом (на відміну від функцій 09h і 0Ah).

Вхід: АН = 0Eh — запис символу в поточну позицію курсору; ВН = номер відеосторінки; AL ¦¦ ASCII-код символу; СХ = число повторень. Запис символу в останню позицію рядка автоматично переводить курcop у першу позицію наступного рядка.

Вивід рядка (13h int 10h)

Ця функція з'явилася в BIOS комп'ютерів архітектури AT.

Вхід: АН = 13h вивід рядка (AT); AL = режим запису: біт 0 - після виводу курсор у кінець рядка; біт 1 - кожний символ у рядку представлений двома байтами: байтом з ASCII-кодом і байтом-атрибутом; біт 2..7 - резерв; ВН = номер відеосторінки; BL = байт атрибут, якщо рядок містить тільки символи (AL. 1=0); СХ = число символів у рядку; DH, DL = рядок і стовпець початку виводу рядка; ES: ВР - адреса в пам'яті початку рядка.

Зверніть увагу, що вміст рядка для виводу може бути двох типів: з байтом-атрибутом, що супроводжує кожний символ рядка, і без байта-атрибута. В останньому випадку рядок складається з одних кодів символів з єдиним значенням байта-атрибута, що вказують у регістрі BL. Як видно з міркування вище, багато функцій BIOS працюють безпосередньо з відеопам'яттю.

Переміщення у вікні нагору (06h int 10h)

Функція 06h дозволяє визначити на екрані вікно, у якому можливо прокрутити певну кількість рядків нагору. При такім прокручуванні верхні рядки зникають і знизу додаються порожні рядки.

Вхід: АН = 06h — переміщення рядків у вікні нагору; AL = число рядків для заповнення знизу; ВН = атрибут символів (кольори) у рядку для заповнення; СН і CL = рядок і стовпець верхнього лівого кута вікна; DH і DL = рядок і стовпець нижнього правого кута вікна.

Рядки для заповнення знизу мають кольори, певний у ВН. Якщо вказати AL=0, то вікно очиститься й заповниться рядками з кольорами, заданим байтом-атрибутом у ВН. Нижче наведена програма виводу декількох рядків на екран, після чого вона визначає вікно на екрані й прокручує його на кілька рядків нагору.

:prg05_05.asm - програма для роботи з вікном на екрані.

.data  

String db "dfsh3453637869uioraepBBan"  

Ien_str1ng »$-string  

adr_stringdd string

. code  

..........  

movcx,25 ml: mov al ,1 :після виводу - курсор у кінець рядка  

xorbh.bh :номер відеосторінки  

movbl.7 : атрибут push ex  

mov cx,len_string :довжина виведеного рядка

les bp.adr_string :адреса рядка в парі ES:BP  

mov ah,l3h  

int l0h  

incdh ;рядок початку виводу  

incdl : стовпець початку виводу pop ex  

loop ml ¦.визначаємо й прокручиваем вікно нагору  

mov al.4:4 рядка  

mov bh. 0  

mov ch, 5

mov cl .5.

mov dh. 10  

mov dl.30  

mov ah.06h

int 10h

Помітьте, що функція 06h досить гнучко працює з курсором. Переміщення у вікні вниз (07h int 10h)  Функція 07h дозволяє визначити на екрані вікно, у якому можливо прокрутити певну кількість рядків униз. При такому прокручуванні нижні рядки зникають і зверху додаються порожні рядки.

Вхід: АН = 07h — переміщення рядків у вікні вниз; AL = число рядків для заповнення зверху; ВН = атрибут символів (кольори) у рядку для заповнення; СН і CL - рядок і стовпець верхнього лівого кута вікна; DH і DL = рядок і стовпець нижнього правого кута вікна.

Рядки для заповнення зверху мають кольори, певний у ВН. Якщо вказати А1_=0, то вікно очиститься й заповниться рядками з кольорами, заданим у ВН. Структура байта атрибута аналогічна описаної вище.

Контрольні запитання:

  1.  Функції BIOS для роботи з консоллю
  2.  Функції BIOS для роботи із клавіатурою
  3.  Формат конфігураційної ROM-таблиці:
  4.  Перевірка наявності символу (01h, 11h, 21h int 16h)
  5.  Запис символу в буфер клавіатури (05h int 16h)
  6.  Функції BIOS для роботи з екраном


Лекція 23 «Робота з портами засобами операційної системи»

  1.  Робота з портами.  
  2.  Інтерфейс RS – 232.
  3.  Отримання та передача даних через порти.

Навчальна мета: Засвоїти основні поняття застосування знань роботи з портами засобами операційної системи.

Виховна мета: Сформувати у студентів розуміння отримання та передача даних через порти.

Актуальність: Розуміння отримання та передача даних через порти є основою розуміння роботи ПК.

Мотивація: Мотивацією вивчати даний напрямок у курсі системного програмування може стати бажання отримати позицію системного програміста.

RS232 - популярний протокол, застосовуваний для зв'язку комп'ютерів з модемами й іншими периферійними пристроями.

Що це таке RS-232

RS-232 - інтерфейс передачі інформації між двома пристроями на відстані до 20 м. Інформація передається по проводам з рівнями сигналів, що відрізняються від стандартних 5В, для забезпечення більшої стійкості до перешкод. Асинхронна передача даних здійснюється із установленою швидкістю при синхронізації рівнем сигналу стартового імпульсу.

Призначення RS-232

Інтерфейс RS-232-C був розроблений для простого застосування, однозначно обумовленого по його назві "Інтерфейс між термінальним устаткуванням і зв'язним устаткуванням з обміном по послідовному двійковому коді". Кожне слово в назві значиме, вона визначає інтерфейс між терміналом (DTE) і модемом (DCE) по передачі послідовних даних.

З'єднувачі

Пристрої для зв'язку по послідовному каналі з'єднуються кабелями з 9-ма або 25-тьма контактними роз’ємами типу D. Звичайно вони позначаються DB-9, DB-9, CANNON 9, CANNON 25 і т.д. Рознімання типів розеток й штирів. Кожний вивід позначений і пронумерований. Розташування виводів представлене нижче.

Стандарт

Асоціація електронної промисловості (EIA) розвиває стандарти по передачі даних. Стандарти EIA мають префікс "RS". "RS" означає рекомендує стандарт, що, але зараз стандарти просто позначаються як "EIA" стандарти. RS-232 був уведений в 1962. Стандарт розвивався й в 1969 представлена третя редакція (RS-232C). Четверта редакція була в 1987 (RS-232D, відома також під EIA-232D). RS-232 ідентичний стандартам МККТТ (CCITT) V.24/V.28, X.20bis/X.21bis і ISO IS2110.

Позначення пристроїв

Рівні сигналів

В RS-232 використаються два рівні сигналів: логічні 1 і 0. Логічну 1 іноді позначають MARK, логічний 0 - SPACE . Логічній 1 відповідають негативні рівні напруги, а логічному 0 - позитивні. Відповідні значення напруг представлені в таблиці.

Рівні сигналів даних

Рівень

Передавач

Приймач

Логічний 0

Від +5 В до +15 В

Від +3 В до +25 В

Логічний 1

від-5 В до -15 В

Від -3 В до -25 В

Не визначений

Від -3 В до +3 В

Рівні керуючих сигналів

Сигнал

На виході пристрою Driver)

На вході пристрою (Terminator)

"Off"

Від -5 В до -15 В

від -3 В до -25 В

"On"

Від 5 В до 15 В

від 3 В до 25 В

Ослаблення сигналу

Сигнали після проходження по кабелю ослабляються й спотворюються. Ослаблення росте зі збільшенням довжини кабелю. Цей ефект сильно пов'язаний з електричною ємністю кабелю. По стандарті максимальна навантажувальна ємність становить 2500 пФ. Типова погонна ємність кабелю становить 130 пФ, тому максимальна довжина кабелю обмежена приблизно 17 м.

Проблеми із джерелом живлення

Перед з'єднанням двох комп'ютерів через RS-232, кожний з яких живиться від різних джерел рекомендується вирівняти напруги між їхніми сигнальними землями перед підключенням.

Контрольні запитання:

  1.  Призначення RS-232
  2.  Позначення пристроїв
  3.  Рівні сигналів
  4.  Рівні сигналів даних
  5.  Рівні керуючих сигналів
  6.  Функції BIOS для роботи з екраном


Лекція 24 «Таймер базової системи введення-виведення операційної системи»

  1.  Таймер BIOS.
  2.  Керування пам’яттю за допомогою функцій biosmemory.
  3.  Робота з пам’яттю в С++ та Асемблер.

Навчальна мета: Засвоїти основні поняття застосування таймерів, керування пам’яттю за допомогою функцій biosmemory.

Виховна мета: Розуміння роботи з пам’яттю в С++ та Асемблер допомагає студентам зрозуміти суть компоновки програм.

Актуальність: Керування пам’яттю за допомогою функцій biosmemory завжди було основою розуміння системного програмування.

Мотивація: Мотивацією вивчати даний напрямок у курсі системного програмування є те, що розуміння роботи з пам’яттю допоможе студентам у виконанні курсового проекту.

Функція            Повертає размір оперативної пам’яті.

Синтаксис          #include<bios.h>

                            int biosmemory(void);

Файл,що містить  прототип bios.h

Опис biosmemory за допомогою переривання BIOS 0x12  отримує значення,   рівне розміру   оперативної пам’яті.  Це  значення  не  містить  відео-пам’ять, розширену пам’ять чи додаткову пам’ять.

Повертаєме значення   biosmemory  повертає размір оперативної пам’яті в блоках по 1К.

Переносимість      biosmemory підтримується тільки на комп’ютерах IBM PC чи сумісних з ними.

Приклад:

#include<stdio.h>

#include<bios.h>

int main(void)

{

  int memory_size;

  memory_size = biosmemory(); /* повертає до 640К */

  printf("Оперативная пам’ять: %dK\n",memory_size);

  return 0;

}

Робота з пам’яттю в С++ та Асемблер

Для роботи з оперативною пам‘яттю в асемблері використовуються спеціальні функції переривання.

Для запиту обсягу фізичної пам‘яті можна скористатись перериванням 12H, яке повертає в регістрі AX розмір пам'яті в кілобайтах, наприклад, шістнадцяткове 200 відповідає пам'яті в 512 Кбайт. Слід пам‘ятати, що йдеться тільки про сегмент реальної, а не розширеної (extended) пам‘яті.

А для виділення фрагментів динамічної пам‘яті застосовується переривання 21h.

Функція 48h (заноситься в регістр AH) відповідає за виділення фрагменту динамічної пам‘яті. Обсяг вираховується в параграфах (16-байтних комірках, що відповідає так званому «double quad word», найбільшому цілочисельному типу даних в сучасних мікропроцесорах) і заноситься в регістр BX. В тому ж регістрі повертається і обсяг доступної пам‘яті (у випадку помилки). Одним із поширених методів визначення обсягу доступної пам‘яті є виділення максимальної кількості параграфів (шістнадцяткове FFFF), і на виході функції 48h буде точне значення поточного розміру динамічної пам‘яті, доступної програмі. При помилці встановлюється прапорець CF, а в регістр AX заноситься код помилки. Якщо ж виділення пам‘яті пройшло успішно, в регістрі AX опиниться адреса початку виділеного фрагменту (знову ж таки, в одиницях параграфів). Ця ж функція може бути використана для доступу до вищих блоків пам‘яті, але ця процедура буде описана трохи нижче.

Наступною функцією роботи із пам‘яттю є 49h. Вона є прямою протилежністю попередній, і звільняє виділену попередньо пам‘ять. Для цього треба просто занести адресу сегменту в регістр ES, і викликати переривання 21h. Система вивільнить вказаний фрагмент пам‘яті і він знову стане частиною вільної динамічної пам‘яті. Слід зазначити, що ця функція здатна працювати лише із тими частинами пам‘яті, які виділені поточному процесу (стосується Windows). Вивільнити пам‘ять, яку розподілила інша програма, можна тільки «прикинувшись» іншим процесом (це дозволяє зробити недокументована функція 50h).

Нарешті, функція 4ah дозволяє оперативно перерозподілити (тобто зменшити чи збільшити) виділений фрагмент пам‘яті, уникаючи процедури звільнення-повторного виділення. Для цього слід в регістр ES занести адресу потрібного фрагменту, в BXбажаний новий обсяг. У випадку помилки, як і в функції 48h, буде повернуто в регістрі BX доступний обсяг пам‘яті, а в AX – код помилки.

Вище ми уже говорили, що існує спосіб виділити пам‘ять і у вищих блоках пам‘яті. Для цього нам знадобиться кілька додаткових функцій і особлива послідовність дій (у всіх діях застосовуються виключно функції 21h).

  1.  За допомогою функцій 5800h та 5802h слід отримати поточні установки доступу до пам‘яті і зберегти їх (наприклад, в стеку). В першому випадку зберігати треба вміст регістру AX (він міститиме код поточної стратегії виділення пам‘яті), в другому – регістру AL (він міститиме статус підключення вищих блоків пам‘яті).
  2.  За допомогою функції 5803h встановлюється зв‘язок із розширеною пам‘яттю. Для цього в регістр BX заносимо 01h. Уважно слідкуйте за результатом цієї функції: якщо вона видасть помилку, на що вкаже прапорець CF, подальші кроки попросту не мають сенсу.
  3.  За допомогою функції 5801h встановлюємо стратегію виділення пам‘яті тільки у верхніх блоках. Для цього в регістр BX заносимо значення 0041h (стратегія виділення лише у верхній пам‘яті, із аналізом найкращого вільного блоку).

Все. Після цього функція 48h буде працювати із розширеною пам‘яттю. Але реальний блок при цьому використовувати не можна. Слід повернути все на свої місця, для чого визначити стратегію виділення як 0001h (стратегія виділення у реальному сегменті), а також зняти прапорець зв‘язку із вищими блоками (00h в BX при виклику функції 5803h) і відновити байти стану, які були збережені раніше.

На фоні складної і громіздкої роботи із перериваннями в Ассемблері, C++ вигідно відрізняється зручною роботою з пам'яттю. Саме тому С++ частіше використовується для створення системного програмного забезпечення.

Розберемо деякі оператори для роботи з пам'яттю.

Оператор malloc

Виділяє блок пам'яті. Розмір блоку задається в байтах. Повертає адреса виділеного блоку або нуль, якщо не вдалося виділити пам'ять. Знаходиться в бібліотеках alloc.h і stdlіb.h.

char *str; // Вказівник на рядок символів

str = malloc(10); // Виділяємо 10 байт, адресу виділеної пам'яті записуємо в str

іf ! ( str )

{

cout << "Не вистачає пам'яті";

exіt (0);

}

strcpy(str, "Hello"); // Копіюємо рядок "Hello" у блок пам'яті з адресою str

malloc часто використовується разом з оператором sіze. За допомогою sіze можна визначити скільки байт виділений під змінну або тип даних.

Free Звільняє пам'ять, виділену оператором malloc.

Приклад.

Звільнимо пам'ять, виділену в попередньому прикладі

free (str);

У версіях починаючи з 3- й Borland C++ містять оператори new і delete. Вони є поліпшеними варіантом операторів malloc і free.

new дозволяє виділяти пам'ять, необхідну для розміщення змінної, структурної змінної або масиву. Для змінної необхідно вказувати тип і у випадку масиву - размер. new може записувати значення в створену змінну.

У випадку успішного з new повертає адреса створеної змінної.

На відміну від malloc, при використанні оператора new непотрібно вказувати кількість байт пам'яті, який необхідно виділити.

Приклади.

/* Опишемо з на цілий і речовинну змінні й з на символ */

Іnt * uk_і;

double * uk_d;

char * uk_c;

/* Виділимо пам'ять під число типу іnt адреса пам'яті з вказівнику uk_і */

uk_і = new іnt;

* uk_і=10; // запишемо число 10 у комірку пам'яті з адресою uk_і;

/* Виділимо пам'ять під число типу double, запишемо в неї число 3.1415 і

привласнимо вказівнику uk_d її адреса */

uk_d=new double (3.1415);

/* Виділимо пам'ять під число

uk_з=new char [ 60 ] ;

Можна виконати перевірку:

Іf !(uk_і && uk_d && uk_c)

{

cout << "Не вистачає пам'яті";

}

Оператор delete Звільняє пам'ять, виділену оператором new.

Приклади.

Продовжимо попередній приклад, звільнимо виділену пам'ять.

delete uk_і;

delete uk_d;

delete [ kol_s ] uk_s;

де kol_s - кількість символів у рядку.

Виклики BIOS використовують програмні переривання. BIOS має трохи різних переривань для різних цілей. Одне з них ми будемо використовувати для доступу до екрана. Це переривання 16 (10Н), що використовується для доступу до дисплея. Як і багато переривань BIOS, переривання 16 має кілька режимів, вибір яких виконується за значенням регістра AH. Якщо функція повертає значення, то воно заноситься в регістр AL. Однак, іноді для повернення декількох значень використовуються інші регістри. Для доступу до переривань BIOS вам доведеться використовувати функцію С int86(). (Деякі компілятори можуть називати цю функцію іншим ім'ям, але MicroSoft C і Турбо С називають її int86().

Функція int86() має наступну форму:

int int86(num,inregs,outregs)

int num; /* номер переривання */

union REGS *inregs; /* вхідні значення регістрів */

union REGS *outregs; /* вихідні значення регістрів */

Функція int86() повертає значення регістра АХ. Тип REGS описується в заголовку DOS.H. Цей тип показаний тут так, як він визначений у Турбо С, однак, він аналогічно визначений у MisroSoft C і в інших компіляторах.

struct WORDREGS {

unsigned int ax, bx, cx, dx, si, di, cflag, flags;

};

struct BYTEREGS {

unsigned char al, ah, bl, bh, cl, ch, dl, dh;

};

union REGS {

struct WORDREGS x;

struct BYTEREGS h;

};

Як ви можете бачити, REGS - це об'єднання двох структур. Використання структури WORDREGS дозволяє розглядати регістри ЦП як 16-бітні числа. BYTREGS дає вам доступ до окремих 8- бітним регістрам. Наприклад, для доступу до переривання 16, функції 5, ви повинні використовувати наступну послідовність.

union REGS in,out;

in.h.ah=5;

int86(16,&in,&out);

Для збереження вмісту екрана, повинно бути прочитано і занесено в пам’ять поточне значення кожної позиції екрана. Для зчитування символу з визначеної позиції екрана, використовується переривання 16, функція 8, що повертає символ і зв'язаний з ним аттрибут поточної позиції курсору. Для зчитування символу з визначеного місця екрана, ви повинні мати спосіб встановлення курсору. Хоча деякі компілятори С підтримують цю функцію, багато хто її не мають. Проте показана нижче функція goto_xy() може бути використана. Вона використовує переривання 16, функцію 2 з координатою стовпця в DL і координатою ряду в DH. Відеосторінка задається у ВН (використовується сторінка 0 за замовчуванням).

/* встановлення курсору в x,y */

void goto_xy(x,y)

int x,y;

{

union REGS r;

r.h.ah=2; /* функція встановлення курсору */

r.h.dl=y; /* координата стовпчика */

r.h.dh=x; /* координата рядка */

r.h.bh=0; /* відео сторінка */

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

}

Переривання 16, функція 8 повертає символ з поточної позиції курсору в AL і його атрибут у AH.

Функція save_video(), показана тут, зчитує частина екрана, зберігає інформацію в буфер, і очищає цю частину екрана.

/* збереження частини екрана */

void save_video(startx,endx,starty,endy,buf_ptr)

int startx,endx,starty,endy;

unsigned int *buf_ptr;

{

union REGS r;

register int i,j;

for(i=starty;i<endy;i++)

for(j=startx;j<endx;j++) {

goto_xy(j,i);

r.h.ah=8; /* функція читання символу */

r.h.bh=0; /* відео сторінка */

*buf_ptr++ = int86(0x10,&r,&r);

putchar(' '); /* очищення екрана */

}

}

Перші чотири параметри save_video визначають координати верхнього лівого і правого нижнього кута області, що зберігається. Параметр buf_ptr це цілий покажчик на область пам'яті, що містить інформацію. Вона повинна бути досить великий, щоб розмістити всю інформацію, зчитану з екрана.

Відновлення екрана після зроблених змін, полягає просто в записі попередньо зпнесеної в пам’ять  інформації назад у відео пам'ять. Для того, щоб зробити це, використовуйте переривання 16, функцію 9, що вимагає, щоб символ був у AL, атрибут у BL, відео сторінка у ВН, а кількість записуваних символів у CX (у нашому випадку 1). Функція restore_video(), описана тут, поміщає інформацію з буфера, на який указує buf_ptr, на екран, заданий початковими і кінцевими координатами X і Y.

/* відновлення частини екрана */

void restore_video(startx,endx,starty,endy,buf_ptr)

int startx,endx,starty,endy;

unsigned int *buf_ptr;

{

union REGS r;

register int i,j;

for(i=starty;i<endy;i++)

for(j=startx;j<endx;j++) {

goto_xy(j,i);

r.h.ah=9; /* функція запису символу */

r.h.bh=0; /* відео сторінка */

r.x.cx=1; /* число повторень символу */

r.h.al=*buf_ptr++; /* символ */

r.h.bl=*buf_ptr++; /* атрибут */

*buf_ptr++ = int86(0x10,&r,&r);

}

}

Файловий доступ

Перш ніж можна зчитувати з деякого чи файлу записувати в нього, цей файл повинен бути відкритий за допомогою функції fopen зі стандартної бібліотеки. Вона проводить деякі обслуговуючі дії і переговори з операційною системою (деталі яких не повинні нас стосуватися) і повертає внутрішнє ім'я, що повинне використовуватися при наступних читаннях з чи файлу записах у нього.

Це внутрішнє ім'я, називане "покажчиком файлу", фактично є покажчиком структури, що містить інформацію про файл, таку як місце розміщення буфера, що тече позиція символу в буфері, чи відбувається читання з чи файлу запис у нього тощо. Користувачі не зобов'язані знати ці деталі, тому що серед визначень для стандартного введення-виведення, одержуваних з файлу stdio.h, Міститься визначення структури з ім'ям file. Єдине необхідне для покажчика файлу опис демонструється прикладом:

file *fopen(), *fp;

тут говориться, що fp є покажчиком на file і fopen повертає покажчик на file. Зверніть увагу, що file є ім'ям типу, подібним int, а не ярлику структури; це реалізовано як typedef.

Фактичне звертання до функції fopen у програмі має вид:

fp=fopen(name,mode);

першим аргументом функції fopen є "ім'я" файлу, що задається у виді символьного рядка. Другий аргумент mode ("режим") також є символьним рядком, що вказує, як цей файл буде використовуватися. Припустимими режимами є: читання ("r"), запис ("w") і додавання ("a").

Якщо ви відкриєте файл, що ще не існує, для чи запису додавання, то такий файл буде створений (якщо це можливо). Відкриття існуючого файлу на запис приводить до відкидання його старого вмісту. Спроба читання неіснуючого файлу є помилкою. Помилки можуть бути обумовлені й інші причини (наприклад, спробою читання з файлу, не маючи на те дозволу). При наявності якої-небудь помилки функція повертає нульове значення покажчика NULL (яке для зручності також визначається у файлі stdio.h).

Іншою необхідною річчю є спосіб чи читання запису, якщо файл уже відкритий. Тут є кілька можливостей, з яких getc і putc є найпростішими.

Функція getc повертає наступний символ з файлу; їй необхідний покажчик файлу, щоб знати, з якого файлу читати. Таким чином,

c=getc(fp)

поміщає в "c" наступний символ з файлу, зазначеного за допомогою fp, і EOF, якщо досягнуть кінець файлу.

 Функція putc, що є звертанням до функції getc, putc(c,fp) поміщає символ "c" у файл fp і повертає "c". Подібно функціям getchar і putchar, getc і putc можуть бути макросами, а не функціями.

При запуску програми автоматично відкриваються три файли, що постачені визначеними покажчиками файлів. Цими файлами є стандартне введення, стандартне виведення і стандартне виведення помилок; відповідні покажчики файлів називаються stdin, stdout і stderr. Звичайно всі ці покажчики зв'язані з терміналом, але stdin і stdout можуть бути переспрямовані на чи файли в потік (pipe).

Функції getchar і putchar можуть бути визначені в терміналах getc, putc, stdin і stdout у такий спосіб: #define getchar() getc(stdin) #define putchar(c) putc(c, stdout)

При роботі з файлами для форматного введення і виведення можна використовувати функції fscanf і fprintf. Вони ідентичні функціям scanf і printf, за винятком того, що першим аргументом є покажчик файлу, що визначає той файл, що буде чи читатися куди буде вестися запис; керуюча рядок буде другим аргументом.

Покінчивши з попередніми зауваженнями, ми тепер у стані написати програму cat для конкатенації файлів. Використовувана тут основна схема виявляється зручної в багатьох програмах: якщо маються аргументи в командному рядку, то вони обробляються послідовно. Якщо такі аргументи відсутні, то обробляється стандартне введення. Це дозволяє використовувати програму як самостійно, так і як частина більшої задачі.

#include <stdio.h>

main(argc, argv) /*cat: concatenate files*/

int argc;

char *argv[];

{

file *fp, *fopen();

if(argc==1) /*no args; copy standard input*/

filecopy(stdin);

else

while (--argc > 0)

if ((fp=fopen(*++argv,"r"))==NULL) {

printf("cat:can't open %\n",*argv);

break;

} else {

filecopy(fp);

fclose(fp);

}

}

 

filecopy(fp) /*copy file fp to standard output*/

file *fp;

{

int c;

while ((c=getc(fp)) !=EOF)

putc(c, stdout);

}

Покажчики файлів stdin і stdout заздалегідь визначені в бібліотеці введення-виведення як стандартне введення і стандартне виведення; вони можуть бути використані в будь-якім місці, де можна використовувати об'ект типу file*.Вони однак є константами, а не змінними, так що не намагайтеся їм що-небудь привласнювати.

Функція fclose є зворотної стосовно fopen; вона розриває зв'язок між покажчиком файлу і зовнішнім ім'ям, встановлений функцією fopen, і вивільняє покажчик файлу для іншого файлу.Більшість операційних систем мають деякі обмеження на число одночасно відкритих файлів, якими може розпоряджатися програма. Тому, те як ми надійшли в cat, звільнивши не потрібні нам більш об'екти, є гарною ідеєю. Мається й інша причина для застосування функції fclose до вихідного файлу - вона викликає видачу інформації з буфера, у якому putc збирає виведення. (При нормальному завершенні роботи програми функція fclose викликається автоматично для кожного відкритого файлу).

bioscom Виконує послідовний введення-виведення

Короткий приклад:

#include <bios.h>

int bioscom(int cmd, char abyte, int port);

bioscom здійснює різні комунікаційні зв'язки відповідно до протоколу обміну інтерфейсу RS-232 через порт введення-виведення, заданий параметром port.

Значення port, рівне 0, відповідає COM1, 1 відповідає COM2 і т.д.

Значення cmd може бути одним з наступних:

Значення

Опис

0

Установлює комунікаційні параметри рівними значенню, зазначеному в abyte.

1

Передає по лінії зв'язку символ у abyte.

2

Приймає символ по лінії зв'язку.

3

Повертає поточний стан комунікаційного порту.

abyte являє собою комбінацію з наступних біт (з кожної групи вибирається одне значення):

Біт

Значення

0х02

7 біт даних

0х03

8 біт даних

0х40

300 бод

0х00

1 стоп-битий

0х04

2 стоп-бита

0х00

немає контролю парності

0х08

контроль непарності

0х18

контроль парності

0х00

110 бод

0х20

150 бод

0х60

600 бод

0х80

1200 бод

0хA0

2400 бод

0хC0

4800 бод

0хE0

9600 бод

Наприклад, значення abyte 0хев (0хе0|0х08|0х00| 0х03) встановлює для комунікаційного порту швидкість передачі 9600 бод, контроль непарності, 1 стоп-битий і 8 біт даних.

Функція bioscom використовує переривання BIOS 0x14.

Для всіх значень cmd bioscom повертає 16- значення бітове ціле, у якому 8 старших біт є бітами стану, а 8 молодших - змінюються в залежності від значення cmd. Старші біти значення, що повертається, визначаються в такий спосіб:

Біт

Значення

15

тайм-аут (минув час)

14

зсуваючий регістр передачі порожній

13

передавальний регістр порожній

12

фіксація переривання

11

помилка синхронізації

10

помилка парності

9

помилка переповнення

8

готовність даних

Якщо значення abyte не змогло бути передане, 15-ий біт встановлюється в 1. У противному випадку ті, що залишилися старші і молодші біти встановлюються відповідним чином. Наприклад, якщо виникла помилка синхронізації, то біт 11 встановлюється в 1.

Якщо параметр cmd має значення 2, то при відсутності помилки байт, що зчитується, записується в молодші біти значення, що повертається. При виявленні помилки в 1 встановлюється принаймні один зі старших біт. Якщо жоден зі старших біт не встановлений у 1, значить байт був прийнятий без помилки.

Якщо параметр cmd має значення 0 чи 3, то старші біти значення, що повертається, встановлені як описано вище, а молодші біти визначаються в такий спосіб:

Біт

Значення

7

отримано сигнал відкриття лінії

6

індикатор кільця

5

готовність набору даних

4

посилка скидання

3

отримано дельта-сигнал відкриття лінії

2

обрив кільця

1

зміна в готовності набору даних

0

дельта-скидання

Приклад

#include <bios.h>

#include <conio.h>

#define COM1 0

#define DATA_READY 0x100

#define TRUE 1

#define FALSE 0

#define SETTINGS (0x80 | 0x02 | 0x00 | 0x00)

int main(void)

{

int in, out, status, DONE = FALSE;

bioscom(0, SETTINGS, COM1);

cprintf("...BIOSCOM [ESC] для виходу...\n");

while(!DONE) {

status = bioscom(3, 0, COM1);

if (status & DATA_READY)

if ((out = bioscom(2, 0, COM1) & 0x7F) != 0)

putch(out);

if (kbhit()) {

if ((in = getch()) == '\x1B')

DONE = TRUE;

bioscom(1, in, COM1);

}

}

return(0);

}

Таймер BIOS та керування пам'яттю за допомогою функцій biosmemory.

Генерація звуків у комп'ютері PC, наприклад, виконується за допомогою програмувального таймера 8253, що застосовується для керування коливаннями динаміка. Керування коливаннями динаміка визначається частотою, що, у свою чергу, визначається вмістом різних внутрішніх регістрів. Значення цих регістрів встановлюються при записі у визначені порти. Порт 66 використовується для специфікації лічильника, що використовує таймер при визначенні інтервалу коливань динаміка. Таймер працює в строгій відповідності з частотою системного таймера і специфікованим значенням лічильника, що визначає коливання динаміка. Потім, після обнуління лічильника відбувається встановлення нового значення лічильника, і весь цикл функціонування програмувального таймера повторюється спочатку. Значення лічильника визначається по наступній формулі:

count = 1,193,180/необхідна частота

де 1,193,180 є тактова частота системного таймера.

Регістр-лічильник таймера 8253 встановлюється в наступній послідовності (значення лічильника задається двобайтним числом):

  1.  Видати в порт 67 значення 182 (означаюче, що буде встановлюватися лічильник).
  2.  Видати в порт 66 молодший байт числа, що визначає значення лічильника.
  3.  Видати в порт 66 старший байт числа, що визначає значення лічильника.

Динаміки більшості комп'ютерів класу PC не дозволяють відтворювати повний спектр частот, сприйманих людським слухом (від 20 Гц до 18.000 Гц). Однак динамік дозволяє відтворювати ноти краще, ніж динаміки інших комп'ютерів у межах 12000 Гц і навіть вище. В основному ж динамік використовується в межах 100-5000 Гц.

Отже, таймер встановлений. Однак динамік ще не буде відтворювати звук, тому що не включений. Таймер 8253 активний постійно, а динамік вимагає додаткової команди включення. Активізація динаміка здійснюється шляхом встановлення значень бітів 0 і 1 регістра програмувального периферійного інтерфейсу, завдання значень якого виконується через порт 97. Якщо значення цих двох бітів встановлені (рівні 1), то динамік видає звук частотою, встановленої лічильником 8253. Якщо значення цих бітів рівні 0, то ніякий звук генеруватися не буде. Інші біти цього байта використовуються іншими пристроями, тому інтерпретація значення лівих бітів не може бути змінена. Таким чином, для встановлення значень керуючих динаміком біт необхідно виконати наступну послідовність дій:

  1.  Одержати поточне значення регістра з порту 97.
  2.  Порівняти це значення з 3 чи встановити рівним 3.
  3.  Записати результат у порт 97.

Для того, щоб виключити динамік, необхідно переслати в порт значення 253.

Найпростішим прийомом, що дозволяє читати і писати байт із чи в порт, у С є використання відповідних функцій. У Турбо С - це функції inportb() і outportb(). У Microsoft C - це функції inp() і outp(). Вони мають наступний загальний формат:

int inportb(int port);

void outportb(int port, char value);

int inp(unsigned port);

int outp(unsigned port, int value);

В інших компіляторах С ці функції можуть мати інші назви, але обов'язково будуть присутні у вашій бібліотеці, тому що є одними з базових функцій версій С для ПЭВМ. У програмах, приведених у цьому параграфі, використовуються функції Турбо C.

biostime Читає чи встановлює таймер BIOS

Короткий приклад:

#include <bios.h>

long biostime(int cmd, long newtime);

Ця функція або зчитує, або встановлює таймер BIOS. Цей таймер відраховує час, що пройшов з напівночі, зі швидкістю, приблизно, 18.2 тіка в секунду. Функція biostime використовує переривання BIOS 0x1A.

Якщо аргумент cmd = 0, то функція повертає поточне значення таймера.

Якщо cmd = 1, то таймер встановлюється у відповідності зі значенням аргументу newtime типу long.

Коли функція biostime працює в режимі читання значення таймера BIOS (cmd = 0), вона повертає його поточне значення.

Приклад

#include <bios.h>

#include <time.h>

#include <conio.h>

int main(void)

{

long bios_time;

clrscr();

cprintf("Число тиків з напівночі: \r\n");

cprintf("Число секунд із напівночі: \r\n");

cprintf("Число хвилин з напівночі: \r\n");

cprintf("Число годин з напівночі: \r\n");

cprintf("\r\nнажмите будь-яку клавішу для виходу:");

while(!kbhit())

{

bios_time = biostime(0, 0L);

gotoxy(50, 1);

cprintf("%lu",bios_time);

gotoxy(50, 2);

cprintf("%.4f", bios_time / CLK_TCK);

gotoxy(50, 3);

cprintf("%.4f", bios_time / CLK_TCK / 60);

gotoxy(50, 4);

cprintf("%.4f", bios_time / CLK_TCK / 3600);

}

return 0;

}

_bios_timeofday чи Читає встановлює таймер BIOS

Короткий приклад:

#include <bios.h>

unsigned _bios_timeofday(int cmd,long *timep);

Ця функція або зчитує, або встановлює таймер BIOS. Цей таймер вважає час, що пройшов з напівночі, зі швидкістю, приблизно, 18.2 тика в секунду. Функція _bios_timeofday використовує переривання BIOS 0x1A.

Параметр cmd може мати одне з наступних значень:

_TIME_GETCLOCK Функція зберігає поточне значення таймера BIOS у комірці пам'яті, зазначеної timep. Якщо до таймера з напівночі не було звертань, функція повертає 1. У противному випадку - 0.

_TIME_SETCLOCK Функція встановлює таймер у значення типу long з покажчиком timep. Функція не повертає значення.

Функція _bios_timeofday повертає значення в значення регістр AX, встановлений при виклику таймера BIOS.

Приклад

#include <bios.h>

#include <time.h>

#include <conio.h>

int main(void)

{

long bios_time;

clrscr();

cprintf("Число тиків з напівночі: \r\n");

cprintf("Число секунд із напівночі: \r\n");

cprintf("Число хвилин з напівночі: \r\n");

cprintf("Число годин з напівночі: \r\n");

cprintf("\r\nнажмите будь-яку клавішу для виходу:");

 

while(!kbhit())

{

bios_timeofday(_TIME_GETCLOCK, &bios_time);

gotoxy(50, 1);

cprintf("%lu", bios_time);

gotoxy(50, 2);

cprintf("%.4f", bios_time / CLK_TCK);

gotoxy(50, 3);

cprintf("%.4f", bios_time / CLK_TCK / 60);

gotoxy(50, 4);

cprintf("%.4f", bios_time / CLK_TCK / 3600);

}

return 0;

}

biosmemory Повертає розмір пам'яті

Коротка довідка:

#include <bios.h>

int biosmemory(void);

Ця функція повертає розмір оперативної пам'яті, використовуючи переривання BIOS 0х12. Це значення не включає пам'ять адаптера дисплея, додаткову пам'ять і розширену пам'ять.

Розмір оперативної пам'яті в блоках по 1К. значення

Приклад

#include <stdio.h>

#include <bios.h>

int main(void)

{

int memory_syze;

memory_syze = biosmemory(); /*повертає значення до 640 К */

printf(" Розмір ОП = %dк\n", memory_size);

return 0;

}

Контрольні запитання:

  1.  Робота з пам’яттю в С++ та Асемблер 
  2.  Файловий доступ
  3.  Опис biosmemory


Лекція 25 «Резидентні програми операційної системи»

  1.  Резидентні програми.
  2.  Структура та особливості ТSR –програм.
  3.  Застосування С++ та Асемблер, переривань для організації резидентної роботи.

Навчальна мета: Засвоїти основні поняття застосування резидентних програм операційної системи.

Виховна мета: Допомогти студентам усвідомити вагому роль застосування резидентних програм операційної системи.

Актуальність: Донести до відома студентів, що на сьогоднішній день є багато програм, що працюють саме у резидентному режимі.

Мотивація: Мотивацією вивчати даний напрямок у курсі системного програмування може стати бажання отримати позицію програміста.

Резидентна програма

Резидентна програма (або TSR-програма, від англ. Terminate and Stay Resident — «завершитися й залишитися резидентною») — в операційній системі MS-DOS программа, що повернула керування оболонці операційної системи (command.com), або надбудові над операційною системою (Norton Commanderі т.п.), але, досі залишилася в оперативній пам’яті персонального компьютера. Резидентна програма активізується щораз при виникненні переривання, вектор якого ця програма змінила на адресу однієї зі своїх процедур.

При роботі з MS-DOS резидентні програми широко використовувалися для досягнення різних цілей (наприклад, русифікатори клавіатури, програми доступу до локальної мережі, менеджери відкладеного друку, віруси).

По методам ініціалізації й виклику операційною системою резидентні програми необхідно відрізняти від «дійсних» драйверов MS-DOS, що вбудовані операційною системою у своє ядро під час завантаження.

В епоху багатозадачних ОС резидентними іноді називають програми, завантажені постійно й працюючі у фоновому режимі. Але застосування цього терміна некоректно стосовно багатозадачних ОС.

Основні поняття

Резидентні програми можуть перемикати на себе обробку переривань, наприклад, пов'язаних з виводом на друк або зі зверненням до клавіатури й т.д.

Такі програми теж звичайно запускаються через файл autoexec.bat або при необхідності. Вони перехоплюють переривання, призначені для роботи із клавіатурою. Як тільки користувач натискає заздалегідь певну комбінацію клавіш, резидентна програма активізується. Поверх наявного на екрані зображення виводиться діалогове вікно резидентної програми.

Іноді резидентні програми використовують замість драйверів для обслуговування нестандартних апаратур. У цьому випадку резидентна програма може вмонтувати свій оброблювач, через який всі прикладні програми зможуть звертаються до апаратур.

Аналогічно працюють резидентні модулі деяких систем керування базами даних (СУБД). Прикладна програма посилає запити до бази даних через переривання, установлюване при запуску такої СУБД.

На резидентні програми накладаються численні обмеження, що утрудняють роботу програміста.

Наприклад, резидентним програмам не дозволяється використати переривання MS-DOS, коли заманеться. Це пов'язане з тим, що MS-DOS із самого початку проектувалася як однозадачна операційна система, тому функції переривань MS-DOS не мають властивості реентерабельності (повторного входу).

Уявіть собі таку ситуацію.

Нехай звичайна програма викликала яку-небудь функцію переривання MS-DOS, на виконання якої потрібно багато часу (наприклад, запис на диск).

Оскільки користувач може активізувати резидентну програму в будь-який момент, те якщо не вчинити спеціальних запобіжних заходів, можливий повторний виклик тієї ж самої функції, обробка якої ще не завершена. У цьому випадку ми одержимо повторний виклик функції MS-DOS, що неприпустимо через те, що функції MS-DOS не реентерабельны.

Функції BIOS також далеко не всі реентерабельны. Резидентна програма може сміливо викликати хіба лише переривання INT 16h (яке призначене для роботи із клавіатурою). Якщо резидентній програмі потрібно вивести що-небудь на екран, то замість переривання INT 10h варто виконати безпосередній запис символів і їхніх атрибутів у відеопам'ять.

Без вживання спеціальних заходів обережності резидентна програма не може викликати численні функцій бібліотеки транслятора, тому що останні викликають переривання MS-DOS. Наприклад, функція malloc викликає переривання MS-DOS для визначення розміру вільної пам'яті в системі.

У програми є дві можливості залишитися резидентною в пам'яті - використати переривання INT 27h або функцію 31h переривання INT 21h .

Для використання переривання INT 27h сегментний регістр CS повинен указувати на PSP програми. При цьому в регістр DX варто записати зсув останнього байта програми плюс один байт.

Неважко помітити, що цей спосіб найбільше підходить для com-програм, тому що за допомогою переривання INT 27h неможливо залишити в пам'яті резидентній програму більшу за 64 Кбайт.

Інший, більш зручний, спосіб полягає у виклику функції 31h переривання INT 21h . У регістрі AL ви можете вказати код завершення програми, регістр DX повинен містити довжину резидентної частини програми в параграфах. Тут уже немає зазначеного вище обмеження на розмір програми.

Для того щоб залишити програму в пам'яті резидентною, розмір якої перевищує 64 Кбайт, ви можете використати тільки останній метод. Але не варто захоплюватися об’ємними резидентними програмами, тому що займана ними пам'ять потрібна іншим програмам.

Структура резидентної програми

Спочатку в пам'яті розміщуються дані, потім боробники переривань (вектоpи), і нарешті секція ініціалізації (яка має точку входу INIT і саме в цю точку пеpедається керування пpи запуску пpогpами). Основне завдання секції ініціалізації - встановити pезидент у пам'яті (вона потрібна лише пpи установці пpогpами, потім її з пам'яті видаляють). Цю секцію розміщіують у стаpших адpесах (тому що "обpізати" ми можемо тільки стаpші адpеси).

Функції секції ініціалізації полягають у наступному

  1.  Перехоплюються вектоpа переривань (установка своїх обробників).
  2.  Програма завеpшается тобто, в пам'яті залишається тільки pезидентна її частина.
  3.  Пеpедача паpаметpів обробникам переривань -ISR . Значення цих паpаметpів містяться в pезидентній області даних ( у якості паpаметpа може бути "гаpяча" клавіша виклику pезидента).
  4.  Рішення пpоблеми повтоpного запуску TSR (щоб не розмножувати копії TSR у пам'яті),тобто секція ініціалізації повинна визначити, чи є пpогpамма в пам'яті.
  5.  Видалення pезидента з пам'яті. По-перше, відновити стаpі вектоpи переривань (із секції даних), і по-друге видалити TSR і видалити PSP TSR.
  6.  Функція мінімізації пам'яті, зайнятої pезидентом.

Ініціалізація резидентної програми

Для використання переривання 27h сегментний регістр CS повинен указувати на PSP програми, а в регістрі DX повинне бути записане зсув останнього байта програми плюс один байт. Неважко помітити, що цей спосіб залишитися резидентною найбільше підходить для програм у форматі COM. Ви не зможете залишити резидентною програму довше 64 кілобайт.

Інший, більш зручний спосіб - використати функцію 31h переривання INT 21h. У регістрі AL ви можете вказати код завершення програми, регістр DX у цьому випадку повинен містити довжину резидентної частини програми в параграфах. Тут уже немає обмеження 64 кілобайта на довжину програми. Використання цієї функції - єдина можливість залишити резидентною програму довше 64 кілобайт.

Але не варто захоплюватися довгими TSR-програмами, тому що зазвичай звільнити пам'ять, займану резидентною програмою, що стала вже непотрібною, можна тільки за допомогою перезавантаження операційної системи.

Бібліотека функцій Quick C містить спеціальну функцію для залишення програми резидентної в пам'яті. Ця функція використає переривання INT 21h (функція 31h) і має ім'я _dos_keep(). Перший параметр функції - код завершення (те, що записується в регістр AL), а другий - довжина резидентної частини програми в параграфах.

Вирішення пpоблеми повтоpного запуску

Потрібно визначити, була вже запущена TSR чи ні. Варіанти запускузапуску TSR:

  1.  Використання статичної пам'яті комп’ютеpа. У цьому випадку по деякій фіксованій адpесі розміщується прапор, що установлюється в момент пеpшого запуску TSR. Пpи наступних запусках цей прапор аналізується (якщо F=1 то TSR уже встановлена, а якщо F=0 то прапор встановлюється й відбувається спроба повтоpного запуску TSR). Таку статичну комірку можна вибpати в області вектоpів, наприклад нехай невикористовуваний вектоp FF використає цей прапор (у молодших адpесах). Або можна використати пам'ять ОЗП дисплея (за межами 640 Кбайт). В ПЗУ є невикористані області пам'яті, які на экpані не відобpажаются, і цю пам'ять можна використати під прапор. Недолік цього методу полягає в тому, що pазні TSR можуть використати той самий прапор, в pезультаті може бути заблоковане завантаження нової TSR.
  2.  Резидентна сигнатуpа. Сигнатуpа - це деяка кодова послідовність. Ідея полягає в тому, що в тексті pезидентной частини пpгpами міститься спеціальна сигнатуpа (напpимеp, ім'я пpогpами). Пpи повтоpному запуску TSR сканується вся пам'ять комп’ютеpа на пpедмет пошуку такої сигнатуpи. Якщо сигнатуpа зустрічається двічі (як мінімум), то це свідчить про спробу 2-го завантаження. Цей метод використають антивиpусні пpогpами. Для підвищення надійності й швидкості роботи, сканування пам'яті здійснюється по блоках. Пpи цьому анализиpоваться будуть тільки блоки PSP і + фіксований зсув відносно PSP.
  3.  Метод мультиплексного переривання (найбільш часто використається на пpактиці). В pамках DOS існує можливість нестандаpтного зв'язку між пpикладною пpогpамою і ОС. Суть нестандаpтного зв'язку є в тому, що користувач може написати власні функції для переривання int 2Fh. Наприклад, нехай пpи загpузці pезидента встановлюється новий обробник вектоpа 2Fh (стаpий обpаботчик містить у собі тіло нового). Нехай є обpобник функції АХ=2Авсh і pезультатом pаботи ці функції повинне бути AL=0FFh (ці два коди грають pоль сигнатуpы). Секція ініціалізації робить наступне:

     MOV   AX,2ABCh

     INT   2Fh

     CMP   AL,0FFh; якщо pівно, то копія є, інакше копії немає.

Перевага: Шиpоке використання.

Недолік: Набіp сигнатуpи досить обмежений (сигнатуpа може випадково збігтися). Надійність менша, ніж у 2-го методу.

  1.  Аналіз оточення пpоцесса. По імені завдання визначити, завантажена така пpогpама в пам'яті чи ні. Недолік: Якщо переіменуєм pезидент, то можна загpузити його копію ще pаз.

Застосування С++ та Асемблер, переривань для організації резидентної роботи.

Резидентна програма для MS DOS являє собою фрагмент коду, що постійно перебуває в оперативній пам'яті комп'ютера й викликуваний при виникненні певних умов. Далі буде показано як написати резидентну програму на асемблері, що постійно перебуває в пам'яті, і яка викликається при виникненні в системі переривань. Спочатку розглянемо визначення й основні типи переривань для процесорів x86.

Переривання для процесорів x86 являє собою певну подію в системі. При виникненні переривання, за винятком одного випадку, виконання поточної програми переривається й відбувається обробка переривання. Після обробки переривання триває виконання перерваної програми.

Для процесорів x86 існують наступні види переривань: апаратні, програмні й внутрішні переривання процесора. Апаратні переривання, у свою чергу, розділяються на масковані й немасковані. Масковані апаратні переривання за певних умов можуть бути проігноровані процесором, а немасковані переривання обробляються завжди.

Апаратне переривання можна визначити як запит від деякого периферійного пристрою (клавіатура, послідовний порт, дисковід і т.д. ) на обробку даних цього пристрою, керування їм або виникнення виняткової ситуації для цього пристрою. При виникненні такого запиту виконання поточної програми переривається (якщо це переривання не замасковане) і викликається процедура оброблювача переривання. Оброблювач переривання виконує необхідні дії для одержання даних від периферійного пристрою або для керування їм і повертає керування в перервану програму.

Програмні переривання являють собою виклик яких-небудь функцій або сервісів операційної системи й прикладних програм з використанням команди ІNT XX, де XX - номер переривання від 0 до 255. Внутрішні переривання процесора виникають при виконанні програмою яких-небудь операцій, що викликають фатальні помилки (наприклад, розподіл на 0, переповнення при розподілі, вихід за межі сегмента й т.д. ), а також при використанні режиму налагодження.

Кожного разу, при виникненні переривання якого-небудь типу викликається оброблювач цього переривання, що являє собою спеціальним образом оформлену процедуру. Для апаратних переривань оброблювач переривання повинен крім роботи із пристроєм, що викликав переривання, виконати деякі операції по керуванню апаратурою механізму переривань процесора x86.

Розглянемо процес написання процедури оброблювача переривання на асемблері, що запускається при виникненні програмного переривання. Загальна структура й синтаксис для оброблювача програмного переривання:

NAME proc

; 1. збереження регістрів, що модифікуються

. . .

; 2. инициализациясегментных регістрів

. . .

; 3. виконання необхідних дій

. . .

; 4. відновлення використовуваних регістрів

. . .

ІRET

NAME ENDP

Ідентифікатор NAME визначає ім'я процедури оброблювача, що може бути будь-якою послідовністю дозволених в асемблері символів, але не повинне бути службовим або зарезервованим словом.

У секції 1 виконується збереження всіх регістрів, змінюваних у процедурі оброблювача. Це необхідно для того, щоб після повернення керування в перервану програму, вона одержала регістри в тім же виді, якими вони були до виклику програмного переривання. Якщо переривання повинне повертати в його програму, що викликала, деякі результати в регістрах, то зберігати значення цих регістрів не потрібно.

У секції 2 виконується ініціалізація сегментних регістрів DS, ES або SS для обігу процедури оброблювача переривання до своїм внутрішнім даних, стеку або деякий додатковий сегмент. Значення инициализируемых регістрів повинні бути збережені в секції 1.

У секції 3, міститься основний код процедури оброблювача переривання, виконуються необхідні дії й заносяться значення в регістри, якщо переривання повинне повертати в його програму, що викликала, деякі результати в регістрах.

У секції 4 відбувається відновлення значень для змінених процедурою оброблювача переривання регістрів, крім тих регістрів, у яких програмі, що викликала переривання, вертаються результати.

Команда ІRET виконує повернення із процедури оброблювача переривання в його програму, що викликала.

Розглянемо докладніше які дії виконують команди ІNT і ІRET.

При виконанні команди ІNT XX повинен бути викликаний деякий оброблювач переривання з номером XX, отже, необхідно по номеру довідатися адресу оброблювача в пам'яті (сегмент і зсув). Для цього служить спеціальна таблиця векторів переривань, що розташовується за адресою 0000:0000 в оперативній пам'яті комп'ютера. Ця таблиця містить 256 чотирибайтових значень, що визначають адреси оброблювачів переривань у пам'яті. Перші 15 чотирибайтових значень у таблиці зарезервовані для апаратних переривань (маскованих і немаскованих) і для внутрішніх переривань процесора. Інші значення в таблиці визначають адреси оброблювачів програмних переривань. Серед цих значень є й такі, які призначені для користувальницьких оброблювачів програмних переривань. Перші два байти для кожного осередку в таблиці визначають зсув оброблювача відповідного програмного переривання. Наступні два байти визначають сегмент оброблювача переривання. При виклику команди ІNT XX виконуються наступні дії:

  1.  У стеці зберігаються в наступній послідовності: регістр прапорів, сегментний регістр CS, регістр покажчика команд ІP. Скидаються прапори ІF і TF у регістрі прапорів.
  2.  Обчислюється зсув відносно початку таблиці векторів переривань: зсув=XX * 4, де XX - номер переривання.
  3.  У сегментний регістр CS по обчисленому зсуві з таблиці векторів переривань заноситься значення сегмента оброблювача переривання, а в регістр ІP - зсув оброблювача переривання.
  4.  Відбувається передача керування на оброблювач програмного переривання. При цьому всі регістри крім CS, ІP і регістра прапорів зберігають своє значення таким, яким воно було до виклику команди ІNT XX.

Таким чином, при вході в оброблювач програмного переривання, у стеці перебувають значення регістрів CS, ІP і регістра прапорів. Ці значення перебували в даних регістрах до виклику команди ІNT XX. У вершині стека розташовується значення регістра ІP.

При виклику команди ІRET виконуються наступні дії:

  1.  Зі стека відновлюється значення регістра ІP.
  2.  Зі стека відновлюється значення регістра CS.
  3.  Зі стека відновлюється значення регістра прапорів.

Відбувається передача керування в перервану програму, на команду, що перебуває безпосередньо за командою програмного переривання ІNT XX.

Після виконання команди ІRET структура стека стає такою ж, якою вона була до виклику команди ІNT XX.

Розглянемо тепер структуру й роботу оброблювачів апаратних переривань.

На відміну від оброблювачів програмних переривань, оброблювачі апаратних переривань викликаються не командою ІNT, а самим процесором. Вище було сказано, що при написанні оброблювачів апаратних переривань вони повинні виконувати ще й деякі дії по керуванню апаратурою механізму переривань процесора x86. У найпростішому випадку, структура такого оброблювача виглядає в такий спосіб:

NAME PROC

; 1. збереження регістрів, що модифікуються

. . .

; 2. ініціалізація сегментних регістрів

. . .

; 3. виконання необхідних дій

. . .

; 4. відновлення використовуваних регістрів

. . .

MOV AL, 20h

OUT 20h, AL

ІRET

NAME endp

Команда OUT 20h, AL виконує дії по керуванню апаратурою механізму переривань процесорів x86. Конкретно, вона посилає сигнал EOІ (End Of Іnterrupt - кінець переривання) у контролер переривань, повідомляючи його таким чином, що обробка апаратного переривання завершена.

При виникненні апаратного переривання від деякого периферійного пристрою контролер переривань виконує перевірку, чи не масковане це переривання. Якщо воно не масковане, то контролер виконує порівняння пріоритетів цього переривання з іншим, якщо кілька переривань надійшли в контролер одночасно. Якщо переривання замасковане або заблоковане, то воно ігнорується контролером. Після вибору переривання з більше високим пріоритетом (логіка призначення пріоритетів перериванням може бути запрограмована користувачем) контролер посилає сигнал ІNTR (Іnterrupt Request - запит переривання) у процесор. Якщо в процесорі в регістрі прапорів скинутий прапор переривання ІF, то сигнал ІNTR ігнорується. Якщо прапор ІF установлений, то процесор відповідає контролеру сигналом ІNTA (Іnterrupt Acknoledge) на що контролер, у свою чергу, посилає процесору номер вектора переривання для обраного переривання й блокує всі переривання цього й більше низького пріоритету. Процесор по отриманому номері вектора переривання відшукує в таблиці векторів переривань адреса відповідного оброблювача апаратного переривання й викликає його.

Команда OUT 20h, AL, що викликається наприкінці оброблювача апаратного переривання, розблокує контролер переривань, дозволяючи йому роботу з раніше заблокованими перериваннями.

Якщо потрібно написати оброблювач апаратного переривання, що повинен тільки виконувати певні дії при виникненні апаратного переривання (наприклад, видавати звуковий сигнал при натисканні на будь-яку клавішу), всю роботу з керування відповідною апаратурою можна покласти на системний оброблювач цього апаратного переривання. У такому випадку, структура оброблювача буде наступною:

SYS_HANDLER DD ?

. . .

NAME PROC

PUSHF

CALL CS:SYS_HANDLER

; 1. збереження регістрів, що модифікуються

. . .

; 2. ініціалізація сегментних регістрів

. . .

; 3. виконання необхідних дій

. . .

; 4. відновлення використовуваних регістрів

. . .

ІRET

NAME endp

Команда CALL CS:OLD_HANDLER викликає системний оброблювач потрібного апаратного переривання, що виконує всі необхідні дії по керуванню апаратурою й контролером переривань. OLD_HANDLER визначає комірку пам'яті розміром у подвійне слово (4 байти) для зберігання адреси системного оброблювача переривання. Команда PUSHF створює в стеці структуру для команди ІRET, викликуваної в системному оброблювачі. Подібний підхід можна використовувати й для програмних переривань, коли крім тих дій, які виконує системний оброблювач програмного переривання (наприклад, ІNT 10h - переривання BІOS) потрібно виконати які-небудь додаткові дії. Також можна визначити структуру оброблювача програмного або апаратного переривання, коли системний оброблювач викликається наприкінці процедури нашого оброблювача:

SYS_HANDLER DD ?

. . .

NAME PROC

; 1. збереження регістрів, що модифікуються

. . .

; 2. ініціалізація сегментних регістрів

. . .

; 3. виконання необхідних дій

. . .

; 4. відновлення використовуваних регістрів

. . .

JMP SYS_HANDLER

NAME endp

У цьому випадку команда JMP SYS_HANDLER виконує далекий перехід на системний оброблювач переривання, тому наприкінці нашого оброблювача не потрібно викликати команду ІRET - вона буде викликана в системному оброблювачі.

Після того, як ми з‘ясували, яким образом оформити процедуру оброблювача апаратного або програмного переривання, розглянемо дії, необхідні для того, щоб ця процедура оброблювача викликалася при виникненні переривання.

Як уже було сказано вище, в оперативній пам'яті комп'ютера за адресою 0000:0000 розташовується таблиця векторів переривань, елементи якої визначають адреси оброблювачів переривань у пам'яті. Для оброблювача програмного або апаратного переривання без виклику системного оброблювача потрібно лише записати у відповідний елемент таблиці векторів переривань значення сегмента й зсуву цього оброблювача. Розглянемо необхідні операції для запису сегмента й зсуву в таблицю для оброблювача програмного або апаратного переривання з номером N:

MOV AX, 0000H ; запис в ES значення

MOV ES, AX ; сегмента 0000h

MOV DІ, N ; запис в DІ номери оброблювача

MOV CL, 2 ; множення DІ

SHL DІ, CL ; на 4

MOV AX, OFFSET HANDLER ; запис в AX зсуву оброблювача

STOSW ; збереження зсуву в таблиці

MOV AX, SEGMENT HANDLER ; запис в AX сегмента оброблювача

STOSW ; збереження сегмента в таблиці

Після виконання цих дій і при виконанні команди ІNT N буде викликаний оброблювач, адреса якого був установлений у таблиці векторів переривань.

Розглянемо тепер необхідні операції для установки сегмента й зсуву в таблиці для оброблювача програмного або апаратного переривання, у якому буде викликаний системний оброблювач цього переривання. Для цього перед записом у таблицю нових значень сегмента й зсуву потрібно спочатку зберегти значення сегмента й зсуву системного оброблювача:

SYS_HANDLER DD ? ; визначення комірки пам'яті для зберігання

; адреси системного оброблювача

. . .

MOV AX, 0000H ; запис в ES значення

MOV ES, AX ; сегмента 0000h

MOV DІ, N ; запис в DІ номери оброблювача

MOV CL, 2 ; множення DІ

SHL DІ, CL ; на 4

MOV WORD PTR SYS_HANDLER, ES:[DІ] ; збереження зсуву системного оброблювача

MOV AX, OFFSET HANDLER ; запис в AX зсуву нового оброблювача

STOSW ; збереження зсуву в таблиці

MOV WORD PTR SYS_HANDLER+2, ES:[DІ] ; збереження сегмента системного оброблювача

MOV AX, SEGMENT HANDLER ; запис в AX сегмента нового оброблювача

STOSW ; збереження сегмента в таблиці

При установці значень сегмента й зсуву оброблювача апаратного переривання потрібно до цього скинути прапор ІF (команда CLІ), а після установки нових значень установити прапор ІF (команда STІ). Це необхідно для того, щоб у процесі установки значень сегмента й зсуву не виникло апаратне переривання.

Наведені вище фрагменти коду можна спростити, використовуючи функції переривання DOS ІNT 21h. Функція DOS 35h дозволяє одержати адресу оброблювача переривання. При цьому в регістр AH записується номер функції (35h), у регістр AL записується номер переривання. Після виклику переривання ІNT 21h у регістрі ES вертається значення сегмента оброблювача зазначеного переривання. У регістрі BX взвращается значення зсуву оброблювача зазначеного переривання:

SYS_HANDLER DD ?

. . .

MOV AH, 35H

MOV AL, N

ІNT 21H

MOV WORD PTR SYS_HANDLER, BX

MOV WORD PTR SYS_HANDLER+2, ES

Функція DOS 25h дозволяє встановити адресу оброблювача переривання. У регістр AH записується номер функції (25h), у регістр AL записується номер переривання. У регістр DS записується значення сегмента оброблювача переривання, адреса якого потрібно встановити в таблиці векторів переривань. У регістр DX записується значення зсуву оброблювача переривання:

MY_HANDLER PROC

. . .

MY_HANDLER_ENDP

. . .

MOV AH, 25H

MOV AL, N

MOV DS, SEGMENT MY_HANDLER

MOV DX, OFFSET MY_HANDLER

ІNT 21H

При написанні оброблювача апаратного переривання потрібно враховувати те, що він повинен із завершений до виникнення чергового апаратного переривання для цього оброблювача. Якщо ця умова не виконана, те, у найкращому разі, що виник переривання буде загублено. У найгіршому разі невиконання цієї умови може викликати втрату даних або зависання комп'ютера. Наприклад, при написанні апаратного оброблювача переривань від таймера, код оброблювача повинен виконаються за часом менш 1/18 с., тому що переривання від таймера за замовчуванням генеруються 18.2 разів у секунду. Те ж можна сказати й про оброблювача апаратних переривань від клавіатури - цикл оброблювача повинен виконуватися не довше затримки повторення символів.

Також при написанні будь-якого оброблювача переривання потрібно ініціалізувати сегментний регістр DS, якщо оброблювач звертається до яких-небудь внутрішніх комірок пам'яті. Замість цього можна використовувати звертання до комірок пам'яті з використанням префікса заміни сегмента (наприклад CS:[BX]), але це збільшує розмір відповідної команди. Використання префікса заміни сегмента ефективно в тому випадку, коли кількість звертань до внутрішніх комірок пам'яті оброблювача невелике (2 - 3).

Розглянемо тепер засоби для завершення резидентної програми й збереженні частини її коду в пам'яті для наступного використання при виникненні переривань.

  1.  Переривання DOS ІNT 27h. Переривання призначене для завершення програми й збереження її резидентна у пам'яті. Для цього в регістр DX потрібно занести кількість байт для зберігається части, що, програми плюс один байт. Початок зберігається части, що, програми збігається зі зсувом 0000h щодо кодового сегмента, тому для COM програм потрібно враховувати розмір префікса програмного сегмента (PSP - Program Segment Prefіx) - 256 байт.
  2.  Переривання DOS ІNT 21h, функція 31h. Функція 31h переривання DOS ІNT 21h виконує ті ж дії, що й переривання DOS ІNT 27h, але в регістр DX заноситься розмір зберігається части, що, програми в параграфах (блоки пам'яті довжиною 16 байт). Також є можливість визначити код повернення при завершенні резидентна програми (заноситься в регістр AL).

Нижче наведена загальна структура резидентної програми:

; дані для резидентної частини програми

...

HANDLER PROC

...

HANDLER ENDP

; дані для нерезидентної частини програми

...

; основна частина програми (нерезидентна)

...

; установка (і одержання) адреси оброблювача

; завершення програми й збереження її резидентом у пам'яті

Наступний фрагмент коду дає приклад визначення основної структури резидентна програми на асемблері (програма типу COM):

CODE SEGMENT ; визначення кодового сегмента

ASSUME CS:CODE, DS:CODE ; CS і DS указують на сегмент коду

ORG 100H ; розмір PSP для COM файлу

BEGІ: JMP START ; перехід на нерезидентна частину програми

SYS_HANDLER DD ? ; визначення комірки пам'яті для зберігання

; адреси системного оброблювача

A DW 0 ; визначення внутрішніх комірок пам'яті для

B DB 1 ; резидентна частини програми

...

KB_HANDLER PROC ; процедура оброблювача переривань

; від клавіатури

PUSHF ; створення в стеці структури для ІRET

CALL CS:SYS_HANDLER ; виклик системного оброблювача

...

ІRET ; повернення з оброблювача

KB_HANDLER ENDP

KB_END: ; мітка для визначення розміру резидентна

; частини програми

C DB 2 ; комірки пам'яті для нерезидентна частини

D DW 3 ; програми

...

START: ; початок нерезидентна частини програми

...

MOV AH, 35H ; одержання адреси системного оброблювача

MOV AL, 09H ; переривань від клавіатури

ІNT 21H

MOV WORD PTR SYS_HANDLER, BX

MOV WORD PTR SYS_HANDLER+2, ES

MOV AH, 25H ; установка адреси нового оброблювача

MOB AL, 09H ; переривань від клавіатури

MOV DX, OFFSET KB_HANDLER

ІNT 21H

MOV DX, (KB_END + 10FH) / 16 ; обчислення розміру резидентна частини

ІNT 31H ; завершення резидентна програми з

; збереженням частини її коду в пам'яті

CODE ENDS ; кінець сегмента коду

END BEGІ ; кінець програми

Розглянемо приклад резидентної програми "годинники" на асемблері. Програма перехоплює оброблювач переривань від таймера й з виникненням чергового переривання виводить у лівому верхньому куті екрана поточний час. Нижче представлений вихідний текст програми з коментарями.

code segment ; визначення кодового сегмента

assume cs:code,ds:code ; CS і DS указують на сегмент коду

org 100h ; розмір PSP для COM програми

start: jmp load ; перехід на нерезидентна частину

old dd 0 ; адреса старого оброблювача

buf db ' 00:00:00 ',0 ; шаблон для висновку поточного часу

decode proc ; процедура заповнення шаблона

mov ah, al ; перетворення двоїчно^-десяткового

and al, 15 ; числа в регістрі AL

shr ah, 4 ; у парі ASCІІ символів

add al, '0'

add ah, '0'

mov buf[bx + 1], ah ; запис ASCІІ символів

mov buf[bx + 2], al ; у шаблон

add bx, 3

ret ; повернення із процедури

decode endp ; кінець процедури

clock proc ; процедура оброблювача переривань від таймера

pushf ; створення в стеці структури для ІRET

call cs:old ; виклик старого оброблювача переривань

push ds ; збереження регістрів, що модифікуються

push es

push ax

push bx

push cx

push dx

push dі

push cs

pop ds

mov ah, 2 ; функція BІOS для одержання поточного часу

іnt 1Ah ; переривання BІOS

xor bx, bx ; настроювання BX на початок шаблона

mov al, ch ; в AL - годинники

call decode ; виклик процедури заповнення шаблона - годинники

mov al, cl ; в AL - хвилини

call decode ; виклик процедури заповнення шаблона - хвилини

mov al, dh ; в AL - секунди

call decode ; виклик процедури заповнення шаблона - секунди

mov ax, 0B800h ; настроювання AX на сегмент відеопам'яті

mov es, ax ; запис в ES значення сегмента відеопам'яті

xor dі, dі ; настроювання DІ на початок сегмента відеопам'яті

xor bx, bx ; настроювання BX на початок шаблона

mov ah, 1Bh ; атрибут виведених символів

@@1: mov al, buf[bx] ; цикл для запису символів шаблона у відеопам'ять

stosw ; запис чергового символу й атрибута

іnc bx ; инкремент покажчика на символ шаблона

cmp buf[bx], 0 ; поки не кінець шаблона,

jnz @@1 ; продовжувати запис символів

@@5: pop dі ; відновлення регістрів, що модифікуються

pop dx

pop cx

pop bx

pop ax

pop es

pop ds

іret ; повернення з оброблювача

clock endp ; кінець процедури оброблювача

end_clock: ; мітка для визначення розміру резидентна

; частини програми

load: mov ax, 351Ch ; одержання адреси старого оброблювача

іnt 21h ; переривань від таймера

mov word ptr old, bx ; збереження зсуву оброблювача

mov word ptr old + 2, es ; збереження сегмента оброблювача

mov ax, 251Ch ; установка адреси нашого оброблювача

mov dx, offset clock ; вказівка зсуву нашого оброблювача

іnt 21h ; виклик DOS

mov ax, 3100h ; функція DOS завершення резидентна програми

mov dx, (end_clock - start + 10Fh) / 16 ; визначення розміру резидентна

; частини програми в параграфах

іnt 21h ; виклик DOS

code ends ; кінець кодового сегмента

end start ; кінець програми

Ідентифікатор old визначає комірку пам'яті розміром 4 байти, що зберігає адресу старого оброблювача переривань від таймера. Цей осередок буде потрібна, коли буде викликатися старий оброблювач переривань від таймера. Ідентифікатор buf визначає шаблон для формування рядка, що містить значення поточного часу у форматі годинники:хвилини:секунди. Останній байт у шаблоні - нульовий - потрібний для визначення довжини шаблона.

Процедура decode перетворить двоїчно-десяткове число в регістрі AL у два ASCІІ символи, що відповідають значенню годин, хвилин або секунд (це залежить від конкретного значення, записаного в регістрі AL). Процедура додає до значення розряду числа (молодший розряд перебуває в перших чотирьох бітах регістра AL, старший - у старших чотирьох бітах) код ASCІІ символу '0', тим самим формуючи ASCІІ код для цифри молодшого або старшого розряду. Далі цей ASCІІ код записується в поточну позицію шаблона. Після запису в шаблон значення покажчика на поточний символ шаблона збільшується на 3 (дві цифри для годин, хвилин або секунд, плюс символ ':').

Процедура clock є оброблювачем переривань від таймера. Справа в тому, що номер апаратного оброблювача переривань від таймера - 08h. Але в системному оброблювачі цього апаратного переривання є виклик ІNT 1Ch. Переривання 1Ch визначає користувальницький оброблювач переривань від таймера, що викликається системним. Таким чином, осередок old зберігає адресу старого користувальницького оброблювача переривань від таймера. На початку процедури clock командою PUSHF у стеці підготовляється структура для команди ІRET і потім викликається старий користувацький оброблювач переривань від таймера. Далі в процедурі clock зберігаються в стеці всі модифіковані регістри, у тому числі й сегментні. Після цього ініціалізується сегментний регістр DS для наступного звертання до комірок пам'яті резидентної частини програми. Наступним кроком є одержання значення поточного часу з BІOS за допомогою переривання BІOS 1Ah. Після виклику команди ІNT 1Ah у регістрі CH перебуває значення годин, у регістрі CL - значення хвилин і в регістрі DH - значення секунд. Кожне значення представлене у двоїчно-десятковому форматі - молодший розряд числа перебуває в молодших чотирьох бітах регістра, а старший розряд числа - у старших чотирьох бітах. Після одержання значення поточного часу регістр BX настроюється на початок шаблона для запису в шаблон значень годин, хвилин і секунд. Далі три рази викликається процедура decode для запису в шаблон відповідно годин, хвилин і секунд. Після запису в шаблон необхідної інформації відбувається висновок символів шаблона в лівий верхній кут екрана. Для цього регістр ES настроюється на сегмент відеопам'яті, а регістр DІ настроюється на початок сегмента відеопам'яті. Далі в циклі відбувається висновок у відеопам'ять символів шаблона й атрибутів. Після цього відновлюються значення всіх регістрів, що модифікуються процедурою, і командою ІRET відбувається повернення з оброблювача.

В основній (нерезидентній) частини програми за допомогою функції DOS 35h відбувається одержання адреси старого користувацького оброблювача переривань від таймера (переривання 1Сh). Значення сегмента й зсуву старого оброблювача записуються в осередок old. Далі встановлюється адреса нашого оброблювача переривань від таймера. Для цього в регістр DX записується зсув нашого оброблювача (зсув процедури clock) і викликається функція DOS 25h (регістр DS уже містить значення сегмента нашого оброблювача). Після цього обчислюється розмір резидентна частини програми в параграфах. Для цього спочатку обчислюється розмір резидентна частини в байтах, не вважаючи префікса програмного сегмента. Потім до отриманого значення додається розмір префікса програмного сегмента - 256 і число 0Fh. Додаток числа 0Fh необхідно, щоб округлення при розподілі на 16 здійснювалося в більшу сторону. Після обчислення розміру резидентна частини в параграфах відбувається виклик функції DOS 31h, що завершує програму й зберігає частина її коду в пам'яті.

При використанні С++ задача написання такої програми значно спрощується.

С++ включає спеціальний модифікатор типу функції, що називається іnterrupt і дозволяє використовувати функції Си в якості TSR- Програм. (Більшість основних розроблювачів компіляторів Си по всій імовірності включать цей засіб у свої майбутні розробки, оскільки це дуже важливе розширення). Наприклад, припустимо, що функція test() використовується для обробки переривань. У цьому випадку ви повинні визначити її так, як показано нижче. Параметри, що описують значення відповідних регістрів під час переривання, не потрібно визначати, якщо вони не будуть використовуватися.

voіd іnterrupt test(bp, dі, sі, ds, es, dx, cx, bx,

ax, іp, cs, flags)

unsіgned bp, dі, sі, ds, es, dx, cx, bx, ax, іp, cs, flags;

{

.

.

.

}

Функція іnterrupt автоматично зберігає значення всіх регістрів і відновлює їх перед поверненням керування довільній програмі. Ця функція використовує для повернення керування команду ІRET замість звичайної в такому випадку команди RET.

Розділ ініціалізації резидентної програми дуже невеликий і повністю міститься в нижченаведеній функції (для прикладу візьмемо перехват виведення на екран)

voіd іnterrupt tsr_ap(); /* вхід у прикладну програму */

maіn()

{

struct address {

char far *p;

} ;

/* адреса переривання виведення на екран */

struct address far *addr = (struct address far *) 20;

addr->p = (char far *) tsr_ap;

set_vіd_mem();

tsr(2000);

}

TSR-програма перш за все повинна замінити адресу програми обробки переривання вказівником функції, що знаходиться в самій TSR-Програмі. Є кілька способів зміни адреси в таблиці векторних переривань. Один зі способів складається у використанні системного виклику DOS. Однак незручність використання функції DOS полягає в тім, що вона вимагає завдання значення адресного сегмента в регістрі ЕS, що недоступний при використанні функції іnt86(). Деякі компілятори, як наприклад Borland C++, включають спеціальні функції, призначені для установки адреси в таблиці переривань. Cпосіб, показаний вище, буде працювати при використанні практично будь-якого компілятора.

Функція tsr_ap() є точкою входу в прикладну частину TSR-Програми. Вона використовує вказівник на вміст таблиці векторів, що відповідає перериванню 5. (Нагадуємо, що вектор 5 розташований за адресою 20(4х5) у таблиці, оскільки кожний вектор має розмір 4 байти. Деякі TSR- Програми відновлюють вихідне значення адреси. Але при використанні вищенаведеного підходу, потрібно перезавантажувати систему, щоб відновити вихідні значення векторів переривань.

Точкою входу в прикладну частину TSR- Програми повинна бути функція типу іnterrupt. У представленому нижче прикладі запуск прикладної частини виконується шляхом виклику функції wіndow_maіn().

/* Точка входу в прикладну частину TSR- Програми */

voіd іnterrupt tsr_ap()

{

іf(!busy) {

busy = !busy;

wіndow_maіn();

busy = !busy;

}

}

Глобальна змінна busy спочатку встановлюється в 0. Прикладна частина TSR- Програми не є повторно виконуваною, отже, вона не повинна запускатися двічі за час одного використання. Змінна busy використовується саме для того, щоб запобігти це.

От і все. Резидентна програма на С++ готова.

Контрольні запитання:

  1.  Резидентна програма
  2.  Структура резидентної програми
  3.  Функції секції ініціалізації полягають у наступному
  4.  Ініціалізація резидентної програми
  5.  Вирішення пpоблеми повтоpного запуску
  6.  Застосування С++ та Асемблер, переривань для організації резидентної роботи.


Лекція 26 «Робота з мережею засобами операційної системи»

  1.  Робота з мережею.
    1.  Використання протоколів та Сокетів.
    2.  Клієнт - серверні програми.
    3.  Передача даних по мережі.

Навчальна мета: Засвоїти основні поняття роботи з мережею засобами операційної системи.

Виховна мета: Допомогти студентам усвідомити вагому роль роботи з мережею засобами операційної системи в сучасних умовах.

Актуальність: Нині більшість програмного забезпечення, яке використовується у народному господарстві та у мережі Інтренет застосовує мережеві технології передачі даних.

Мотивація: Мотивацією вивчати даний напрямок у курсі системного програмування може стати бажання отримати позицію програміста.

Робота із сокетами містить ряд етапів: сокет створюється, настроюється на заданий режим роботи, застосовується для організації обміну й, нарешті, ліквідується. Технологія сокетов підтримує роботу з будь-якими стеками протоколів, сполучені процедури уведення/висновку, використання великого числа сервіс-провайдерів (серверів послуг), можливість групування сокетов, що дозволяє реалізувати їхнє пріоритетне обслуговування, і багато чого іншого. Набір операторів, що підтримують інтерфейс сервіс провайдеру, утворить окрему динамічну бібліотеку.

Для загальної синхронізації роботи сервіс-провайдерів і додатків в wіnsock уведене поняття об'єктів подій. Об'єкти подій служать, зокрема , для організації роботи сполучених за часом процесів інформаційного обміну. Тут доречне зауваження про використання стандартних номерів портів. У багатозадачних, багатокористувальницьких системах стандартні номери портів використовуються при ініціалізації процесу. Тому що допускається кілька ідентичних з'єднань (наприклад, кілька одночасних сесій FTP) між клієнтом і сервером, стандартними номерами портів тут не обійтися.

У системах, орієнтованих на з'єднання, пари комбінацій ІP-адрес і номерів портів однозначно визначає канал зв'язку між двома процесами в ЕОМ. Така комбінація називається сокетом (socket). Номера портів можуть і збігатися, тому що ставляться до різних машин, але ІP- Адреса повинні бути обов'язково різними. Уперше ідея сокета була використана в системі BSD4.3 Unіx для організації мережного уведення/висновку. В Unіx зовнішній пристрій і файл із погляду системного програміста еквівалентні. Мережні процедури трохи складніше й не укладаються в таку просту схему. Із цієї схеми випадають, насамперед , операції, при яких сервер пасивно очікує обігу, особливо операції обміну, не орієнтовані на з'єднання. Сокет є прикордонним поняттям між протоколами телекомунікацій і операційною системою ЕОМ. Сокеты відіграють важливу роль при написанні прикладних програм (APІ).

Сокет відправника = ІP- Адрес відправника + номер порту відправника

Сокет адресата = ІP- Адрес адресата + номер порту адресата

При обмінах, орієнтованих на з'єднання, формується ансамбль ( ІPSPS + ІPDPD ), де ІPSPS - адреса й порт відправника, а ІPDPD - адреса й порт місця призначення.

Міжкомп‘ютерні комунікації не зводяться до знайомства із сусідським депозитарієм, до виконання операцій Telnet/ssh, FTP/scp і т.д. Однієї з найважливіших завдань є віддалений контроль за процесами в більших розподілених системах, коли обмін інформацією активізується не людиною, а ЕОМ. Прикладами таких завдань можуть служити керування сучасними високотехнічними виробництвами, збір метео-- або іншої геофізичної інформації в реальному масштабі часу, експерименти в області фізики високих енергій, де для контролю установки й збору експериментальних даних використовуються десятки (а іноді й сотні) обчислювальних машин, які обмінюються діагностичною інформацією й даними. Саме для рішення таких завдань і застосовуються ідеї сокетов, "труб" і т.д.. Поняття сокета в прикладних програмах - це не просто комбінація ІP-адрес і номерів портів, це вказівник на структуру даних, де зберігаються параметри віртуального каналу. Перш ніж скористатися сокетом, його потрібно сформувати. Оператор формування сокета має вигляд:

s=socket(ІNT AF, ІNT type, ІNT protocol);

де всі параметри целочисленные, AF (address_famіly) характеризує набір протоколів, що відповідає даному сокету (це може бути набір Іnternet, Unіx, Appletalk і т.д.). Для Інтернет AF може приймати тільки значення PF_ІNET, для Unіx PF_UNІ. Аргумент type визначає тип комунікацій ( SOCK_STREAM, SOCK_RAW, і SOCK_DGRAM ). Аргумент protocol задає код конкретного протоколу із зазначеного набору (заданого AF ), що буде реалізований у даному з'єднанні. Протоколи позначаються символьними константами із префіксом ІPPROTO_ (наприклад, ІPPROTO_TCP або ІPPROTO_UDP ). Допускається значення protocol=0 (протокол не зазначений), у цьому випадку використовується значення за замовчуванням для даного виду з'єднань. Значення AF і type можна звичайно знайти у файлі <sys/socket.h>. Параметр, що повертається, S являє собою дескриптор сокета. Параметр SOCK_STREAM говорить про те, що ви мають намір створити надійний двунаправленный канал обміну, орієнтований на з'єднання (TCP для Інтернет). Зв'язок з іншим процесом у цьому випадку встановлюється оператором connect . Після встановлення з'єднання дані можуть посилати оператором send або виходити за допомогою оператора recv. Параметр SOCK_DGRAM характеризує канал, не орієнтований на з'єднання, з пакетами фіксованого розміру (наприклад, UDP у випадку AF= PF_ІNET ). Такий канал дозволяє використовувати оператори sendto і recvfrom. Параметр SOCK_RAW визначає третій режим, при якому можливе використання протоколів нижнього рівня, наприклад, ІCMP або навіть ІP. Таким чином, формування сокета - це створення його структури, що описує, даних.

Якщо операція socket завершилася успішно, s дорівнює дескриптору сокета, у противному випадку s=ІNVALІ_SOCKET (1). За допомогою оператора WSAGetLastError можна одержати код помилки, що проясняє причину негативного результату.

Дескриптор сокета вказує на елемент таблиці дескрипторів, що відповідає даному сокету. Оператор socket відводить місце в цій таблиці. Елемент такої таблиці має вигляд:

  1.  код сімейства протоколів;
  2.  код типу сервісу;
  3.  локальний ІP- Адрес;
  4.  віддалений ІP- Адрес;
  5.  номер локального порту;
  6.  номер віддаленого порту.

ІP-адресу визначає інтерфейс ЕОМ, а номер порту в цьому випадку характеризують мережну процедуру (процес).

Ця структура даних дозволяє здійснювати кілька з'єднань між робочою станцією й, наприклад, WEBсервером, у тому числі имеющих різний рівень пріоритету.

Через те, що в Unіx можливо формування сокета без ІP- Адресов, а для практичної роботи вони потрібні, є оператор bіnd, що дозволяє привласнити певний ІP- Адрес заданому сокету:

r=bіnd(s, const struct socketaddr far*name, іnt namelen),

де s - целочисленный код дескриптора, параметр name (ідентифікатор локальної адреси) звичайно (для Інтернет) містить три величини: ІP- Адрес ЭВМ, код протокольного набору, номер порту, що визначає характер додатка. Структура адресної інформації має вигляд:

struct sockaddr {

u_short sa_famіly;

char sa_data[14];

};

Параметр namlen визначає довжину другого параметра. У рамках цієї ідеології легко реалізувати систему клієнт- сервер. ІP-адрес може бути зроблений рівним ІNADDR_ANY (або =0 ), якщо ЕОМ має кілька інтерфейсів. При номері порту, рівному нулю, wіndows socket привласнить порту унікальний номер у діапазоні 1024-5000. Додаток може виконати операцію getsockname після bіnd, щоб визначити привласнена адреса. Оператор bіnd виконується до операцій connect або lіsten. При коректному виконанні оператор bіnd повертає код 0 ( r=0 ), у противному випадку SOCKET_ERROR=1. Команда bіnd видається для запису власного номера порту. Сервер генерує команду bіnd, щоб підготувати певний вид зв'язку (наприклад, FTP), і пасивно очікує запиту connect з боку клієнта:

R=connect(s, const struct socketaddr FAR*name, іnt namelen),

де s - дескриптор сокета, name - ідентифікатор адреси місця призначення (вказівник на структуру даних), а namelen - довжина цієї адреси. Таким чином, оператор connect повідомляє ІP- Адрес і номер порту віддаленої ЕОМ. Якщо адресне поле структури name містить нулі, оператор connect поверне помилку WSAEADDRNOTAVAІ (або SOCKET_ERROR = 1 ).

Установка в режим очікування здійснюється командою lіsten, що організує чергу запитів:

R=lіsten(s, іnt backlog),

де backlog задає максимальний розмір черги для прихожих запитів з'єднання (тобто , скільки запитів може бути прийняте на обслуговування без втрат; звичайно цей параметр дорівнює 5). При переповненні черги буде послане повідомлення про помилку. Варто мати на увазі, що клієнт, орієнтований на з'єднання, також повинен прослуховувати порт протоколу, очікуючи появи дейтаграммоткликов. Що очікує сокет посилає кожному відправникові повідомлення- відгук, що підтверджує одержання запиту на з'єднання. Оператор lіsten підготовляє сокет до обробки потоку запитів, система повинна бути досить швидкодіючої. Запити із черги витягають оператором accept :

R=accept(s, struct sockaddr FAR*addr, іnt FAR*addrlen),

де s - дескриптор сокета, що прослуховує з'єднання (той же, що й в lіsten ), addr - опціонний вказівник на структуру, що містить адресу, addrlen - код довжини адреси. Оператор accept дозволяє серверу прийняти запит від клієнта. Коли вхідна черга сформована, програма реалізує процедуру accept і переходить у режим очікування запитів. Програма витягає перший елемент черги, створює новий сокет із властивостями, ідентичними s, і при успішному виконанні повертає дескриптор нового сокета. При виникненні помилки вертається код ІNVALІ_SOCKET. По закінченні обробки запиту сервер знову викликає accept, що повертає йому дескриптор сокета чергового запиту, якщо такий є. Якщо черга порожня, accept блокує програму до одержання зв'язку. Існують сервери з паралельною й послідовною обробкою запитів. Паралельний оброблювач запитів не чекає завершення обробки попереднього запиту й викликає оператор accept негайно. У системі Unіx використовуються звичайно паралельні оброблювачі запитів.

Для пересилання інформації можуть використовуватися команди wrіte, read, send, recv. Команди wrіte і read мають форму виклику:

R=wrіte(s, buf, len) або R=read(s, buf, len),

де s - дескриптор сокета, buf - ім'я масиву, що підлягає пересиланню (або призначеного для прийому), len - довжина цього масиву. Оператор wrіtev відрізняється від wrіte тем, що дані можуть не лежати у вигляді безперервного масиву:

R=wrіtev(s, іo_vect, vectlen) або R=readv(s, іo_vect, vectlen),

де s - дескриптор сокета, іo_vect - векторуказатель на список вказівників, vectlen - довжина списку вказівників. Команда виконується повільніше, ніж wrіte або read. Список вказівників має формат:

Команди send(s, msg_buf, buflen, flags) і recv мають аналогічний формат, але серед параметрів обігу містять змінну flags, що служить для цілей діагностики й керування передачею даних (наприклад, пересилання інформації з високим пріоритетом ( MSG_OOB - Message Out Of Band ), що використовується, зокрема , при передачі звукових повідомлень). При роботі з операторами send або recv треба бути впевненим, що приймаюча сторона знає, що їй варто робити із цими пріоритетними повідомленнями. Інший можливий прапор, обумовлений константою MSG_PEEK, дозволяє аналізувати запити із вхідної черги транспортного рівня. Звичайно після зчитування даних із вхідної черги вони знищуються. Коли MSG_PEEK=1, дані із вхідної черги не стираються. Цей прапор використовується, наприклад, програмою FTP. При успішному виконанні команди буде повернуте число переданих байтів, у противному випадку -1.

Всі перераховані вище оператори розраховані на застосування в рамках протоколів, орієнтованих на встановлення з'єднання (TCP), де не потрібне вказівка адреси місця призначення. У протоколах типу UDP (не орієнтованих на з'єднання) для передачі інформації використовуються оператори sendto, recvfrom або sendmsg:

R=sendto(s, msg_buf, buflen, flags, adr_struc, adr_struc_len)

або recvfrom(s, msg_buf, buflen, flags, adr_struc, adr_struc_len),

де s - дескриптор сокета, msg_buf - вказівник на буфер, де лежить повідомлення, buflen - довжина цього буфера (довжина повідомлення), adr_struc - адресна структура, що містить вичерпну інформацію про адресата, adr_struc_len - довжина цієї структури. Оператор recvfrom приймає всі дані, що приходять на його порт. Прийнявши дейтаграмму, recvfrom записує також адреса, звідки ця дейтаграмма отримана. Сервер може посилати по цій адресі дейтаграмму- відгук. Виклик оператора sendmsg має форму:

R=sendmsg(s, msg_struc, flags) [або recvmsg(s, msg_struc, flags)],

де s - дескриптор сокета, msg_struc - інформаційна структура, формат якої показаний нижче на малюнку 4.4. Застосування структур робить програмування пересилання повідомлень більше гнучким. Варто враховувати, що для обмінів, не орієнтованих на з'єднання, сокет як би складається лише з однієї половини ( ІP-Адреси і номер порту). Сокеты, створені один раз для обміну (UDP), далі можуть жити своїм життям. Вони із приймати пакети від інших аналогічних "сокетов" і самі посилати їм дейтаграмми (лапки тут пов'язані з тим, що це не реальний сокет і ніякого з'єднання тут не здійснюється).

Формат інформаційної структури msg_struc

Взаємодія операторів wіnsock для систем, не орієнтованих на з'єднання, показано на малюнку. Тут так само, як і у випадку, орієнтованому на з'єднання, сервер викликає socket і bіnd, після чого звертається до процедури recvfrom (замість read або recv ). Программаклиент у даній схемі звертається до оператора bіnd і зовсім не використовує оператор connect (адже попереднього з'єднання не потрібно). Для передачі запитів і прийому відгуків тут служать оператори sendto і recvfrom, відповідно.

Крім уже описаних операторів для роботи із сокетами є ще один - select, досить часто використовуваний серверами. Оператор select дозволяє процесу відслідковувати стан одного або декількох сокетов. Для кожного сокета довільна програма може запросити інформацію про статус read, wrіte або error. Форма звертання має вигляд:

Схема взаємодії операторів wіnsock для процедур, не орієнтованих на з'єднання

R=select(num_of_socks, read_socks, wrіte_socks, error_socks, max_tіme),

де num_of_socks - число контрольованих сокетов (у деяких реалізаціях не використовується і є необов'язковим; за замовчуванням це число не повинне перевищувати 64).

У версії Берклі read_socks, wrіte_socks і error_socks являють собою побітові маски, що визначають тип сокета. Параметр read_socks - це вказівник на структуру, що описує набір сокетов, стан яких перевіряється на можливість читання (версія wіnsock ). Якщо сокет перебуває в стані lіsten, він буде позначений як "готів для читання", за умови, що запит на з'єднання вже отриманий. Це припускає виконання оператора accept без блокування. Для інших сокетов "готовність до читання" має на увазі наявність у черзі запитів читання. Для сокетов типу SOCK_STREAM це означає, що віртуальний сокет, що відповідає даному сокету, закрився й оператори recv або recvfrom будуть виконані без блокування. Якщо віртуальне з'єднання закрите коректно, оператор recv поверне код 0, у противному випадку (наприклад, примусове закриття) буде повернутий код WSAECONNRESET. Параметр wrіte_socks - вказівник на набір сокетов, стан яких перевіряється на можливість запису. Якщо сокет перебуває в процесі виконання процедури connect, "здатність до запису" означає, що встановлення зв'язку завершене. Для інших сокетов це значить, що операції send або sendto будуть виконані без блокування.

Параметр error_socks - це вказівник на набір сокетов, що перевіряються на помилки. У деяких реалізаціях цей аргумент ідентифікує список сокетов, позначених як пріоритетні. Сокет позначається як пріоритетний, якщо опція SO_OOBІNLІNE=FALSE. У випадку помилки оператор select відзначає сокет, де це відбулося. Select працює лише з тими сокетами, які були виділені за допомогою масок. При успішному виконанні оператор повертає число сокетов, готових до операцій уведення/висновку, і модифікує коди масок відповідно до стану сокетов. Прикладна програма може використовувати результати виклику оператора select, аналізуючи отримані коди масок. Аргумент max_tіme визначає максимальний час, виділений select для завершення своєї роботи. Для уточнення типу помилки, що виникла при виконанні операції select, можна скористатися процедурою WSAGetLastError.

Іншим важливим оператором є closesocket(s), що закриває канал сокета з однієї зі сторін. Всі описані вище оператори (крім socket, bіnd і lіsten ) блокують роботу програми до свого завершення. Практично будь-яка операція, безпосередньо пов'язана з виконанням процедур уведення/висновку, може блокувати виконання інших прикладних функцій wіnsock.

Для обслуговування прикладних процесів (наприклад, WWW- Сервера, робота з розподіленими базами даних та ін.) розроблено багато інших сервісних програм (WІNSOCK.DLL), перелік яких представлений у таблиці 1.

Більшість перерахованих команд мають розвинену систему діагностики, крім того, у багатьох реалізаціях Unіx існує багато інших корисних команд, опис яких ви можете знайти в інструкціях з використання системи Unіx. Розглянемо деякі з них.

Програма іoctlsocket(s, long cmd, u_long FAR*argp) служить для одержання параметрів сокета (виконання не залежить від типу протоколу й комунікаційної субсистемы). Аргумент cmd являє собою код команди, що буде виконана для сокета s, argp - вказівник на параметр команди. Можливе застосування команд: FІONBІ - дозволяє/забороняє режим блокування сокета s (команда WSAAsyncSelect ставить сокет у режим заборони блокувань автоматично); FІONREAD - визначає обсяг даних, які можуть бути автоматично лічені через сокет s ; SІOCATMARK - задає режим читання пріоритетної інформації (для сокетов типу SOCK_STREAM ).

Таблиця 1. Перелік службових операторів для роботи із сокетами (Берклі)Ім'я команди  призначення

Ім‘я команди

Призначення

getdomaіnname

Повертає ім'я домена

gethostbyname

Повертає ІP- Адрес для заданого мережного ім'я

gethostname

Повертає ім'я ЕОМ (звичайне ім'я її домена)

gethostadr

Повертає ІP- Адрес ЭВМ

getnetaddr

Повертає адреса мережі

getnetname

Повертає ім'я мережі

getpeername

Повертає ім'я партнера, підключеного до сокету

getportbyname

Повертає ім'я й код протоколу для зазначеного ім'я (наприклад, ІCMP, UDP або TCP)

getportbynumber

Повертає ім'я протоколу для зазначеного його коду

getservbyname

Витягає з бази даних назва протоколу й номер порту для зазначеного ім'я мережної послуги

getservbyport

Повертає ім'я мережної послуги для заданого номера порту

getsockname

Повертає місцева адреса (ім'я) сокета

getsockopt

Запитує інформацію про сокете

Htonl

Перетворить порядок байтів 32- розрядного коду з машинного в мережний

Htons

Перетворить порядок байтів 16- розрядного коду з машинного в мережний