Перхватываем прерывание 08h


Содержание

Типы прерываний и источники возникновения запросов. Принципы обработки прерываний и флаговая логика микропроцессоров , страница 8

3.4.2. Программа работы

В процессе подготовки к выполнению работы написать и отладить следующие процедуры:

· вывода на экран строки символов прямым отображением в память, так как при использовании функций DOS или BIOS аппаратные прерывания, возникающие в случайные моменты времени, могут привести к разрушению операционной системы [13],

· преобразования байта информации, хранящегося в ОЗУ, в десятичный эквивалент в символьном виде.

Выполните следующие эксперименты по перехвату прерываний:

· Перехватите прерывание int 8h, предусмотрев в программе обработки передачу управления исходному обработчику. Для иллюстрации результата выведите в левом верхнем углу дисплея звездочку прямым отображением в память.

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

· Замените в обработчике прямое отображение в видеопамять на процедуру инкрементации счетчика прерываний от таймера так, чтобы по истечении одной секунды происходил вызов пользовательского прерывания int 060h. Перед возвратом из обработчика int 8 передайте управление исходному обработчику, чтобы не сбивать системные часы. Для иллюстрации результата в обработчик int 60h включите вывод на экран символа.

· Убедившись, что перехватывание аппаратного прерывания и вновь созданное собственное прерывание происходят успешно, замените процедуру вывода в int 60h на подсчет относительного времени с момента начала работы программы.

· Напишите программу вывода на экран времени работы вашей программы. Для этого в основную программу включите цикл, ограничивающий время работы. Функции коррекции времени удобнее выполнять в пользовательском прерывании int 60h, а функции преобразования в символьный вид и вывод на экран — в теле основной программы. Окончание цикла можно установить по значению относительного времени работы программы. Возможный алгоритм решения этой задачи приведен на рис. 3.9, 3.10

Рис. 3.9. Рекомендуемый алгоритм основной программы вывода времени работы программы

Рис. 3.10. Рекомендуемый алгоритм счета времени

· Используя свою программу, замаскируйте доступ к клавиатуре на 1 мин. Попробуйте «перезапустить» компьютер с «теплого старта».

· В основной программе замените функцию 25h прерывания DOS 21h установки вектора прерывания. Позаботьтесь о том, чтобы во время смены вектора аппаратного прерывания не произошло другое аппаратное прерывание.

· Исключите цикл, ограничивающий время работы вашей программы. Реализуйте возможность выхода из программы по «горячим клавишам». Для этого перехватите аппаратное прерывание от клавиатуры.

· Преобразуйте программу так, чтобы на экран выводились часы суточного времени. Для этого в начале основной программы примените вызов функции 2CH прерывания DOS 21h.

· Выполните индивидуальное задание, полученное у преподавателя.

3.4.3. Методические указания к работе

Режим прерываний в общей системе обмена информацией с периферийными устройствами

Обмен с ПУ может осуществляться двумя способами: по прерываниям и по прямому доступу к памяти (ПДП). Как правило, ПДП

применяется для поблочной передачи информации между ОЗУ и ВЗУ.

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

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

MS-DOS для программиста

5.3. Установка обработчиков прерываний

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

Перед тем как приступить к изменению векторов прерываний, функция tsrinit запрещает аппаратные прерывания, вызывая функцию _disable . После того как изменение векторов прерываний завершено, вызывается функция _enable , разрешающая обработку аппаратных прерываний:

Обработчики всех прерываний, за исключением прерывания INT 13h, составлены на языке С. Так как прерывание INT 13h возвращает результат выполнения операций в регистре флагов, соответствующий обработчик удобнее составить на языке ассемблера.

Расскажем подробно о том, какие вектора прерываний мы переопределяем и зачем.

Прерывание INT 1Ch

Прерывание INT 1Ch является программным и вызывается обработчиком аппаратного прерывания от таймера INT 08h приблизительно 18,2 раза в секунду.

Наша программа использует это прерывание, для того чтобы выводить в правом верхнем углу экрана мигающие символы «*» и «+». Такое мигание нужно только для индикации активности резидентной программы. Если индикация не требуется, вы можете не изменять соответствующий вектор прерывания и не предусматривать обработчик для этого прерывания.

Наш обработчик прерывания INT 1Ch называется new_int1c и имеет следующий вид:

Массив screen содержит дальние указатели на массив целых чисел, определенные следующим образом:

В первый элемент этого массива мы записываем указатель на область видеопамяти , соответствующую самой верхней строке экрана. Для цветного видеоконтроллера этот адрес равен B800h:0000h.

Для того чтобы символы не мигали слишком часто, обработчик прерывания INT 1Ch подсчитывает прерывания в статическом счетчике count. Если значение этого счетчика больше 2, выводится символ ‘*», если меньше — символ «+».

Перед тем как возвратить управление, функция new_int1c вызывает старый обработчик прерывания INT 1Ch , адрес которого хранится в переменной old_int1c. Для этого используется функция _chain_intr .

Прерывание INT 2Fh

Обработчик прерывания INT 2Fh , который встраивает наша программа, выполняет две функции.

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

Во-вторых, он нужен для выгрузки резидентной программы из памяти.

Исходный текст обработчика прерывания INT 2Fh представлен ниже:

Вызов прерывания INT 2Fh происходит при запуске нашей программы, а также и при запуске других резидентных программ. Регистр AH при этом должен содержать идентификатор резидентной программы. Для программы TSRDEMO мы выбрали идентификатор FFh, хотя никто не сможет гарантировать, что такой идентификатор уже не используется другой программой. Для надежности вы можете указать дополнительный идентификатор, например, в виде текстовой строки, адрес которой передается через другие регистры. Мы не стали этого делать для сокращения объема листинга программы.

Итак, если при вызове прерывания INT 2Fh регистр AH содержит значение FFh, наш обработчик прерывания считает, что вызов выполняет программа TSRDEMO.

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

Если этот код равен 0, прерывание INT 2Fh вызвано для проверки наличия программы TSRDEMO в памяти. В ответ обработчик возвращает в регистре AX значение 00FFh. Это и есть признак того, что программа TSRDEMO уже загружена в память и ее повторная загрузка невозможна.

Если же код равен 1, программа TSRDEMO была запущена с параметром u для выгрузки своей копии из памяти.

В этом случае обработчик прерывания INT 2Fh сохраняет в глобальной переменной ExitAddress адрес завершения, переданный обработчику в регистрах BX:DX. Затем проверяется флаг tsr_already_active, который установлен, если резидентная программа активна и ее в данный момент нельзя выгружать из памяти.

Далее обработчик разрешает аппаратные прерывания, которые были запрещены перед вызовом прерывания INT 2Fh для выгрузки, и предпринимает попытку выгрузить резидентную программу, вызывая функцию tsr_exit.

Заметим, что после выгрузки резидентной программы функция tsr_exit передает управление MS-DOS, а не возвращает его обратно в программу.

Попытка выгрузки программы может окончиться неудачно, если пользователь загрузил после программы TSRDEMO другую резидентную программу, изменившую вектора прерываний, для которых программа TSRDEMO установила свои обработчики. В этом случае наша программа «не знает», как восстановить вектора прерываний и не выгружается из памяти. Тем не менее, она блокирует свою работу, записывая в переменную tsr_already_active значение -FFFFh.

Подробнее процесс выгрузки резидентной программы будет рассмотрен позже.

Заметим, что если содержимое регистра AX при вызове прерывания INT 2Fh не равно FF00h или FF01h, наш обработчик прерывания передает управление по цепочке, вызывая для этого функцию _chain_intr .

Прерывание INT 09h

Аппаратное прерывание от клавиатуры INT 09h обрабатывается для того чтобы обнаружить комбинацию клавиш, предназначенную для активизации резидентной программы:

Когда программа уже активна, установлен флаг tsr_already_active. В этом случае наш обработчик прерывания передает управление по цепочке, вызывая старый обработчик.

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

Однако активизация во время обработки аппаратного прерывания от клавиатуры — не самое лучшее решение. Поэтому наш обработчик просто устанавливает флаг popup_while_dos_busy, который служит запросом на активизацию.

Активизация резидентной программы будет выполнена позднее, при обработке аппаратного прерывания INT 08h или прерывания INT 28h .

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

Прерывание INT 08h

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

Наша программа использует несколько возможностей для своей активизации. В частности, обработчик аппаратного прерывания таймера INT 08h периодически проверяет возможность активизации:

Прежде всего, проверяется флаг tsr_already_active. Этот флаг устанавливается, когда резидентная программа уже активизирована. Проверка флага активизации позволяет избежать повторной активизации, которая может привести к катастрофе.

Активизация не выполняется также и в том случае, если установлен флаг InDos или unsafe_flag (последний устанавливается, если вызван обработчик прерывания INT 13h ).

Флаг popup_while_dos_busy установлен в том случае, когда был запрос на активизацию. Он устанавливается обработчиком аппаратного прерывания от клавиатуры INT 08h . Если запроса на активизацию нет, этот флаг не установлен и, следовательно, активизацию выполнять не нужно.

Если активизация возможна, сбрасываются флаги popup_while_dos_busy и устанавливается флаг tsr_already_active. Затем вызывается старый обработчик прерывания INT 08h и разрешаются прерывания.

Далее вызывается функция activate_tsr, которая выполняет все действия, необходимые для активизации. Она будет описана отдельно. После возвращения управления из этой функции флаг tsr_already_active сбрасывается.

В том случае, когда активизация резидентной программы невозможна, наш обработчик прерывания INT 08h вызывает старый обработчик и возвращает управление прерванной программе.

Прерывание INT 28h

Прерывание INT 28h вызывается MS-DOS, когда она ожидает ввод данных от клавиатуры или, иными словами, ничем особенным не занята. Поэтому обработчик прерывания INT 28h может активизировать резидентную программу, если на это есть запрос от пользователя.


Приведем исходный текст обработчика прерывания INT 28h :

Обработчик прерывания INT 28h содержит счетчик рекурсивных вызовов int_28_in_progress, который анализируется при активизации резидентной программы функцией activate_tsr.

Если есть запрос на активизацию, проверяются флаги tsr_already_active и unsafe_flag. Дополнительно проверяется, не выполняется ли попытка активизировать резидентную программу во время обработки прерывания MS-DOS, отличного от INT 28h . Для этого вызывается функция Int28DosBusy.

Обратите внимание на различие в способе проверки возможности активизации при обработке прерывания INT 08h и INT 28h .

В первом случае вызывается функция DosBusy:

Эта функция проверяет содержимое флагов InDos и флага обработки критической ошибки. Если MS-DOS не выполняет обработку критической ошибки и если прерываемая программа не вызывает функцию MS-DOS, можно выполнять активизацию. В этом случае функция DosBusy возвращает значение 0.

Однако при вызове прерывания INT 28h флаг InDos установлен всегда, так как указанное прерывание — это тоже прерывание MS-DOS. В данном случае для проверки возможности активизации используется другая функция, которая называется Int28DosBusy.

Эта функция допускает однократный (не рекурсивный) вызов функции INT 28h , проверяя значение, которое записывается в байт памяти, отведенный для флага InDos:

При рекурсивных вызовах функций MS-DOS значение, хранящееся в этом байте, увеличивается на 1. Активизация резидентной программы допускается только в том случае, когда в этом байте находится значение 1, т. е. когда нет рекурсии.

Обработчик прерывания INT 28h активизирует резидентную программу точно таким же способом, что и обработчик прерывания INT 08h , а именно, вызывая специально предназначенную для активизации функцию activate_tsr, определенную в нашей программе.

Прерывание INT 13h

Обработчик прерывания INT 13h составлен на языке ассемблера. Его единственное назначение — увеличение значения флага unsafe_flag при каждом вызове прерывания INT 13h и уменьшение при возврате из этого прерывания. Когда программа TSRDEMO будет предпринимать попытку активизации во время обработки прерывания INT 13h, она проверит значение флага unsafe_flag. Если оно не будет равно 0, активизация невозможна, так как в данный момент времени выполняется обработка прерывания INT 13h.

Исходный текст обработчика прерывания INT 13h представлен ниже:

Для обеспечения возможности адресации глобальной переменной unsafe_flag регистр DS устанавливается на сегмент данных программы TSRDEMO.

Адрес старого обработчика прерывания INT 13h находится в переменной old_int13, куда он записывается функцией get_int_13. Эта функция вызывается из функции tsrinit. Ее исходный текст вы найдете в листинге 5.3 (см. ниже).

Перехват прерываний

Перехват прерываний в работе процессора во время выполнении текущей программы. Типы и особенности развития данных ситуаций. Практические примеры обработчика программного прерывания. Определение значения нескольких векторов, установление нового значения.

Рубрика Программирование, компьютеры и кибернетика
Вид контрольная работа
Язык русский
Дата добавления 13.08.2011
Размер файла 81,9 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

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

Размещено на http://www.allbest.ru/

Размещено на http://www.allbest.ru/

1. Перехват прерываний

В архитектуре процессоров 80×86 предусмотрены особые ситуации, когда процессор прекращает (прерывает) выполнение текущей программы и немедленно передает управление программе-обработчику, специально написанной для обработки этой конкретной ситуации. Такие особые ситуации делятся на два типа: прерывания и исключения, в зависимости от того, вызвало ли эту ситуацию какое-нибудь внешнее устройство или выполняемая процессором команда. Исключения делятся далее на три типа: ошибки, ловушки и остановы, в зависимости от того, когда по отношению к вызвавшей их команде они происходят. Ошибки происходят перед выполнением команды, так что обработчик такого исключения получит в качестве адреса возврата адрес ошибочной команды (начиная с процессоров 80286), ловушки происходят сразу после выполнения команды, так что обработчик получает в качестве адреса возврата адрес следующей команды, и наконец, остановы могут происходить в любой момент и вообще не предусматривать средств возврата управления в программу.

Команда INT (а также INTO и INT3) используется в программах как раз для того, чтобы вызывать обработчики прерываний (или исключений). Фактически они являются исключениями ловушки, поскольку адрес возврата, который передается обработчику, указывает на следующую команду, но так как эти команды были введены до разделения особых ситуаций на прерывания и исключения, их практически всегда называют командами вызова прерываний. Ввиду того, что обработчики прерываний и исключений в DOS обычно не различают механизм вызова, с помощью команды INT можно передавать управление как на обработчики прерываний, так и исключений.

Когда в реальном режиме выполняется команда INT, управление передается по адресу, который считывается из специального массива, таблицы векторов прерываний, начинающегося в памяти по адресу 0000h:0000h. Каждый элемент этого массива представляет собой дальний адрес обработчика прерывания в формате сегмент: смещение или 4 нулевых байта, если обработчик не установлен. Команда INT помещает в стек регистр флагов и дальний адрес возврата, поэтому, чтобы завершить обработчик, надо выполнить команды popf и retf или одну команду iret, которая в реальном режиме полностью им аналогична.

; Пример обработчика программного прерывания

int_handler proc far

После того как обработчик написан, следующий шаг — привязка его к выбранному номеру прерывания. Это можно сделать, прямо записав его адрес в таблицу векторов прерываний, например так:

push 0; сегментный адрес таблицы

pushf; поместить регистр флагов в стек

cli; запретить прерывания

; (чтобы не произошло аппаратного прерывания между следующими

; командами, обработчик которого теоретически может вызвать INT 87h

; в тот момент, когда смещение уже будет записано, а сегментный

; адрес еще нет, что приведет к передаче управления

; в неопределенную область памяти)

; поместить дальний адрес обработчика int_handler в таблицу

; векторов прерываний, в элемент номер 87h (одно из неиспользуемых прерываний)

mov word ptr es: [87h*4], offset int_handler

mov word ptr es: [87h*4+2], seg int_handler

popf; восстановить исходное значение флага IF

Теперь команда INT 87h будет вызывать наш обработчик, то есть приводить к записи 0 в регистр АХ.

Перед завершением работы программа должна восстанавливать все старые обработчики прерываний, даже если это были неиспользуемые прерывания типа 87h — автор какой-нибудь другой программы мог подумать точно так же. Для этого надо перед предыдущим фрагментом кода сохранить адрес старого обработчика, так что полный набор действий для программы, перехватывающей прерывание 87h, будет выглядеть следующим образом:

; скопировать адрес предыдущего обработчика в переменную old_handler

mov eax, dword ptr es: [87h*4]

mov dword ptr old_handler, eax

; установить наш обработчик

mov word ptr es: [87h*4], offset int_handler

mov word ptr es: [87h*4+2], seg int_handler

; восстановить предыдущий обработчик

mov eax, word ptr old_handler

mov word ptr es: [87h*4], eax

Хотя прямое изменение таблицы векторов прерываний и кажется достаточно удобным, все-таки это не лучший подход к установке обработчика прерывания, и пользоваться им следует только в случаях крайней необходимости, например внутри обработчиков прерываний. Для обычных программ DOS предоставляет две системные функции: 25h и 35h — установить и считать адрес обработчика прерывания, которые и рекомендуются к использованию в обычных условиях:

; скопировать адрес предыдущего обработчика в переменную old_handler

mov ax, 3587h; АН = 35h, AL = номер прерывания

int 21h; функция DOS: считать

; адрес обработчика прерывания

mov word ptr old_handler, bx; возвратить

mov word ptr old_handler+2, es; и сегментный

; установить наш обработчик

mov ax, 2587h; АН = 25h, AL = номер прерывания

mov dx, seg int_handler; сегментный адрес

mov dx, offset int_handler; смещение в DX

int 21h; функция DOS: установить

; (не забывайте, что ES изменился после вызова функции 35h!)

; восстановить предыдущий обработчик

lds dx, old_handler; сегментный адрес в DS и смещение в DX

mov ax, 2587h; АН = 25h, AL = номер прерывания

int 21h; установить обработчик

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

; находит минимальное и максимальное значения в массиве слов


; Ввод: DS:BX = адрес начала массива

; СХ = число элементов в массиве

; АХ = максимальный элемент

ВХ = минимальный элемент

minmax proc near

; установить наш обработчик прерывания 5

mov еах, dword ptr es: [5*4]

mov dword ptr old_int5, eax

mov word ptr es: [5*4], offset int5_handler

mov word ptr es: [5*4]+2, cs

; инициализировать минимум и максимум первым элементом массива

mov ax, word ptr [bx]

mov word ptr lower_bound, ax

mov word ptr upper_bound, ax

mov di, 2; начать со второго элемента

mov ax, word ptr [bx] [di]; считать элемент в АХ

bound ax, bounds; команда BOUND вызывает

; исключение — ошибку 5,

; если АХ не находится в пределах lower_bound/upper_bound

add di, 2; следующий элемент

loop bcheck; цикл на все элементы

; восстановить предыдущий обработчик

mov eax, dword ptr old_int5

mov dword ptr es: [5*4], eax

mov ax, word ptr upper_bound

mov bx, word ptr lower_bound

; обработчик IT 5 для процедуры minmax

; сравнить АХ со значениями upper_bound и lower_bound и копировать

; AX в один из них, обработчик не обрабатывает конфликт между

; исключением BOUND и программным прерыванием распечатки экрана INT 5.

; Нажатие клавиши PrtScr в момент работы процедуры minmax приведет

; к ошибке. Чтобы это исправить, можно, например, проверять байт,

; на который указывает адрес возврата, если это CDh

; (код команды INT), то обработчик был вызван как INT 5

int5_handler proc far

cmp ax, word ptr lower_bound; сравнить АХ с нижней границей,

jl its_lower; если не меньше —

; это было нарушение

mov word ptr upper_bound, ax; верхней границы

mov word ptr lower_bound, ax; если это было нарушение

iret; нижней границы

Прерывания от внешних устройств, или аппаратные прерывания — это то, что понимается под термином «прерывание». Внешние устройства (клавиатура, дисковод, таймер, звуковая карта и т.д.) подают сигнал, по которому процессор прерывает выполнение программы и передает управление на обработчик прерывания. Всего на персональных компьютерах используется 15 аппаратных прерываний, хотя теоретически возможности архитектуры позволяют довести их число до 64.

Рассмотрим их кратко в порядке убывания приоритетов (прерывание имеет более высокий приоритет, и это означает, что, пока не завершился его обработчик, прерывания с низкими приоритетами будут ждать своей очереди).

IRQ0 (INT 8) — прерывание системного таймера. Это прерывание вызывается 18,2 раза в секунду. Стандартный обработчик этого прерывания вызывает INT 1Ch при каждом вызове, так что, если программе необходимо только регулярно получать управление, а не перепрограммировать таймер, рекомендуется использовать прерывание 1Ch.

IRQ1 (INT 9) — прерывание клавиатуры. Это прерывание вызывается при каждом нажатии и отпускании клавиши на клавиатуре. Стандартный обработчик этого прерывания выполняет довольно много функций, начиная с перезагрузки по Ctrl-Alt-Del и заканчивая помещением кода клавиши в буфер клавиатуры BIOS.

IRQ2 — к этому входу на первом контроллере прерываний подключены аппаратные прерывания IRQ8 — IRQ15, но многие BIOS перенаправляют IRQ9 на INT 0Ah.

IRQ8 (INT 70h) — прерывание часов реального времени. Это прерывание вызывается часами реального времени при срабатывании будильника и если они установлены на генерацию периодического прерывания (в последнем случае IRQ8 вызывается 1024 раза в секунду).

IRQ9 (INT 0Ah или INT 71h) — прерывание обратного хода луча. Вызывается некоторыми видеоадаптерами при обратном ходе луча. Часто используется дополнительными устройствами (например, звуковыми картами, SCSI-адаптерами и т.д.).

IRQ10 (INT 72h) — используется дополнительными устройствами.

IRQ11 (INT 73h) — используется дополнительными устройствами.

IRQ12 (INT 74h) — мышь на системах PS используется дополнительными устройствами.

IRQ13 (INT 02h или INT 75h) — ошибка математического сопроцессора. По умолчанию это прерывание отключено как на FPU, так и на контроллере прерываний.

IRQ14 (INT 76h) — прерывание первого IDE-контроллера «операция завершена».

IRQ15 (INT 77h) — прерывание второго IDE-контроллера «операция завершена».

IRQ3 (INT 0Bh) — прерывание последовательного порта COM2 вызывается, если порт COM2 получил данные.

IRQ4 (INT 0Ch) — прерывание последовательного порта СОМ1 вызывается, если порт СОМ1 получил данные.

IRQ5 (INT 0Dh) — прерывание LPT2 используется дополнительными устройствами.

IRQ6 (INT 0Eh) — прерывание дисковода «операция завершена».

IRQ7 (INT 0Fh) — прерывание LPT1 используется дополнительными устройствами.

Самые полезные для программ аппаратные прерывания — прерывания системного таймера и клавиатуры. Так как их стандартные обработчики выполняют множество функций, от которых зависит работа системы, их нельзя заменять полностью, как мы делали это с обработчиком INT 5. Следует обязательно вызвать предыдущий обработчик, передав ему управление следующим образом (если его адрес сохранен в переменной old_handler, как в предыдущих примерах):

Эти две команды выполняют действие, аналогичное команде INT (сохранить флаги в стеке и передать управление подобно команде call), так что, когда обработчик завершится командой IRET, управление вернется в нашу программу. Так удобно вызывать предыдущий обработчик в начале собственного. Другой способ — простая команда jmp:

приводит к тому, что, когда старый обработчик выполнит команду IRET, управление сразу же перейдет к прерванной программе. Этот способ применяют, если нужно, чтобы сначала отработал новый обработчик, а потом он передал бы управление старому.

Посмотрим, как работает перехват прерывания от таймера на следующем примере:

; демонстрация перехвата прерывания системного таймера: вывод текущего времени

; в левом углу экрана

186; для pusha/popa и сдвигов

start proc near

; сохранить адрес предыдущего обработчика прерывания 1Ch

mov ax, 351Ch; АН = 35h, AL = номер прерывания

int 21h; функция DOS: определить адрес обработчика

mov word ptr old_int1Ch, bx; прерывания


mov word ptr old_int1Ch+2, es; (возвращается в ES:BX)

; установить наш обработчик

mov ax, 251Ch; АН = 25h, AL = номер прерывания

mov dx, offset int1Ch_handler; DS:DX — адрес обработчика

int 21h; установить обработчик прерывания 1Ch

; здесь размещается собственно программа, например вызов command.com

int 21h; ожидание нажатия на любую клавишу

; восстановить предыдущий обработчик прерывания 1Ch

mov ax, 251Ch; АН = 25h, AL = номер прерывания

mov dx, word ptr old_int1Ch+2

mov dx, word ptr cs:old_int1Ch; DS:DX — адрес обработчика

old_int1Ch dd?; здесь хранится адрес предыдущего обработчика

start_position dw 0; позиция на экране, в которую выводится текущее время

; обработчик для прерывания 1Ch

; выводит текущее время в позицию start_position на экране

; (только в текстовом режиме)

int1Ch_handler proc far

pusha; обработчик аппаратного прерывания

push es; должен сохранять ВСЕ регистры

push cs; на входе в обработчик известно только

pop ds; значение регистра CS

mov ah, 02h; Функция 02h прерывания 1Ah:

int 1Ah; чтение времени из RTC,

jc exit_handler; если часы заняты — в другой раз

; AL = час в BCD-формате

call bcd2asc; преобразовать в ASCII,

mov byte ptr output_line[2], ah; поместить их в

mov byte ptr output_line[4], al; строку output_line

mov al, cl; CL = минута в BCD-формате

mov byte ptr output_line[10], ah

mov byte ptr output_line[12], al

mov al, dh; DH = секунда в BCD-формате

mov byte ptr output_line[16], ah

mov byte ptr output_line[18], al

mov cx, output_line_l; число байт в строке — в СХ

pop es; адрес в видеопамяти

mov di, word ptr start_position; в ES:DI

mov si, offset output_line; адрес строки в DS:SI

rep movsb; скопировать строку

pop ds; восстановить все регистры

jmp cs:old_int1Ch; передать управление предыдущему обработчику

; преобразует старшую цифру упакованного BCD-числа из AL в ASCII-символ,

; который будет помещен в АН, а младшую цифру — в ASCII-символ в AL

bcd2asc proc near

and al, 0Fh; оставить младшие 4 бита в AL

shr ah, 4; сдвинуть старшие 4 бита в АН

or ах, 3030h; преобразовать в ASCII-символы

; строка «00h 00:00» с атрибутом 1Fh (белый на синем) после каждого символа

output_line db ‘ ‘, 1Fh, ‘0’, 1Fh, ‘0’, 1Fh, ‘h’, 1Fh

db ‘ ‘, 1Fh, ‘0’, 1Fh, ‘0’, 1Fh, ‘:’, 1Fh

db ‘0’, 1Fh, ‘0’, 1Fh, ‘ ‘, 1Fh

output_line_l equ $ — output_line

Если в этом примере вместо ожидания нажатия на клавишу поместить какую-нибудь программу, работающую в текстовом режиме, например tinyshell из главы 1.3, она выполнится как обычно, но в правом верхнем углу будет постоянно показываться текущее время, то есть такая программа будет осуществлять два действия одновременно. Именно для этого и применяется механизм аппаратных прерываний — они позволяют процессору выполнять одну программу, в то время как отдельные программы следят за временем, считывают символы из клавиатуры и помещают их в буфер, получают и передают данные через последовательные и параллельные порты и даже обеспечивают многозадачность, переключая процессор между разными задачами по прерыванию системного таймера.

Разумеется, обработка прерываний не должна занимать много времени: если прерывание происходит достаточно часто (например, прерывание последовательного порта может происходить 28 800 раз в секунду), его обработчик обязательно должен выполняться за более короткое время. Если, например, обработчик прерывания таймера будет выполняться 1/32,4 секунды, то есть половину времени между прерываниями, вся система будет работать в два раза медленнее. А если еще одна программа с таким же долгим обработчиком перехватит это прерывание, система остановится совсем. Именно поэтому обработчики прерываний принято писать исключительно на ассемблере.

Пусть у нас есть собственный обработчик программного прерывания, который вызывают обработчики двух аппаратных прерываний, и пусть эти аппаратные прерывания произошли сразу одно за другим. В этом случае может получиться так, что второе аппаратное прерывание осуществится в тот момент, когда еще не закончится выполнение нашего программного обработчика. В большинстве случаев это не приведет ни к каким проблемам, но, если обработчик обращается к каким-либо переменным в памяти, могут произойти редкие, невоспроизводимые сбои в его работе. Например, пусть в обработчике есть некоторая переменная counter, используемая как счетчик, считающий от 0 до 99:

mov al, byte ptr counter; считать счетчик в AL,

cmp al, 100; проверить его на переполнение,

Учим систему страничной адресации и обработке прерываний

Приветствую. Сегодня поговорим обо всём понемногу. Введём в нашу наработку paging, разберёмся с прерываниями и их видами. Напишем несколько функций, добавим сие в код из предыдущего поста.

1) Paging.
Все, наверно, уже покопались в манах и знают, что за лепота этот paging. Вырываемся за пределы 1 Мб и можем адресовать все 4 гигабайта оперативки. Но зачем нам в нашей скромной поделке 4 Гб (тем более что не у всех есть столько RAM’а). Нам вполне будет достаточно 32Мб (ну, это тоже очень много, но давайте помечтаем). Итак, будем использовать 4Кб’айтные страницы. Так, теперь считаем – 1024 страницы описывают 4Мб. Нам, значит, нужно всего-то 1024*8 страниц. Иными словами нужно завести 8 таблиц и 1 каталог. Ещё, для удобства, страницы будут тождественными т.е логический и физический адреса совпадают. Теперь, давайте напишем функцию, которая сформирует всё необходимое.

.set_cat:
mov edi,100000h;базовый адрес директории
mov eax,101007h;базовый адрес таблицы страниц и флаги

mov cx,8 ;8*4Мб=32Мб

.fill_cat_usef: ;опишем таблицы страниц
stosd
add eax,1000h
loop .fill_cat_usef

mov cx,1016 ;а остальное забьём нулями
xor eax,eax

mov eax,00000007h
mov ecx,1024*8;32Mb

.fill_page_table: ;теперь опишем страницы
stosd
add eax,1000h
loop .fill_page_table

;End;
mov eax,00100000h;1 Mb;и установим базовый адрес первого каталога в cr3
mov cr3,eax
mov eax,cr0
or eax,80000000h

Возможно у вас возникнет вопрос, зачем же забивать нулями другие каталоги? А не забываем, что располагать таблицы, как и каталоги, можно по адресам, кратным 1000h.

2) Interrupts.
И с прерываниями PM преподносит сюрпризы: нет больше 4-ых байтных векторов прерываний, как в RM. На их место пришли Interrupt Gates (для нас сейчас важны именно они), Trap Gates, Task Gates – 64-битные структуры, находящиеся в IDT. И структура такова:

Здесь назначение полей ясно (тем более, что некоторые из них встречались нам ещё в segment descriptor’ах). Мы пока рассмотрим только Interrupt Gates. IDT нужно составить до перехода в PM, загрузить размер и смещение в регистр IDTR (его структура аналогична структуре GDTR) командой lidt. Кстати, IDT – сегмент (скажем так, антипод GDT, которая просто в линейном адресном пространстве находится) т.е она располагается в определённом сегменте. Например, если вы до перехода в PM описали, к примеру, 4Кб памяти, а располагаете IDT за этими пределами, и разрешите прерывания после перехода в PM, то всё рухнет.
Еще пара замечаний: Intel зарезервировала прерывания 0-31. Туда нужно класть обработчики для этих exception’ов. Среди них ошибка деления на 0 (#DE), исключение общей защиты #GP и другие не менее весёлые вещи. Поэтому нужно базовый адрес прерываний сместить т.е сделать так, чтобы IRQ0 занимало 32 позицию и.т.д. Сразу оговорюсь, что использовать будем старую-добрую микросхему i8259a. Конечно, можно использовать и APICAdvanced Programmable Interrupt Controller (кстати, его нужно ручками включить), но нам просто не придётся пользоваться преимуществами такового (расширение кол-ва аппаратных прерываний, приспособленность под многопроцессорность и.т.д). Надеюсь, все помнят, что такое ICW (Initialization Control Word) и OCW (Operation Control Word)? Давайте повторим, что для чего используется (структуру приводить не буду):
ICW:
1) Определение особенности последовательности приказов.
2) Определение базового адреса (вот о чём я говорил).
3) Связь контроллеров.
4) Дополнительные особенности обработки прерываний.
OCW:
1) Управление регистром масок IMR.
2) Управление приоритетом.
3) Общее управление контроллером.

Процедура инициализации выглядит следующим образом:

Init_PIC:
mov al,11h;ICW1 – прерывание по перепаду сигнала, схемы подключены каскадно
out 20h,al;Мастеру
out 0A0h,al;Слэйву


mov al,20h;ICW2;базовый адрес (он абстрактный! Не путайте с адресом в RAM)
out 21h,al;Мастеру одно значение
mov al,28h;Слэйву другое
out 0A1h,al

mov al,04h;ICW3 – слэйв к входу IRQ2 подключён
out 21h,al
mov al,02h
out 0A1h,al

mov al,11h;ICW4 – сбрасываем флаг наличия прерывания вручную и используем камень Pentium
out 21h,al
mov al,01h
out 0A1h,al
ret

Теперь построим IDT:

IDT:
dd 0,0; 0
dd 0,0 ; 1
dd 0,0
dd 0,0 ; 3
;…. Убрал для краткости!
dd 0,0 ; 12
dw GP_handler and 0FFFFh,08h, 1000111000000000b, GP_handler shr 16 ; 13 #GP
dd 0,0 ; 14
;…. Я просто для краткости так написал. Забейте хоть тем же dup’ом это свободное место,
;чтоб не писать наскучившее dd 0,0
dd 0,0 ; 30
dd 0,0 ; 31;Здесь заканчиваются зарезервированные Intel номера ;gate’ов
dw timer and 0FFFFh, 08h, 1000111000000000b, timer shr 16 ; IRQ 0 — системный таймер
dw keyboard and 0FFFFh , 08h, 1000111000000000b, keyboard shr 16 ; IRQ 1 — клавиатура — ;предлагаю вам самим написать обработчик
dd 0,0;IRQ2
dd 0,0;IRQ3
dd 0,0;IRQ4
dd 0,0;IRQ5
dd 0,0;IRQ6

label IDT_size at $-IDT

IDTR dw IDT_size-1
dd IDT+10000h

Так, а зачем здесь пишем and’ы и shr’ы? – спросите вы. Вот тут трюк: мы же расположим весь код для PM за org’ом (смотрим код в предыдущей статье), в том числе и interrupt handlers… вот здесь и есть уловка: мы составляем 32-битный адрес из 2-х половинок, имея на руках лишь адрес обработчика. Вообще в этом нет ничего магического, просто нужно понимать, что за значение будет в этом двойном слове.
Теперь возникает вопрос, а почему же на местах многих gate’ов нули? А вот почему – совершенно не нужно писать все обработчики, ведь это, мягко говоря тяжело. Проще написать обработчик #GP, ведь, не найдя gate для прерывания, процессор генерирует пресловутое General Protection Fault.
Обработчики аппаратных прерываний вольны делать всё, что им вздумается, но должны сбрасывать флаг наличия прерывания – слать сигнал EOIEnd Of Interrupt (мы же так сконфигурировали PIC, верно?).
К примеру вот так:

mov al, 20h
out 20h, al

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

timer:
push ax
mov al, 20h
out 20h, al
pop ax
jmp int_EOI

int_EOI: ;вот здесь посылаем и Master’у и Slave’у EOI
push ax
mov al,20h
out 20h,al
out 0a0h,al
pop ax
iretd ;возврат из прерывания

int_EOI удобно использовать для всех обработчиков прерываний.

Ладно, теперь немного про исключения. Когда они происходят стек выглядит так:

Здесь error_code выталкиваем из стека и работаем с ним. Остальным займётся инструкция iretd.

Замечу, что тут содержимое ещё зависит от того, переключали ли мы ring’ или нет.
Структура error_code:

Где:
1) EXT — показывает, что сбой произошёл в обработчике прерывания или исключения.
2) IDT — когда установлен, показывает, что поля индекса относится к IDT.
3) TI — когда бит IDT не установлен, показывает, что икать нужно в GDT или LDT.
4) Segment Selector Index — показывает номер дескриптора (в GDT и LDT) или gate в IDT.

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

Теперь давайте скомпануем код. Я схитрю: предоставлю вам возможность потренироваться. Давайте вы попробуете самостоятельно написать рабочий код. Функции мы уже написали.
Дам несколько ‘подсказок’:
1) IDT расположите до org’a (короче вместе с GDT).
2) IDTR загружаем до перехода в PM.
3) Обработчики прерываний распологаем за org’ом.
4) К текстовой видеопамяти можно обращаться как раньше.
5) Не забываем разрешить ВСЕ прерывания после того, как в PM проинициализируем PIC!
6) Paging инициализируем уже в PM.
И ещё, напишите простой обработчик для клавы.

Если будут проблемы — обращайтесь. До следующего поста.
****Исправление****
Функция set_pages сперва была написана неправильно т.к там описывалась всего 1 таблица, вместо 8. Код исправлен.

Перхватываем прерывание 08h

Аппаратные интерфейсы, описанные в книге, в IBM — PC-совместимом компьютере «живут» в специфическом архитектурном окружении. Эту специфику приходится учитывать при проектировании аппаратной части устройств, чтобы обеспечить с ними эффективное программное взаимодействие. В этой главе вкратце рассматриваются особенности процессоров х86 и связанные с этими особенностями распределение памяти, организация ввода-вывода и прерываний. Здесь же рассматривается традиционный контроллер DMA, системные средства измерения времени, а также способы внедрения собственных расширений BIOS и нетрадиционной (бездисковой) загрузки ПО в специализированные компьютеры на базе IBM PC.

12.1. Пространство физической памяти
вперед к началу Главы вернуться назад

Основную часть физического адресного пространства PC занимает оперативная память (ОЗУ), начинающаяся с нулевого адреса. В нее вклинивается область адресов A0000h-FFFFFh — Upper Miory Area (UMA), 384 Кбайт — верхняя память, зарезервированная со времен IBM PC для системных нужд. В UMA размещаются области буферной памяти адаптеров шины (E)ISA (например, видеопамять) и постоянная память (BIOS с расширениями). ОЗУ продолжается и за областью UMA. Под самой верхней границей физического адресного пространства имеется образ памяти системной ROM BIOS.
Для доступности сервисов BIOS в реальном режиме все ПК имеют образ ROM BIOS в адресах E0000h-FFFFFh или F0000h-0FFFFFh. Кроме того, образ BIOS должен находиться и под самой верхней границей адресного пространства, поскольку все процессоры х86 по аппаратному сбросу стартуют с адреса начала последнего параграфа памяти (FFFF0h — 8086/88, FFFFF0h — 80286 и 386SX, FFFFFFF0h — 386DX и выше с 32-разрядной шиной адреса, FFFFFFFF0h — Р6 и выше с 36-разрядной шиной адреса).
nbsp; Для компьютеров класса АТ-286 и 386SX с 24-битной шиной адреса верхняя граница оперативной памяти — FDFFFFh (максимальный размер 15,9 Мбайт). Область FE0000h-FFFFFFh содержит образ ROM BIOS, обращение к этой области эквивалентно обращению к ROM BIOS по адресам 0E0000h-0FFFFFh.
Для ПК на процессорах 386DX и выше с 32-битной шиной адреса теоретический предел объема ОЗУ — почти 4 Гбайт, верхний образ BIOS находится в адреса: FFFE0000h-FFFFFFFFh. Для ПК на процессорах Р6+ с 36-битной шиной адрес; предел объема ОЗУ — почти 64 Гбайт и верхний образ BIOS находится в адресам FFFFE0000h-FFFFFFFFFh.
Области физических адресов, не занятые ОЗУ и ROM BIOS, могут быть использованы устройствами шин (E)ISA и PCI (AGP).
Для памяти адаптеров, устанавливаемых в шину ISA, безусловно, доступна часть области адресов UMA A0000h-EFFFFh или A0000h-DFFFFh (до начала ROM BIOS). В этой области располагаются и модули расширений BIOS (см. п. 12.7.1) Карты ISA могут иметь память и в области FE0000h-FFFFFFh, но она программно доступна лишь в защищенном (и большом реальном) режимах процессора. Для отображения этой области памяти на шину ISA (а не ОЗУ) в CMOS Setup пpeдусмотрен параметр Miory Hole At 15-16М, но его включение не позволит использовать оперативную память свыше 15 Мбайт.
Поскольку шина ISA имеет 24-разрядную шину адреса, ведущие устройства этих шин (ISA Bus Master) способны обращаться к памяти (ОЗУ и память адаптеров в пределах первых 16 Мбайт (000000-FFFFFFh). To же ограничение касается стандартного контроллера DMA, которым могут пользоваться устройства шины ISA (и иные устройства системной платы).
Шина PCI имеет 32-разрядную шину адреса, так что ее ведущим устройствам доступна вся физическая память1. Для устройств PCI могут выделяться любые области адресов, свободные от ОЗУ, ROM BIOS и устройств ISA. Области адресов памяти, используемые каждым устройством PCI, описаны в заголовках их конфигурационных пространств. Эти данные требуются при распределении ресурсов и настройке мостов PCI в процессе инициализации шины.

12.2. Пространство ввода-вывода
вперед к началу Главы вернуться назад

Таблица 12.1. Стандартная карта портов ввода-вывода

AT и PS/2 PC/XT Назначение
000-00F 000-00F Контроллер DMA#1 8237
010-01F нет PS/2 — расширение DMA#1
020-021 020-021 Контроллер прерываний #1 — 8259А
040-05F 040-043 Таймер (PC/XT:8253, AT:8254)
060 060 Диагностический регистр POST (только запись)
нет 060-063 Системный интерфейс 8255
060, 064 нет Контроллер клавиатуры AT 8042
061 Нет Источники NMI и управление звуком
070-07F Нет Память CMOS и маска NMI
080 Нет Диагностический регистр
080-08F 080-083 Регистры страниц DMA
090-097 Нет PS/2 микроканал, арбитр
Нет 0А0 Маска NMI
0A0-0BF нет Контроллер прерываний #2 — 8259А
0C0-0DF нет Контроллер DMA #2 8237А-5
0F0-0FF нет Сопроцессор 80287
100-1EF нет; PS/2 управление микроканалом
170-177 нет Контроллер НЖМД #2 (IDЕ#2)
1F0-1F7 нет Контроллер НЖМД#1 (IDЕ#1)
200-207 200-20F Игровой адаптер
нет 210-217 Блок расширений
238-23F нет COM4
278-27F 278-27F Параллельный порт LPT2 (LPT3 при наличии MDA)
нет 2А2-2АЗ часы МSМ48321RS
2C0-2DF 2C0-2DF EGA#2
2Е0-2Е7 нет COM4
2E8-2EF нет COM4
2F8-2FF 2F8-2FF COM2
300-31F нет Плата прототипа
нет 320-32F Жесткий диск XT
338-33F нет COM3
370-377 нет Контроллер НГМД#2
376-377 нет Порты команд IDЕ#2
378-37F 378-37F Параллельный порт LPT1 (LPT2 при наличии MDA)
380-38F 380-38F Синхронный адаптер SDLC/BSC #2
3A0-3AF ЗА0-ЗА9 Синхронный адаптер BSC#1
ЗВ0-ЗВВ ЗВ0-ЗВВ Монохромный адаптер (MDA)
ЗВ4-ЗС9 нет PS/2 видеосистема
3BC-3BF 3BC-3BF Параллельный порт LPT1 платы MDA
3C0-3CF 3C0-3CF EGA#1
3C0-3DF 3C0-3DF VGA
3D0-3DF 3D0-3DF CGA/EGA
ЗЕ0-ЗЕ7 нет COM3
3E8-3EF нет COM3
3F0-3F7 3F0-3F7 Контроллер НГМД#1
3F6-3F7 нет Порты команд IDE#1
3F8-3FF 3F8-3FF СОМ1

Каждой шине назначается своя область адресов ввода, поэтому дешифратор адресов, расположенный на системной плате, при чтении открывает соответствующие буферы данных, так что реально считываться будут данные только с одной шины. При записи в порты данные (и сигнал записи) могут распространяться по всем шинам компьютера. В стандартном распределении адреса 0h-0FFh отведены для устройств системной платы. При наличии (и разрешении работы) периферийных устройств на системной плате чтение по этим адресам не распространяется на шины расширения. Для современных плат со встроенной периферией и несколькими шинами (ISA, PCI) распределением адресов управляет BIOS через регистры конфигурирования чипсета.

12.3. Аппаратные прерывания
вперед к началу Главы вернуться назад

Таблица 12.2. Аппаратные прерывания (в порядке убывания приоритета)
Имя (номер 1 ) Вектор Контроллер/маска Описание
NMI 02h Контроль канала, паритет (в XT — сопроцессор)
IRQ0 08h #1/1h Таймер (канал 0 8253/8254)
IRQ1 09h #1/2h Клавиатура
IRQ2 0Ah #1/4h XT — резерв, AT — недоступно (подключается каскад IRQ8-IRQ15)
IRQ8 70h #2/1h CMOS RTC — часы реального времени
IRQ9 71h #2/2h Резерв
IRQ10 72h #2/4h Резерв
IRQ11 73h #2/8h Резерв
IRQ12 74h #2/10h PS/2-Mouse (резерв)
IRQ13 75h #2/20h Математический сопроцессор
IRQ14 76h #2/40h HDC — контроллер НЖМД
IRQ15 77h #2/80h Резерв
IRQ3 0Bh #1/4h COM2, COM4
IRQ4 0Ch #1/10h COM1, COM3
IRQ5 0Dh #1/20h XT — HDC, AT — LPT2, Sound (резерв)
IRQ6 0Eh #1/40h FDC — контроллер НГМД
IRQ7 0Fh #1/80h LPT1 — принтер
1 Запросы прерываний 0, 1, 8 и 13 на шины расширения не выводятся.

Каждому устройству, для поддержки работы которого требуются прерывания, должен быть назначен свой номер прерывания. Назначения номеров прерываний выполняются с двух сторон: во-первых, адаптер, нуждающийся в прерываниях, должен быть сконфигурирован на использование конкретной линии шины (джамперами или программно). Во-вторых, программное обеспечение, поддерживающее данный адаптер, должно быть проинформировано о номере используемого вектора. В процессе назначения прерываний может участвовать система РnР для шин ISA и PCI, для распределения линий запросов между шинами служат специальные параметры CMOS Setup.
Контроллер прерываний позволяет программировать свои входы на чувствительность к уровню или перепаду сигнала.
• Чувствительность к уровню (level sensitive) означает, что контроллер прерываний вырабатывает запрос прерывания процессора по факту обнаружения определенного уровня (на ISA — высокого) на входе DRQx . Если к моменту завершения обработки этого запроса (после записи команды EOI в регистр контроллера прерываний) контроллер снова обнаруживает активный уровень на том же входе DRQx , то он снова сформирует запрос на прерывание процессора.
• Чувствительность к перепаду (edge sensitive) означает, что контроллер прерываний вырабатывает запрос прерывания процессора только по факту обнаружения перепада (на ISA — положительного) на входе DRQx . Повторно запрос по этому входу возможен только по следующему такому же перепаду, то есть сигнал предварительно должен вернуться в исходное состояние.
В любом случае сигнал запроса аппаратного прерывания IRQx должен удерживаться генерирующей его схемой, по крайней мере, до цикла подтверждения прерывания процессором. В противном случае источник прерывания корректно идентифицирован не будет, и контроллер сообщит ложный вектор прерывания (spurious interrupt), соответствующий его входу с максимальным номером ( IRQ7 для первого контроллера и IRQ 15 для второго). Обычно адаптеры строят так, что сигнал запроса сбрасывается при обращении программы обслуживания прерывания к соответствующим регистрам адаптера.
В шине ISA прерывание вырабатывается по положительному перепаду сигнала на линии запроса. Это плохо по двум причинам: такой способ подачи сигнала, во-первых, имеет меньшую помехозащищенность, чем срабатывание поотрицатель ному перепаду, во-вторых, отрезает путь к нормальному разделению линий запросов (см. ниже), для которого полностью пригоден способ подачи сигнала по низкому уровню. Поскольку традиционный контроллер позволяет задавать чувствительность — уровень (Level) или перепад (Edge) — только для всех входов одновременно, в общем случае разделяемые прерывания на шине ISA вместе с корректной работой системных устройств использоваться не могут.
На современных системных платах функции контроллеров прерываний возлагаются на чипсет, который может иметь и более гибкие возможности управления, чем пара контроллеров 8259А. В операционном режиме всегда сохраняется программная совместимость с 8259А. Процедура инициализации контроллеров может и отличаться от традиционной, но ею занимается тест POST, который «знает» особенности системной платы. В симметричных мультипроцессорных системах аппаратные прерывания работают сложнее, поскольку их могут обслуживать различные процессоры. Для реализаций системы прерываний процессоры Pentium и выше имеют встроенный контроллер прерываний APIC (Advanced Programmable Interruption Controller). Внутренние контроллеры процессоров связаны между собой по шине APIC, к которой подключена и «ответная часть» чипсета, преобразующая запросы аппаратных прерываний в сигналы протокола APIC. В операционном режиме такая связка также совместима с 8259А.

12.3.1. Совместное использование прерываний
вперед к началу Главы вернуться назад
Линии запросов прерываний в компьютере, насыщенном дополнительными адаптерами, являются самым дефицитным ресурсом, поэтому возникает желание использовать эти линии совместно, то есть применять разделяемые прерывания между несколькими устройствами (shared interrupts). Обработчики прерываний (программы) от разных устройств, разделяющих одну линию запроса (и следовательно, общий вектор прерывания), должны быть выстроены в цепочку. В процессе обработки прерывания очередной обработчик в цепочке чтением известного ему регистра своего устройства должен определить, не это ли устройство вызвало прерывание. Если это, то o6pa6oтчик должен выполнить необходимые действия и сбросить сигнал запроса прерывания от своего устройства, после чего передать управление следующему обработчику в цепочке; в противном случае он просто передает управление следующему обработчику.
Разделяемые прерывания для разнотипных устройств в общем случае работоспособными считать нельзя. Во-первых, у каждого устройства факт прерывания программно обнаруживается по-своему, и этот способ знает только драйвер этого устройства. Так что программно для совместного использования прерываний их обработчики должны уметь выстраиваться в цепочки, что на практике выполняется не всегда корректно. Во-вторых, возможны потери прерываний от устройств, требующих быстрой реакции. Это может происходить, если обработчик такого устройства окажется в конце цепочки, а предшествующие ему обработчики окажутся «нерасторопными» (не самым быстрым способом обнаружат, что прерывание — не их). Поведение системы в такой ситуации может меняться в зависимости от порядка загрузки драйверов. Для нескольких однотипных устройств (например, сетевых адаптеров на одном и том же кристалле), пользующихся одним драйвером, разделяемые прерывания работают вполне успешно.
Чтобы прерывания, одновременно возникающие от нескольких устройств, не терялись, контроллер прерываний должен быть чувствительным к уровню , а не к перепаду на входе запроса. В соответствие со схемотехникой логики ТТЛ и КМОП активным уровнем должен быть низкий; выходной формирователь сигнала запросов у адаптеров — с открытым коллектором (ТТЛ) или открытым стоком (КМОП); вход запроса у контроллера должен быть «подтянут» к высокому уровню резистором. Тогда непосредственное соединение этих выходов со входом контроллера («Монтажное И») даст требуемый результат в аппаратном плане, а в программном плане необходимо корректно выстроить обработчики в цепочку.
Поясним, почему надежное разделение прерываний при чувствительности к перепаду на линии запроса невозможно. Если устройство 1 выработает сигнал запроса после того, как его выработает (но еще не снимет) устройство 2, то контроллер обработает только один запрос. Цепочка программных обработчиков окажется ненадежной: если обработчик устройства 1 в этой цепочке будет проверять свое устройство до возникновения прерывания, то прерывание будет потеряно. Поскольку прерывания по своей природе обычно асинхронны, работа этих устройств совместно с поддерживающими программами будет загадочно нестабильной.
Как уже говорилось, в шине ISA прерывание вырабатывается по положительному перепаду сигнала на линии запроса. Стандартный контроллер 8259А позволяет задавать чувствительность — уровень или перепад — только для всех входов одновременно, поэтому разделяемые прерывания на шине ISA неработоспособны. Тем не менее некоторые чипсеты, реализующие контроллеры прерываний, допускают индивидуальное управление чувствительностью каждого входа. Тогда при соответствующих возможностях CMOS Setup, адаптеров и их ПО разделяемые прерывания технически реализуемы.
Для шины PCI, казалось бы, проблема разделения прерываний решена — здесь активным уровнем запроса является низкий, так что, запрограммировав входы контроллера на чувствительность к уровню, создается аппаратная база совместного использования. Однако на практике разделяемые прерывания работают не всегда, и иногда приходится подбирать положение карт расширения в слотах PCI , при которых устройства не конфликтуют друг с другом по прерываниям. Виной конфликтов могут быть как сами карты расширения, так и их драйверы, неспособные выстраиваться в корректную цепочку.
Если карта PCI использует одну линию запроса прерываний, то этой линией по умолчанию является INTRА . Если все четыре карты PCI используют по одной линии запроса, то, как это видно на рис. 12.1, каждая линия занимается монопольно. Однако если сложная карта нуждается в большем числе линий запроса, то ей придется разделять линии с соседними картами. На современных системных платах часто устанавливают более четырех слотов PCI, при этом, естественно, «угроза» совместного использования линий запросов «нависает» и над картами с одной линией запроса. Порт AGP в плане прерываний следует рассматривать наравне со слотами PCI.
Проявления конфликтов и ошибок назначения прерываний могут быть разнообразными. Сетевая карта при ошибке в прерываниях не сможет принимать кадры из сети (при этом она может их успешно посылать). У устройств хранения доступ к данным будет поразительно медленным (иногда можно минутами ожидать, например, появления информации о файлах и каталогах) или вообще невозможным. Звуковые карты будут молчать или «заикаться», на видеопроигрывателях изображение будет дергаться и так далее. Конфликты могут приводить и к внезапным перезагрузкам компьютера, например по приходу кадра из сети или сигналу от модема.

12.4. Прямой доступ к памяти — DMA
вперед к началу Главы вернуться назад
Прямой доступ к памяти (Direct Miory Access, DMA) позволяет выполнять пересылку данных между регистрами устройств и памятью, минуя центральный процессор. Для устройств, использующих DMA, различают два типа доступа.
* Пассивный доступ, он же Slave DMA, — устройство пользуется общим контроллером DMA, расположенным на системной плате.
* Активный доступ, он же Bus Master DMA, — устройство само является ведущим на своей шине и способно генерировать обращение к памяти (как правило, системной). Реализация активного DMA зависит от типа шины расширения, к которой подключается устройство (см. главу 6). Примером устройств с активным DMA являются контроллеры ATА, расположенные на современных системных платах.
Процессор при обмене по DMA занят только инициализацией контроллера, которая сводится к записи в его регистры нескольких байт, задающих начальный адрес и размер пересылаемого блока памяти, направление и режим обмена. В самом обмене данных занят только контроллер DMA, память, к которой он обращается, и связующие их шины. Во время операций DMA процессор может продолжать работу, если выбранный режим обмена не занимает всей пропускной способности шин, используемых процессором в данный момент (шины памяти, шины PCI, через которые подключается ISA в современных компьютерах). Контроллер DMA можно считать простейшим сопроцессором ввода-вывода, разгружающим центральный процессор от рутинных операций обмена.
Обмен по DMA не всегда дает выигрыш в скорости обмена, в ряде случаев быстрее работает программированный ввод-вывод (PIO). Однако РIO занимает процессор полностью, а во время DMA процессор может заниматься полезной работой. Поскольку для инициализации контроллера DMA требуется выполнение ряда инструкций ввода-вывода, передача коротких блоков по каналу DMA нецелесообразна. Пассивный DMA реализуется стандартизованным контроллером, который первоначально был ориентирован на шину ISA. Для интерфейса ПУ каждый канал DMA представляется парой сигналов: запрос обмена — DRQx и подтверждение обмена — DACKx# . В PC/AT доступны 7 каналов DMA — четыре 8-битных (номера 0-3) и три 16-битных (5-7), — подключенные к первичному и вторичному контроллерам соответственно. Канал 4 используется для каскадирования (соединения контроллеров). В PC/XT были только три 8-битных канала, канал 0 использовался для регенерации памяти. Контроллеры DMA программно совместимы с системами 18237, применяемыми в первых моделях PC/XT и AT. Стандартные каналы и адреса регистров приведены в табл. 12.3.

Таблица 12.3. Стандартные каналы прямого доступа к памяти

Номер канала DMA# 0 1 1 2 3 4 2 5 6 7
Стандартное назначение XT MRFR FDD HDD Отсутствуют
АТ FDD Каскад
Разрядность, байт 1 2 с четного адреса
Макс. размер блока 64 Кбайта 128 Кбайт, четный
Граница блока Кратна 1000h Кратна 2000h
Регистр страниц 8 бит А16-А23 7 бит А17-А23
Адреса регистров:
— страниц 087 083 081 082 08F 08В 089 087
— адреса 000 002 004 006 ОСО ОС4 ОС8 ОСС
— счетчика 001 003 005 007 ОС2 ОС6 ОCA ОСЕ
1 Канал 0 в XT использовался для регенерации памяти (MRFR).
2 Канал 4 доступен только в PS/2 МСА.

16-битные каналы DMA 5-7 могут быть использованы интеллектуальными устройствами для прямого управления шиной ISA (bus mastering), при этом контроллер DMA фактически лишь играет роль арбитра шины.
Устройства, использующие стандартные каналы DMA, могут располагаться лишь в слотах ISA/EISA или на системной плате (контроллер НГМД, LPT-порт в режиме ЕСР или Fast Centonics , аудиокодек). Если эти устройства системной платы используют каналыDMA, то данные каналы становятся недоступными для абонентов шины ISA.
На время переходного периода, связанного с «изживанием» шины ISA, потребовалась возможность эмуляции каналов DMA для устройств шины PCI. Существует два механизма эмуляции каналов DMA: PC/PCI и DDMA. Механизм PC/PCI (см. п. 6.2.7) былразработан фирмой Intel для обеспечения возможности использования слотов ISA блокнотными ПК,подключаемыми к док-станции по шине PCI. Альтернативное решение — механизм DDMA (Distributed DMA — распределенный DMA) позволяет «расчленить» стандартный контроллер и отдельные его каналыэмулировать средствами карт PCI. Оба этих механизма реализуемы только как часть моста междупервичной шиной PCI и шиной ISA, поэтому их поддержка может обеспечиваться (или не обеспечиваться)только на системной плате и разрешаться в CMOS Setup.

12.4.1. Контроллер прямого доступа 8237А
вперед к началу Главы вернуться назад
Микросхема 8237А, применявшаяся в PC вплоть до первых моделей AT, представляет собой четырехканальный контроллер прямого доступа к памяти, допускающий каскадирование. Вторичный контроллер (8237#2) каскадно соединен с первичным, при этом теряется возможность использования одного канала вторичного контроллера. Контроллер 8237А имеет 16-разрядные регистры адреса и счетчики, что обеспечивает возможность программирования передачи блока данных размером до 64 Кбайт или слов. Назначение регистров контроллеров DMA, применительно к их адресам в пространстве ввода-вывода компьютера, приведено в табл. 12.4. Контроллер допускает довольно гибкое конфигурирование. Корректное оперативное управление отдельными каналами не затрагивает общих настроек. Общее конфигурирование контроллеров (запись в регистры 008 и 0D0) выполняет BIOS при инициализации во время теста POST; в XT тогда же программируется и канал 0, применяемый для регенерации памяти. Для использования каналов устройствами шины ISA запись в регистры 008 и 0D0 не рекомендуется. Обмен с регистрами контроллера выполняется только однобайтными операциями ввода-вывода. Для загрузки 16-битных значений задействуется триггер младшего/старшего байта. По сбросу контроллера или записи любого байта по адресу 00Ch (0D8h для второго контроллера) этот триггер сбрасывается, и контроллер готовится к приему младшего байта. После приема этого байта триггер меняет состояние, и контроллер воспринимает старший байт, после которого триггер опять переключается.

Таблица 12.4. Регистры контроллера DMA 8237A

8237#1 8237#2 R/W, Назначение регистров
000, 002
004, 006
0С0, 0С4
0С8, 0СС
W — регистры начального адреса для каналов 0-3 (8237#1 ) и 4-7 (8237#2)
R — регистры текущего адреса тех же каналов
001, 003
005, 007
0С2, 0С6
0CA, 0CE
W — начальное значение счетчика передач для каналов 0-3 (8237#1) и 4-7 (8237#2)
R — текущее значение счетчика передач тех же каналов
005, 007 0СА, 0СЕ W, Command Register — конфигуратор контроллера.
Бит 7: 1 —активный уровень (DACK# — высокий, 0 — низкий);
бит 6: 1 — активный уровень (DRQ — низкий, 0 — высокий);
бит 5: 1 — режим расширенной записи (должен быть 0);
бит 4: 0 — фиксированный приоритет, 1 — циклический;
бит 3: 1 — укороченный цикл обмена (должен быть 0);
бит 2: 1 — запрет работы контроллера;
бит 1: 1 — фиксация адреса 0 канала (должен быть 0);
бит 0: 1 — передача память-память (в PC не используется, должен быть 0)
008 0D0 R, Status Register — состояние каналов.
Биты 4-7: запросы каналов 0-3;
биты 0-3: завершение цикла каналов 0-3
009 0D2 W, Request Register — регистр программных запросов.
Биты 7-3 не используются;
бит 2: 1 — установка, 0 — сброс бита запроса;
биты 1-0: выбор канала (00 — 0; 01 — 1; 10 — 2; 11 — 3>
00A 0D4 W, Single Mask Bit Register — управление масками.
Биты 7-3 не используются;
бит 2: 1 — установка, 0 — сброс бита маски;
биты 1-0: выбор канала (00 — 0; 01 — 1; 10 — 2; 11 — 3)
00В 0D6 W, Mode Register — режимы работы каналов.
Биты 7-6: режим передачи (00 — по запросу,
01 —одиночный, 10 — блочный, 11 — каскадирование);
бит 5: 0 — инкремент, 1 — декремент адреса;
бит 4: 1 — разрешение автоматической реинициализации
биты 3-2: тип передачи (00 — холостой, проверка канала,
01 — запись в память, 10 — чтение памяти, 11 — недопустимо);
биты 1-0: выбор канала (00 — 0; 01 — 1; 10 — 2; 11 — 3)
00C 0D8 W, Clear Byte Pointer Flip/Flop — сброс триггера младшего/старшего байта
00D 0DA W, Master Clear — общий сброс 8237 (вывод любого байта в регистр вызывает сброс)
00E 0DC W, Clear Mask Register — общий сброс масок всех каналов (вывод любого байта в регистр вызывает сброс)
00F 0DE W, All Mask Register Bits — регистр масок всех каналов.
Биты 0-3: маски каналов 0-3 (0 — канал разрешен, 1 — замаскирован);
биты 4-7 не используются

Стандартный контроллер DMA на шине ISA с частотой 8 МГц работает на половинной частоте и требует для одиночной передачи не менее пяти своих тактов. Длительность одиночного цикла составляет 1,125 мкс. В блочных передачах пропускная способность DMA достигает 1 Мбайт/с для 8-битных каналов и 2 Мбайт/с для 16-битных (время цикла составляет 1 мкс). На современных компьютерах контроллер DMA реализуется чипсетом системной платы; при сохранении программной совместимости с 8237А он может работать на шине гораздо быстрее. Количество тактов шины на один цикл может программироваться опциями BIOS Setup.

12.5. Процессоры х86
вперед к началу Главы вернуться назад

Все программы в IBM PC-совместимом компьютере исполняются центральным процессором, принадлежащим к семейству х8б. Любое устройство для процессора представляет собой лишь набор регистров (ячеек), отображенных в пространство памяти и (или) ввода-вывода, и необязательно источник аппаратных прерываний. Современные процессоры х86, работающие в защищенном режиме, имеют довольно сложные механизмы виртуализации памяти, ввода-вывода и прерываний, из-за которых приходится различать физические и логические пространства (адреса памяти и ввода-вывода) и события (операции ввода- вывода, прерывания). Физический адрес ячейки памяти или порта ввода-вывода — это адрес, формируемый для обращения к данной ячейке на физических шинах компьютера (системной шине процессора, шине PCI, ISA). Логический адрес — это тот адрес, который формируется исполняемой программой (по замыслу программиста) для доступа к требуемой ячейке. Физическая операция ввода-вывода или обращения к памяти — это процесс (шинный цикл), во время которого генерируются электрические сигналы, обеспечивающие доступ к данной ячейке (порту). Логическая операция — это исполнение программной инструкции (команды) обращения к интересующей ячейке. огическая операция не всегда порождает ожидаемую физическую операцию: при определенных условиях она может блокироваться средствами защиты процессора, вызывая даже принудительное завершение программы, или же эмулироваться, создавая иллюзию физического исполнения.
Безопасность в защищенном режиме базируется на 4-уровневой системе привилегий. В большинстве современных ОС ради упрощения и экономии процессорного времени используются только два крайних уровня — нулевой (supervisor), с неограниченными возможностями, и третий (user), с самыми жесткими ограничениями. Смена уровней привилегий при исполнении программы занимает много тактов процессора, но это вынужденная плата за реализацию защиты, без которой устойчивую ОС не построить. Более подробно механизмы защиты и виртуализации памяти, ввода-вывода и прерываний в процессорах х86 описаны в литературе [6, 7], здесь же изложены лишь некоторые прикладные аспекты их работы.

12.5.1. Возможности адресации памяти процессорами различных поколений
вперед к началу Главы вернуться назад
Сложность обращения к памяти в PC обусловлена свойствами процессоров х86 разных поколений и требованием обратной совместимости новых процессоров и компьютеров со старым ПО.
Процессорам 8086/88 было доступно адресное пространство1 Мбайт с диапазоном адресов 0-FFFFFh, причем физический 20-битный адрес вычислялся с помощью двух 16-битных компонентов по формуле Addr = Seg x 16 + Offset , где Seg — содержимое сегментного регистра ( CS, DS, SS или ES ), a Offset — исполнительный адрес, формируемый из одного или нескольких слагаемых в соответствии с выбранным режимом адресации. Эта сегментная модель адресации позволяет программам оперировать с непрерывными блоками памяти (сегментами) размером не более 64 Кбайт. Для манипуляций с памятью большего размера требовалось переключение сегментов с помощью специальных инструкций процессора, что усложняло программирование. Заметим, что при Seg = FFFFh и 0ffset = FFFFh данная формула дает адрес 10FFEFh, но ввиду 20-битного ограничения на шину адреса эта комбинация в физической памяти указывает на 0FFEFh. Таким образом, адресное пространство как бы сворачивается в кольцо с небольшим «нахлестом».
В процессоре 80286 шина физического адреса была расширена до 24 бит, и введен новый режим работы — защищенный (Protected Mode), в котором программа может обращаться к 16-мегабайтному пространству физической памяти через логическое пространство виртуальной памяти. Здесь виртуальная память строилась на основе той же сегментной модели памяти с 16-разрядными регистрами. Физический адрес формировался суммированием 16-разрядного исполнительного адреса (смещения внутри сегмента) с 24-разрядным базовым адресом сегмента.
Кроме защищенного режима, в процессоре 80286 имеется и реальный режим, в котором процессор ведет себя почти так же, как и 8086 (но более быстрый). Здесь физический адрес вычисляется так же, как и в 8086/88, но из-за ошибки разработчиков та самая единица в бите А20, которая отбрасывалась в процессорах 8086/88, теперь попадает на шину адреса, и в результате максимально доступный физический адрес в реальном режиме достиг 10FFEFh. Для обеспечения полной совместимости с процессором 8086/88 в схему PC ввели вентиль линии А20 шины адреса — GateA20 , который либо пропускает сигнал от процессора, либо принудительно обнуляет линию А20 системной шины адреса. Этот вентиль должен быть открыт при работе в защищенном режиме, а также когда в реальном режиме нужны дополнительные (64 К-16) байт памяти. Вентиль управляется через контроллер клавиатуры (см. п. 8.1.2) или иным специфическим способом.
В 32-разрядных процессорах , начиная с 80386, сохранена та же идея обращения к памяти с участием сегментных регистров (16-разрядных), но регистры процессора, участвующие в формировании адреса, позволяют адресовать уже 2 32 = 4 Гбайт памяти в каждом сегменте. Базовый адрес сегмента берется из специальных структур данных — дескрипторов сегментов . Кроме базового адреса в дескрипторе описывается его лимит (длина), назначение (код или данные),возможность записи и чтения, а также уровень привилегий программы, позволяющий обращаться к данномусегменту. Дескрипторы предварительно программно формируются в памяти, где их наборы хранятся в видетаблиц дескрипторов. Процессор имеет средства защиты памяти, контролирующие использование сегментов.Программа может обращаться лишь к тем сегментам памяти, описание которых имеется в доступных дескрипторах. Виртуальное адресное пространство, доступное программе, имеет объем до (16 К-2) сегментов (число возможных дескрипторов), каждый из которых может иметь размер до 4 Гбайт. Дескриптор выбирается с помощью селектора , загружаемого в сегментный регистр ( СS, DS, SS, ES, FS или GS ). Однакоэто виртуальное адресное пространство отображается блоком сегментации в логическое адресное пространство с опять-таки 32-разрядным линейным адресом, то есть объемом 4 Гбайт. По замыслу разработчиков процессора, это отображение с подкачкой требуемых сегментов с диска и выгрузкой неиспользуемых должно выполняться диспетчером виртуальной памяти операционной системы. Практически такая виртуализация применялась на процессорах 80286 (с 16-разрядными регистрами), поскольку иных механизмов не существовало.
Для виртуализации памяти (и защиты) в 32-разрядных процессорах применяется иной механизм, основанный на блоке страничной переадресации — принципиальной новинке 32-разрядных процессоров х86. В его задачу входит отображение 32-разрядного линейного адреса (продукта блока сегментации) на 32- или 36-разрядный физический адрес, формируемый на системной шине процессора при его обращениях к памяти. В отличие от блока сегментации, оперирующего блоками разного размера (сегментами), блок страничной переадресации оперирует страницами одинакового размера. Переаресация выполняется на основе таблиц страниц , где для каждой страницы логической памяти имеется свой описатель. В этом описателе имеется признак присутствия страницы в физической памяти, и для присутствующих страниц указывается базовый адрес физического отображения. Кроме того, имеются биты, управляющие доступом к странице по чтению и записи с различных уровней привилегий, возможностью ее кэширования, и некоторые служебные биты. При обращении программы к отсутствующей странице процессор вырабатывает исключение, обработчик которого занимается подкачкой нужной страницы из внешней памяти (с диска) в ОЗУ. Этот обработчик и реализует виртуальную память с подкачкой страниц по запросу (Diand-Paged Virtual Miory), которая в настоящее время обычно и подразумевается под виртуальной памятью. При недостатке свободного места в физической памяти обработчик выполняет и замещение страниц, по его мнению, наименее нужных, выгружая их на диск. Создав несколько наборов описателей страниц, можно получить несколько виртуальных адресных пространств, каждое из которых имеет размер до 4 Гбайт, причем страницы разных пространств могут быть полностью изолированы друг от друга, а могут и частично пересекаться. В многозадачной ОС каждая задача (виртуальная машина) имеет собственное (как ей представляется) адресное пространство.
Первоначально блок страничной переадресации работал со страницами размером 4 Кбайт. В дополнение к этому базовому механизму в процессор Pentium ввели возможность работы и со страницами размером 4 Мбайт (режим PSE ). В ряде процессоров Р6 разрядность физического адреса увеличена до 36 бит, и все процессоры Р6 имеют возможность включение режима переадресации РАЕ , позволяющего отображать страницы размером 4 Кбайт и 2 Мбайт с расширением физического адреса. С процессорами Pentium III появился режим преобразования PSE-36 , в котором блок оперирует 4-Мбайтными страницами в 36-битном физическом пространстве и сохраняется возможность работы со стандартными 4-Кбайтными страницами базового режима. Это позволяет довольно эффективно управляться с современными объемами физической памяти компьютера.
В стандартном реальном режиме 32-разрядные процессоры работают с памятью так же, как и 80286, с возможностью адресации в диапазоне 0-10FFEFh, причем вентиль Gate A20 ввели уже в сам процессор. Физический адрес вычисляется с участием сегментных регистров, размер непрерывного сегмента — 64 Кбайт. По умолчанию в реальном режиме адреса формируются с использованием только младших 16 бит 32-разрядных регистров, правда, для каждой инструкции можно с помощью префиксов изменить разрядность адресных компонентов на 32 бита. Однако и при этом невозможно пересечь границу 64-Кбайтного сегмента — сработает исключение защиты.
В стандартном реальном режиме блок страничной переадресации не работает, и физический адрес совпадает с линейным. С помощью временного переключения в защищенный режим можно настроить таблицы страниц, разрешить преобразование и далее в реальном режиме задействовать страничное преобразование. Этот трюк используется менеджерами памяти типа EMM386 для работы со свободными блоками UMА.
Есть и еще один режим, неофициальный, но тоже работающий на всех 32-разрядных процессорах х86, — «нереальный» (unreal), он же «большой реальный» (big real). Он позволяет процессору в реальном режиме обращаться к данным, расположенным в любом месте 4-Гбайтного пространства линейных (и физических) адресов. Этот режим базируется на логике блока сегментации, которая при вычислении линейного адреса во время обращений к памяти пользуется скрытыми программно-недоступными регистрами дескрипторов сегментов. Из этих регистров берется базовый адрес, из них же берется и лимит, который используется схемой защиты. В этих регистрах кэшируются дескрипторы сегментов, загружаемые из памяти во время исполнения инструкций, переопределяющих значения сегментных регистров ( СS, DS, SS, ES, FS и G5 ) в защищенном режиме. По аппаратному сбросу в эти скрытые регистры заносятся «неинтересные» параметры стандартного реального режима, с лимитом 64 Кбайт. В реальном режиме при переопределении сегментных регистров значение базового адреса берется как 16-кратное значение, загружаемое в соответствующий сегментный регистр, а лимит устанавливается в 64 Кбайт. Тем не менее,если в защищенном режиме в сегментный регистр загрузить селектор дескриптора, в котором описан сегмент размером 4 Гбайт с нулевым базовым адресом и возможностью полного доступа на любом уровне привилегий, переключиться в реальный режим и не трогать этот сегментный регистр, то далее процессор будет иметь доступ ко всему этому сегменту в данной модификации реального режима. Однако такая «благодать» распространяется только лишь на доступ к данным через сегментные регистры FS и GS , которые используются в инструкциях обращений к памяти, снабженных префиксами замены сегмента. Эти сегментные регистры появились только с 32-разрядными процессорами, и никакие традиционные сервисы BIOS (и DOS) их не затрагивают. Остальные сегментные регистры настолько часто используются, что «время жизни» описания большого сегмента в их кэширующих регистрах будет слишком коротким. Программный код, увы, исполняется только из сегмента, которым командует CS , поэтому для него остается лишь первый мегабайт с 64-Кбайтными сегментами. Так что большие программные модули приходится подгружать в эту область по мере надобности, но это можно выполнять довольно быстро пересылками данных из любого места «большого сегмента». Большой реальный режим широко используется менеджерами памяти, а также игровыми DOS-программами, всецело захватывающими ресурсы компьютера.
Итак, самые широкие возможности адресации имеются в защищенном 32-разрядном режиме, наиболее естественном для современных процессоров. В этом режиме может использоваться как плоская, так и сегментная модели памяти. Под плоской (flat) понимается модель, в которой все сегментные регистры указывают на один и тот же сегмент памяти (как правило, начинающийся с нулевого адреса), и его лимит может достигать 4 Гбайт, что позволяет адресовать этот немалый (даже по нынешним меркам) объем памяти без манипуляций сегментными регистрами. Однако при этом теряются все возможности виртуализации памяти на основе сегментов, а также отсутствует сегментная защита. В сегментной модели памяти сегментные регистры кода, стека и данных настраиваются на разные, возможно и не пересекающиеся сегменты. Здесь имеются все возможности сегментной защиты и сегментной виртуализации памяти. Поскольку современным приложениям пока достаточно 4 Гбайт памяти (надолго ли?), сегментную модель ради упрощения диспетчера памяти стараются не использовать. Защита памяти имеется и на уровне страниц, правда, не такая развитая и надежная, как сегментная.

12.5.2. Проблемы страничной переадресации
вперед к началу Главы вернуться назад
В реальном режиме (при отключенной страничной переадресации) логический адрес, формируемый прикладной программой, совпадает с физическим адресом, фигурирующим на шинах расширения. Тут все просто, правда, в стандартном (а не большом) реальном режиме доступен только первый мегабайт адресов (только устройства в области UMA).
В защищенном режиме в принципе доступно все физическое адресное пространство, но появляются проблемы, связанные с отображением логических адресов на физические. Отображением (поддержкой таблиц переадресации) ведает ОС, приложения могут только узнать карту отображений (получить список физических адресов страниц для какой-то области своей виртуальной памяти). Какие-то области могут в данный момент и не присутствовать в ОЗУ (они могут быть выгруженными на диск). У драйверов устройств возможностей больше — они могут запросить блок памяти с последовательными физическими страницами и потребовать фиксации определенных страниц (запретить их выгрузку из ОЗУ).
При организации прямого доступа к памяти, как по стандартным каналам DMA, так и используя ведущие устройства шин ISA и PCI, возникает проблема пересечения границ страниц. Если приложение хочет выполнить обмен по DMA с областью доступной ей памяти непосредственно, то оно должно запросить у ОС физический адрес, которому соответствует логический адрес предполагаемого буфера обмена. Именно этот физический адрес должен задаваться устройству, выполняющему DMA, при инициализации сеанса обмена (указании начального адреса, длины блока и запуске канала). В каждом сеансе обмена не должна пересекаться граница страницы, которой оперирует блок страничной переадресации, поскольку следующая логическая страница может иметь физическое отображение в произвольном (относительно предыдущей страницы) месте. Чаще всего ОС оперирует страницами по 4 Кбайт, при этом пересылка больших блоков данных ведется «короткими перебежками», между которыми процессор должен выполнять повторную инициализацию DMA. Эта проблема решается усложнением контроллеров DMA — применением «разбросанной записи» в память (scatter write) и «собирающего чтения» памяти (gather read). Контроллеру DMA задается список описателей блоков (начальный адрес и длина). Отработав очередной блок памяти, контроллер переходит к следующему, и так до конца списка. Такие возможности имеет, например, стандартный контроллер PCI IDE (см. п. 9.2.1). Стандартный контроллер DMA имеет и другую «страничную проблему», связанную с реализацией регистров страниц (см. п.12.4).
Проблема пересечения границ может решаться и иначе, без усложнения контроллера DMA. Для этого в памяти резервируется буфер значительного размера, отображенный на непрерывную область физической памяти, и обмен данными физическое устройство выполняет только с этим буфером. Однако такой буфер рядовое приложение создать не может; он может быть организован лишь драйвером устройства. Приложения могут только получать указатели на этот буфер и обмениваться с ним данными. Таким образом, по пути от приложения к устройству появляется дополнительная «перевалочная база» (буфер драйвера) и дополнительная пересылка данных, что приводит к дополнительным затратам времени.

Для обращения программы к пространству ввода-вывода предназначены всего четыре инструкции процессора: IN (ввод из порта в регистр процессора), OUT (вывод в порт из регистра процессора), INS (ввод из порта в элемент строки памяти) и OUTS (вывод элемента из строки памяти в порт). Последние две инструкции, появившиеся с процессором 80286, могут использоваться с префиксом повтора REP , что обеспечивает быструю пересылку блоков данных между портом и памятью. Обмен данными с портами, при котором применяют строковые инструкции ввода-вывода, получил название РIO (Programmed Input/Output — программированный ввод-вывод). Скорость такого обмена превышает скорость стандартного канала прямого доступа (DMA), правда, DMA в отличие от РIO почти не занимает процессорного времени.
Разрядность слова, передаваемого за одну инструкцию ввода-вывода, может составлять 8, 16 или 32 бита. В зависимости от «выровненности» адреса по границе слова и разрядности данных используемой шины это слово может передаваться за один или несколько циклов шины с указанием соответствующего нарастающего адреса в каждом цикле обращения к памяти. Инструкции ввода-вывода порождают шинные циклы обмена, в которых вырабатываются сигналы чтения порта/записи в порт. На шине ISA это сигналы IORD# и IOWR# соответственно; они и отличают пространство ввода-вывода от пространства памяти, где соответствующие операции чтения и записи вырабатывают сигналы MEMRD# и MEMWR# . На шине PCI разделение памяти и пространства ввода-вывода происходит иначе — здесь тип операции кодируется четырехбайтной командой, в зависимости от типа инструкции, выполняемой процессором.
Во избежание недоразумений и для экономии шинных циклов рекомендуется выравнивать адреса 16-битных портов по границе слова, а 32-битных — по границе двойного слова. Обращения по выровненным адресам выполняется за один цикл системной шины. Обращение по невыровненным адресам выполняется за несколько циклов, причем однозначная последовательность адресов обращений (которая зависит от модели процессора) не гарантируется. Так, например, одна инструкция вывода слова по нечетному адресу приведет к генерации двух смежных шинных циклов записи. При программировании обращений следует учитывать специфику устройств ввода-вывода. Если, например, устройство допускает только 16-разрядные обращения, то старший байт его регистров будет доступен лишь при вводе-выводе слова по четному адресу.
Некоторую сумятицу в стройную систему адресации вводят регистры ATА. Здесь регистр 1F0 (1 канал) является 16-битным регистром данных, но в то же время есть и совершенно независимый от него 8-битный регистр 1F1. В Serial ATA эта тема развита — здесь имеются еще четыре 16-битных регистра с адресами (относительно базового адреса блока командных регистров) 2, 3, 4 и 5, которые раньше были 8-битными.
В реальном режиме процессора программе доступно все пространство адресов ввода-вывода. В защищенном режиме 32-разрядных процессоров (частным случаем которого является и виртуальный режим V86) имеется возможность программного ограничения доступного пространства ввода-вывода, определяя его максимальный размер (начиная с нулевого адреса и в пределах 64 К), а внутри разрешенной области доступ может быть разрешен или запрещен для каждого конкретного адреса. Размер области и карта разрешенных портов (IO Permission Bitmap) задается операционной системой в дескрипторе сегмента состояния задачи (TSS). При обращении по неразрешенному адресу вырабатывается исключение процессора, а поведение его обработчика определяется операционной системой. Возможно снятие задачи-нарушителя (знаменитое сообщение «приложение. выполнило недопустимую операцию и будет закрыто»). Возможен и другой вариант, когда по обращению к порту монитор операционной системы выполняет некоторые действия, создавая для программы иллюзию реальной операции ввода-вывода. Таким образом виртуальная машина по операциям ввода-вывода может общаться с виртуальными устройствами. Заметим, что ОС Windows 9x не особо заботится о виртуализации и защите ввода-вывода; здесь, например, из DOS-окна можно обращаться к любым портам, даже к портам устройств, занятых операционной системой.

12.5.4. Прерывания
вперед к началу Главы вернуться назад
В процессорах х86 используются аппаратные прерывания, программные прерывания и исключения. Аппаратные прерывания были описаны выше; кроме того, к ним относится и специфичное (и неиспользуемое прикладными программами) прерывание SMI для входа в режим системного управления (SMM). Программные прерывания по сути прерываниями и не являются — это лишь короткая форма дальнего вызова ограниченного количества процедур, выполняемая инструкцией Int N (N-0-255). Программные прерывания, в частности, используются для вызовов сервисов BIOS и DOS. Исключения генерируются процессором и сопроцессором, когда при исполнении инструкций возникают особые условия (например, деление на ноль или срабатывание защиты). Исключения занимают векторы прерываний 0-31, которые частично пересекаются с векторами аппаратных прерываний ведущего контроллера и NMI, а также с векторами сервисов BIOS. В процессорах 8086/88 исключения назывались внутренними прерываниями, их было совсем мало. По мере «взросления» процессоров добавлялись новые исключения; исключениями особо богаты современные процессоры при работе в защищенном режиме. На исключениях строится защита и виртуальная память в многозадачных ОС защищенного режима.
В реальном режиме прерывания работают довольно просто, и их обработчики могут находиться в любом месте физически адресуемой памяти (ОЗУ или ПЗУ). В таблице прерываний, начинающейся с нулевого адреса, каждый вектор прерываний представляется дальним указателем на процедуру обработки (16-байтные смещение и сегмент). Внедрение собственных обработчиков прерываний представляет собой несложную задачу, если прерывание используется монопольно одним устройством и соответствующим ему единственным модулем ПО. В реальном режиме любая программа может управлять флагом разрешения аппаратных прерываний; некорректное управление флагом может приводить к различным неприятностям — от сбоя системного времени до «зависания» компьютера.
В защищенном режиме прерывания работают гораздо сложнее. Таблица прерываний здесь содержит 8-байтные дескрипторы прерываний. Их обработчики должны быть подключены к ядру ОС, постоянно присутствующему в физической памяти. Иначе возможна ситуация, когда, например, аппаратное прерывание вызовет обработчик, выгруженный в данный момент на диск менеджером виртуальной памяти. Обработка такого прерывания будет чрезвычайно долгой (потребуется подкачка страницы). Позволять любой программе управлять флагом разрешения прерываний для многозадачных ОС нельзя из соображений общей устойчивости системы. Сам процесс обработки прерываний (и исключений) в защищенном режиме существенно отличается от прерываний реального режима, и в современных процессорах и ОС имеются средства виртуализации прерываний, о чем подробнее можно прочитать в [6, 7]. Заметим, что в ОС Windows 9x каждое окно MS-DOS представляет собой отдельную виртуальную машину с собственной таблицей прерываний «реального» вида, и работа с прерываниями в ней практически не отличается от работы в «чистой» MS-DOS. Для установки обработчиков прерываний, требуемых программам защищенного режима, используются вызовы специальных сервисов ОС, и обработчик оформляется особым образом в соответствии с соглашениями этой ОС (не так, как для MS-DOS).

12.6. Аппаратные средства измерения времени
вперед к началу Главы вернуться назад
В IBM PC/AT имеются аппаратные средства для измерения времени. Трехканальный счетчик-таймер , программно совместимый с i8254 (в XT — 8253), выполняет следующие функции:
* канал 0 — генерация аппаратных прерываний ( IRQ0 ) каждые 54, 936 мс (частота 18, 206 Гц), вызывающих инкремент системного таймера (счетчика в ячейке 40: 006Е BIOS Data Area);
* канал 1 — генерация запросов на регенерацию памяти;
* канал 2 — генерация звуковых сигналов или измерение времени.
Внутренние счетчики микросхемы имеют разрядность 16 бит, но общение с ними возможно только 8-битными операциями. При этом можно задавать значение только младшего байта счетчика (LSB), только старшего (MSB) или обоих (LSB/MSB), причем сначала передается младший, а потом старший байт. Программирование микросхемы осуществляется записью байт в управляющий регистр по отдельности для каждого канала. Назначение регистров счетчиков-таймеров приведено в табл. 12.5. Входная частота для всех каналов 1,19318 МГц. Штатно все каналы работают в режиме генерации импульсов. Счет для каналов 0 и 1 разрешен постоянно. В канале 2 используется управляющий вход GATE, разрешающий счет, который управляется битом 0 ( T2G , R/W) системного порта AT (061h). Выходной сигнал канала 2 может быть программно считан ( Т20 , бит 5 того же порта). При использовании канала 2 для измерения времени необходимо отключить формирование звука (обнулив бит SPK , R/W, бит 1 порта 061h).

Таблица 12.5. Регистры счетчиков-таймеров
Порт, R/W Назначение регистров
040 RW Счетчик 0 — системные часы.
Режим 011, LSB/MSB, Binary, константа счетчика равна 0 (соответствует коэффициенту деления 65 536)
041 RW Счетчик 1 —регенерация памяти.
Режим 010, LSB, Binary, константа счетчика — равна 12h(18)
042 RW Счетчик 2 — генератор звука, измерение времени.
Вход GATE от бита 0 порта В 8255 (061).
Режим 011, LSB/MSB, Binary, значение счетчика определяет высоту тона
043 W Управляющий регистр.
Биты 7, 6 — выбор счетчика 0, 1, 2.
Биты 5, 4 — режим обращения:
00 —защелка текущего значения;
01 — LSB —только младший байт;
10 — MSB — только старший байт;
11 — LSB/MSB — сначала младший, затем старший байты.
Биты 3-1 — режим счетчика:
000 — прерывание по счетчику;
001 — ждущий мультивибратор (одновибратор, у 8254 несколько отличается от 8253);
х10 — генератор коротких импульсов заданной частоты;
х11 — генератор меандра;
100 — счетчик событий с разрешением;
101 — счетчик событий с перезапуском.
Бит 0 — 0=Bin (двоичный счет), 1 =BCD — (двоично-десятичный счет)

Таблица 12.6. Назначение ячеек таймерной части CMOS RTC
Индекс Назначение
00h-09h, 32h
(37 в PS/2)
Ячейки RTC в BCD-формате:
00 — секунды;
01 — секунды будильника;
02 — минуты;
03 — минуты будильника;
04 — часы;
05 — часы будильника;
06 — день недели;
07— день месяца;
08 — месяц;
09 — год (2 младшие цифры);
32h — век-1 (2 старшие цифры года);
37h — век-1 (2 старшие цифры года) в PS/2
0Ah RTC Status Register А (регистр статуса А):
бит 7 — обновление времени (0 — готов к чтению);
биты [6:4] — делитель частоты (для кварца на 32,768 кГц — 010);
биты [3:0] — 0110 — выходная частота меандра 1 024 Гц
0Bh RTC Status Register В (регистр статуса В):
бит 7 — остановка часов (0 — нормальный ход);
бит 6 — разрешение периодических прерываний (0 — запрещено);
бит 5 — разрешение прерывания от будильника (0 — запрещено);
бит 4 — разрешение прерывания по окончании смены времени (0 — запрещено);
бит 3 (см. также регистр OAh) — разрешение выходного меандра (0 — запрещено);
бит 2 — формат BCD/BIN (0 — BCD); бит1 — 12/24-часовой режим (1 —24-часовой);
бит 0 — зимнее/летнее время (0 — переключение запрещено)
0Ch RTC Status Register С (регистр статуса С): чтение флагов идентификаторов прерывания:
бит 7 — IRQF (общий запрос прерывания);
бит 6 — PF (периодические прерывания);
бит 5 — AF (прерывание от будильника);
бит 4 — UF (прерывание по окончании смены времени);
биты [3:0] — зарезервированы
0Dh RTC Status Register D (регистр статуса D):
бит 7 — питание ( 1 — норма, 0 — разряд батареи);
биты [6:0] — зарезервированы

Аппаратные таймеры имеют поддержку функциями BIOS (подробнее см. [1, 8, 9]). Сервисы BIOS Int 1Ah позволяют считывать и модифицировать значения системного таймера (ячейки 40: 006Eh в BIOS Data Area ), а также даты, времени и будильника CMOS RTC.
Функции BIOS Int 15h позволяют с помощью CMOS RTC вводить задержку или запускать таймер установки флага (через заданное время установить бит 7 указанной ячейки памяти). Время задается в микросекундах, но минимальная выдержка зависит от производительности ПК (достижимы единицы миллисекунд), максимальная выдержка — около 70 часов.
Начиная с процессоров Pentium, появилась возможность измерения времени с точностью до такта ядра процессора. Для этого процессоры имеют внутренний 64-битный счетчик TSC (Time Stamp Counter), обнуляющийся по аппаратному сбросу (сигналом RESET# ). Разрядность позволяет считать без переполнения в течение нескольких столетий. Для доступа к счетчику имеется специальная инструкция RDTSC , правда, установкой флага TSD в управляющем регистре CR4 (процессора) ОС может сделать ее привилегированной (доступной только на нулевом уровне привилегий). В этом случае приложение, исполняемое на уровне 3, может аварийно завершаться по отказу исполнения инструкции. ОС может и позволить обращение к этому регистру, но «подсовывая» программе угодное ей значение времени. Заметим, что из-за внутреннего умножения частоты в процессоре результат чтения счетчика может отставать от реального времени на число, достигающее коэффициента умножения частоты. Правда, такая точность никому и не нужна (она потеряется в измеряющих программах).

12.7. Способы запуска программ
вперед к началу Главы вернуться назад
Традиционным способом запуска программ является загрузка их с какого-либо устройства хранения (диска) в оперативную память и исполнение в ОЗУ, До того как пользователь получает возможность такого запуска, требуется множество предварительных действий. По включении питания (и аппаратному сбросу) процессор начинает исполнять процедуру POST (начальный запуск и самотестирование) из ROM BIOS, причем большая часть кода исполняется прямо в ПЗУ. POST инициализирует стандартное оборудование ПК (о котором «знает» ROM BIOS системной платы), а также обнаруживает модули расширения ROM BIOS и запускает их процедуры инициализации. Далее POST определяет загрузочное устройство (обычно диск), ищет на нем загрузочную запись (сектор), загружает этот сектор в фиксированную область ОЗУ и передает управление на его начальный адрес. С этого момента, как правило, начинается процесс загрузки операционной системы с того же носителя; сначала базовой системы, а затем и всех необходимых дополнительных компонентов в виде драйверов и автоматически загружаемых программ. Только после этого пользователь может запускать требуемые программы с любого доступного устройства хранения (в том числе и через сеть). Программы могут загружаться и автоматически, без участия пользователя, по предварительно составленному и сохраненному сценарию (файлы config.sys, autoexec.bat и т. п. средства).
Для ряда специальных применений ПК приходится нарушать эти традиции. Для сравнительно простых систем можно отказаться от использования операционных систем. Программу функционирования компьютера можно «зашить» в ПЗУ, оформив в виде модуля расширения BIOS, и эта программа получит управление от POST. Можно и не связываться с ПЗУ, а загружать программу с устройства хранения простым загрузчиком, первая ступень которого должна совпадать со стандартным начальным загрузчиком. Однако не стоит отказываться от операционной системы без веских причин, поскольку она обеспечивает не только удобное операционное окружение, но и средства разработки и отладки программ. Операционную систему и необходимые программы можно загружать не только с привычных дисков (гибких, жестких, оптических), но и с компактных твердотельных носителей (см. п. 9.3). Эти носители могут подключаться к обычным интерфейсам устройств хранения.
Интересный вариант «твердотельного диска» — DiskOnChip — для микрокомпьютеров и микроконтроллеров, не имеющих стандартных интерфейсов устройств хранения, предлагает фирма M-Systis. Это микросхема, имеющая интерфейс 8/16-битной статической памяти, легко подключаемый к шине ISA (или локальной шине). Модель Millenium Plus объемом 32 Мбайт содержит массив флэш-памяти архитектуры NAND, модуль статической памяти SRAM (1 Кбайт), интерфейсные схемы, логику защиты записи и чтения и схемы обнаружения и исправления ошибок. Микросхема отображается на 8-Кбайтную страницу пространства памяти компьютера в области C8000-EFFFFh. По сигналу аппаратного сброса начальный блок из флэш-памяти выгружается в SRAM; если обнаруживается ошибка, то берется следующий (резервный) блок. Этот блок содержит процедуру инициализации «диска», которая обнаруживается тестом POST как модуль расширения BIOS. Процедура загружает из флэш-массива в системное ОЗУ драйвер своего «электронного диска» (блочного устройства), которое становится первым или последним логическим жестким диском (по выбору при конфигурировании). Далее к этому «диску» можно обращаться обычным способом (через Int 13h ), с него же может и загружаться ОС. Интерфейс допускает каскадирование — объединение в единый диск до 4 микросхем, увеличивая его объем до 128 Мбайт, при этом все микросхемы отображаются через общее окно памяти (используют общий сигнал выборки). Встроенное ПО обеспечивает полную эмуляцию диска с прозрачным исправлением ошибок и переназначением дефектных секторов. Микросхема поддерживает длительную скорость записи 750 Кбайт/с, считывания — 2, 4 Мбайт/с. Пиковая скорость считывания/записи достигает 20 Мбайт/с. В устройстве имеется уникальный идентификационный номер, область для однократного программирования (ОТР), возможность защиты от записи отдельных зон и возможность ограничения доступа по паролю (нечитаемому).

ПРИМЕЧАНИЕ

Функции ROM BIOS 16-битные сервисы):
* Int 05h (F000:FF54h) — печать экрана;
* Int 10h — видеосервис;
* Int 11h — чтение списка оборудования (слово из BDA 0040:0010h), возвращает в АХ:
• биты 15:14 — число обнаруженных LPT-портов: 00 —0, 11 — 3;
• бит 13 — резерв;
• бит 12 — обнаружен игровой адаптер;
• биты 11:9 — число обнаруженных СОМ-портов: 000 —0, 111 — 7;
• бит 8 — наличие контроллера DMA;
• биты 7:6 — число обнаруженных НГМД: 00 — 1, 11 — 4;
• биты 5:4 — активный видеорежим: 00 — резерв, 10 — 80-колоночный цветной, 01 — 40-колоночный цветной, 11 — монохромный;
• биты 3:2 — размер ОЗУ на системной плате (теперь обычно 00);
• бит 0 — присутствие дисководов;
* Int 12h — размер непрерывной памяти;
* Int 13h — дисковый сервис (блочный ввод-вывод);
* Int 14h — обслуживание СОМ-портов;
* Int 15h — АТ-функции (системный сервис, функции определяются значением АН/АХ):
• 00-0Зh — управление и обмен данными с кассетным магнитофоном (были когда-то и такие «стриммеры») на старых PC;
• 4fh — перехват клавиатуры;
• 53xxh — сервисы управления потреблением АРМ (Advanced Power Managient);
• 8300h — запуск таймера, устанавливающего флаг в заданной ячейке;
• 8301h — сброс того же таймера;
• 84h — джойстик (см. п. 8.6);
• 86h — программируемая задержка;
• 87h — перемещение блока расширенной памяти;
• 88h — получение размера расширенной памяти;
• 89h — переключение в режим V86;
•C0h — получение системной конфигурации, при успешном выполнении (CF=0, AH=0) ES: BX указывает на таблицу данных конфигурации;
•80-82h, 85h, 90h, 91h — функции многозадачных ОС (BIOS устанавливает заглушки);
* Int 16h — клавиатурный ввод-вывод;
* Int 17h — обслуживание LPT-портов;
* Int 18h — процедура восстановления при неудаче начальной загрузки (прежде — ROM-Basic);
* Int 19h — начальная загрузка (вызов процедуры Bootstrap);
* Int 1Ah — системное время, дата, будильник и 16-битные вызовы сервисов PCI;
* Int 1Bh — обработчик нажатия клавиш Ctrl+Break;
* Int 1Ch — User Timer Interrupt, процедура, вызываемая обработчиком Int 08h каждые 55 мс; BIOS устанавливает простую заглушку ( IRET ), но программы могут перехватывать это прерывание; на время отработки этой процедуры все аппаратные прерывания запрещены (кроме NMI).
* Int 33h — поддержка мыши;
* Int 4Ah — обработчик будильника пользователя, установленного функцией BIOS Int lAh(6); прерывание вызывается асинхронно, так что при возврате из процедуры все регистры и флаги должны быть в том же состоянии, что и при входе; BIOS ставит заглушку ( IRET );
* Int 67h — EMS-функции.
Указатели на таблицы:
* Int 1Dh — видеопараметры;
* Int 1Eh — параметры дискет;
* Int IFh — знакогенератор CGA;
* Int 41h — параметры HDD0;
* Int 46h — параметры HDD1;
* Int 43h — знакогенератор EGA.

Поддержка клавиатуры заключается в обработке прерываний от устройства ввода и предоставлении сервисов ввода прикладным программам.
Прерывания , вызванные приходом кодов нажатия и отпускания клавиш , обрабатывает BIOS Int 9h . Каждый принятый скан-код (или цепочка) обрабатывается с учетом состояния клавиатурных флагов . Результат обработки (как правило, ASCII-символ в младшем байте и скан-код в старшем) помещается в клавиатурный буфер , расположенный в ОЗУ. По приему каждого символа указатель головы буфера увеличивается. Буфер организован в виде кольца, после достижения конца области буфера указатель головы установится на начало области. В случае переполнения буфера (указатель головы «догнал» указатель хвоста) очередное слово не записывается, и подается звуковой сигнал. Размер позволяет хранить описание шестнадцати фактов нажатий клавиш. Нажатие клавиш Ctrl, Shift, Alt — и некоторых комбинаций в буфере не отмечается, но приводит к модификации бит ячеек флагов клавиатуры. Нажатие «системной» комбинации Ctrl+Alt+Del , клавиши PrintScreen (SysRq) и некоторых других к записи в клавиатурный буфер не приводит, а вызывает специальные процедуры.
Для обслуживания клавиатуры используются ячейки ОЗУ из области данных BIOS (BIOS Data Area):
* 0:0417, 0:418 — флаги клавиатуры;
* 0:0419 — аккумулятор кода Alt -набора;
* 0:041А — указатель головы буфера (Buffer Head), 2 байта (модифицируется при помещении символа в буфер);
* 0:041C — указатель хвоста буфера (Buffer Tail), 2 байта (модифицируется при извлечении символа из буфера);
* 0:041E-0:042D — область кольцевого буфера (16 слов).
Обработчик аппаратного прерывания до обработки принятого скан-кода вызывает прерывание BIOS Int15h с AH=4Fh , а в AL находится принятый скан-код. Стандартный обработчик Int 15h (4Fh) просто выполняет возврат с CF=0 , но его можно заменить специальным обработчиком, который будет при необходимости подменять принятые скан-коды на какие-либо иные (оставляя их в AL ), что должно отмечаться установкой CF=1 . В старых версиях BIOS такой возможности перехвата не было, ее наличие можно определить вызовом Int 15h (C0h).
Для клавиатуры USB или иного устройства ввода, заменяющего клавиатуру в качестве консоли, прерывание Int 9h должно вызываться программно при обработке каждого клавиатурного события. Обработчик этого прерывания должен выполнять те же действия: скан-код пропускать через Int 15h (4Fh) и помещать в клавиатурный буфер, а также модифицировать флаги клавиатуры.
Интерфейс прикладного уровня для клавиатуры представляет BIOS Int 16h . Его основное назначение — извлечение слов из клавиатурного буфера. Функция задается в регистре АН при вызове, результат помещается в регистр АХ.
* АН = 00Н — чтение (с ожиданием готовности) и выборка слова из буфера (меняется указатель хвоста). Индикаторы клавиатуры обновляются в соответствии с состоянием флагов. Если буфер пуст, то на AT выполняется прерывание Int 15h (подфункция 90), что может использоваться ОС, например, для переключения задач. Чтобы программа не «зависала» на ожидании символа, предварительно стоит проверить готовность функцией 01h. Символы расширенной клавиатуры фильтруются — преобразуются в их аналоги 83-клавиш-ной клавиатуры.
* АН = 01h — проверка готовности, чтение без выборки (указатели не изменяются). Признак наличия символа в буфере — установленный флаг ZF.
* АН = 02h — чтение состояния флагов (в AL — байт 0:417h, см. выше).
* АН = 03h — установка задержки и частоты автоповтора: BL — код задержки (00=250, 01-500, 02=750, 03=1000 мс), ВН — код частоты (см. п. 9.2.1).
* АН = 05h — запись слова из регистра СХ в буфер (меняется указатель головы). Признак успешной записи — АL=0 , если в буфере нет места, то AL=1 .
* АН = 10h и AH = 11h — функции, аналогичные 00h и 01h, но предназначены специально для 101/102-клавишных клавиатур — в них не выполняется фильтрация символов расширенной клавиатуры. Для ряда клавиш, отсутствующих в клавиатуре АТ-84, эти функции дадут результаты, отличающиеся от вызовов 00h и 01h.
* AH = 12h — чтение расширенного состояния флагов (в АХ — слово KbdShiftFlags101Rec ), в котором младший байт совпадает с тем, что дает функция 02h (слово из 0:417h), а старший байт похож на слово из 0:418h. Назначение бит АХ:
* бит 0 — клавиша Shift (правая) нажата;
* бит 1 — клавиша Shift (левая) нажата;
* бит 2 — клавиша Ctrl (любая) нажата;
* бит 3 — клавиша Alt (любая) нажата;
* бит 4 — включен индикатор Scroll Lock ;
* бит 5 — включен индикатор Num Lock ;
* бит 6 — включен индикатор Caps Lock ;
* бит 7 — включен режим Insert ;
* бит 8 — клавиша Ctrl (левая) нажата;
* бит 9 — клавиша Alt (левая) нажата;
* бит 10 — клавиша Ctrl (правая) нажата;
* бит 11 — клавиша Alt (правая) нажата;
* бит 12 — клавиша Scroll Lock нажата;
* бит 13 — клавиша Num Lock нажата;
* бит 14 — клавиша Caps Lock нажата;
* бит 15 — клавиша SysReq нажата.
Функции чтения буфера (00 и 10h) в регистре AL возвращают ASCII-код символа, в АН — скан-код . Символы, полученные нестандартным способом (в русском регистре или Alt -набором), сопровождаются нулевым скан-кодом. Alt -набор позволяет ввести в буфер любой символ — для этого его код в десятичной системе набирается на цифровой клавиатуре при нажатой клавише Alt , результат заносится в буфер при отпускании клавиши Alt .
При AL=0 регистр АН содержит расширенный ASCII-код (Extended ASCII Keystroke). Дополнительные клавиши 101/102 клавиатур при использовании функций 10h-12h генерируют код E0h в младшем байте и скан-код, соответствующий аналогичным управляющим клавишам 83/84-клавишных клавиатур.
Функция записи (05h), несколько неожиданная для клавиатуры, позволяет легко имитировать работу оператора для различных демонстрационных программ. Если прикладная программа не перехватывает обслуживание клавиатуры на уровне аппаратного прерывания ( Int 9h ), то резидентная программа может ей «подбрасывать» слова в буфер, которые будут восприниматься как нажатие клавиш.
ASCII-коды буфера, соответствующие нажатию клавиш, приведены в [1, 7]. При русификации (или другой локализации) клавиатуры отслеживание переключения регистров (языков) ложится на обработчик аппаратного прерывания клавиатуры.

12.8.2. Int 10h — видеосервис
вперед к началу Главы вернуться назад
Int 10h — видеосервис — предназначен для работы с графическим адаптером. Его первичной задачей является управление видеорежимом (BIOS Video Mode), определяющим формат экрана. BIOS адаптера должна выполнять программирование всех стандартных и специфических управляющих регистров для установки (смены) требуемого видеорежима и выбранных параметров развертки — кроме нее о способах этих переключений остальное ПО может и не знать.
В пределах возможностей установленного видеорежима видеосервис предоставляет возможности отображения информации на различных уровнях. Простейший для программиста телетайпный режим позволяет посылать поток символов, которые будут построчно отображаться на экране с отработкой символов возврата каретки, перевода строки, обеспечивая «прокрутку» изображения при заполнении экрана. Есть функции и для полноэкранной работы с текстом, при которой доступны и атрибуты символа. В графическом режиме имеется возможность чтения и записи пиксела с указанными координатами. Однако видеосервисом Int 10h программисты пользуются далеко не всегда, поскольку работает он довольно медленно. Подробно рассматривать функции видеосервиса не будем (этому посвящены отдельные книги), отметим особо лишь функцию телетайпного вывода Int 10h (0Eh). При вызове AH=0Eh , в AL — код выводимого символа, в BL — цвет (только для графического режима). Символ выводится в текущую позицию курсора, и курсор сдвигается на следующую, переходя на новую строку после конца предыдущей и прокручивая экран при его заполнении. Специальные символы вызывают возврат на начало строки ( CR , код 0Dh), перевод строки ( LF , 0Ah) и короткий гудок ( BEL , 07h). Этой функцией часто пользуются для вывода сообщений программами, работающими на нижнем уровне (например, модули инициализации ПЗУ расширений BIOS, загрузчики и другие, не имеющие еще доступа к сервисам операционных систем). Программа вывода получается простейшей, работает на всех адаптерах и во всех режимах, но довольно медленно.

12.8.3. Int 13h — поддержка дисков
вперед к началу Главы вернуться назад
Функции дискового сервиса вызываются программным прерыванием Int 13h .
Традиционно дисковый сервис подразделяет физические диски на дискеты (diskette) и фиксированные диски (fixed disk). Набор функций (табл. 7.8) для этих классов устройств несколько различается как по составу, так и по реализации. Классы различаются по диапазонам номеров физических устройств: для дискет отводятся номера 0-7FH (реально только 0-3), а для фиксированных дисков — 80h-FFh.
Контроллеры дисковых интерфейсов, имеющие в своем составе дополнительные модули BIOS, перехватывают вектор Int 13h , беря на себя обслуживание своих устройств. Когда в IBM PC/XT появились жесткие диски со своим контроллером, модуль BIOS этого контроллера, инициализирующийся во время теста POST, вставал на место Int 13h , а указатель на исходный обработчик дискового сервиса (драйвер НГМД из системной BIOS) сохранялся на месте Int 40h . Хотя поддержка жестких дисков давно уже включена в системную BIOS, ради совместимости возможность использования прерывания Int 40h для вызова драйвера гибких дисков сохраняется. Интерфейс этого вызова совпадает c Int 13h , нo номер устройства (в регистре DL ) не должен превышать 7Fh.
Кроме функций дискового сервиса ( Int 13h )c дисковыми устройствами связаны еще и векторы, обслуживающие аппаратные прерывания от контроллера НГМД — Int 0Eh (линия IRQ 6 ) и от контроллера жестких дисков — Int 76h (линия IRQ 14 ). При наличии двухканального порта АТА второй канал обычно задействует линию IRQ 15 (вектор 77h). В XT контроллер жестких дисков занимал линию IRQ 5 (вектор 0Dh). Дополнительные контроллеры дисков могут использовать и другие прерывания. Аппаратные прерывания вырабатываются контроллерами по завершении (нормальному и аварийному) внутренних операций. На эти прерывания BIOS не реагирует, а при инициализации их векторы направляются на программную заглушку (инструкцию IRET ).
Стандартные драйверы дисковых функций BIOS (включая и расширенный сервис) имеют однозадачное происхождение. Во время выполнения функции значительное процессорное время может затрачиваться на ожидание завершения операции устройством. Драйверы многозадачного режима построены иначе: у них есть вызывающая часть, инициализирующая начало операции, и обработчик аппаратного прерывания от контроллера, сообщающий операционной системе о выполнении операции и результате.

Таблица 12.7. Функции традиционного дискового сервиса
Номер функции АН Назначение параметров Использование регистров, указателей и таблиц
DL DH, CL, CH AL ES:BX DPT/HDPT
00h Reset Disk System — сброс дисковой системы (всех контроллеров и устройств), позиционирование на нулевой цилиндр
01h Read Status of Last Operation — чтение состояния последней операции +
02h Read Sectors into Memory — чтение секторов с диска в память + + + + +
03h Write Sectors from Memory — запись секторов из памяти на диск + + + + +
04h Verify Sectors — верификация секторов (холостое чтение без записи в память и проверка CRC/ECC) + + + +
05h Format Desired Track — форматирование трека + + + + +
08h Get Drive Parameters — получение параметров диска + 3 + 3 + 3 + 3
09h 1 Initialize Drive Parameters — инициализация таблиц параметров диска + +
0Ah 1 Read Long — «длинное» чтение (сектор и поле ЕСС) + + + + +
0Bh 1 Write Long — «длинная» запись (сектор и поле ЕСС) + + + + +
0Ch 1 Seek — поиск цилиндра + +
0Dh 1 Alternative Disk Reset — альтернативный сброс (не затрагивая контроллера дискет) +
10h 1 Test Drive Ready — проверка готовности +
11h 1 Recalibrate — рекалибровка (позиционирование на нулевой цилиндр) +
14h 1 Controller Internal Diagnostics — диагностика контроллера жестких дисков
15h 1 Read DASD Туре — получение типа диска:
• АН=0 — нет диска;
• АН=1 —дискета, без датчика смены диска;
• АН=2 —дискета, сдатчиком смены диска;
• АН=3 — жесткий диск;
• иные значения — код ошибки.
CX: DX содержат число 512-байтных секторов на диске
+
16h 2 Diskette Change Line Status — проверка статуса смены дискеты:
• CF=0:AH=0 — смены носителя не было;
• CF=1:АН=1 —недопустимый номер диска;
• АН=6 — была смена диска или определение смены не поддерживается;
• АН=80h— дисковод не готов или не установлен;
• иные значения — код ошибки
+
17h 2 Set Diskette Type for Format — установка типа дискеты для форматирования (перед форматированием) + + 3
18h 2 Set Media Type for Format — установка типа носителя (для форматирования) + + 3
20h 2 Get Media Type — получение типа установленного носителя +
24h 1 Set Multiple Mode — установка параметров режима многосекторного обращения (в AL — число секторов за операцию) + +
25h 1 Identify Drive ATA — идентификация накопителя (только для ATA—дисков) +

Формально традиционный сервис позволяет работать с дисками, имеющими до 1024*256*63=16 515 072 секторов (около 8,4 Гбайт). Ряд операционных систем имеет ошибку, не позволяющую использовать полный объем, допустимый данным сервисом. Для дисков объемом более 15 481 935 секторов следует пользоваться только функциями расширенного сервиса (см. ниже). Однако при работе с устройствами АТА имеется еще и барьер в 528 Мбайт. Дело в том, что контроллер жесткого диска АТА, на который ориентированы драйверы Int 13h , имеет только 4-битный регистр номера головки (а в BIOS — 6 бит). Правда, этот же контроллер способен принимать 16-битный номер цилиндра (в BIOS — 10 бит). Понятно, что непосредственно без искажений через эти два фильтра (формат вызова и формат регистров контроллера) может пройти только вызов с самыми жесткими ограничениями по каждой координате. Тогда ограничение, полученное тем же перемножением диапазонов координат, получается около 528 миллионов байт:
(2 10 = 1024 цилиндра) х (2 4 = 16 головок) х (2 6 — 1 = 63 сектора) х 512 байт = 528 482 304 байт.
Для преодоления 528-мегабайтного барьера дисков АТА, не трогая программного интерфейса, в BIOS ввели расширение традиционного дискового сервиса. Интерфейс АТА в трехмерной геометрии позволяет реализовать довольно большой (но уже не запредельный) объем диска:
(216 = 65 536 цилиндров)*(24 = 16 головок)* (28 — 1 = 255 сектора)* 512 байт = = 136,9 Гбайт.
Чтобы достичь хотя бы интерфейсного ограничения BIOS (8,4 Гбайт), стали применять трансляцию параметров вызова функций Int 13h , которые будем теперь называть логическими , в физические 1 параметры, передаваемые контроллерам АТА-дисков. В функции, которая сообщает параметры диска (функция 8), производится обратная трансляция, так что на стороне вызова программного интерфейса Int 13h присутствуют только логические параметры . Естественно, логический объем диска не может превышать физического: (С х Н х 5) лог физ .
Подробнее о преодолении барьеров и способах трансляции (LBA, Large Disk, ЕСН5) см. в[1, 4, 9]
1 Зная устройство современных винчестеров, здесь и далее не будем добираться до истинно физических параметров — реального номера цилиндра, головки и сектора.

Расширенный сервис BIOS
вперед к началу Главы вернуться назад

Чтобы получить возможность работы через BIOS с дисками объема более 8,4Гбайт, потребовалось ввести новые функции дискового сервиса.
Расширенный дисковый сервис BIOS, Enhanced Disk Drive Services (EDD), продвигаемый фирмой Phoenix Technologies LTD, реализуется многими разработчиками BIOS и устройств массовой памяти. Он позволяет работать с устройствами, имеющими объем до 2 64 секторов, эффективно используя архитектуру процессоров IA-32 и IA-64. Сервис оперирует линейным логическим адресом сектора (LBA). Вместо традиционных таблиц параметров дисков в нем используются новые, дающие исчерпывающую информацию об устройствах, их физической организации и интерфейсе. Устройства могут иметь сменные носители и сами быть съемными в процессе работы компьютера (например, подключенные к шине USB или IEEE1394), так что понятие «сменяемость носителя» несколько размывается. Такие устройства должны поддерживать механизм уведомления о смене носителя и программное блокирование смены носителя. По прогнозам емкости данного интерфейса должно хватить на 15-20 лет.
Расширения BIOS Int 13h используют ОС Windows 95, Windows 98, Windows 2000. Правда, это использование ограничено лишь начальной загрузкой и процессом установки (FDISK, FORMAT), поскольку в регулярной работе применяются собственные 32-разрядные драйверы. Расширения BIOS Int 13h не используют DOS (все версии), Windows 3.1x, Windows NT, Novell NetWare, OS/2 Warp, Linux, Unix.
В настоящее время определены три набора функций:
* доступ к фиксированным дискам (fixed disk access subset) — функции 41-44h, 47h и 48h;
* блокировка и смена носителя (device locking and ejecting subset) — функции 41h, 45h, 46h, 48h и 49h;
* поддержка расширенных дисков (enhanced disk drive (EDD) support subset) — функции 41h и 48h.
Расширенный сервис, как и традиционный, вызывается программным прерыванием Int 13h с номерами функций свыше 3Fh (регистр АН ); номер устройства (регистр DL ) допустим в диапазоне 80h-FFh. Основные параметры вызова — начальный адрес блока, число секторов для передачи и адрес буфера — передаются через адресный пакет (device address packet). Формат пакета в сравнении с передачей параметров традиционного сервиса через регистры процессора довольно просторный.
Поскольку расширение BIOS может и отсутствовать, имеется функция проверки его наличия (номер 41h). Расширение может действовать избирательно (не для всех устройств), так что проверку надо производить для конкретного устройства, интересующего программу. Проверка дает номер версии расширения и карту поддерживаемых наборов функций. Функции расширенного чтения, записи, верификации и поиска (42h, 43h, 44h и 47h) по смыслу не отличаются от их аналогов из традиционного сервиса. Для работы со сменными носителями введены функции отпирания/запирания, извлечения и проверки факта смены носителя (45h, 46h и 49h). От идеологии традиционного сервиса сильно отличается функция получения параметров устройства (48h). Она возвращает в ОЗУ буфер с набором параметров и детальным описанием устройства, позволяющим ОС и приложениям работать с ним, минуя BIOS. Функция установка аппаратной конфигурации (4Eh) позволяет управлять режимом передачи (РIO, DMA), а также предварительной выборкой (поиском).
Для эмуляции дисков на загружаемых CD-ROM к сервисам BIOS Int 13h добавляется несколько новых функций:
* начать /завершить эмуляцию диска (4Ah/4Bh), начать эмуляцию диска и выполнить загрузку (4Ch);
* прочитать секторы загрузочного каталога (4Dh); функции 41-48h позволяют обращаться к любым логическим секторам CD-ROM (в режиме LBA с размером сектора 2048 байт), когда для данного привода включена эмуляция.
Подробнее расширенный сервис рассмотрен в [4].

12.8.4. Int 14h — поддержка СОМ-портов
вперед к началу Главы вернуться назад
CОМ-порты поддерживаются сервисом BIOS Int 14h , который обеспечивает описанные ниже функции.
* 00h — инициализация (установка скорости обмена и формата посылок, заданных регистром AL ; запрет источников прерываний). На сигналы DTR и RTS влияния не оказывает (после аппаратного сброса они пассивны).
* 01h — вывод символа из регистра AL (без аппаратных прерываний). Активируются сигналы DTR и RTS , и после освобождения регистра THR в него помещается выводимый символ. Если за заданное время регистр не освобождается, фиксируется ошибка тайм-аута и функция завершается.
* 02h — ввод символа (без аппаратных прерываний). Активируется только сигнал DTR ( RTS переходит в пассивное состояние), и ожидается готовность принятых данных, принятый символ помещается в регистр AL . Если за заданное время данные не получены, функция завершается с ошибкой тайм-аута.
* 03h — опрос состояния модема и линии (чтение регистров MSR и LSR ). Эту гарантированно быструю функцию обычно вызывают перед функциями ввода-вывода во избежание риска ожидания тайм-аута.
При вызове Int 14h номер функции задается в регистре АН , номер порта (0-3) — в регистре DX (0 — СОМ1, 1 — COM2. ). При возврате из функций 0, 1 и 3 регистр АН содержит байт состояния линии (регистр LSR ), AL — байт состояния модема ( MSR ). При возврате из функции 2 нулевое значение бита 7 регистра АН указывает на наличие принятого символа в регистре AL ; ненулевое значение бита 7 — на ошибку приема, которую можно уточнить функцией 3.
Байт состояния линии (регистр АН ) имеет следующий формат:
* бит 7 — ошибка тайм-аута (после вызова функции 2 — признак любой ошибки);
* бит 6 — регистр сдвига передатчика пуст (пауза передачи);
* бит 5 — промежуточный регистр передатчика пуст (готов принять символ для передачи);
* бит 4 — обнаружен обрыв линии;
* бит 3 — ошибка кадра (отсутствие стон-бита);
* бит 2 — ошибка паритета принятого символа;
* бит 1 — переполнение (потеря символа);
* бит 0 — регистр данных содержит принятый символ.
Байт состояния модема (регистр AL при возврате из функций 0, 1, 3) имеет следующий формат:
* бит 7 — состояние линии DCD ;
* бит 6 — состояние линии RI ;
* бит 5 — состояние линии DSR ;
* бит 4 — состояние линии CTS ;
* бит 3 — изменение состояния DCD ;
* бит 2 — изменение огибающей RI ;
* бит 1 — изменение состояния DSR ;
* бит 0 — изменение состояния CTS .
При инициализации порта биты регистра AL имеют следующее назначение:
* биты [7:5] — скорость обмена:
• 000=110; 100=1200; 001 = 150; 101=2400;
• 010=300; 110=4800; 011=600; 111=9600 бит/с;
* биты [4:3] — контроль паритета:
• 01 — число единиц нечетное;
• 11 — четное;
• 0 и 10 — без контроля;
* бит 2 — количество стоп-бит: 0 — 1 бит, 1 — 2 бита (на скорости 110 бит/с — 1,5 стоп-бит);
* биты [1:0] — длина посылки: 00 — 5 бит, 01 — 6 бит, 10 — 7 бит, 11 — 8 бит.
В процессе начального тестирования POST BIOS проверяет наличие последовательных портов (регистров UART 8250 или совместимых) по стандартным адресам и помещает базовые адреса обнаруженных портов в ячейки BIOS Data Area 0:0400, 0402, 0404, 0406. Эти ячейки хранят адреса портов с логическими именами СОМ1- СОМ4. Нулевое значение адреса является признаком отсутствия порта с данным номером. В ячейки 0:047С, 047D, 047Е, 047F заносятся константы, задающие тайм-аут для портов.
Обнаруженные порты инициализируются на скорость обмена 2400 бит/с, 7 бит данных с контролем на четность (even), 1 стоп-бит. Управляющие сигналы интерфейса DTR и RTS переводятся в исходное состояние («выключено» — положительное напряжение).

12.8.5. Int 17h — поддержка принтера
вперед к началу Главы вернуться назад
Сервисы BIOS Int 17h : обеспечивают инициализацию, вывод байта данных и опрос состояния принтера, подключенного к LPT-порту. При вызове функция задается в регистре АН , номер LPT-порта — в регистре DX.
* АН = 00h — вывод байта из регистра AL по протоколу Centronics (без аппаратных прерываний). Данные помещаются в выходной регистр, и, дождавшись готовности принтера (снятия сигнала Busy ), формируется строб.
* АН = 01h — инициализация интерфейса и принтера (установка исходных уровней управляющих сигналов, формирование импульса Init# , запрет аппаратных прерываний и переключение на вывод двунаправленного интерфейса).
* АН = 02h — опрос состояния принтера (чтение регистра состояния порта).
При возврате регистр АН содержит байт состояния , который собирается из бит-регистра состояния SR [7:3] и программно формируемого флага тайм-аута. Биты 6 и 3 относительно байта, считанного из регистра состояния, инвертированы. Назначение бит байта состояния:
* бит 7 — не занято (сигнал Busy ); нулевое значение означает, что принтер занят (буфер полон или состояние Off-Line, или ошибка);
* бит 6 — подтверждение (сигнал Ack# ); единичное значение означает, что принтер подключен;
* бит 5 — конец бумаги (сигнал PaperEnd );
* бит 4 — принтер готов (сигнал Select); нулевое значение означает, что принтер в состоянии Off-Line;
* бит 3 — ошибка принтера (сигнал Error# ); единичное значение соответствует ошибке;
* биты 2:1=00 (не используются);
* бит 0 — флаг тайм-аута, устанавливается при неудачной попытке вывода символа, если сигнал Busy не снимается в течение времени, определенного для данного порта в ячейках тайм-аута (в BIOS Data Area ); в этом случае согласно протоколу Centronics строб данных не вырабатывается.
Перехват прерывания Int 17h является удобным способом внедрения собственных драйверов принтера. Потребность в них может возникать при подключении к порту принтера с интерфейсом ИРПР или необходимости перекодировки символов. Если разрабатываемый драйвер предназначен не только для перекодировки, но и изменения протокола (через Int 17h можно организовать вывод через LPT-порт по протоколу ИРПР и даже через СОМ-порт), следует внимательно отнестись к битам возвращаемого байта состояния. При их неправильном формировании попытки вывода на печать могут приводить к ошибочным сообщениям.

12.8.6. Int 1Ah и Int 15h—поддержка таймеров
вперед к началу Главы вернуться назад
Сервисы BIOS Int 1Ah позволяют считывать и модифицировать значения системного таймера, даты и времени, а также установки будильника часов реального времени CMOS RTC. Перечисленные ниже номера функций указываются при вызове в регистре АН .
* 1. АН=0 — чтение системного таймера (двойного слова по адресу 40:006Eh в BIOS Data Area, инкрементируемого по прерываниям от канала 0 счетчика-таймера 8253/8254 примерно раз в 55 мс. Таймер обнуляется при выполнении теста POST после аппаратного сброса). Возвращает значение таймера, в СХ — старшую часть, в DX — младшую. AL=0 , если за последние 24 часа не было переполнения таймера. В современных версиях сброс AL возвращает счетчик переполнений таймера, хранящийся в ячейке 40:0070h (в старых версиях это был флаг).
* 2. АН=1 — установка системного таймера ( СХ — старшая часть, в DX — младшая)и сброс флага (счетчика) переполнения таймера в ячейке 40:0070h. В случае ошибки устанавливается флаг CF=1 .
* 3. АН=2 — чтение времени из RTC. Возвращает в упакованном BCD-формате час (в регистре СН), минуту ( CL ), секунду ( DH ) и признак коррекции летнего/зимнего времени ( DL=1 — коррекция используется, DL=0 — нет). Признаком успешной операции является флаг CF=0 . Во избежание ошибок некоторых BIOS при вызове флаг CF должен быть сброшен.
* 4. АН=3 — установка времени в RTC, назначение регистров и признак результата аналогичен функции 2.
* 5. АН=4 — чтение даты из RTC. Возвращает в упакованном BCD-формате век (в регистре СН ), две старшие цифры года ( CL ), месяц ( DH ) и день ( DL ). Признаком успешной операции является флаг CF=0 . Во избежание ошибок некоторых BIOS при вызове флаг CF должен быть сброшен.
* 6. АН=5 — установка даты в RTC, назначение регистров и признак результата аналогичен функции 4.
* 7. АН=6 — установка времени срабатывания будильника RTC. Возвращает в упакованном BCD-формате час (в регистре СН), минуту ( CL ) и секунду ( DH ). Если будильник уже установлен, переустановка не производится и возвращается флаг CF=1 . При срабатывании будильник вызывает прерывание Int 4Ah .
* 8. АН=7 — отмена установки будильника.
Функции BIOS Int 15h позволяют программировать таймер CMOS RTC — вводить задержку или запускать таймер установки флага, указывая время в микросекундах (СХ — старшее слово, DX — младшее). Нулевое значение интервала не вызывает никаких действий. Достижимое разрешение в зависимости от производительности ПК может достигать единиц миллисекунд, максимальная выдержка — около 70 часов. Перечисленные ниже номера функций указываются при вызове в регистре АН или АХ .
* 9. AH=86h — задержка на заданное время. Управление будет возвращено вызвавшему процессу только через указанный интервал. По окончании задержки будет установлен бит 7 в ячейке BDA 0040:00А0. Таймер может оказаться занятым, тогда вызов сразу возвратит флаг CF=1 (при успехе CF=0 , а в AL окажется маска, записанная в 8259А#2).
* 10. AX=8300h — запуск таймера, устанавливающего флаг после указанной задержке бит 7 в ячейке, заданной регистрами ES:ВХ . При успешном запуске CF=0 ; если таймер занят (он один) — CF=1 и AL=0 . Управление возвращается процессу сразу, а флаг будет установлен через заданное время. Перед завершением программа, запускавшая таймер, должна его сбросить функцией 8301h (во-первых, чтобы освободить; во-вторых, чтобы снять «адскую машинку», которая неожиданно сама может изменить значение ячейки памяти, вполне возможно уже задействованную другим, ничего не «подозревающим» процессом).
* 11. AX=8301h — сброс того же таймера.

12.8.7. PCI BIOS
вперед к началу Главы вернуться назад
Функции PCI BIOS используются только для поиска и конфигурирования устройств PCI — процедур, требующих доступа к их конфигурационному пространству (см. п. 8.2). Регулярная работа с этими устройствами выполняется через обращения к регистрам устройств по адресам, полученным при конфигурировании, и обработке известных номеров прерываний от этих устройств. Для 16-битного интерфейса реального режима , V86 и 16-битного реального режима, функции PCI BIOS вызываются через прерывание Int 1Ah ; номер функции задается при вызове в регистре АХ . Возможна и программная имитация прерывания дальним вызовом по физическому адресу 000FFEGEh (стандартная точка входа в обработчик Int 1Ah ) с предварительным занесением в стек регистра флагов.
Признаком нормального выполнения является CF=0 и АН=0 ; при CF=1 АН содержит код ошибки :
* 81h — неподдерживаемая функция;
* 83h — неправильный идентификатор производителя;
* 86h — устройство не найдено;
* 87h — неправильный номер регистра PCI.
Вызовы требуют глубокого стека (до 1024 байт). Для 32-разрядных вызовов защищенного режима все эти же функции вызываются через точку входа, найденную через каталог 32-разрядных сервисов (см. выше), при этом назначение входных и выходных регистров и флага CF сохраняется. До использования 32-разрядного интерфейса следует сначала найти его каталог и убедиться в наличии сервисов PCI. Функции PCI BIOS перечислены ниже:
* АХ = B101h — проверка присутствия PCI BIOS . При наличии PCI BIOS возвращает CF=0, AH=0 и EDX =20494350h (строка символов «PCI»); проверяться должны все три признака. При этом в AL находится описатель аппаратного механизма доступа к конфигурационному пространству и генерации специальных циклов PCI:
• Бит 0 — поддержка механизма №1 для доступа к конфигурационному пространству;
• Бит 1 — поддержка механизма №2 для доступа к конфигурационному пространству;
• Биты 2:3=00 (резерв);
• Бит 4 — поддержка генерации специального цикла по механизму №1;
• Бит 5 — поддержка генерации специального цикла по механизму №2;
• Биты 6:7=00 (резерв).
В регистрах ВН и BL возвращается старший и младший номер версии (BCD-цифры), в CL — максимальный номер шины PCI, присутствующий в системе (число шин +1, поскольку они нумеруются с нуля последовательно). В регистре EDI может возвращаться линейный адрес точки входа 32-разрядных сервисов BIOS. Этот адрес возвращается не всеми версиями BIOS (некоторые не изменяют EDI ); для проверки можно при вызове обнулять EDI и проверять на нуль возвращенное значение.
* АХ = B102h — поиск устройства по идентификатору . При вызове в СХ указывается идентификатор устройства, в DX — идентификатор производителя, в SI — индекс (порядковый номер) устройства. При успешном возврате в ВН — номер шины, в BL [7:3] — номер устройства, BL [2:0] — номер функции. Для нахождения всех устройств с указанными идентификаторами вызовы выполняют, последовательно инкрементируя SI от 0 до получения кода возврата 86h.
* АХ = B103h — поиск устройства по коду класса . При вызове в ЕСХ [23:16] указывается код класса, в ЕСХ [15:8] — подкласса, в ЕСХ [7:0] — интерфейс, в SI — индекс устройства (аналогично предыдущему). При успешном возврате в ВН — номер шины, в ВL [7:3] — номер устройства, ВL [2:0] — номер функции.
* АХ = В106Н — генерация специального цикла PCI . При вызове в BL указывается номер шины, в EDX — данные специального цикла.
* АХ = В108h — чтение байта конфигурационного пространства устройства PCI . При вызове в ВН — номер шины, в BL [7:3] — номер устройства, BL [2:0] — номер функции, в DI — номер регистра (0-FFh). При успешном возврате в CL — считанный байт.
* АХ = B109h — чтение слова конфигурационного пространства устройства PCI . При вызове в ВН — номер шины, в BL [7:3] — номер устройства, BL [2:0] — номер функции, в DI — номер регистра (0-FFh, четный). При успешном возврате в СХ — считанное слово.
* АХ = В10Ah — чтение двойного слова конфигурационного пространства устройства PCI . При вызове в ВН — номер шины, в BL [7:3] — номер устройства, BL [2:0] — номер функции, в DI — номер регистра (0-FFh, кратный 4). При успешном возврате в ЕСХ — считанное двойное слово.
* АХ = В10Bh — запись байта конфигурационного пространства устройства PCI . При вызове в ВН — номер шины, в BL [7:3] — номер устройства, BL [2:0] — номер функции, в DI — номер регистра (0-FFh), в CL — записываемый байт.
* АХ = В10СН — запись слова конфигурационного пространства устройства PCI . При вызове в ВН — номер шины, в BL [7:3] — номер устройства, BL [2:0] — номер функции, в DI — номер регистра (0-FFh, четный), в СХ — записываемое слово.
* АХ = B10Dh — запись двойного слова конфигурационного пространства устройства PCI . При вызове в ВН — номер шины, в BL [7:3] — номер устройства, BL [2:0] — номер функции, в DI — номер регистра (0-FFh, кратный 4), в ЕСХ — записываемое двойное слово.

12.9. Расширения ROM BIOS
вперед к началу Главы вернуться назад
В микросхеме ROM BIOS, установленной на системной плате, поддерживаются только стандартные (по назначению и реализации) устройства. При необходимости дополнительные устройства, устанавливаемые в слоты шин расширения (ISA, PCI, PCMCIA), могут иметь микросхемы ПЗУ своей программной поддержки — Additional ROM BIOS (дополнительные модули ROM BIOS), они же Expansion ROM. Эта необходимость возникает, когда программная поддержка устройств требуется до загрузки ОС и прикладного ПО. В таком модуле может содержаться и вся программа функционирования специализированного бездискового контроллера на базе PC. Расширения ROM BIOS используют графические адаптеры EGA/VGA/SVGA, некоторые контроллеры жестких дисков, контроллеры SCSI, сетевые адаптеры с удаленной загрузкой и другие периферийные устройства. Для модулей расширения устройств с шиной ISA в пространстве памяти зарезервирована область CS000h-F4000h. POST сканирует эту область с шагом 2 Кбайт в поисках дополнительных модулей BIOS на завершающем этапе выполнения (после загрузки векторов прерываний указателями на собственные обработчики). Дополнительный модуль BIOS графического адаптера (EGA, VGA, SVGA. ) имеет фиксированный адрес С0000 и инициализируется раньше (на шаге инициализации видеоадаптера). Устройства с шиной PCI в своем конфигурационном пространстве содержат лишь признак использования модуля расширения, а его приписку к адресам памяти назначает POST.
Дополнительный модуль ROM BIOS должен иметь заголовок, выровненный по границе 2-килобайтной страницы памяти, формат заголовка ПЗУ иллюстрирует табл. 12.8.

Таблица 12.8. Заголовок модуля дополнительного ПЗУ
Смещение Длина Назначение
2 Сигнатура (признак начала модуля): байт 0=55h, байт 1=AAh
2 1 Длина, указанная в блоках по 512 байт
3 3 Точка входа процедуры инициализации, заканчивающейся дальним возвратом Ret Far (вызывается инструкцией Far Call во время POST ). Обычно здесь располагается трехбайтная инструкция JMP , указывающая на начало процедуры
6-17h Резерв
18h 2 Указатель на структуру данных PCI (только для карт PCI ), см. ниже п. 12.9.1
1Ah 2 Указатель на структуру расширенного заголовка карт ISA PnP , см. ниже п. 12.9.2

В традиционном заголовке присутствовали только первые 3 поля, указатели на структуры PCI и ISA PnP ввели позже. Корректным считается модуль, начинающийся с признака AA55h (значения слова с учетом порядка байтов) и нулевой суммой (по модулю 256) всех байтов в объявленной области (реальная длина модуля может превышать объявленную, но байт контрольной суммы, естественно, должен входить в объявленную область).
В случае обнаружения корректного модуля POST дальним вызовом ( Call Far ) вызывает процедуру инициализации модуля, начинающуюся с 3-го адреса заголовка модуля. Ответственность за ее корректность полностью ложится на разработчика. Процедура может переопределять векторы прерываний, обслуживаемых BIOS. Переопределив на себя Bootstrap (Int 19h) , можно получить управление при загрузке, что и используется, например, для удаленной загрузки компьютеров через локальную сеть (Remote Boot Reset). Если стандартное продолжение процедуры загрузки не требуется, а дополнительный модуль представляет собой, например, управляющую программу для какого-либо оборудования, вместо процедуры инициализации в ПЗУ может находиться и основная программа, не возвращающая управление системной последовательности POST.
Процедура инициализации и программная поддержка устройства в ПЗУ должны быть написаны таким образом, чтобы им были безразличны абсолютные адреса,по которым они размещаются в пространстве памяти. На картах расширения, как правило, имеются аппаратные средства изменения базового адреса, а иногда и размера ПЗУ (джамперы или программно-управляемые переключатели). Это позволяет бесконфликтно разместить модули ПЗУ нескольких установленных карт.
По сравнению с традиционным способом использования ПЗУ, когда оно, будучи разрешенным, постоянно присутствует в области памяти, имеется более рациональный способ подключения расширений ROM BIOS, основанный на модели DDIM (Device Driver Initialization Model — модель инициализации драйвера устройств). POST определяет наличие ПЗУ по найденному заголовку и копирует его содержимое (по объявленной длине) в свободное пространство верхней памяти (ОЗУ), оставляя разрешенной запись в эту область. Далее в этой копии (в ОЗУ) вызывается процедура инициализации (по адресу 3). Эта процедура, написанная в соответствии с моделью DDIM, должна определить, каким образом ее запустили: традиционным (в ПЗУ) или в соответствии с DDIM (в ОЗУ). Определить это она может просто — попыткой модификации области ее «тела», которая в ПЗУ, естественно, не приведет к изменению содержимого памяти. Обнаружив режим DDIM (память модифицируема), процедура выполняет все необходимые действия по инициализации. Далее она определяет, какую часть копии (начиная от начала заголовка) требуется оставить в памяти на время загрузки и регулярной работы системы, отсекая не нужное в дальнейшем тело процедуры инициализации. Попутно она может в оставляемом модуле установить какие-либо параметры, требуемые для работы драйвера устройства. Наконец, она модифицирует поле длины в заголовке и контрольную сумму так, чтобы фрагмент модуля оставался корректным, и дальним возвратом отдает управление тесту POST. Теперь POST снова анализирует заголовок (но уже копии в ОЗУ) и запрещает запись в область ОЗУ (страницу с размером, кратным 4 К), которую «попросила» оставить процедура инициализации. Далее POST, по возможности, запрещает работу (отображение в область UMA) исходного модуля ПЗУ и продолжает свой путь к вызову процедуры начальной загрузки. Основное преимущество данного метода — возможность более рационального использования памяти в UMA (обычные ПЗУ «висят» в ней в полном объеме, невзирая на реальные потребности). Второе преимущество — возможность сохранения параметров, вычисляемых процедурой инициализации (она ожет задействовать параметры, полученные в процессе выполнения теста POST), в «замораживаемой» области памяти. Кроме того, как правило, медленные микросхемы ПЗУ на все время исполнения подменяются быстрым системным ОЗУ (не используя впрямую механизма теневой памяти). Процедура инициализации ПЗУ карт ISA с моделью DDIM должна проверять окружение, в котором она работает (см. выше); безусловная работа DDIM гарантируется только для карт PCI.
Для более эффективной работы DDIM желательно использовать не только стандартную, но и расширенную память (за пределами первого мегабайта), в то время как POST работает в реальном режиме процессора. Решить эту проблему помогает режим «Big Real Mode», который поддерживают все 32-разрядные процессоры (см. п. 12.3.1). Специально для предоставления доступа ко всей памяти процедурами инициализации фирмы Phoenics и Intel разработали спецификацию РММ (POST Memory Manager Specification), версия 1.01 была опубликована в конце 1997 г. Эта спецификация определяет несколько дополнительных сервисов BIOS, позволяющих выделять, находить и освобождать блоки в любой, в том числе и расширенной памяти. Клиенты этого сервиса запрашивают блок памяти требуемого размера, a BIOS возвращает физический 32-разрядный адрес начала выделяемого блока (если она способна его выделить). Клиент помечает свой блок 32-битным индексом (handle), по которому его в дальнейшем можно найти функцией поиска. Анонимный блок (индекс FFFFFFFFh) поиску не поддается. Этими сервисами можно пользоваться только до начала процедуры начальной загрузки ( Int 19h ), работу с вентилем GateA20 они берут на себя. Перед начальной загрузкой BIOS освобождает и обнуляет все блоки расширенной памяти, занятые с помощью этих сервисов. Сервисами РММ могут пользоваться процедуры инициализации карт расширения, а также процедуры BCV , описанные в заголовке ПЗУ карт РnР (см. ниже). Процедуры, на которые указывает BEV , ими пользоваться не могут, поскольку вызываются после входа в Int 19h . Наличие сервисов РММ определяется по контрольной структуре, начинающейся со строки-сигнатуры $РММ и расположенной на границе параграфа в области E0000-FFFF0h. Программный интерфейс можно найти в вышеуказанном документе, который доступен на сайте http://www.phoenix.com/techs.

12.9.1. ROM BIOS карт ISA PnP
вперед к началу Главы вернуться назад
Для поддержки технологии РnР и расширения возможностей управления начальной загрузкой в спецификации PnP BIOS ввели дополнительный указатель на структуру расширенного заголовка (Expansion Header Structure). Расширенный заголовок имеет формат, приведенный в табл. 12.9. В одном ПЗУ может находиться несколько расширенных заголовков (это требуется для многофункциональных карт расширения), связанных в цепочку. В каждом расширенном заголовке может указываться смещение следующего заголовка относительно начала стандартного заголовка. Наличие и действительность расширенного заголовка проверяется по его сигнатуре и контрольной сумме. Сумма всех байтов расширенного заголовка, включая байт контрольной суммы, должна быть нулевой.

Таблица 12.9. Расширенный заголовок ROM BIOS карт ISA PnP
Смещение Длина Назначение
0h 4 байта Сигнатура, строка $РnР (символы ASCII)
04h байт Версия структуры (01h)
05h байт Длина (в параграфах по 16 байт)
06h слово Смещение следующего заголовка (0000h, если нет больше)
08h байт Резерв (0)
09h байт Контрольная сумма(01h)
0Аh двойное слово Идентификатор устройства РпР
0Еh слово Указатель на строку идентификатора производителя (0, если нет)
10h слово Указатель на строку названия продукта (0, если нет)
12h 3 байт Код типа устройства
15h слово Индикаторы устройства
10h слово Указатель на строку названия продукта (0, если нет)
16h слово Вектор подключения BCV (Boot Connection Vector) — 0, если нет
18h слово Вектор отключения (Disconnect Vector) — 0, если нет
1Аh слово Точка входа для загрузки BEV (Bootstrap Entry Point) — 0, если нет
1Сh слово Резерв (0)
1Еh слово Вектор получения информации о статических ресурсах (Static Resource Information Vector) — Real/Protected mode (0 если нет)

Расширенныйзаголовок позволяет определить идентификатор устройства РпР ,его название и код производителя. Код типа состоит из байта общего типа, байта подтипа и байта идентификатора программного интерфейса, по которым система может узнать знакомые устройства.
Байт индикаторов устройства имеет следующее назначение битов:
* бит 7 — ПЗУ поддерживает модель инициализации устройства (Device Driver Initialization Model);
* бит 6 — ПЗУ может затеняться оперативной памятью;
* бит 5 — ПЗУ может кэшироваться по чтению;
* бит 4 — ПЗУ требуется лишь для загрузки с данного устройства;
* бит 3 — резерв (0);
* бит 2 — является устройством загрузки (IPL-устройство);
* бит 1 — устройство ввода (может заменять клавиатуру);
* бит 0 — устройство вывода (дисплей).
Вектор подключения BCV (Boot Connection Vector , он же Interrupt Connection Vector) указывает смещение для процедуры, дальний вызов которой приведет к перехвату векторов прерываний первичных устройств ввода, вывода или загрузки (сервисов Int 9h, Int 10h или Int 13h соответственно), в зависимости от параметров, переданных в регистрах процессора. При вызове этой процедуры в регистре АХ единицы в битах 0, 1 и 2 запрашивают перехват сервисов Int 9h, Int I0h или Int 13h соответственно (остальные биты нулевые), ES:D1 указывает на контрольную структуру РnР BIOS (System BIOS PnP Installation Check Structure), BX содержит селективный номер ( CSN ) карты ISA PnP (для других карт FFFFh); DX содержит адрес порта чтения ISA PnP (для других карт FFFFh).
Вектор отключения указывает на процедуру, восстанавливающую старое значение векторов при безуспешной попытке загрузки с данного устройства.
Точка входа для загрузки BEV требуется, если устройство может использоваться в качестве загрузочного, но не обеспечивает блочных функций сервиса Int 13h . Тогда системная микросхема BIOS может дальним вызовом вызвать эту процедуру вместо выполнения сервиса Int 19h . Таким образом, например, может выполняться удаленная загрузка (Remote Programm Loading, RPL) по сети.
Вектор получения информации о статических ресурсах задает смещение процедуры, вызов которой выгрузит в память дескрипторы занимаемых ресурсов (в форматах, аналогичных структурам для ISA PnP). Адрес буфера размером не менее 1024 байт задается регистрами ES:DI при вызове данной процедуры.
Процедура инициализации , которая начинается со смещения 3 в заголовке ПЗУ, для карт РnР должна подчиняться определенным требованиям (до этой спецификации специальных требований не было), принимать параметры и сообщать код возврата.
* При вызове процедуры ЕS:DI указывает на контрольную структуру PnP BIOS, ВХ содержит CSN карты ISA PnP (для других карт FFFFh); DX — адрес порта чтения ISA PnP (для других карт FFFFh).
* При исполнении процедура может переопределять любые векторы прерываний и изменять данные в BDA и EBDA , но перед возвратом она обязана восстановить прежние указатели для Int 9h, Int 10h, Int 13h и все прежние значения связанных с ними переменных в BDA и EBDA .
* При возврате в АХ возвращаются признаки проинициализированного устройства:
• бит 7 — устройство вывода, поддерживающее символьный вывод («телетайпный» режим) INT 10h ;
• бит 6 — устройство ввода, поддерживающее символьный ввод INT 9h ;
• биты 5:4 — состояние подключения загрузочного устройства: 00 — не подключено, 01 — неизвестно, 10 — подключено (для устройства RPL соединение установлено), 11 — резерв;
• биты 3:2 — состояние подключения устройства вывода (аналогично предыдущему);
• биты 1:0 — состояние подключения устройства ввода (аналогично предыдущему).
Как видно из данного описания, расширенный заголовок и правила поведения процедуры инициализации позволяют системной BIOS более гибко пользоваться функциями дополнительных модулей BIOS — традиционные дополнительные модули со стороны системной BIOS были практически неуправляемыми. Заголовок данного вида может использоваться и картами ISA без поддержки РnР. Если эти карты будут передавать информацию о своих статических ресурсах, они окажут большую услугу для распределения ресурсов системой BIOS с поддержкой PnP. Таким образом, приспособить карту для работы в среде РnР можно всего лишь модификацией содержимого ее ПЗУ расширения BIOS.
Карта ISA PnP может быть установлена в разные системы, имеющие BIOS как с поддержкой РnР, так и без. Процедура инициализации должна исполняться адекватно обнаруженной среде: без PnP BIOS она должна работать традиционным способом, при необходимости загрузки перехватывая INT 19h , а в среде PnP BIOS она должна вести себя скромнее, лишь предоставляя системной BIOS требуемые нтерфейсы и точки входа.

12.9.2. Expansion ROM карт PCI
к началу Главы вернуться назад
Для содержимого ПЗУ расширения BIOS, установленных на картах PCI, принят стандарт, несколько отличающийся от традиционных дополнительных модулей ROM BIOS. Заголовок ПЗУ соответствует традиционному, но дополнительно имеет указатель на структуру данных PCI (табл. 12.10). Идентификаторы производителя и устройства, а также код класса совпадают с описанными в конфигурационном пространстве устройства PCI. Поскольку шина PCI используется не только в PC, в ПЗУ карты может храниться несколько модулей. Каждый модуль начинается со структуры данных, сам модуль следует сразу за структурой. За ним начинается структура для следующего модуля (если у предыдущего не установлен признак последнего модуля) и так далее. Тип платформы (процессора) указывается в заголовке модуля, и при инициализации BIOS активизируется только нужный. Такой механизм позволяет, например, один и тот же графический адаптер устанавливать и в IBM PC, и в Power PC.

Перхватываем прерывание 08h

1. Заголовок или название темы должно быть информативным
2. Все тексты программ должны помещаться в теги [CODE=asm] [/CODE]
3. Прежде чем задавать вопрос, см. «FAQ»,если там не нашли ответа, воспользуйтесь ПОИСКОМ, возможно, такую задачу уже решали!
4. Не предлагайте свои решения на других языках, кроме Ассемблера. Исключение только с согласия модератора.
5. НЕ используйте форум для личного общения! Все, что не относиться к обсуждению темы — на PM!
6. Проверяйте программы перед тем, как выложить их на форум!!

Группа: Пользователи
Сообщений: 146
Пол: Мужской

Написать на ассемблере IBM PC программу перехвата заданного аппаратного прерывания. Программа должна перехватить прерывание и продемонстрировать обработку перехваченного прерывания выводом заданного набора символов на экран прямым доступом к видеопамяти.


При этом:
• Номер прерывания – 08h
• Способ перехвата – прямым доступом к вектору прерывания
• Способ отображения – инверсия атрибутов символов всего экрана

Программа не работает, ничего не происходит после запуска! Подскажите плиз почему?

Сообщение отредактировано: Neon6868 — 12.04.2008 3:27

Группа: Пользователи
Сообщений: 1 168
Пол: Мужской
Реальное имя: Сергей Андрианов

1. Размещеть программу без комментариев IMHO дурной тон. Я, например, уже лет 10 не пользовался Ассемблером под DOS и, естественно, не помню наизусть номера функций DOS. Поэтому без комментариев могу только догадываться, что делает программа. Кроме того, если бы ты откомментировал, а потом сам прочитал собственные комментарии, вероятно, ты бы сам и обнаружил ошибку, не прибегая к посторонней помощи.

2. Твоя программа трижды вызывает функцию DOS. Насколько я понимаю, это:
— запрос текущего (старого) вектора прерывания,
— установка нового,
— восстановление старого.
Так вот, когда именно должен сработать твой обработчик прерывания, если ты сразу после установки нового заменяешь его обратно на старый?
Да, ты заменяешь обработчик и затем возвращаешь старый, но за это время не успевает случиться ни одного прерывания.
Я по номеру не мог вспомнить, какое прерывание ты переопределяешь, но если это прерывание от таймера, то между sti и cli можно вставить временную задержку. Если от клавиатуры, то ожидание нажатия на клавишу и т.п.

Группа: Пользователи
Сообщений: 146
Пол: Мужской

Перхватываем прерывание 08h

Глава 8. Обработчики аппаратных прерываний.

Обработка аппаратных прерываний значительно отличается в различных ОС, поэтому имеет смысл давать лишь общие рекомендации. Более серьёзно к этому вопросу мы подойдём после того, как изучим мультизадачность и виртуальную память, а пока при реализации обработчиков аппаратных прерываний придерживайтесь следующего:

1. Не используйте в IDT шлюзы ловушек, а только прерываний, т.к. при переходе через шлюз прерывания процессор автоматически запрещает маскируемые прерывания (сбрасывая флаг IF в EFLAGS), но не делает этого для шлюза ловушки.
2. В начале обработки прерывания посылайте в контроллер 8259A команду конца прерывания (EOI). Контроллер состоит из двух контроллеров master и slave. Master обслуживает первые 8 IRQ, slave — вторые и для них посылка EOI будет выглядеть так:
  • для master (IRQ 0..7)
  • для slave (IRQ 8..15)
  • 3. Постарайтесь сделать обработку прерывания как можно быстрее, т.к. процессор не допустит генерации нового прерывания, пока не будет завершён обработчик.
    4. При перенаправлении прерываний процедура «redirect_IRQ» запрещает контроллеру генерацию аппаратных прерываний. Значения в портах 21h и A1h содержат флаги маскировки прерываний для master- и slave-контроллера соответственно.
    Для того, чтобы разрешить какое-либо прерывание, нужно сбросить соответствующий бит, а для запрещения — установить.
    Прерывания master:
    Бит IRQ Устройство
    0 0 Таймер
    1 1 Клавиатура
    2 2 Каскад (подключён ко второму контроллеру)
    3 3 COM 2/4
    4 4 COM 1/3
    5 5 LPT 2
    6 6 Контроллер дисковода FDC (Floppy Drive Controller)
    7 7 LPT 1
    Прерывания slave:
    Бит IRQ Устройство
    0 8 Часы реального времени RTC (Real Time Clock)
    1 9 Редирект с IRQ 2
    2 10 Резерв (т.е. не имеет устройства по умолчанию)
    3 11 Резерв (т.е. не имеет устройства по умолчанию)
    4 12 Резерв (т.е. не имеет устройства по умолчанию)
    5 13 Исключение сопроцессора
    6 14 Контроллер винчестера HDC (Hard Drive Controller)
    7 15 Резерв (т.е. не имеет устройства по умолчанию)

    Например, для разрешения прерывания таймера нужно выполнить следующее:

    Как правило, операционная система защищённого режима подразумевает возврат в режим реальных адресов и выход в ту ОС, из которой её запускали (например, в MS-DOS). В таком случае необходимо предусмотреть правильное маскирование прерываний IRQ перед возвратом в такую ОС, так как обычно не все прерывания разрешены.
    Начиная со следующего примера в начале будет использоваться процедура, сохраняющая маску прерываний IRQ:

    Для корректного возврата в режим реальных адресов нужно изменить одну команду в процедуре перенаправления векторов IRQ для R-Mode:

    Теперь, казалось бы, наш пример должен правильно работать, но MS-DOS приготовил один неприятный «подводный камень». Дело в том, что при повторном запуске нашего примера, при условии, что в нём выполняются какие-либо процессы, длительностью более, чем примерно 2 секунды, контроллер клавиатуры генерирует символ. Если не обработать его должным образом, то клавиатура будет заблокирована, поэтому во всех наших примерах предлагается следующее:

    1. Обязательно размаскировывать прерывание клавиатуры (IRQ 1).
    2. Обязательно разрешать прерывания на время выполнения части программы, работающей в защищённом режиме.
    3. Установить обработчик IRQ клавиатуры или хотя бы следующую заглушку:

    Как видите, установка обработчика IRQ клавиатуры свелась к простой замене определяющего его макроса «IRQ_1_handler».

    А теперь вашему вниманию предлагается демонстрация обработки прерываний по таймеру. В приведенном ниже примере внесены следующие изменения (по сравнению с предыдущим и с учётом всего, сказанного выше):

    1. Введена переменная «timer_count», в которой накапливаются «тики» таймера и ещё одна переменная — «timer_sec» — счётчик секунд. После каждого 18-го «тика» счётчик секунд увеличивается на 1. В качестве часов данный пример не совсем годится, т.к. за одну секунду таймер выдаёт около 18.2 «тиков» (если его дополнительно не программировать), а данный пример предназначен в качестве иллюстрации обработки IRQ и поэтому подсчёт времени здесь упрощённый.
    2. Макрос «IRQ_0_handler» изменён — он считает «тики» таймера. Теперь это не заглушка, а Обработчик Прерывания.
    3. Перед тем, как в программе будут разрешены прерывания (командой STI), размаскировывается IRQ 0 (а так же и IRQ 1, для корректной обработки контроллера клавиатуры).
    4. В программе приводится простой алгоритм, в котором на экран выводится dd-число, которое в бесконечном цикле увеличивается на 1. При это постоянно проверяется содержимое переменной «timer_count» и:
  • сбрасывается в 0, как только она превышает 18,
  • при этом увеличивается на 1 переменная «timer_sec»
  • и как только она превысит значение 4, производится возврат в R-Mode.
  • Вот так теперь выглядит обработчик IRQ 0:

    Как видите, всё что он делает — это посылает контроллеру прерываний команду конца прерывания (EOI) и увеличивает значение «timer_count» на 1. И всё! Так просто!
    На самом деле, когда вы будете писать свою ОС, то, скорее всего, добавите в обработчик IRQ 0 функции подсчёта времени, даты и ещё что-нибудь важное, но даже в таком виде он будет корректно работать.

    А вот так в примере разрешены прерывания и реализован алгоритм подсчёта и вывода времени:

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

    Исходный текст примера вы можете скачать здесь: examp_6.asm, pmode_6.lib и examp_6.com в архиве examp_6.zip (9594 байт).

    Внешние прерывания и приоритеты прерываний

    Система внешних прерываний в STM8 устроена довольно хитро. Разработчики дали нам возможность ловить прерывания с любого пина, но при этом выделять по вектору на каждый пин не стали. В результате эта часть STM8L (в S- с этим как-то получше) просто утыкана разными костылями и хитростями.
    Разберемся, как все устроено.

    До кучи, кроме внешних прерываний рассмотрим настройку приоритетов прерываний.

    Нам обещали прерывания на всех ножках. Вот с них, то-есть с ножек, и начнем.

    Разрешить или запретить прерывание для конкретного пина можно через регистр GPIOx_CR2 (где x — порт, для которого настраивается прерывание). Если ножка настроена на вход, то запись 1 в соответствующий бит регистра GPIOx_CR2 разрешит прерывание для неё.

    Например вот-так можно настроить кнопку на STM8L-Discovery (пин C1):

    За исключением настройки ножек, система внешних прерываний STM8 выглядит немного по-разному в разных семействах и линейках. Сначала подробно рассмотрим, как она организована в STM8L15xx. Там хитроумные выверты разработчиков достигают предельной концентрации, а в других сериях все устроено проще. Особенно в STM8S — там система внешних прерываний очень похожа на PCINT в AVR.

    Первой неожиданностью (для меня, после AVR) является то, что есть две группы прерываний: прерывание порта (EXTIB, EXTID. ) без указания пина, куда прилетают прерывания с каждой ножки порта (как PCINT); и прерывание пина (EXTI0, EXTI1… EXTI7) без указания порта, куда слетаются прерывания с нескольких портов, но с одинаковых пинов. Сначала это немного выносит мозг, но потом привыкаешь.

    Каждую половину порта можно настроить на генерацию 1го прерывания для любого пина (EXTID, EXTIG — по названию порта) или генерацию отдельного прерывания для каждого пина (EXTI1,EXTI2. ). Настраивается это через регистры EXTI_CONF1 и 2, а точнее, через биты PxLIS и PxHIS в них.

    PxLIS отвечает за младшие 4 бита, а PxHIS — за старшие. Если бит установлен (1), то эта половина порта будет генерировать одно прерывание на все пины. А если бит сброшен (0) — отдельные прерывания на каждый пин: EXTI0..3 для младшей половины и EXTI4..7 для старшей.

    Для некоторых портов общие прерывания (которые по штуке на порт) не доступны. С ними можно работать только через прерывания пинов. К таким обделенным относятся порты А и С в STM15x. А в STM101 своими прерываниями обладают только порты B и D.

    Для STM8S наоборот, есть только прерывания портов, но нет никаких EXTI0, EXTI1. Это сильно снижает возможности по настройке — фронт, по которому сработает прерывание, настраивается для целого порта. Но об этом чуть ниже.

    Так-как в старших STM8L15x векторов на все порты трагически не хватает, было придумано переключение. Например, вектор EXTIB/G может обрабатывать прерывания с порта B или G. За переключение векторов между портами отвечают биты PFES, PHDS, PBGS в регистрах EXTI_CONFx. Если в бит PFES записана 1, то вектор EXTIE/F будет ловить прерывания с порта F, иначе — с порта E. Аналогично с битами PHDS и PBGS (Они есть только в старших моделях, на дискавери нет).

    Фронт или уровень, по которому сработает прерывание, настраивается через регистры EXTI_CRx. В STM8L15x таких регистров 4 штуки, в STM8L101 — 3.

    Биты в них зовутся PxIS и собраны парами. Например пара P0IS[1:0] отвечает за фронт, по которому сработает прерывание EXTI0. Здесь возможны четыре варианта:

    00 — Падение напряжения и низкий уровень
    01 — Переход из низкого уровня в высокий (__/)
    10 — Переход из высокого в низкий (\__)
    11 — Любое изменение уровня

    Фанаты библиотек, для настройки прерывания, могут написать что-то типа этого:

    Для примера, вот так можно заставить кнопку на STM8L-Discovery (пин C1) генерировать прерывание EXTI1 по падению напряжения (т.е. когда лог уровень меняется с 1 на 0):

    А вот так, кнопка, висящая на B3, будет настроена на генерацию прерывания EXTIB/G по любому изменению уровня:

    Теперь посмотрим, как правильно оформить обработчик прерывания.
    В IAR шаблон обработчика выглядит вот так:

    Interrupt_Name это название прерывания. Оно может быть любым.
    Interrupt_Number — номер прерывания в таблице. Таблица в даташите — «Interrupt vector mapping»

    Например, обработчик прерывания EXTI1, в котором тупо переключается светодиод на E7:

    Обратите внимание, что перед выходом из прерывания надо сбросить его флаг. Иначе — день сурка — МК будет вечно крутится в этом обработчике.

    Флаги разбросаны в регистрах EXTI_SR1 и EXTI_SR2. Для сброса флага в него надо записать 1. Любители библиотек могут просто написать:

    В данном случае так и надо делать, ибо констант для сброса флагов прерываний все-равно нет, что приводит к появлению в коде волшебных чисел (1 +2

  • 19 августа 2011, 19:46
  • dcoder
  • 1
  • «Assembler IBM PC 8. Лабораторная работа № 3. Применение сервисных функций BIOS для работы с экраном и клавиатурой»

    8.1. ЦЕЛЕВЫЕ УСТАНОВКИ

    ¨ Вывод текста на экран путём непосредственного программирования видеобуфера.

    ¨ Разработка прикладных программ с использованием сервисных функций BIOS для работы с экраном и клавиатурой.

    ¨ Введение задержки для программных операций.

    8.2. МЕТОДИЧЕСКИЕ РЕКОМЕНДАЦИИ

    8.2.1. ВВЕДЕНИЕ

    В работе № 2 были рассмотрены различные системные функции DOS вывода на экран символьной информации. Однако возможности DOS весьма ограничены: она не имеет функций для изменения цвета выводимых символов и позиционирования курсора. Кроме того, в DOS отсутствуют средства формирования графических изображений.

    Все возможности видеосистемы компьютера можно реализовать с помощью видеофункций BIOS прерывания int 10h. Прерывание int 10h обеспечи-вает: смену видеорежима (текстовый или графический); вывод символьной и текстовой информации; смену шрифтов, настройку цветовой палитры, работу с графическим изображением. Программирование видеосистемы с помощью средств BIOS более громоздко, однако большие возможности и высокая скорость вывода обуславливают широкое использование этого метода в прикладных программах.

    В данной работе рассматриваются функции BIOS [10, 12] для обслуживания видеосистемы компьютера, а также функции для работы с клавиатурой. Перечислим функции, являющиеся предметом рассмотрения в лабораторной работе.


    Int 10h:

    функция 00h – установка видеорежима;

    функция 02h – установка позиции курсора;

    функция 03h – считывание позиции и размера курсора;

    функция 05h – установка видеостраницы;

    функция 06h (07h) – инициализация или прокрутка окна вверх (вниз);

    функция 08h – чтение символа и атрибута в позиции курсора;

    функция 09h – запись символа и атрибута в позицию курсора;

    функция 0Ah – запись символа в позицию курсора с текущим атрибутом;

    функция 0Eh – запись символа в режиме телетайпа с текущим атрибутом;

    функция 0Fh – получить режим дисплея;

    функция 1003h – переключение назначения старшего бита байта атрибута: мерцание/яркость,

    функция 13h – запись строки с заданным атрибутом в режиме телетайпа.

    Int 16h:

    функция 00h (10h) – чтение символа с клавиатуры с ожиданием;

    функция 01h (11h) – проверка буфера клавиатуры на наличие в нём символа;

    функция 02h (12h) – получение флагов (расширенной) клавиатуры.

    Int 15h, функция 86h – задержка.

    Int 1Ah, функция 00h – получение системного времени.

    8.2.2. ПРЯМОЕ ПРОГРАММИРОВАНИЕ ВИДЕОБУФЕРА В ТЕКСТОВОМ РЕЖИМЕ

    Современные видеоконтроллеры поддерживают разнообразные текстовые и графические режимы. Текстовые режимы различаются по разрешению (число отображаемых символов по горизонтали и вертикали) и цветовой палитре (монохромный или 16-цветный режим). Для графических режимов основным признаком классификации является количество одновременно отображаемых цветов и, соответственно, количество бит видеопамяти, отводимое на каждую точку (пиксел) изображения. Различают следующие типы графических режимов:

    – монохромный (1-битное кодирование);

    – 16-цветный EGA/VGA (4-битное кодирование);

    – 256-цветный SVGA (8-битное кодирование);

    HiColor (16-битное кодирование);

    TrueColor (24-битное / 32-битное кодирование).

    Графические режимы VGA (SVGA) сильно устарели, а текстовые продолжают успешно применяться (см. табл. 3.2 п. 8.2.3).

    Всё, что изображено на мониторе – графика, текст – одновременно присутствует в памяти, встроенной в видеоадаптер. Для того чтобы изображение появилось на мониторе, оно должно быть записано в память видеоадаптера. В текстовом режиме для VGA-совместимых систем для видеопамяти отводится адресное пространство (исключая 7-й видеорежим с монохромным адаптером), начинающееся с логического адреса B800h:0000h и заканчивающееся адресом BF00h:0FFFh. Данная область разбивается на 8 секторов по числу видеостраниц (4 Кбайта на страницу). Таким образом, постраничное деление адресного пространства видеопамяти в текстовом режиме имеет следующий вид:

    – B800h:0000h – страница 0, смещение в диапазоне 0000h – 0FFFh

    – B900h:0000h – страница 1, смещение в диапазоне 0000h – 0FFFh

    – BF00h:0000h – страница 7, смещение в диапазоне 0000h – 0FFFh

    На экране отображается видеобуфер, соответствующий активной странице. В текстовых режимах для изображения каждого символа отводится 2 байта: байт с ASCII-кодом символа и байт с его атрибутом. При этом по адресу B800h:0000h находится байт с кодом символа (левый верхний угол экрана), а в B800h:0001h – атрибут этого символа; B800h:0002h – код второго символа, а в B800h:0003h – атрибут второго символа и т.д. Вообще при формировании изображения непосредственно в видеобуфере, в обход программ DOS и BIOS, все управляющие коды ASCII теряют свои управляющие функции и отображаются в виде соответствующих символов. Структура байта атрибутов приведена на рис. 3.1.

    Рис. 3.1. Структура байта атрибутов

    Из рис. 3.1 следует, что каждый символ может принимать любой из 16 возможных цветов, определяемых сочетанием младших 4-х битов. Биты 4-6 байта атрибутов задают цвет фона под данным символом. Последний бит 7, в зависимости от режима видеоадаптера, определяет либо яркость фона под данным символом (тогда фон также может принимать 16 разных цветов), либо мерцание символа (устанавливаетсяDOS по умолчанию).

    При загрузке машины устанавливается стандартная палитра, коды цветов которой приведены в табл. 3.1. Рассмотрим некоторые примеры. Так, в режиме мерцания значение старшего полубайта атрибута 8hобозначает не серый фон, а чёрный при мерцающем символе, цвет которого по-прежнему определяется младшим полубайтом; значение старшего полубайта 0Ch – красный фон при мерцающем символе. Переключение назначения бита 7 осуществляется подфункцией 03h функции 10h прерывания int 10h.

    Коды цветов стандартной палитры

    Двухбайтовые коды символов записываются в видеобуфер в том порядке, в каком они должны появиться на экране: первые 80*2 байт соответствуют первой строке экрана, вторые 80*2 байт – второй и т.д. При этом переход на следующую строку экрана определяется не управляющими кодами возврата каретки и перевода строки, а размещением кода в другом месте видеобуфера. Для того чтобы из программы получить доступ к видеобуферу, надо занести в один из сегментных регистров данных сегментный адрес видеобуфера. После этого, задавая те или иные смещения, можно выполнить запись в любые места (ячейки) видеобуфера. Вычислить смещение ячейки в координатах «строка-столбец» (row, clm) можно так:

    При большом объёме выводимых данных, информационный кадр формируется заранее в буфере пользователя, располагающегося в сегменте данных программы.

    Листинг 3.1. Запись строки в видеобуфер 0-страницы.

    ;Настроим сегментный регистр ES на страницу 0 видеобуфера, а ds на сегмент данных

    ;Перешлём в видеобуфер строку символов, настроив соответствующим образом

    ;регистры si, di и cx

    mov si,offset msg ;Смещение источника

    mov di,160*12+36*2 ;Смещение приёмника (36 столбец 13 -ой строки),

    mov cx,msglen ;Число пересылаемых байт

    cld ;Просмотр вперёд

    rep movsb ;)* ;Переслать строку символов с атрибутами в видеобуфер

    ;Остановим программу для наблюдения результата (иначе после завершения программы

    ;запрос DOS на ввод команды может затереть выведенную информацию)

    ;Поля данных в сегменте данных программы. Символы и атрибуты: 0B0h – cветло-

    ;бирюзовый по чёрному, 0E4h –красный по жёлтому

    msg db ‘*’,0B0h,’T’,0E4h,’E’,0E4,’S’,0E4,’T’,0E4,’*’,0B0h

    В данном фрагменте программы символьные коды выводимого сообщения перемежаются с их атрибутами. Такой способ формирования полей данных, предназначенных для прямой записи в видеопамять, становится громоздким, однако его можно существенно упростить, если выводимые символы имеют одни и те же атрибуты. Так, если мы хотим осуществить вывод символов текста из сегмента данных с единственным атрибутом 0E4h, то нам нужно просто заменить одну командную строку, отмеченную в выше приведённом фрагменте символом «*)», на три. При этом задание строки данных приобретёт привычный для нас вид.

    mov si,offset msg ;Смещение источника

    mov di,160*12+36*2 ;Смещение приёмника (36 столбец 13 -ой строки),

    mov cx,msglen ;Число пересылаемых байт

    cld ;Просмотр вперёд

    mov ah,0E4h ;Атрибут выводимых символов 0E4h – красный по жёлтому

    cycle: lodsb ;Загрузка в al очередного символа (al ← ds:si)

    stosw ;Выгрузка “символ + атрибут” из ах в видеобуфер (ax→es:di)

    loop cycle ;Повторить msglen раз

    ;Поля данных в сегменте данных программы.

    Изложенный выше способ вывода текста форматируется длиной видеостроки без учёта символов переноса или отступов от левой границы. Внесение элементарных правил текстового редактора в процедуру вывода сильно усложнит программу. В этом случае для вывода сообщений целесообразно использовать функции BIOS.

    Разработка структуры программ, осуществляющих просмотр произвольных видеостраниц, на которые предварительно записана информация способом прямого программирования видеобуфера, удобно производить с применением функции 05h int 10h BIOS (п. 8.2.3.2).

    8.2.3. СПРАВОЧНЫЕ ДАННЫЕ ПО ФУНКЦИЯМ BIOS

    8.2.3.1. Прерывание int 10h. Видеофункции BIOS

    ¨ Функция 00h. Установка видеорежима (табл. 3.2) текущей видеостраницы с очисткой экрана (быстрая очистка экрана реализуется функцией 06h и 07h).

    Al = видеорежим (код режима задаётся в младших 7 битах, установка в 1 старшего бита запрещает очистку экрана).

    Текстовые видеорежимы и страницы в стандарте VGA, поддерживаемые
    современными видеоконтроллерами

    Режим

    Тип


    Разрешение

    Цвет

    Размер знака

    Адрес

    Страницы

    3

    text

    80×25

    16/8

    9×16

    B8000

    0 – 7

    3 (Mono)

    По умолчанию в DOS используется режим 3 (впрочем, корректно оформленная программа должна выполнять проверку или установку требуемого текстового режима с последующим восстановлением прежнего).

    ¨ Функция 02h. Установка позиции курсора.

    Задаёт положение курсора на экране в текстовых координатах, с которых в дальнейшем будет выводиться текст. Отсчёт номера строки и столбца ведётся от верхнего левого угла. Курсор можно установить как в текстовом, так и в графическом режиме, однако, в графическом режиме курсор не виден. BIOS поддерживает до восьми независимых курсоров – по одному на каждую страницу (см. табл. 3.2) независимо от того, какая страница является активной. Функцию 02h BIOS можно использовать в комбинации с функциями DOS для организации вывода на экран.

    Вызов: AH = 02h; BH = номер страницы (0,1. 7), обычно 0;

    ¨ Функция 03h. Считывание позиции и размера курсора.

    Возвращает текущие координаты состояния курсора на выбранной странице. Это даёт возможность временно перейти для работы на другое место экрана, а затем вернуться на старое место. Функцию 03hBIOS можно использовать в комбинации с функциями DOS для организации вывода на экран.

    Вызов: AH = 03h, BH = номер страницы (0,1. 7), обычно 0.

    Возврат: DH, DL = строка и столбец текущей позиции курсора,

    CH, CL = первая и последняя строки развёртки курсора.

    Вызов разрушает регистры AX, BP, SI и DI.

    ¨ Функция 05h. Установка видеостраницы.

    Устанавливает активную видеостраницу (как текстовую, так и графическую).

    Вызов: AH= 05h, AL= номер страницы (0. 7).

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

    ¨ Функция 06h (07h). Инициализация или прокрутка окна вверх (вниз).

    Инициализирует окно с указанными координатами, пробелами ASCII с заданным атрибутом (AL = 0), или прокручивает содержимое окна вверх (вниз) на заданное число строк (AL = число строк). При прокрутке появляющиеся снизу (сверху) строки заполняются пробелами ASCII с заданным атрибутом. Функцию удобно использовать для быстрой очистки экрана или некоторого прямоугольного окна.

    AL = 0 – очистка, AL = N (N >0) – прокрутка на N строк;

    BH = атрибут символов в окне;

    CH, CL = координаты строки и столбца (Y,X) левого верхнего угла;

    DH, DL = координаты строки и столбца (Y,X) правого нижнего угла.

    ¨ Функция 08h. Чтение символа и атрибута в текущей позиции курсора на выбранной странице.

    Вызов: AH = 08h, BH = номер страницы (0. 7), обычно 0.

    Возврат: AH = атрибут символа, AL = ASCII-код символа.

    Вызов разрушает регистры BP, SI и DI.

    ¨ Функция 09h. Запись символа с заданным атрибутом на экран в позицию курсора. Действует как в графическом, так и в текстовом режимах. В графическом режиме символы не должны переходить на следующую строку. Все коды в AL рассматриваются как символьные и не управляют положением курсора. После вывода символа курсор смещается к следующей позиции функцией 02h. Коэффициент повторения позволяет выводить строки одинаковых символов. В текстовом режиме символ выводится с указанным в BL атрибутом. В графическом – содержимое BL влияет только на цвет символа, но не на фон под ним. Графическое изображение под знакоместом затирается.

    Вызов: AH =09h, AL = ASCII-код символа,

    BL = атрибут символа (текстовый режим) или только цвет символа (графический режим),

    BH = номер страницы (0,1. 7), CX = коэффициент повторения.

    ¨ Функция 0Ah. Запись символа с текущим атрибутом на экран в позицию курсора. Функция действует как в графическом, так и в текстовом режимах. Символ принимает атрибут, установленный ранее для этой позиции. Все ASCII-коды в AL рассматриваются как символьные и не управляют положением курсора (также как и в функции 09h). После вывода символа курсор смещается к следующей позициифункцией 02h.

    Вызов: AH = 0Ah, AL = ASCII-код символа,

    BH = номер страницы (0,1. 7), CX = коэффициент повторения.

    ¨ Функция 0Eh. Запись символа с текущим атрибутом в режиме телетайпа.

    Записывает символ ASCII в позицию курсора (предварительно установленную функцией 02h) на активной странице и смещает курсор к следующей позиции. Коды ASCII: 07h – звонок (BEL), 08h – шаг назад(BS), 0Dh – возврат каретки (CR), 0Ah – перевод строки (LF), рассматриваются как управляющие и выполняются соответствующие им действия. Остальные управляющие коды рассматриваются как символы и выводятся на экран. Действует автоматический перевод курсора на следующую строку после завершения предыдущей, а также прокрутка экрана вверх на 1 строку после заполнения самой нижней.

    Вызов: AH = 0Eh, AL = ASCII-код символа,

    BL = цвет символа (только для графического режима),

    BH = номер страницы (0,1. 7), по умолчанию действует активная страница.

    ¨ Функция 0Fh. Получить режим дисплея и номер текущей страницы.

    Возврат: AL = режим дисплея, AH = ширина экрана в текстовом формате

    BH =номер активной страницы.

    Вызов разрушает регистры BP, SI и DI.

    Пример. Процедура установки позиции курсора на текущей странице.

    Вход: dh = строка (0 – 25), dl = столбец (0 – 79)

    . ;Сохранить регистры (по необходимости)

    . ;Восстановить регистры

    ¨ Функция 10h. Подфункция 03h. Переключение бита «мерцание/яркость».

    Определяет назначение старшего бита 7 атрибута символа: мерцание символа или повышенная яркость фона.

    Вызов: AX = 1003h, BL = назначение 7-го бита атрибута:

    0 – повышенная яркость, 1 – мерцание (устанавливается по умолчанию).

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

    ¨ Функция 13h. Запись строки символов с заданными атрибутами.

    Записывает строку в текущую страницу видеобуфера, начиная с указанной позиции. Коды ASCII: 07h – звонок, 08h – шаг назад, 0Ah – перевод строки,
    0Dh – возврат каретки, рассматриваются как управляющие, остальные – как символьные.

    Вызов: AH = 13h, AL = режим записи:

    0 – атрибут символа в BL, строка содержит только коды символов, после записи курсор принимает исходное положение (т.е. вывод следующей строки, если не изменить позицию курсора, начинается с изначально установленной позиции);

    1 – отличается от режима 0 тем, что после записи курсор остаётся в конце строки;

    2 – строка содержит попеременно коды символов и атрибутов (т.е. каждый символ описывается 2 байтами – ASCII-кодом и атрибутом), после записи курсор принимает исходное положение;

    3 – отличается от режима 2 тем, что по окончании вывода курсор остаётся в конце строки.

    BH = номер страницы (0,1. 7), BL = атрибут для режимов 0 и 1,

    CX = длина символьной строки (в длину входят только коды символов, но не байты атрибутов),

    DX = DH.DL = координаты курсора (строка, столбец) в исходной точке вывода строки на экране,


    ES:BP = адрес начала строки в памяти.

    Обратите внимание на особенность задания адреса!

    8.2.3.2. Рекомендации по использованию видеосервиса BIOS

    1. Программы (учебный практикум), выполняемые в операционной среде DOS, используют по умолчанию текстовый режим 3, страницу 0.

    2. Программы более широкого назначения должны запрашивать текущий видеорежим и страницу (функция 0Fh, int 10h) с последующим их применением в используемых функциях BIOS.

    Mov ah,0Fh ;Запрос текущего режима

    Mov v_mode, al ;Сохраним режим

    Mov current_page, bh ;Сохраним строку

    3. Если программа выводит изображение на разные страницы, то последовательность действий с каждой страницей может быть следующей (предполагается режим по умолчанию с «0» – страницей):

    – установка страницы функцией 05h;

    – установка позиции курсора функцией 02h;

    – построчное форматирование текста BIOS или DOS.

    В дальнейшем может быть организован циклический просмотр содержания страниц путём их переключения функцией 05h, int 10h. При выходе из программы обязательно восстанавливаем искомую «0»-страницу. Сделать это, к примеру, можно так.

    ;Анализ буфера клавиатуры функцией DOS 06h int 21h с целью её завершения нажатием ;произвольной клавиши

    mov ah,06h ;Функция ввода без ожидания

    mov dl,0FFh ;Ввод

    jnz out_program ;zf=0, есть символ, на выход

    jmp continue ;zf=1, символа нет, продолжим работу

    out_program: ;Восстановим страницу функцией 05h, int 10h

    exit: mov ax,4C00h ;Вызов функции завершения программы

    Страницы видеобуфера могут быть последовательно отформатированы и способом непосредственного программирования памяти. Выбор страниц при этом осуществляется соответствующей инициализацией сегментного регистра ES (см. п. 8.2.2). Просмотр содержимого страниц также может быть выполнен путём их последовательного переключения с помощью функции 05h, int 10h.

    4. Структура демонстрационной программы, исследующей функцию «мерцание – яркость фона» (функция 10h, подфункция 03h, int 10h).

    ;Инициализация 2-х локальных окон, каждое со своим атрибутом и текстом. При задании

    ;атрибутов цвета старший (7-ой по номеру) бит выбран равным «1».

    continue: ;Включим мерцание

    mov bl,1 ;Мерцание

    ;Введём задержку на 3 сек

    ;Включим повышенную яркость

    ;Введём задержку на 3 сек

    ;Анализ буфера клавиатуры функцией DOS 06h int 21h с целью её завершения нажатием

    jnz out_program ;zf=0, есть символ, на выход

    jmp continue ;zf=1, символа нет, продолжим работу

    out_program: ;Восстановим мерцание (по умолчанию)

    exit: mov ax,4C00h ;Вызов функции завершения программы

    5. Если в программе организован бесконечный цикл вывода данных на экран функциями BIOS (09h, 0Ah, 0Eh, 13h), то его нельзя будет аварийно прервать с помощью нажатия клавиш Ctrl+C (т.е. выйти из программы, как это можно сделать при использовании соответствующих функций DOS). Чтобы можно было это сделать, включите в тело цикла функцию 0Bh прерывания Int 21h.

    8.2.3.3. Прерывание int 16h

    ¨ Функция 00h (10h). Чтение символа клавиатуры с ожиданием.

    Читает из кольцевого буфера ввода символ и скан-код. После считывания они удаляются из буфера и возвращаются в регистре AX. Если буфер пуст, ожидает ввода. Каждой клавише на клавиатуре соответствует так называемый скан-код, соответствующий только этой клавише. Этот код посылается клавиатурой при каждом нажатии и отпускании клавиши и обрабатывается в BIOS обработчиком прерывания Int 09h. Функция 00h даёт возможность получить код нажатия, не перехватывая этот обработчик. Если нажатой клавише соответствует ASCII-символ, то:

    AL – ASCII-код символа, AH – скан-код клавиши.

    Если нажатой клавише соответствует расширенный ASCII-код, то:

    Возврат: AL = ASCII-код символа, изображённый на клавише/00h,

    AH = скан-код/расширенный ASCII-код клавиши.

    Функция 10h (AH = 10) – усовершенствованный вариант функции 00h для расширенной клавиатуры (101/102-key). Позволяет получить расширенные
    ASCII-коды для клавиш F11, F12, а также для ряда других комбинаций.
    В качества признака управляющих клавиш или их комбинаций, помимо значения 00h, используются 0Ah, 0Dh и E0h.

    ¨ Функция 01h (11h). Поверка буфера клавиатуры на наличие в нём символа.

    Определяет, имеются ли в кольцевом буфере ожидающие ввода символы; возвращает флаг ожидания и сам символ при его наличии. Однако символ и его скан-код не извлекаются из буфера и могут быть снова получены при повторном вызове функции 00h Int 16h. Данная функция относится к числу асинхронных: определив состояние буфера ввода, она возвращает управление про-
    грамме.

    Возврат: ZF = 1, если буфер пуст и ZF = 0, если в буфере имеется ожидающий считывания символ. В этом случае:

    AL = ASCII-код символа/00h, AH = скан-код клавиши/расширенный ASCII-код.

    Функция 11h (AH = 11h) – усовершенствованный вариант функции 01h для расширенной клавиатуры (101/102-key). Позволяет получить расширенные ASCII-коды для клавиш F11, F12, а также для ряда других комбинаций. В качестве признака управляющих клавиш или их комбинаций, помимо значения 00h, используются 0Ah, 0Dh и E0h.

    ¨ Функция 02h (12h). Получение флагов клавиатуры.

    Возвращает байт флагов клавиатуры, описывающих состояние управляющих клавиш, записанное в байте (слове) области данных BIOS по адресу 0000h:0417h.

    Возврат: A L=1-ый байт флагов клавиатуры.

    Биты байта имеют следующие значения:

    0: 1 – правая Shift нажата

    1: 1 – левая Shift нажата

    2: 1 – Ctrl (любая) нажата

    3: 1 – Alt (любая) нажата

    4: 1 – режим Scroll Lock

    5: 1 – режим Num Lock

    6: 1 – режим Caps Lock

    7: 1 – режим Insert активен

    Функция 12h (AH = 12h) – усовершенствованный вариант функции 02h для расширенной клавиатуры (101/102-key). Выводит такое же значение байта, как и функция 02h, по адресу 0000h:0417h, и, дополнительно, второй байт статуса клавиатуры (адрес 0000h:0418h) со следующими значениями:

    0: 1 – левая Ctrl нажата 4: 1 – нажата Scroll Lock

    1: 1 – левая Alt нажата 5: 1 – нажата Num Lock

    2: 1 – правая Ctrl нажата 6: 1 – нажата Caps Lock

    3: 1 – правая Alt нажата 7: 1 – нажата SysReg

    8.2.3.4. Задержка программных операций

    Программные задержки используются в тех случаях, когда в какой-либо точке программы надо приостановить её выполнение на некоторое время. По виду исполнения программные задержки делятся на два типа: задержки, реализуемые на основе выполнения программой «пустых» вложенных циклов, и задержки, реализуемые на основе системного таймера компьютера. В листинге 3.2 приведён пример реализации задержки первого типа.

    Листинг 3.2. Программная задержка на основе выполнения вложенных циклов с командой Loop.

    Proc delay ;Подпрограмма задержки

    Mov cx, N ;N – счётчик внешнего цикла

    Outer: push cx ;Сохраним содержание счётчик внешнего цикла


    Mov cx,0 ;Обеспечим максимальное число повторений (64К раз)

    Inner: loop Inner ;Внутренний цикл

    Pop cx ;Восстановим содержание счётчик внешнего цикла

    Loop Outer ;Повторим вешний цикл N раз

    В листинге 3.2 параметр N выполняет роль масштабного множителя времени задержки

    При этом наименьшей единицей времени (т.е. «тиком») является время выполнения внутреннего цикла, состоящего, в свою очередь, из времени исполнения 65535 раз команды Loop. Параметр Nподбирается экспериментально для получения tзад (в мсек или сек) с учётом быстродействия конкретного компьютера.

    Из рассмотрения данного примера очевидны недостатки данного подхода, когда требуется обеспечить выполнение временной задержки в программе, независимо от типа используемого компьютера.Поэтому разумно определять время программной задержки непосредственно по таймеру. Выходные сигналы таймера с частотой 18,2 раза в секунду не зависят от производительности компьютера и играют роль счетчика суточного времени. Реализация данного способа использует функцию 00h прерывания BIOS Int 1Ah.

    Int 1Аh, функция 00h. Чтение счетчика циклов таймера.

    Обработчик прерывания BIOS от системного таймера (Int 8) подсчитывает количество прерываний (каждые 55 мсек или 18,2 раза в секунду) в двойном слове памяти с адресом 0040h:006Сh. Данная функция возвращает накопленное значение (двоичный код) и сбрасывает его в . В регистре AL возвращается , если содержимое счетчика не превысило значения, соответствующего 24 часам (при достижении этого значения счетчик сбрасывается), иначе возвращается AL = 1.

    Возврат: СХ:DX – число тактов системного времени от полуночи,

    AL – флаг перехода через сутки.

    Примеры возвращаемых значений в СХ:DX:

    1 сек 12h или 18,

    1 минута 04 44h или 1092,

    1 час 1 00 07h или 65543,

    24 часа 18 00 B0h или 1 573 040.

    Для задержек меньших 14 секунд можно пользоваться только младшим байтом регистра DX

    Листинг 3.3. B данном примере установлена задержка на 5 секунд, что соответствует 91 отсчету таймера

    mov ah,0 ;Функция «чтения» циклов таймера

    int 1Ah ;Получаем значение счетчика циклов в cx:dx

    add dx,91 ;Добавляем 5 сек. к младшему слову в dx

    mov bx,dx ;Запоминаем требуемое значение в bx и выполняем

    ;постоянную проверку значений счетчика времени суток

    repeat: int 1Ah ;Вновь получаем значение счетчика

    cmp dx,bx ;Сравниваем с искомым

    jne repeat ;Если не равно, то повторяем снова,

    ;иначе задержка окончена

    Если требуется введение задержки с высокой точностью, то необходимо использовать функцию 86h прерывания BIOS Int 15h. Она позволяет определить время задержки в микросекундах. Во время выполнения задержки разрешены прерывания. Управление программе возвращается после истечения заданного времени.

    Int 15h, функция 86h

    Вызов: AH = 86h, СX:DX = время задержки в мксек.

    Возврат: CF = 0 – нормальное исполнение, CF = 1 – функция не поддерживается.

    Пример: CX:DX = 0098h:9680h = 10 000 000 мксек = 10 сек.

    8.3. ВАРИАНТЫ ИНДИВИДУАЛЬНОГО ЗАДАНИЯ

    1. Инициализировать экран с определённым атрибутом. Наложить на него локальное окно меньшего размера с другим атрибутом цвета. В центральную часть окна вывести текст (несколько строк) из памяти с циклической реализацией скроллинга окна в несколько строк вверх и вниз. Смена типа скроллинга задаётся программной задержкой (2. 3 сек.). Предусмотреть выход из программы.

    2. Инициализировать две видеостраницы, каждая со своим атрибутом и записанным текстом (некоторые символы текста обязательно должны иметь отличный от других цвет). Организовать циклическую смену видеостраниц с периодом 2. 3 сек. Предусмотреть выход из программы с восстановлением текущей страницы.

    3. На экране инициализировать 2 локальных окна. Каждое окно со своим атрибутом и текстом с несколькими строками. Организовать циклическое переключение атрибутов первого окна на второе и обратно. Цикл переключения задаётся временной задержкой в 2. 3 сек. Предусмотреть выход из программы.

    4. На экране инициализировать 2 локальных окна. Каждое окно со своим атрибутом и текстом в несколько строк. Организовать циклическое переключение текста из одного окна в другое с временной задержкой 2. 3 сек. Предусмотреть выход из программы.

    5. На экране инициализировать окно_1 с атрибутом и текстом в несколько строк. Спустя время задержки 2. 3 сек частично наложить на него окно_2 с другим атрибутом и текстом. Процесс зациклить. Предусмотреть выход из программы.

    6. На экране инициализировать локальное окно с атрибутом (и текстом), сообщить ему дрейф в горизонтальном (вертикальном) направлении. При достижении границы экрана окно изменяет дрейф в противоположную сторону. Шаг движения локального окна в пространстве экрана должен быть во много раз меньше размеров самого экрана.

    7. На экране инициализировать локальное окно с атрибутом (и текстом). После нажатия командной клавиши окно начинает изменять свои размеры (пульсировать), увеличиваясь и уменьшаясь с определённым периодом. Временной шаг изменения размера окна должен быть много меньше периода
    пульсации.

    8. Инициализировать экран и локальное окно в нём со своими атрибутами. Организовать режим вывода текста в локальное окно с клавиатуры. Предусмотреть возможность редактирования текста, а также скроллинга окна при его заполнении.

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

    10. Инициализировать экран и два локальных окна в нём. В левое окно вывести первую половину таблицу ASCII, а в правое – вторую половину. Предусмотреть очистку окон и выход из программы.

    11. Инициализировать экран и два локальных окна в нём (каждое со своим атрибутом и текстом). Организовать циклическое переключение бита «яркость фона/мерцание». Выход из программы должен восстанавливать значение бита по умолчанию.

    12. Инициализировать экран и два локальных окна в нём. В левое окно вывести вторую половину таблицы ASCII c символами псевдографики. Используя навигацию курсора, c помощью клавиш (¬,­,®,¯)организовать возможность непрерывного воспроизведения прямых линий во втором окне.

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

    CX – число выводимых символов;

    Indent_L, Indent_R – поля отступа (в столбцах) слева и справа.

    Необходимо оптимизировать расчёт адреса видеобуфера ES:DI. Процедура должна возвращать исходное значение регистра ES.

    14. Используя прямое программирование видеопамяти, заполнить несколько страниц видеобуфера с последующим просмотром их (выводом на экран) в циклическом режиме. При выходе из программы обеспечить восстановление текущей страницы.

    15. Разработать программу рисования прямоугольника, используя графические символы в кодировке ASCII. Координаты верхнего левого угла (строка, столбец) и нижнего правого должны вводиться с клавиатуры после соответствующего приглашения.

    8.4. КОНТРОЛЬНЫЕ ВОПРОСЫ

    1. Краткая характеристика возможностей, предоставляемых программисту базовой системой ввода-вывода BIOS, в сравнении с сервисными функциями DOS.

    2. Назовите объём видеопамяти для изображения одного символа и, соответственно, одной видеостраницы монитора в текстовом режиме.

    3. Дайте характеристику атрибута символа в видеобуфере.

    4. Разработайте макросы для:

    ¨ очистки экрана с установкой курсора в левый верхний угол экрана;

    ¨ позиционирования курсора в произвольную точку экрана с запоминанием его координат в памяти с помощью переменных row и clm;

    ¨ вывода сообщения mes длиною leng и атрибутом цвета attrib с позиции, определяемой переменными row и clm.

    5. Какая функция BIOS предоставляет пользователю исчерпывающую информацию о нажатой клавише клавиатуры.

    Разработка графического структурного алгоритма программы

    Прикладная программа, управляющая разработанным устройством, представляет собой исполняемый файл main.com. Работу устройства можно задать изначально в начале выполнения main.com, с помощью параметра D — число, заносимое в регистр RG для установки соответствующего сопротивления.

    1. Запросить управляющий байт.

    2. Занести в указанный порт введённый байт.

    3. Ожидать сигнала с шины данных, если он получен — вывести сообщение

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

    Блок схема работы программы (структурный графический алгоритм) приведен в Приложении данного курсового проекта.

    Разработка прикладной программы и описание её возможностей

    По сложности программирования интерфейс ISA занимает среднее место между Centronics с одной стороны, и PCI и SCSI с другой. Особенностью программирования Centronics является абсолютная простота, т.к все сигналы доступны для программирования. ISA — доступность только шины данных и портов ввода-вывода, PCI — сложность программирования шины в целом.

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

    Программа является резидентной, т.е. находится постоянно в памяти. Загружается командой “main.com”, инициализирует устройство, и предлагает ввести байт D, где D — число, заносимое в управляющий регистр (по умолчанию оно равно 0), и выгружается “main.com u».

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

    Илон Маск рекомендует:  Отправка SMS сообщений с подменой отправителя
    Понравилась статья? Поделиться с друзьями:
    Кодинг, CSS и SQL