Главная » Ядро Linux » Реализациясистемыобработкипрерываний

0

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

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

Аппаратура

Генерация запроса на прерывание

Функция

handle_IRQ_event()

Да

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

Процессор прерывает работу ядра

Есть ли обработчик для данной линии прерывания?

Нет

Выполнить все обработчики данной линии прерывания

Функция

do_IRQ()

\

Функция

Возвратится

к выполнению

ret_from_int()

прерванного

кода ядра

Процессор

Рис.   6.1.  Прохождение запроса на  прерывание в  аппаратном обеспечении и  в ядре

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

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

Функция  do_IRQ()  определена следующим образом.

unsigned int do_IRQ(struct pt_regs regs)

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

int irq = regs.orig_eax & 0xff;

После вычисления значения номера линии прерывания, функция do_IRQ()  отправляет уведомление о  получении прерывания и запрещает доставку прерываний с данной линии. Для обычных машин платформы PC, эти действия выполняются с помощью  функции  mask_and_ack_8295A () , которую вызывает функция do_IRQ () . Далее функция do_IRQ ()  выполняет проверку, что для данной линии прерывания зарегистрирован правильный  обработчик прерывания,  что этот обработчик разрешен и что он не выполняется в данный момент. Если все эти условия выполнены, то вызывается функция  handle_IRQ_event () , которая выполняет установленные для данной линии обработчики прерывания. Для аппаратной платформы х86  функция handle_IRQ_event ()  имеет следующий вид.

int handle_IRQ_event (unsigned int irq, struct pt_regs *regs, struct irqaction *action)

{

int status = 1;

if (!(action->flags & SA_INTERRUPT))

local_irq_enable ();

do {

status != action->flags;

action->chandler (irq, action->dev_id, regs);

action = action->next;

} while (action);

if (status & SA_SAMPLE_RANDOM)

add_interrupt_randomness (irq);

local_irq_disable();

return status;

}

Так как процессор запретил прерывания,  они  снова разрешаются, если не указан флаг SA_INTERRUPT  при регистрации обработчика. Вспомним, что флаг SA_INTERRUPT указывает, что обработчик должен выполняться при всех запрещенных прерываниях.  Далее в  цикле вызываются все потенциальные обработчики прерываний. Если эта линия не является совместно используемой, то  цикл заканчивается после первой итерации. В  противном случае вызываются все обработчики. После этого вызывается функция  add_interrupt_randomnes s () , если при регистрации указан флаг SA_SAMPLE_RANDOM.  Данная функция использует временные  характеристики прерывания, чтобы сгенерировать значение энтропии для  генератора случайных чисел. В  приложении Б,  "Генератор случайных чисел  ядра",  приведена более подробная информация  о  генераторе случайных чисел ядра.

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

Функция  ret_from_int r () , так  же как  и код  входа, написана на языке  ассемблера.  Эта  функция проверяет, есть  ли  ожидающий запрос на  перепланирование  выполнения процессов (следует  вспомнить главу 4, "Планирование выполнения процессов", и  флаг  need_resched) .  Если  есть  запрос на  перепланирование и  ядро  должно передать управление  в  пространство пользователя (т.е.  прерывание прервало работу пользовательского процесса),  то  вызывается функция  schedul e () .  Если  возврат производится в пространство ядра  (т.е.  прерывание прервало работу  кода  ядра), то функция  schedul e ()   вызывается, только   если  значение  счетчика preempt_coun t равно  нулю  (в  противном случае  небезопасно производить вытеснение кода  ядра), После  возврата из  функции schedul e ()   или  если  нет  никакой ожидающей работы, восстанавливаются первоначальные значения  регистров процессора и  ядро  продолжает  работу  там, где  оно  было  прервано.

Для  платформы х86, подпрограммы, написанные на  языке  ассемблера, находятся в  файле   arch/i386/kernel/entry.S , а соответствующие функции  на  языке   С — в файле   arch/i386/kernel/irq.с .  Для  других   поддерживаемых  аппаратных  платформ  имеются аналогичные файлы.

Интерфейс /proc/interrupts

Файловая система procfs— это  виртуальная файловая  система,  которая существует только   в  памяти ядра  и  обычно монтируется на  каталог   /ргос .  Чтение или  запись файлов на  файловой  системе  procfs  приводит к  вызовам функций  ядра,  которые имитируют чтение  или  запись обычных файлов. Важный пример—  это  файл  /ргос / interrupts ,  который  содержит  статистику,  связанную  с  прерываниями в системе, Ниже  приведен пример вывода  из  этого  файла  на  однопроцессорном персональном компьютере.

CPU0

0:

3602371

XT-PIC

timer

1:

3048

XT-PIC

i8042

2:

0

XT-PIC

cascade

4:

2689466

XT-PIC

uhci-hed, ethO

5:

0

XT-PIC

EMU10K1

12: 85077

15: 24571

XT-PIC XT-PIC

uhei-hcd aic7xxx

NMI: 0

LOC: 3602236

ERR: 0

Первая колонка содержит названия линий прерывания. В показанной системе присутствуют линии прерываний с номерами 0-2, 4, 5, 12 и  15. Линии, для  которых не  инсталлирован обработчик, не  показываются. Вторая  колонка — это  количество запросов на прерывания с данным номером. В действительности такая  колонка является   отдельной для  каждого   процессора,  но  в данной машине только   один  процессор.

Как  легко  видеть,   обработчик прерываний  таймера  получил   3.602.371 2    запрос  на  прерывание, в то время  как  обработчик прерываний звукового  адаптера (EMU10K1) не получил  ни одного  прерывания (это  говорит  о том,  что он не использовался  с того  момента, как  машина была  загружена). Третья  колонка—  это  контроллер  прерываний,  который обслуживает данное  прерывание. Значение XT-PIC соответствует   программируемому контроллеру прерываний  PC  (PC  programmable interrupt controller). Для  систем  с устройством I/О  APIC  для  большинства прерываний  в качестве  контроллера прерываний будет указано  значение IO-APIC-level или  IO-APIC-edge. И наконец, последняя колонка—  это устройство, которое  связано  с прерыванием. Имя  устройства  указывается в параметре  dev_name  при  вызове функции request_ir q () , как обсуждалось  ранее.  Если  прерывание используется совместно, как  в случае  прерывания номер  4 в этом  примере, то перечисляются все устройства, зарегистрированные на данной  линии  прерывания.

Для любопытствующих, код,  связанный с файловой системой procfs,  находится  в файле  fs/proc.  Функция, которая  обеспечивает работу интерфейса /proc/interrupts , называется show_interrupt s ()  и является зависимой от аппаратной платформы.

Источник: Лав,  Роберт. Разработка ядра  Linux, 2-е  издание. : Пер.  с англ.  — М.  : ООО  «И.Д.  Вильяме» 2006. — 448 с. : ил. — Парал. тит. англ.

По теме:

  • Комментарии