Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекції_СПр.docx
Скачиваний:
37
Добавлен:
21.08.2019
Размер:
947.09 Кб
Скачать
  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 основних етапів:

  • Визначення підтримки інструкції CPUІ.

  • Якщо вона підтримується - визначення інших параметрів.

  • Визначення тактової частоти.

Процесори підтримують інструкцію 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 відбувається в такий спосіб:

  • Маскуються всі переривання крім таймерного.

  • Робиться HLT.

  • Зчитується й зберігається значення лічильника.

  • Знову HLT.

  • Зчитується значення лічильника.

Різниця значень лічених у пунктах 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) відсотках випадків прочитаються нулі). Сам алгоритм має вигляд:

  • Ініціалізувати лічильник.

  • Зберегти в регістрі значення з пам'яті за адресою [лічильник]

  • Записати якесь тестове значення (наприклад, AAh)

  • Прочитати з пам'яті.

  • Відновити старе значення по цій адресі.

  • Зрівняти записане й прочитане значення

  • Якщо рівні - лічильник=лічильник+1, якщо немає - вихід із циклу.

  • JMP пункт 2

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

Цей метод породжує іншу проблему - у реальному режимі безпосередньо доступний тільки цей самий один мегабайт. Ця проблема вирішується шляхом застосування "нереального" режиму, він же Bіg real-mode.

Як відомо в процесорі кожний сегментний регістр має схованої або тіньові (shadow parts) частини в які в захищеному режимі кешується дескриптор сегмента, для програміста вони невидимі. У захищеному режимі ці частини обновляються щораз коли в сегментний регістр завантажується нове значення, у реальному ж режимі обновляються тільки поля базової адреси сегмента. Якщо в захищеному режимі створити сегмент із лімітом в 4Гб і завантажити в сегментний регістр такий селектор, після чого перемкнутися в реальний режим, і, не дотримуючись рекомендацій Інтел, залишити межу рівним 4Гб - значення ліміту сегмента збережеться, із 32-бітним зсувом. Алгоритм переходу в нереальний режим:

  • Створити дескриптор з базою рівну 0

  • Установити межа сегмента в 4Гб

  • Вийти у захищений режим

  • Перенести поточний селектор сегмента в який-небудь сегментний регістр

  • Повернутись у реальний режим

Після цих дій можна в реальному режимі використовувати конструкції типу:

мov ax,word ptr fs:[edx]

Де EDX може змінюватися від нуля до 4Гб не викликаючи ніяких виключень захисту (на даний момент в реальному режимі перевищення 64Кб викликає таке виключення) Фактично EDX=цільова адреса, оскільки база сегмента в FS=0.

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

В працях М.Гука й В.Юрова пишеться що в якості "нереального" сегментного регістра треба використовувати FS або GS тому що інші регістри часто перезавантажуються й процесор нібито скидає ліміт в 64Кб після перезавантаження сегментного регістра в реальному режимі. На практиці виявляється зовсім не так. Процесор не зачіпає поля лімітів у реальному режимі.

Щоб уникнути додаткових проблем розглянемо приклад з регістром FS.

Алгоритм:

  • Установити "нереальний режим"

  • Відкрити старші адресні лінії (GateA20)

  • Установити лічильник в 1048576 (1Mb)

  • Цикл запису- читання

  • Вивести значення лічильника

  • Закрити регістр A20

  • Вихід

Приклад лістингу:

.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 «Базова система введення-виведення для роботи з периферійними пристроями»