Обработка прерываний, векторы прерываний, программные прерывания, IRQ. Вложенные прерывания

Обработка прерываний, векторы прерываний, программные прерывания, IRQ. Вложенные прерывания

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

Простой пример — таймер и его прерывание по переполнению.
Мы можем задавать выдержку и по прерыванию делать какие-нибудь операции. Но если в один момент времени мы хотим чтобы таймер по прерванию сделал одну операцию, а потом другую, третью. Да сколько угодно, в зависимости от состояния. А вектор один.

Или, например, USART. Нам запросто может потребоваться, чтобы в зависимости от режима на прерывание по приходу байта выполнялся разный код. В одном режиме — выдача приветствия, в другом посыл матом в баню. В третьем удар в голову. А вектор один.

Конечно, можно добавить в обработчик прерывания switch-case конструкцию и по выбору режима перейти на нужный участок кода, но это довольно громоздко, а самое главное — время перехода будет разное, в зависимости от того в каком порядке будет идти опрос-сравнение switch-case структуры.

То есть в свитче вида:

1 2 3 4 5 6 7 switch (x) { 1 : Действие 1 2 : Действие 2 3 : Действие 3 4 : Действие 4 }

switch(x) { 1: Действие 1 2: Действие 2 3: Действие 3 4: Действие 4 }

Будет последовательное сравнение х вначале с 1, потом с 2, потом с 3 и так до перебора всех вариантов. А в таком случае реакция на Действие 1 будет быстрей чем реакция на Действие 4. Особо важно это при расчете точных временных интервалов на таймере.

Но есть простое решение этой проблемы — индексный переход. Достаточно перед тем как мы начнем ожидать прерывание предварительно загрузить в переменные (а можно и сразу в индексный регистр Z) направление куда нам надо перенаправить наш вектор и воткнуть в обработчик прерывания индексный переход. И вуаля! Переход будет туда куда нужно, без всякого сравнения вариантов.

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

Timer0_Vect_L: .byte 1 ; Два байта адреса, старший и младший Timer0_Vect_H: .byte 1

Подготовка к ожиданию прерывания проста, мы берем и загружаем в нашу переменную нужным адресом

CLI ; Критическая часть. Прерывания OFF LDI R16,low(Timer_01) ; Берем адрес и сохраняем STS Timer0_Vect_L,R16 ; его в ячейку памяти. LDI R16,High(Timer_01) ; Аналогично, но уже со старшим вектором STS Timer0_Vect_H,R16 SEI ; Прерывания ON

Все, можно запускать таймер и ждать нашего прерывания. С другими случаями аналогично.

А обработчик получается вида:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 ;============================= ; Вход в прерывание по переполнению от Timer0 ;============================= TIMER_0: PUSH ZL ; сохраняем индексный регистр в стек PUSH ZH ; т.к. мы его используем PUSH R2 ; сохраняем R2, т.к. мы его тоже портим IN R2,SREG ; Извлекем и сохраняем флаговый регистр PUSH R2 ; Если не сделать это, то 100% получим глюки LDS ZL,Timer0_Vect_L ; загружаем адрес нового вектора LDS ZH,Timer0_Vect_H ; оба байта. CLR R2 ; Очищаем R2 OR R2,ZL ; Проверяем вектор на ноль. Иначе схватим аналог OR R2,ZH ; reset"a. Проверка идет через операцию OR BREQ Exit_Tm0 ; с накоплением результата в R2 ; так мы не портим содержимое Z и нам не придется; загружать его снова IJMP ; Уходим по новому вектору; Выход из прерывания. Exit_Tm0: POP R2 ; Достаем и восстанавливаем регистр флагов OUT SREG,R2 POP R2 ; восстанавливаем R2 POP ZH ; Восстанавливаем Z POP ZL RETI ; Дополнительный вектор 1 Timer_01: NOP ; Это наши новые вектора NOP ; тут мы можем творить что угодно NOP ; желательно недолго - в прерывании же NOP ; как никак. Если используем какие другие NOP ; регистры, то их тоже в стеке сохраняем RJMP Exit_Tm0 ; Это переход на выход из прерывания; специально сделал через RJMP чтобы; Дополнительный вектор 2 ; сэкономить десяток байт на коде возврата:))) Timer_02: NOP NOP NOP NOP NOP RJMP Exit_Tm0 ; Дополнительный вектор 3 Timer_03: NOP NOP NOP NOP NOP RJMP Exit_Tm0

;============================= ; Вход в прерывание по переполнению от Timer0 ;============================= TIMER_0: PUSH ZL ; сохраняем индексный регистр в стек PUSH ZH ; т.к. мы его используем PUSH R2 ; сохраняем R2, т.к. мы его тоже портим IN R2,SREG ; Извлекем и сохраняем флаговый регистр PUSH R2 ; Если не сделать это, то 100% получим глюки LDS ZL,Timer0_Vect_L ; загружаем адрес нового вектора LDS ZH,Timer0_Vect_H ; оба байта. CLR R2 ; Очищаем R2 OR R2,ZL ; Проверяем вектор на ноль. Иначе схватим аналог OR R2,ZH ; reset"a. Проверка идет через операцию OR BREQ Exit_Tm0 ; с накоплением результата в R2 ; так мы не портим содержимое Z и нам не придется; загружать его снова IJMP ; Уходим по новому вектору; Выход из прерывания. Exit_Tm0: POP R2 ; Достаем и восстанавливаем регистр флагов OUT SREG,R2 POP R2 ; восстанавливаем R2 POP ZH ; Восстанавливаем Z POP ZL RETI ; Дополнительный вектор 1 Timer_01: NOP ; Это наши новые вектора NOP ; тут мы можем творить что угодно NOP ; желательно недолго - в прерывании же NOP ; как никак. Если используем какие другие NOP ; регистры, то их тоже в стеке сохраняем RJMP Exit_Tm0 ; Это переход на выход из прерывания; специально сделал через RJMP чтобы; Дополнительный вектор 2 ; сэкономить десяток байт на коде возврата:))) Timer_02: NOP NOP NOP NOP NOP RJMP Exit_Tm0 ; Дополнительный вектор 3 Timer_03: NOP NOP NOP NOP NOP RJMP Exit_Tm0

Реализация для RTOS
Но что делать если у нас программа построена так, что весь код вращается по цепочкам задач через диспетчер RTOS? Просчитать в уме как эти цепочки выполняются относительно друг друга очень сложно. И каждая из них может попытаться завладеть таймером (конечно не самовольно, с нашей подачи, мы же программу пишем, но отследить по времени как все будет сложно).
В современных больших осях на этот случай есть механизм Mutual exclusion — mutex. Т.е. это своего рода флаг занятости. Если какой нибудь процесс общается, например, с UART то другой процесс туда байт сунуть не смеет и покорно ждет пока первый процесс освободит UART, о чем просемафорит флажок.

В моей механизмов взаимоисключений нет, но их можно реализовать. По крайней мере сделать некоторое минимальное подобие. Полноценную реализацию всего этого барахла я делать не хочу, т.к. моей целью является удержания размера ядра на уровне 500-800 байт.
Проще всего зарезервировать в памяти еще один байт — переменную занятости. И когда один процесс захватывает ресурс, то в эту переменную он записывает время когда ориентировочно он его освободит. Время идет в тиках системного таймера которое у меня 1ms.
Если какой либо другой процесс попытается обратиться к этому же аппаратному ресурсу, то он вначале посмотрит на состояние его занятости, считает время в течении которого будет занято и уйдет покурить на этот период — загрузит сам себя в очередь по таймеру. Там снова проверит и так далее. Это простейший вариант.

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

Решение проблемы — добавление еще одной очередной цепочки, на этот раз уже на доступ к ресурсу. Чтобы он не простаивал вообще. Т.е. один выскочил, тут же второй, третий и так далее пока все процессы не справят свою нужду в какой нибудь там USART.
Недостаток очевиден — еще одна очередь это дополнительная память, дополнительный код, дополнительное время. Можно, конечно, извратиться и на очередь к вектору натравить код диспетчера основной цепи. Но тут надо все внимательно отлаживать, ведь вызываться он будет по прерыванию! Да и громоздко, требуется лишь тогда, когда у нас много желающих.

Второе решение — выкинуть переменную времени занятости, оставив только флаг «Занято!». А процесс который пытается обратиться не убегает покурить, а отскакивает на пару шагов назад — на конец очереди задач и сразу же ломится обратно. Народ вокруг сортира не вокруг бегает, а толкется локтями у входа по принципу кто первый пролезет.
Недостаток другой — большая нагрузка на главный конвеер, куча запросов на постановку в очередь так недолго распухнуть на всю оперативку и повстречаться со стеком, а это черевато глобальным апокалипсисом.

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

Сторожевые таймеры.

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

Это устройство вызывает сброс микроконтроллера, если его содержимое не будет обновлено в течение определенного промежутка времени (обычно от десятков миллисекунд до нескольких секунд). Если изменение содержимо­го программного счетчика не соответствует заданной программе, то команда модификации сторожевого таймера не будет выполнена. В этом случае сторо­жевой таймер производит сброс микроконтроллера, устанавливая его в ис­ходное состояние.

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

Не рекомендуется использовать сторожевой таймер для маскирования программных проблем. Хотя этот таймер может уменьшить вероятность про­граммных ошибок, однако вряд ли он обеспечит исключение всех возмож­ных причин их возникновения. Вместо того, чтобы надеяться на предотвра­щение программных сбоев аппаратными средствами, лучше более тщательно протестировать программное обеспечение в различных ситуациях.

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

Если вы никогда не имели дело с прерываниями, то у вас возникнет вопрос - что это такое? В компьютерной системе прерывание - это запуск специальной подпрограммы (называемой «обработчиком прерывания» или «программой обслуживания прерывания»), который вызывается сигналом аппаратуры. На время выполнения этой подпрограммы реализация текущей программы останавливается. Термин «запрос на прерывание» (interrupt request) используется потому, что иногда программа отказывается подтвердить пре­рывание и выполнить обработчик прерывания немедленно (рис 2.19).


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

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

Рис. 2.18 - Выполнение прерывания.

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

Обработчик прерывания всегда обеспечивает следующую последователь­ность действий:

2. Сбросить контроллер прерываний и оборудование, вызвавшее запрос.

3. Обработать данные.

4. Восстановить содержимое регистров контекста.

5. Вернуться к прерванной программе.

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

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

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

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

Восстановление регистров контекста и выполнение команды возврата из прерывания переводит процессор в состояние, в котором он находился до возникновения прерывания.

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

Если содержимое регистра состояния сохраняется перед началом выпол­нения обработчика прерывания, то по команде возврата производится его автоматическое восстановление.

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

Адрес, который загружается в программный счетчик при переходе к обра­ботчику прерывания, называется «вектор прерывания». Существует несколь­ко типов векторов. Адрес, который загружается в программный счетчик при запуске микроконтроллера (reset) называется «вектор сброса». Для различных прерываний могут быть заданы разные вектора, что избавляет программу обслуживания от необходимости определять причину прерывания. Использо­вание различными прерываниями одного вектора обычно не вызывает про­блем при работе микроконтроллеров, так как чаще всего микроконтроллер исполняет одну единственную программу. Этим микроконтроллер отличается от персонального компьютера, в процессе эксплуатации которого могут до­бавляться различные источники прерываний. (Если вы когда-либо подклю­чали два устройства к портам СОМ1 и COM3, то вы представляете, о чем идет речь). В микроконтроллере, где аппаратная часть хорошо известна, не должно возникнуть каких-либо проблем при совместном использовании век­торов прерываний.

Последнее, что осталось рассмотреть, - это программные прерывания. Существуют процессорные команды, которые могут быть использованы для имитации аппаратных прерываний. Наиболее очевидное использование этих команд - это вызов системных подпрограмм, которые располагаются в про­извольном месте памяти, или требуют для обращения к ним межсегментных переходов. Эта возможность реализована в микропроцессорах семейства Intel i86 и используется в базовой системе ввода-вывода BIOS (Basic Input/Output System) и операционной системе DOS персональных компьютеров для вызо­ва системных подпрограмм без необходимости фиксирования точки входа. Вместо этого используются различные вектора прерываний, выбирающие команду, которая должна выполняться, когда происходит такое программ­ное прерывание.

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

Здесь мы разберем такие важные темы, как: обработка прерываний, векторы прерываний, программные прерывания, IRQ , в общем поговорим на темы прерывания.

Идея прерывания была предложена в середине 50-х годов и основная цель введения прерываний – реализация синхронного режима работы и реализация параллельной работы отдельных устройств ЭВМ.

Прерывания и обработка прерываний зависят от типа ЭВМ, поэтому их реализацию относят к машинно-зависимым свойствам операционных систем.

Прерывание (interrupt) – это сигнал, заставляющий ЭВМ менять обычный порядок выполнения команд процессором.

Возникновение подобных сигналов обусловлено такими событиями , как:

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

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

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

Например прерывание с номером 9 — прерывание от клавиатуры, которое генерируется при нажатии и при отжатии клавиши. Используется для чтения данных с клавиатуры. Обозначается в ОС как IRQ 1, где IRQ – обозначение прерывания, а 1 – приоритет прерывания. Данные о запросах на прерывание можно проанализировать в диспетчере устройств:

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

Предположим, что в момент поступления сигнала прерывания от некоторого источника программа А находится в решении. В результате управление автоматически передается обработчику прерываний. После завершения обработки управление может быть снова передано в ту точку программы А, где ее выполнение было прервано:

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

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

Для микропроцессора требуется простой способ определения местоположения программы обработки прерывания и это осуществляется путем использования таблицы векторов прерываний .

Таблица векторов прерываний занимает первый килобайт оперативной памяти — адреса от 0000:0000 до 0000:03FF. Таблица состоит из 256 элементов — FAR-адресов обработчиков прерываний. Эти элементы называются векторами прерываний . В первом слове элемента таблицы записано смещение, а во втором — адрес сегмента обработчика прерывания. Векторами являются просто полные адреса памяти программы (в сегментированной форме), которая должна быть активизирована в случае возникновения прерывания.

Прерыванию с номером 0 соответствует адрес 0000:0000, прерыванию с номером 1 — 0000:0004 и т.д. Адрес такой состоит из пары 2-байтовых слов, поэтому каждый из векторов занимает четыре байта.

Можно просмотреть таблицу векторов прерываний в компьютере, если воспользоваться программой DEBUG. Используйте команду D для вывода содержимого начала памяти: D 0:0. Программа DEBUG покажет вам первые 128 байтов или 32 вектора, которые могут иметь вид наподобие следующего:

0000:0000 E8 4E 9A 01 00 00 00 00-C3 E2 00 F0 00 00 00 00
0000:0010 F0 01 70 00 54 FF 00 F0-05 18 00 F0 05 18 00 F0
0000:0020 2C 08 51 17 D0 0A 51 17-AD 08 54 08 E8 05 01 2F
0000:0030 FA 05 01 2F 05 18 00 F0-57 EF 00 F0 F0 01 70 00
0000:0040 90 13 C7 13 4D F8 00 F0-41 F8 00 F0 3E 0A 51 17
0000:0050 5C 00 B7 25 59 F8 00 F0-E2 0A 51 17 9C 00 B7 25
0000:0060 00 00 00 F6 8E 00 DE 09-6E FE 00 F0 F2 00 7B 09
0000:0070 27 08 51 17 A4 F0 00 F0-22 05 00 00 00 00 00 F0

Векторы хранятся как «слова наоборот»: сначала смещение, а потом сегмент. Например, первые четыре байта, которые программа DEBUG показала выше (E8 4E 9A 01) можно преобразовать в сегментированный адрес 019A:4EE8.

Можно встретить три вида адресов в таблице векторов . Это могут быть адреса, указывающие на ROM-BIOS, которые можно идентифицировать шестнадцатеричной цифрой F, которая предшествует номеру сегмента. Это могут быть адреса, которые указывают на главную память (как в примере: 019A:4EE8). Эти адреса могут указывать на подпрограммы ДОС или на резидентную программу (например, SideKick или Prokey), либо они могут указывать на саму программу DEBUG (поскольку DEBUG должна временно управлять прерыванием). Также векторы могут состоять из одних нулей, когда прерывание с данным номером не обрабатывается в текущий момент.

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

Ниже приведено назначение некоторых векторов:

Описание
0 Ошибка деления. Вызывается автоматически после выполнения команд DIV или IDIV, если в результате деления происходит переполнение (например, при делении на 0).
2 Аппаратное немаскируемое прерывание. Это прерывание может использоваться по-разному в разных машинах. Обычно вырабатывается при ошибке четности в оперативной памяти и при запросе прерывания от сопроцессора.
5 Печать копии экрана. Генерируется при нажатии на клавиатуре клавиши PrtScr. Обычно используется для печати образа экрана.
8 IRQ0 — прерывание интервального таймера, возникает 18,2 раза в секунду.
9 IRQ1 — прерывание от клавиатуры. Генерируется при нажатии и при отжатии клавиши. Используется для чтения данных от клавиатуры.
A IRQ2 — используется для каскадирования аппаратных прерываний в машинах класса AT
B IRQ3 — прерывание асинхронного порта COM2.
C IRQ4 — прерывание асинхронного порта COM1.
D IRQ5 — прерывание от контроллера жесткого диска для XT.
E IRQ6 — прерывание генерируется контроллером флоппи-диска после завершения операции.
F IRQ7 — прерывание принтера. Генерируется принтером, когда он готов к выполнению очередной операции. Многие адаптеры принтера не используют это прерывание.
10 Обслуживание видеоадаптера.
11 Определение конфигурации устройств в системе.
12 Определение размера оперативной памяти в системе.
13 Обслуживание дисковой системы.
14 Последовательный ввод/вывод.
1A Обслуживание часов.
1B Обработчик прерывания Ctrl-Break.
70 IRQ8 — прерывание от часов реального времени.
71 IRQ9 — прерывание от контроллера EGA.
75 IRQ13 — прерывание от математического сопроцессора.
76 IRQ14 — прерывание от контроллера жесткого диска.
77 IRQ15 — зарезервировано.

IRQ0 — IRQ15 — это аппаратные прерывания.

Механизм обработки прерываний

При обработке каждого прерывания должна выполняться следующая последовательность действий:

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

Главные функции механизма прерывания:

  1. распознавание или классификация прерываний.
  2. передача управления соответственно обработчику прерываний.
  3. корректное возвращение к прерванной программе (перед передачей управления обработчику прерываний содержимое регистров процессора запоминается либо в памяти с прямым доступом либо в системном стеке).

Типы прерываний

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

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

Аппаратные прерывания не координируются c работой программного обеспечения. Когда вызывается прерывание, то процессор оставляет свою работу, выполняет прерывание, a затем возвращается на прежнее место.

Внешние прерывания возникают по сигналу какого-либо внешнего устройства например:

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

Прерывание по таймеру вызывается интервальным таймером. Этот таймер содержит регистр, которому может быть присвоено определенное начальное значение посредством специальной привилегированной команды. Значение этого регистра автоматически уменьшается на 1 по истечении каждой миллисекунды времени. Когда это значение становятся равным нулю, происходит прерывание по таймеру. Подобный интервальный таймер используется операционной системой для определения времени, в течение которого программа пользователя может оставаться под управлением машины.

Маскируемые и немаскируемые внешние прерывания

Существуют два специальных внешних сигнала среди входных сигналов процессора, при помощи которых можно прервать выполнение текущей программы и тем самым переключить работу центрального процессора. Это сигналы NMI (Non Mascable Interrupt, немаскируемое прерывани ) INTR (interrupt request, запрос на прерывание ).

Соответственно внешние прерывания подразделяются на два вида: немаскируемые и маскируемые.

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

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

Внутренние прерывания вызываются событиями, которые связаны с работой процессора и являются синхронными с его операциями, а именно прерывание происходит, когда:

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

Программные прерывания

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

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

Механизм программных прерываний был специально введен для того, чтобы:

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

Пример (программные прерывания):

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

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

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

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

Каждому прерыванию назначается свой уникальный приоритет. Если происходит одновременно несколько прерываний, то система отдает предпочтение самому высокоприоритетному, откладывая на время обработку остальных прерываний.

В случае о прерывании самой программы обработки прерывания говорят о вложенном прерывании . Уровни приоритетов обозначаются сокращенно IRQ0 — IRQ15 или IRQ0 – IRQ23 (в зависимости от микросхемой реализации).

Пpepывaнию вpeмeни cутoк дан мaкcимaльный пpиopитeт, пocкoльку ecли oнo будет пocтoяннo тepятьcя, то будут нeвepными пoкaзaния cиcтeмныx чacoв. Пpepывaниe от клaвиaтуpы вызывaeтcя при нaжaтии или oтпуcкaнии клавиши; oнo вызывaeт цепь coбытий, кoтopaя oбычнo зaкaнчивaeтcя тем, что код клавиши пoмeщaeтcя в буфep клaвиaтуpы (oткудa он зaтeм мoжeт быть пoлучeн пpoгpaммными пpepывaниями).

Ну и наконец реализация механизма обработки прерываний

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

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

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

Сохранение и восстановление состояния процессора и содержимого регистров называют операцией контекстного переключения .

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

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

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

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

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

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

Прерывания в микроконтроллерах представляет собоймеханизм, который позволяет микроконтроллеру реагировать на внешние события. Этот механизм работает таким образом, что при наступлении некоторого события в процессоре возникает сигнал, заставляющий процессор прервать выполнение текущей программы, т.е. говорят, что возникло прерывание. После того как выполнение текущей программы прервано, процессор должен перейти к выполнению программной процедуры, связанной с этим событием (прерыванием) – процедуры обработки прерывания. Однако, прежде чем перейти непосредственно к процедуре обработки прерывания, процессор должен выполнить ряд предварительных действий. Прежде всего, для того чтобы в будущем он смог корректно продолжить прерванную программу, необходимо сохранить состояние процессора (счетик команд, слово состояния процессора, внутренние регистры и т.д.) на момент, предшествующий прерыванию. Т.е. другими словами, требуется сохранить состояния всех тех ресурсов,которые так или иначе могут быть изменены в процессе обработки прерывания. Далее, если в системе имеется несколько возможных источников прерываний (а обычно так и бывает), процессор должен определить источник запроса прерываний. И, наконец, затем перейти к самой процедуре прерываний, конкретной для данного прерывания. По завершению обработки прерывания процессор должен восстановить состояние ресурсов, соответствующее прерванной программе, после чего она может быть продолжена. Следует отметить, что для сохранения всех требуемых ресурсов, поиска источника прерывания и перехода к процедуре обработки прерывания процессор должен затратить вполне определенное время. Это время называется скрытым временем прерывания. Чем меньше скрытое время прерывания, тем выше скорость реакции системы на внешние события и тем выше производительность системы. Во многом это определяется системой прерывания процессора и она является одной из основных особенностей архитектуры контроллера.

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

Одноуровневые прерывания

Данная система прерываний реализована таким образом, что при возникновении прерывания процессор аппаратно переходит к подпрограмме обработки прерываний, расположенной по некоторому фиксированному адресу. Чтобы упростить аппаратную часть системы прерываний, этот адрес обычно располагается либо в начале, либо в конце адресного пространства программной памяти. Поскольку для обработки ВСЕХ прерываний используется только ОДНА точка входа, то такая система прерываний получила название одноуровневой. В такой системе выявление источника прерываний путем опроса состояния флажков признаков прерываний в начале программы обработки прерываний. При обнаружении установленного флажка происходит переход к соответствующему участку процедуры. Чем больше возможных источников прерываний, тем больше времени необходимо для обнаружения источника прерывания. Такой метод обнаружения источника прерывания называется программным опросомили поллингом (polling ). Его недостатком является довольно большое время, затрачиваемое на поиск источника прерывания и, как следствие, замедленная реакция системы на внешние события. Его достоинство – простота реализации системы прерываний.


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

Чтобы значительно уменьшить время реакции на внешние события, используются многоуровневые или, что то же самое, векторные прерывания. В векторных прерываниях КАЖДОМУ источнику прерывания соответствует СВОЙ, вполне определенный, адрес процедуры обработки прерывания, который принято называть вектором прерывания.

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

PIC vs . AVR vs. MSP vs mcs51. В контроллерах PIC 16 реализована одноуровневая система прерывания. При возникновении прерывания, процессор переходит по адресу 0x0004 (точка входа по прерыванию). Далее, после контекстного сохранения регистров, выполняется программный опрос признаков прерываний (поллинг ). Нужно также отметить, что при обнаружении источника прерывания требуется сбросить соответствующий установленный флажок запроса на прерывания.

В семействе PIC 18 используется как одноуровневая (в режиме совместимости с PIC 16), так и двухуровневая система прерываний. В режиме совместимости при возникновении прерывания процессор переходит к процедуре обработки прерывания по адресу 0x 000008 и далее все происходит аналогично PIC 16. При двухуровневой системе прерывания имеются два вектора перехода 0x 000008 и 0x 000018. Присвоение уровня каждому из имеющихся источников прерывания задается программным путем, с помощью соответствующих признаков. Способ организации системы прерывания (одно- или двухуровневая ) также определяется значением соответствующего разряда в регистре управления прерываниями.

В контроллерах семейства AVR реализована векторная система прерываний. При обнаружении прерывания, процессор сразу переходит по вектору прерывания к процедуре обработки прерываний от данного источника. Вектора прерываний расположены в начальных адресах программной памяти и представляют из себя команду перехода на обработчик прерывания. Количество векторов прерываний соответствует числу возможных источников прерываний, которые зависят от конкретного типа контроллера. Следует добавить, что сброс флажков запроса на прерывания происходит автоматически при переходе по вектору прерывания и выполнение каких-либо инструкций для этого не требуется.

В контроллерах семейства MSP 430 система прерываний также является векторной, т.е. каждому периферийному модулю соответствует свой вектор прерывания. Однако, это не исключает необходимости программного контроля (поллинга ), т.к. некоторые периферийные модули имеют множественные источники прерываний. Пример – прерывания от порта ввода/вывода. В данном случае имеется возможность программно разрешать прерывания от индивидуальных выводов порта. Даже в том случае, если разрешеныпрерывания от более, чем одного входа, они все будут иметь одинаковый вектор прерываний. Определить какой конкретно вход являлся источником прерывания можно только программно. Эта особенность также влияет и на сброс флагов прерываний – флаги прерывания с множественными источниками не сбрасываются автоматически в отличие от флагов прерывания с одним источником. Адрес и количество векторов прерывания зависят от конкретного типа контроллера. Вектора прерываний находятся в конце программной памяти (адресного пространства) и представляют из себя адрес обработчика прерывания.

В контроллерах семейства mcs 51 система прерываний также является векторной, но для вектора прерывания зарезервирован довольно большой обьем памяти (8 байт), что иногда бывает достаточно для его обработчика. Флаги прерывания сбрасываются автоматически при переходе к обработчику прерываний, если у прерывания возможен только один источник и несбрасываются если у прерывания может быть два и более источников. В последнем случае необходимо программно сбросить флаг вызвавший прерывание после выяснения причины прерывания (поллинга ). Вектора располагаются в начальных адресах программной памяти.

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

Обычно, значимость тех или иных событий в системе неодинакова. Одни события более важны и требуют немедленной реакции, другие менее важны, и с ответом на них можно подождать. Естественно, что и соответствующие этим событиям прерывания должны иметь разный приоритет. При одновременном возникновении нескольких прерываний, процессор должен перейти к обработке прерывания, имеющего более высокий приоритет. Этот процесс происходит на аппаратном уровне ядра процессора и называется последовательностью опроса прерываний (interrupt polling sequence ).

PIC vs . AVR vs MSP vs. mcs51. В семействе PIC 16 приоритет опроса того или иного прерывания определяется очередностью опроса соответствующего флажка прерывания. Приоритет опроса прерывания будет выше утех прерываний, у которых флажки запросов на прерывания будут опрашиваться в первую очередь. Порядок опроса флажков признаков прерывания целиком определяется программой обработки прерывания и может быть изменен при ее изменении.

В контроллерах PIC 18 при двухуровневой системе прерывания более высокий уровень приоритетаимеют прерывания с вектором 0x 000008. В пределах одного уровня приоритетность прерывания определяется программно, так же как и у PIC 16.

В семействе AVR приоритета опроса жестко фиксирован и не может быть изменен. Чем меньше адрес вектора прерывания, тем выше уровень опроса прерывания ему соответствующего.

В семействе MSP 430 приоритет опроса также жестко фиксирован и неизменяем, но зависимость приоритета опроса прерывания обратная – чем выше адрес вектора прерывания, тем выше приоритет опроса данного прерывания.

В семействе mcs 51 приоритет опроса полностью анологичен контроллерам семейства AVR .

Вложенные прерывания

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

PIC vs . AVR . В семействе PIC16 процедура обработки любого прерывания начинается с одного и того же адреса и реализовать вложенные прерывания крайне затруднительно, если это вообще возможно.

В контроллерах PIC 18 при двухуровневой системе прерывания возможно прерывание процедур прерывания с низким уровнем приоритета прерываниями, имеющими более высокий уровень.

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

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

В семействе mcs 51 аппаратно предусмотрена возможность вложенных прерываний. Для этого каждому типу прерывания может быть задан уровень приоритета high и прерывание с данным уровнем может прервать обработку другого прерывания с уровнем приоритета low . Приоритеты внутри одного уровня приоритета располагаются согласно последовательности опроса прерываний (interrupt polling sequence ).

Вложенные прерывания

Этот механизм полностью поддерживается в ОС QNX Neutrino. В предыдущих сценариях описывалась самая простая и наиболее распространенная ситуация, когда возникает только одно прерывание. Однако для получения максимального значения задержки в отсутствие немаскированных прерываний следует рассматривать время с учетом сразу всех текущих прерываний, так как немаскированное прерывание с более высоким приоритетом будет вытеснять текущее прерывание.

На рис. 2.25 показан выполняемый Поток А. Прерывание IRQx запускает обработчик прерываний Intx, который вытесняется прерыванием IRQy и обработчиком прерываний lnty. Обработчик прерываний Inty возвращает событие, которое запускает Поток В, а обработчик прерываний Intx возвращает событие, которое запускает Поток С.

Вызовы, связанные с прерываниями

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

Посредством этого программного интерфейса поток с соответствующими пользовательскими привилегиями может вызывать функцию InterruptAttachQ или Interrupt Attach EventQ, передавая номер аппаратного прерывания и адрес функции в адресном пространстве потока, которая должна быть вызвана при возникновении прерывания. ОС QNX Neutrino позволяет с каждым номером аппаратного прерывания связывать множество обработчиков прерываний (ISR). Немаскированные прерывания могут обрабатываться во время выполнения уже запущенных обработчиков прерываний.

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

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

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

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

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

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

Таким образом устанавливается период (т. н. задержка обработки прерывания) между возникновением прерывания и выполнением первой инструкции обработчика прерываний, а также период (т. н. задержка планирования) между последней инструкцией обработчика прерываний и первой инструкцией потока, приведенного обработчиком прерываний в состояние готовности.

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

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

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

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

Следует отметить, что вызов функции InterruptAttachEventQ не приводит к запуску обработчика прерываний. Вместо этого по каждому прерыванию генерируется заданное пользователем событие. Как правило, это событие приводит к планированию ожидающего потока, чтобы он мог выполнить основную работу. Прерывание автоматически маскируется после генерации события и должно в нужный момент явно демаскироваться потоком, обслуживающим устройство.

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

Пользовательские процессы и потоки могут "перехватывать" не только аппаратные прерывания, но и различные "события" внутри микроядра. Когда происходит какое-либо из этих событий, ядро может вызвать указанную внешнюю функцию (upcall) в пользовательском потоке для обработки данного события. Например, при каждом вызове потока idle пользовательский поток может указать ядру сделать внешний вызов для реализации специальных режимов энергосбережения оборудования.



© 2024 beasthackerz.ru - Браузеры. Аудио. Жесткий диск. Программы. Локальная сеть. Windows