Книга: Разработка ядра Linux
Реализация системы обработки прерываний
Реализация системы обработки прерываний
Возможно, не вызовет удивления, что реализация системы обработки прерываний в операционной системе Linux очень сильно зависит от аппаратной платформы. Она зависит от типа процессора, типа контроллера прерываний, особенностей аппаратной платформы и устройства самой вычислительной машины.
На рис. 6.1 показана диаграмма пути, который проходит запрос на прерывание в аппаратном обеспечении и в ядре.
Рис. 6.1. Прохождение запроса на прерывание в аппаратном обеспечении и в ядре
Устройство инициирует прерывание путем отправки электрического сигнала контроллеру прерывания по аппаратной шине. Если соответствующая линия запроса на прерывание не запрещена (линия может быть в данный момент времени замаскирована), то контроллер прерываний отправляет прерывание процессору. Для большинства аппаратных платформ это осуществляется путем подачи сигнала на специальный вывод процессора. Если прерывания не запрещены в процессоре (может случиться, что они запрещены), то процессор немедленно прекращает ту работу, которую он выполнял, запрещает систему прерываний, осуществляет переход на специальный предопределенный адрес памяти и начинает выполнять программный код, который находится по этому адресу. Этот предопределенный адрес памяти устанавливается ядром и является точкой входа в обработчики прерываний.
Прохождение прерывания в ядре начинается из жестко определенной точки входа, так же как и в случае системных вызовов. Для каждой линии прерывания существует своя уникальная точка, куда переходит процессор. Именно этим способом ядро получает информацию о номере IRQ приходящего прерывания. В точке входа сначала в стеке ядра сохраняется значение номера прерывания и значения всех регистров процессора (которые соответствуют прерванному заданию). После этого ядро вызывает функцию do_IRQ()
. Далее, начиная с этого момента, почти весь код обработки прерываний написан на языке программирования С, хотя несмотря на это код все же остается зависимым от аппаратной платформы.
Функция do_IRQ()
определена следующим образом.
unsigned int do_IRQ(struct pt_regs regs);
Так как соглашение о вызовах функций в языке С предусматривает сохранение аргументов функций в вершине стека, то структура pt_regs
содержит первоначальные значения всех регистров процессора, которые были сохранены ассемблерной подпрограммой в точке входа. Так как значение номера прерывания также сохраняется, то функция do_IRQ()
может это значение восстановить. Для аппаратной платформы x86 код будет следующим.
int irq = regs.orig_eax & 0xff;
После вычисления значения номера линии прерывания, функция do_IRQ()
отправляет уведомление о получении прерывания и запрещает доставку прерываний с данной линии. Для обычных машин платформы PC, эти действия выполняются с помощью функции mask_and_ack_8295A()
, которую вызывает функция do_IRQ()
. Далее функция do_IRQ()
выполняет проверку, что для данной линии прерывания зарегистрирован правильный обработчик прерывания, что этот обработчик разрешен и что он не выполняется в данный момент. Если все эти условия выполнены, то вызывается функция handle_IRQ_event()
, которая выполняет установленные для данной линии обработчики прерывания. Для аппаратной платформы x86 функция 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_randomness()
, если при регистрации указан флаг SA_SAMPLE_RANDOM
. Данная функция использует временные характеристики прерывания, чтобы сгенерировать значение энтропии для генератора случайных чисел. В приложении Б, "Генератор случайных чисел ядра", приведена более подробная информация о генераторе случайных чисел ядра.
В конце прерывания снова запрещаются (для функции do_IRQ()
требуется, чтобы прерывания были запрещены). Функция do_IRQ()
производит очистку стека и возврат к первоначальной точке входа, откуда осуществляется переход к функции ret_from_intr()
.
Функция ret_from_intr()
, так же как и код входа, написана на языке ассемблера. Эта функция проверяет, есть ли ожидающий запрос на перепланирование выполнения процессов (следует вспомнить главу 4, "Планирование выполнения процессов", и флаг need_resched
). Если есть запрос на перепланирование и ядро должно передать управление в пространство пользователя (т.е. прерывание прервало работу пользовательского процесса), то вызывается функция schedule()
. Если возврат производится в пространство ядра (т.е. прерывание прервало работу кода ядра), то функция schedule()
вызывается, только если значение счетчика preempt_count
равно нулю (в противном случае небезопасно производить вытеснение кода ядра), После возврата из функции schedule()
или если нет никакой ожидающей работы, восстанавливаются первоначальные значения регистров процессора и ядро продолжает работу там, где оно было прервано.
Для платформы x86, подпрограммы, написанные на языке ассемблера, находятся в файле arch/i386/kernel/entry.S
, а соответствующие функции на языке С — в файле arch/i386/kernel/irq.с
. Для других поддерживаемых аппаратных платформ имеются аналогичные файлы.
Интерфейс /proc/interrupts
Файловая система procfs — это виртуальная файловая система, которая существует только в памяти ядра и обычно монтируется на каталог /proc
. Чтение или запись файлов на файловой системе procfs приводит к вызовам функций ядра, которые имитируют чтение или запись обычных файлов. Важный пример — это файл /proc/interrupts
, который содержит статистику, связанную с прерываниями в системе, Ниже приведен пример вывода из этого файла на однопроцессорном персональном компьютере.
CPU0
0: 3602371 XT-PIC timer
1: 3048 XT-PIC i8042
2: 0 XT-PIC cascade
4: 2689466 XT-PIC uhci-hcd, eth0
5: 0 XT-PIC EMU10K1
12: 85077 XT-PIC uhci-hcd
15: 24571 XT-PIC aic7xxx
NMI: 0
LOC: 3602236
ERR: 0
Первая колонка содержит названия линий прерывания. В показанной системе присутствуют линии прерываний с номерами 0–2, 4, 5, 12 и 15. Линии, для которых не инсталлирован обработчик, не показываются. Вторая колонка — это количество запросов на прерывания с данным номером. В действительности такая колонка является отдельной для каждого процессора, но в данной машине только один процессор.
Как легко видеть, обработчик прерываний таймера получил 3.602.371
[32] запрос на прерывание, в то время как обработчик прерываний звукового адаптера (EMU10K1
) не получил ни одного прерывания (это говорит о том, что он не использовался с того момента, как машина была загружена). Третья колонка— это контроллер прерываний, который обслуживает данное прерывание. Значение XT-PIC
соответствует программируемому контроллеру прерываний PC (PC programmable interrupt controller). Для систем с устройством I/О APIC для большинства прерываний в качестве контроллера прерываний будет указано значение IO-APIC-level
или IO-APIC-edge
. И наконец, последняя колонка — это устройство, которое связано с прерыванием. Имя устройства указывается в параметре dev_name
при вызове функции request_irq()
, как обсуждалось ранее. Если прерывание используется совместно, как в случае прерывания номер 4 в этом примере, то перечисляются все устройства, зарегистрированные на данной линии прерывания.
Для любопытствующих, код, связанный с файловой системой procfs
, находится в файле fs/proc
. Функция, которая обеспечивает работу интерфейса /proc/interrupts
, называется show_interrupts()
и является зависимой от аппаратной платформы.
- Обработчики прерываний
- Глава 6 Прерывания и обработка прерываний
- Написание обработчиков прерываний
- Уровни прерываний и уровни приоритета
- 9.4.1. Реализация графа в виде матрицы смежности
- Особенности системы защиты данных в InterBase
- 5.4 Команда trap: обработка прерываний
- Реализация языка SQL
- 1.2. Понятие информации. Общая характеристика процессов сбора, передачи, обработки и накопления информации
- Установка системы на уже подготовленный жесткий диск
- 1.3. Системы счисления
- 7.4. Модель системы автоматизированного проектирования защиты информации