Прерывания

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

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

bits

31-16

15-8

7-5

4

3,2

1

0

target

unused

Int. mask

unused

K/U

unused

Exception level

Int enable

31

30-16

15-8

7

6-2

1-0

Br

unused

Pending interrupts

unused

Exception code

unused

  1. Br - 1 если исключение произошло на инструкции в слоте задержки перехода.
  1. Pending interrupts - ожидающие (ещё не обработанные) прерывания.
  2. Exception code - код исключения. Прерывания, в отличие от исключений, могут возникать в произвольное время (например, прерывание ввода зависит от того, когда человек нажал на кнопку). Прерывания в Mars обрабатываются тем же кодом, что и исключения — специальным обработчиком по адресу 0x8000180.
    • Нужно сохранять все используемые регистры, кроме $k0 и $k1 (все, включая $at)

  3. Нельзя пользоваться стеком (а вдруг он испорчен, или прерывание произошло во время его изменения?)
    • Можно предусмотреть отдельный стек ядра (скажем, от 0xfffeeffc вниз) и пользоваться им (тогда $sp тоже сохраняется)

  4. Нужно различать исключения (поле Exception code регистра Cause ненулевое) и прерывания (поле EXC нулевое)
    • возврат из исключения по eret требует прибавить 4 к значению EPC (ошибочную инструкцию выполнять повторно обычно не надо)

    • возврат из прерывания по eret не требует увеличения EPC (инструкция по этому адресу ещё не выполнена)

  5. В Mars нужно как можно быстрее запретить обрабатывать исключения, чтобы исключение не случилось в ядре

    • Значит, в обработчике надо проводить как можно меньше времени — не все устройства Mars умеют выставлять бит в регистре, когда обработчик запрещён (бит IE регистра Status равен 0)

    • Если в поле Pending interrupts приехало несколько битов, значит, произошло несколько прерываний, и все надо обработать (или игнорировать)

  6. Перед выходом из обработчика
    • Очистить регистр Cause (биты прерываний и тип исключения)
    • Разрешить обработку прерываний
    • (бит EXL в Mars очистит инструкция eret)

    Программа, использующая прерывания, должна их включать: выставлять 1 в биты разрешения прерываний и во все нужные позиции маски прерываний, а также переводить используемые врешние устройства в режим работы по прерыванию:
            mfc0    $a0 $12                 # read from the status register
            ori     $a0 0xff11              # enable all interrupts
            mtc0    $a0 $12                 # write back to the status register
    
            li      $a0 2                   # enable keyboard interrupt
            sw      $a0 0xffff0000
    Сам обработчик событий по адресу 0x800000180, таким образом, обычно состоит из следующих частей:
    • Запрет вызова обработчика (бит IE)
  7. Сохранение всех регистров
  8. Вычисление типа исключений (0 — прерывание)
    • Переход на обработчик соответствующего исключения или на обработчик прерываний
  9. Обработчик прерываний:
    • Выяснение источника/ов прерывания (биты Pending)
    • Обработка всех случившихся прерываний (порядок определяется программно)
  10. Обработчик исключения
    • Обработка исключения :)

    • Вычисление нового EPC
  11. Восстановление всех регистров
  12. Разрешение вызова обработчика
  13. eret

    Замечание: как и во время обработки прерывания, во время системного вызова прерывания или вообще запрещены, или накапливаются (делаются «Pending») без вызова обработчика. Поэтому задача обработчика — как можно быстрее принять решение, что делать с прерыванием и вернуть управление пользовательской программе.

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

Пример: консоль Mars

Консоль Mars («Keyboard and Display MMIO Simulator») — воображаемое устройство, осуществляющее побайтовый ввод и вывод. Вернее окошко — «дисплей», куда выводятся байты, а нижнее — «клавиатура» (для удобства набираемый на клавиатуре текст отображается в этом окошке).

atttachment:Console.png

Консоль имеет следующие регистры ввода-вывода

0xffff0000

RcC

Управляющий регистр ввода

RW

0 бит — готовность, 1 бит — прерывание

0xffff0004

RcD

Регистр данных ввода

R

введённый байт

0xffff0008

TxC

Управляющий регистр вывода

RW

0 бит — готовность, 1 бит — прерывание

0xffff000c

TxD

Регистр данных вывода

W

необязательные координаты курсора, байт для вывода