как обрабатывается прерывание в linux?

<p>я просто знаю, что <code>interrupt</code> это <code>hardware signal assertion</code> вызвано в выводе процессора. но я хотел бы знать, как ос linux справляется с этим.<br> что все происходит, когда происходит прерывание?</p>

<p>вот высокоуровневое представление низкоуровневой обработки. я описываю простую типичную архитектуру, реальные архитектуры могут быть более сложными или отличаться способами, которые не имеют значения на этом уровне детализации.</p><p>когда происходит <a href="http://en.wikipedia.org/wiki/interrupt">прерывание</a> , процессор проверяет, маскируются ли прерывания. если они есть, ничего не происходит, пока они не будут разоблачены. когда прерывания становятся не маскированными, и если есть какие-либо ожидающие прерывания, процессор выбирает одно.</p><p>затем процессор выполняет прерывание путем ветвления по определенному адресу в памяти. код по этому адресу называется <a href="http://en.wikipedia.org/wiki/interrupt\_handler">обработчик прерываний</a> . когда процессор там разветвляется, он маскирует прерывания (поэтому обработчик прерываний имеет исключительный контроль) и сохраняет содержимое некоторых регистров в определенном месте (обычно в других регистрах).</p><p>обработчик прерываний делает то, что должен, обычно посредством связи с периферийным устройством, которое инициировало прерывание для отправки или получения данных. если прерывание было вызвано таймером, обработчик может запустить планировщик ос, чтобы переключиться на другой поток. когда обработчик заканчивает выполнение, он выполняет специальную инструкцию возврата из прерывания, которая восстанавливает сохраненные регистры и снимает маскировку прерываний.</p><p>обработчик прерываний должен работать быстро, потому что он предотвращает запуск любого другого прерывания. в ядре linux обработка прерываний делится на две части:</p><ul> <li>"верхняя половина" - это обработчик прерываний. он выполняет необходимый минимум, обычно связывается с оборудованием и устанавливает флаг где-то в памяти ядра.</li> <li>"нижняя половина" выполняет любую другую необходимую обработку, например копирование данных в память процесса, обновление структур данных ядра и т.д. это может занять некоторое время и даже заблокировать ожидание какой-либо другой части системы, поскольку она работает с включенными прерываниями.</li> </ul><p>как обычно в этой теме, для получения дополнительной информации читайте <a href="http://lwn.net/images/pdf/ldd3/">драйверы устройств linux</a> ; <a href="http://lwn.net/images/pdf/ldd3/ch10.pdf">глава 1</a> о прерываниях.</p>

<p><sub>жиль уже <a href="https://unix.stackexchange.com/questions/5788/how-is-an-interrupt-handled-in-linux/5816#5816">описано</a> общий случай прерывания, следующее относится конкретно к linux 2.6 на архитектуре intel (часть этого также основана на спецификациях intel).</sub></p><p>прерывание - это событие, которое изменяет последовательность команд, выполняемых процессором.<br> существует два вида прерываний:</p><ul> <li><strong> синхронное прерывание (исключение) </strong>, создаваемое процессором во время обработки инструкций</li> <li><strong> асинхронное прерывание (interrupt) </strong>, выданное другими аппаратными устройствами</li> </ul><hr><p>исключения вызваны ошибками программирования (например, = <em> ошибка деления</em>, <em> ошибка страницы</em>, <em> переполнение</em>), которые должны обрабатываться ядром , он посылает сигнал программе и пытается восстановиться после ошибки.</p><p>следующие два исключения классифицируются:</p><ul> <li><strong> обнаруженное процессором исключение </strong>, сгенерированное цп при обнаружении аномального состояния; разделены на три группы: <em> неисправности</em> обычно можно исправить, <em> ловушки</em> сообщить о выполнении, <em> прерывает</em> серьезные ошибки.</li> <li><strong> запрограммированное исключение </strong>, запрошенное программистом, обрабатывается как ловушка.</li> </ul><hr><p>прерывания могут выдаваться устройствами ввода-вывода (клавиатура, сетевой адаптер, ...), интервальными таймерами и (в многопроцессорных системах) другими процессорами. когда происходит прерывание, цпу должен остановить свою текущую инструкцию и выполнить вновь прибывшее прерывание. он должен сохранить старое состояние прерванного процесса, чтобы (возможно) возобновить его после обработки прерывания.</p><p>обработка прерываний является деликатной задачей:</p><ul> <li>прерывания могут произойти в любое время, ядро пытается убрать его с дороги как можно скорее.</li> <li>прерывание может быть прервано другим прерыванием</li> <li>в ядре есть области, которые вообще не должны прерываться</li> </ul><p>определены два разных уровня прерывания:</p><ul> <li><strong> маскируемые прерывания </strong>, выдаваемые устройствами ввода/вывода; может быть в двух состояниях, в маске или без маски. только немаскированные прерывания обрабатываются.</li> <li><strong> немаскируемые прерывания </strong>; критические неисправности (например, аппаратный сбой); всегда обрабатывается процессором.</li> </ul><p>каждое аппаратное устройство имеет свою собственную линию запроса прерывания (irq). irq нумеруются начиная с 0. все линии irq подключены к программируемому контроллеру прерываний (pic). pic прослушивает irq и назначает их цпу. также возможно отключить конкретную линию irq.<br> современные многопроцессорные системы linux обычно включают в себя более новый advanced pic (apic), который равномерно распределяет запросы irq между процессорами.</p><p>промежуточным шагом между прерыванием или исключением и его обработкой является таблица дескрипторов прерываний (idt). эта таблица связывает каждый вектор прерывания или исключения (число) с указанным обработчиком (например, <em> divide error</em> обрабатывается функцией <code>divide\_error()</code>).</p><p>благодаря idt ядро точно знает, как обрабатывать возникшие прерывания или исключения.</p><hr><p>итак, что же делает ядро при возникновении прерывания?</p><ul> <li>процессор проверяет после каждой инструкции, есть ли irq от (a) pic</li> <li>если это так, консультируется с idt для сопоставления полученного вектора с функцией</li> <li>проверяет, было ли прерывание выдано авторизованным источником</li> <li>сохраняет регистры прерванного процесса</li> <li>вызовите соответствующую функцию для обработки прерывания</li> <li>загрузите недавно сохраненные регистры прерванного процесса и попытайтесь возобновить его</li> </ul>

<p>в первую очередь, участниками обработки прерываний являются периферийные аппаратные устройства, контроллер прерываний, процессор, ядро операционной системы и драйверы. периферийные устройства отвечают за генерацию прерываний. они утверждают строки запроса прерывания, когда хотят внимания от ядра операционной системы. эти сигналы мультиплексируются контроллером прерываний, который отвечает за сбор сигналов прерываний. он также отвечает за определение порядка, в котором сигналы прерывания будут передаваться в cpu. контроллер прерываний может временно отключить определенную строку запроса прерывания (irql) и снова включить ее (маскировка irql). контроллер прерываний передает собранные запросы на прерывание цп последовательно. cpu после завершения выполнения каждой команды cpu проверяет, есть ли ожидающие запросы прерывания от контроллера прерываний. если цпу обнаруживает, что имеется ожидающий запрос и флаг включения прерывания установлен во внутреннем регистре управления цп, то цпу начинает обработку прерываний. как вы можете видеть, манипулируя флагом прерывания в цп и связываясь с контроллером прерываний, ядро linux может контролировать принятие прерывания. например, linux может отключить прием прерываний от конкретного устройства или вообще запретить прием прерываний.</p><p>что происходит, когда процессор получает запрос на прерывание? во-первых, cpu автоматически отключает прерывания путем сброса флага прерываний. они будут включены после завершения обработки прерывания. в то же время процессор выполняет минимальный объем работы, необходимый для переключения процессора из пользовательского режима в режим ядра таким образом, чтобы он мог возобновить выполнение прерванного кода. cpu консультируется со специальными структурами управления cpu, заполненными ядром linux, чтобы найти адрес кода, на который будет передано управление. этот адрес является адресом первой инструкции обработчика прерываний, которая является частью ядра linux.</p><p>в качестве первого шага обработки прерывания ядро идентифицирует вектор полученного прерывания, чтобы определить, какое событие произошло в системе. вектор прерывания определяет, какие действия предпримет linux. в качестве второго шага linux сохраняет остальные регистры процессора (которые не были сохранены процессором автоматически) и которые потенциально могут использоваться прерванной программой. это очень важное действие, поскольку оно позволяет linux прозрачно обрабатывать прерывания в отношении прерванной программы. в качестве третьего шага, linux выполняет переключение в режим ядра, устанавливая среду ядра и устанавливая состояние процессора, необходимое для этого. и, наконец, вызывается вектор-зависимый обработчик прерываний. (вы можете посмотреть макрос build\_interrupt3 в arch\x86\kernel\entry\_32.s, чтобы получить дополнительную информацию для примера, связанного с архитектурой x86). в случае периферийных устройств это процедура do\_irq (). (загляните в arch\x86\kernel\irq.c)</p><p>зависимый от вектора обработчик прерываний обычно оборачивается вызовами irq\_enter () и irq\_exit (). область кода, заключенная в паре этих функций, является атомарной по отношению к любым другим таким областям, а также атомарной по отношению к парам cli/sti. irq\_enter () и irq\_exit () также собирают некоторую статистику, связанную с обработкой прерываний. наконец, ядро просматривает таблицу vector\_irq, чтобы найти номер irq, назначенный вектору полученного прерывания, и вызвать handle\_irq () (из arch\x86\kernel\irq\_32.c).</p><p>на этом общая часть обработки прерываний в linux заканчивается, потому что ядро рассматривает зависимую от устройства подпрограмму обработчика прерываний, установленную драйвером устройства, как часть дескриптора irq и вызывает ее. если такой обработчик не был установлен драйвером, ядро просто подтверждает прерывание на контроллере прерываний и переходит к выходу из общего обработчика прерываний.</p><p>после окончания обработки прерывания ядро восстанавливает состояние программы, которая была прервана ранее, и возобновляет выполнение этой программы.</p>

<p>с точки зрения теории, почти все было объяснено. но если вы ищете объяснение по структуре кода обработки прерываний ядра, вам следует перейти по следующей ссылке: <a href="http://linuxburps.blogspot.in/2013/10/linux-interrupt-handling.html">обход кода внутри обработки прерываний ядра</a> </p><p>и если вы все еще изучаете теорию о прерываниях и обработчиках прерываний, то я рекомендую прочитать это: <a href="http://linuxburps.blogspot.in/2013/09/linux-kernel-interrupts-and-handlers.html">понимание прерываний и обработчиков прерываний</a> </p>