22. Прерывания. Обработка прерываний в реальном режиме работы процессора. - Tulenenok/_Assembler Wiki

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

Виды прерываний

  • аппаратные (асинхронные) - события от внешних устройств;
  • внутренние (синхронные) - события в самом процесооре, например, деление на ноль;
  • программные - вызванные командой int.

Таблица векторов прерываний

Вектор прерывания - номер, который идентифицирует соответствующий обработчик прерываний.

Векторы прерываний объединяются в таблицу векторов прерываний, содержащую адреса обработчиков прерываний.

  • Располагается в самом начале памяти, начиная с адреса 0.
  • Доступно 256 прерываний.
  • Каждый вектор занимает 4 байта - полный адрес.
  • Размер всей таблицы - 1 Кб.

Срабатывание прерывания

  • Сохранение в текущий стек регистра флагов и адреса возврата (адреса следующей команды)
  • Передача управления по адресу обработчика из таблицы векторов
  • Настройка стека

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

  • Повторная входимость (реентерабельность), необходимость запрета прерываний

    Кузнецов: "таймер тикает, срабатывают прерывания. В какой-то момент прерывание тика таймера не успевает отработать до след тика, вызывается еще раз тоже прерывание и нужно обеспечить корректную работу в такой ситуации"; запрет прерывания можно делать только на короткий срок, иначе можно потерять данные (переполнение буфера клавиатуры, например)

Возврат из обработчика прерываний

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

  • Восстанавливает FLAGS, CS:IP.
  • При необходимости выставить значение флага обработчик меняет его значение непосредственно в стеке.

Маскировка прерываний

Внешние прерывания, в зависимости от возможности запрета, делятся на:

  • маскируемые - прерывания, которые можно запрещать установкой соответствующего флага
  • немаскируемые - обрабатываются всегда, независимо от запретов на другие прерывания

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

  • Сохранение старого адреса обработчика
  • Изменение вектора на "свой" адрес
  • Вызов старого обработчика до/после обработки своего кода
  • При деактивации - восстановление адреса старого обработчика

Установка обработчика прерывания в DOS

int 21h
  • AH = 35h, AL = номер прерывания - вернет в ES:BX адрес обработчика
  • AH = 25h, AL = номер прерывания - вернет в DS:DX адрес обработчика

Пример 1. По заявкам телезрителей как мы устанавливали собственное прерывание в лр7

INSTALL_BREAKING:
    ; Скачали процедуру, которая обрабатывает прерывание 1C сейчас
    MOV AX, 351CH 
    INT 21H

    ; Если установка уже была, то нужно наоборот вернуть все как было
    CMP ES:WAS_INSTALL, 1
    JE UNINSTALL_BREAKING

    ; Сохраняем адрес вектора прерывания старого
    ; 'word ptr' нужно для того, чтобы обратиться по двухбайтному адресу
    MOV WORD PTR OLD_INTERR, BX      
    MOV WORD PTR OLD_INTERR + 2, ES  

    ; Установка нашего собственного прерывания
    MOV AX, 251CH               
    LEA DX, MY_NEW_INTERR
    INT 21H                     

    ; Прерывание 27h – завершиться, но остаться в памяти. При этом в DX кладется адрес первого байта за резидентным участком программы
    ; То есть всё, начиная с адреса метки init, будет освобождено из памяти
    LEA DX, INSTALL_BREAKING
    INT 27H 

Некоторые прерывания

  • 0 - деление на 0
  • 1 - прерывание отладчика, вызывается после каждоый команды при флаге TF
  • 3 - отладочное (int 3 занимает 1 байт)
  • 4 - переполнение при команде INTO (команда контроля переполнения)
  • 5 - при невыполнении условия в команде BOUND (команда контроля индексов массива)
  • 6 - недопустимая (несуществующая) инструкция)
  • 7 - отсутствие FPU
  • 8 - таймер
  • 9 - клавиатура
  • 10h - прерывание BIOS

Прерывание 21h

  • Аналог системного вызова в современных ОС
  • Используется наподобие вызова подпрограммы
  • Номер функции передается через AH
Функция Назначение Вход Выход
01 Считать символ из stdin с эхом - AL = ascii-код сивола
02 Вывод символа в stdout DL = ascii-код сивола -
06 Считать символ без эха, без ожидания, без проверки на Ctrl+Break DL = FF AL = ascii-код сивола
07 Считать символ без эха, с ожиданием, без проверки на Ctrl+Break - AL = ascii-код сивола
08 Считать символ без эха - AL = ascii-код сивола
09 Вывод строки в stdout DS:DX = адрес строки, заканчивающейся $ -
10 Считать строку из stdin в буфер DS:DX = адрес буфера Введенная строка помещается в буфер
0Bh Проверка состояние клавиатуры - AL = 0, если клавиша не была нажата, и FF, если была
0Ch Очистить буфер и считать символ AL = 01, 06, 07, 08, 0Ah

Пример 1. Считывание строки

input_str_from_stdin:
    mov ah, 0ah
    lea dx, string
    int 21h            ; вызываем прерывание для считывания строки в string

Пример 2. Завершение программы

mov ah, 4Ch
int 21h            

Вопросы про прерывания с РК1

Значения каких регистров помещаются в стек при срабатывании прерывания?

FLAGS, CS, IP

Что программа обязательно должна сделать для корректного перехвата прерывания?

Сохранить адрес старого обработчика прерывания

Какие прерывания могут быть замаскированы?

Аппаратные (асинхронные)

Чем команда IRET отличается от RETF в архитектуре 8086?

IRET восстанавливает из стека значение регистра флагов, RETF - нет

Что необходимо для перехвата прерывания?

Указать адрес нового обработчика в таблице векторов прерываний