Тема OS21асу. понятие прерывания Понятие прерывания возникло вместе с созданием ЭВМ. Тогда стала задача о совместной работе процессора и медленных внешних устройств. Хорошим примеров может служить клавиатура. Когда пользователь нажмет клавишу не известно. Это может случиться в любой момент, вот когда он нажимает клавишу и сообщается процессору что нужно бы обработать это дело и получить клавишу, которая нажата. Отсюда можно сделать вывод, что прерывания рождают внешние устройства. Но мы же с Вами использовали прерывание в программе. Конечно, кроме получения информации от устройства, этим устройствами нужно еще и управлять. Устройства медленные и помимо прочего еще нужно будет дождаться окончание выполнения операции. Это то же реализуется с помощью прерываний только вызываем их мы из программы. Итак, прерывания бывают двух типов: Программные, Аппаратные. Если не пользоваться прерываниями, то постоянно операционная система должна опрашивать устройства, нажата ли клавиша, хотите ли вывести данные на монитор и так далее. Намного проще оговорить некоторый механизм который и будет обращаться внимание операционной системы и процессора на необходимость проведения некоторых действий. Итак, давайте посмотрим на все это в динамике. Ваша программа что то считает. В этот момент нажимается клавиша. Программа должны быть прервана. И это будет сделано, управление будет передано специальному коду (процедура обработки прерывания) а потом Ваша программа будет выполняться дальше. То же самое когда мы вызываем прерывание для вывода символов на монитор (int 21h 04Ch) то сами генерируем прерывание. Зачем ? В этот момент может происходить считывание с дисковода или вывод других символов на экран. А тут мы не с того не с сего со своими символами. Так как прерывания могут наступать одновременно, то есть приоритет их обработки. Есть прерывание, которые выполняться в любом случае даже если идет обработка другого прерывания. Процедура обработки прерывания это программа. Вопрос в том только где она храниться. Базовая обработка прерывания храниться в BIOS и в самих микросхемах оборудования. Но использовать их довольно тяжело. Представьте, для того , что бы записать файл нужно завести двигатель дисковода, установить головку, дать команду перейти в тот сектор прочитать таблицу файлов, проверить что там нет файла и так далее так далее. Все эти задачи облегчает операционная система, которая предоставляет Вам прерывания более высоко уровня. Используя эти прерывания, Вы можете одним заходом создать файл, например. Различают прерывания по номерам: 21h - прерывание DOS; 13h - прерывание BIOS; вызываете прерывание (INT) Вы указываете еще и номер (21h) то есть, кто будет выполнять это действие. Прерывание также является важным понятием в системном программировании, поскольку оно тесно связано с состоянием процесса и переключением процессов. Любая система управления процессами так или иначе использует прерывания. ПРЕРЫВАНИЕ - - асинхронная прозрачная процедура (функция), вызываемая по внешнему событию. Прежде всего прерывание является ПРОЦЕДУРОЙ, то есть некоторым алгоритмом, после выполнения которого происходит возврат к той части основной программы (точнее к тому состоянию процесса), в котором она была вызвана. Понятие АСИНХРОННАЯ процедура означает, что она вызывается не как обычная процедура (функция) в языке программирования, то есть в основной программе (прерываемом процессе) отсутствует вызов этой процедуры в явном виде. Ее вызов осуществляется независимо от хода выполнения основной программы. Условием вызова ее является наступление некоторого внешнего по отношению к процессу события (например, поступление входных данных от внешнего устройства). Прерывающая процедура "вклинивается" между любыми последовательными шагами процесса, поэтому она должна обладать ПРОЗРАЧНОСТЬЮ , то есть ее выполнение не должно влиять на прерываемый процесс. Можно сформулировать понятие прерывания и в терминологии процессов. ПРЕРЫВАНИЕ - - приоритетный процесс, выполняемый по внешнему событию. В этом определении учитывается и асинхронный характер процессов, и их прозрачность по отношению друг к другу. Приоритетность обозначает, что основной (прерываемый) процесс не может выполняться до завершения процесса обработки прерывания. Понятие прерывания возникло вместе с созданием ЭВМ. Тогда стала задача о совместной работе процессора и медленных внешних устройств. Хорошим примером может служить клавиатура. Когда пользователь нажмет клавишу не известно. Это может случиться в любой момент, вот когда он нажимает клавишу и сообщается процессору что нужно бы обработать это дело и получить код клавиши, которая была нажата. Отсюда можно сделать вывод, что прерывания рождают внешние устройства. Конечно, кроме получения информации от устройства, этим устройствами нужно еще и управлять. Устройства медленные и помимо прочего еще нужно будет дождаться окончание выполнения операции. Это то же реализуется с помощью прерываний. Итак, прерывания бывают двух типов: Программные, Аппаратные. Если не пользоваться прерываниями, то постоянно операционная система должна опрашивать устройства, нажата ли клавиша, хотите ли вывести данные на монитор и так далее. Намного проще оговорить некоторый механизм который и будет обращаться внимание операционной системы и процессора на необходимость проведения некоторых действий. Итак, давайте посмотрим на все это в динамике. Ваша программа что то считает. В этот момент нажимается клавиша. Программа должны быть приостановлена. И это будет сделано, управление будет передано специальному коду (процедура обработки прерывания) а потом Ваша программа будет выполняться дальше. То же самое когда мы вызываем прерывание для вывода символов на монитор (int 21h 04Ch) то сами генерируем прерывание. Зачем ? В этот момент может происходить считывание с дисковода или вывод других символов на экран. А тут мы не с того не с сего со своими символами. Так как прерывания могут наступать одновременно, то есть приоритет их обработки. Есть прерывание, которые выполняться в любом случае даже если идет обработка другого прерывания. Процедура обработки прерывания это программа. Вопрос в том только где она храниться. Базовая обработка прерывания храниться в BIOS и в самих микросхемах оборудования. Но использовать их довольно тяжело. Представьте, для того , что бы записать файл нужно завести двигатель дисковода, установить головку, дать команду перейти в тот сектор прочитать таблицу файлов, проверить что там нет файла и так далее так далее. Все эти задачи облегчает операционная система, которая предоставляет Вам прерывания более высоко уровня. Используя эти прерывания, Вы можете одним заходом создать файл, например. Различают прерывания по номерам: 21h - прерывание DOS; 13h - прерывание BIOS; вызываете прерывание (INT) Вы указываете еще и номер (21h) то есть, кто будет выполнять это действие. Прерывание также является важным понятием в системном программировании, поскольку оно тесно связано с состоянием процесса и переключением процессов. Любая система управления процессами так или иначе использует прерывания. ПРЕРЫВАНИЕ - - асинхронная прозрачная процедура (функция), вызываемая по внешнему событию. Прежде всего прерывание является ПРОЦЕДУРОЙ, то есть некоторым алгоритмом, после выполнения которого происходит возврат к той части основной программы (точнее к тому состоянию процесса), в котором она была вызвана. Понятие АСИНХРОННАЯ процедура означает, что она вызывается не как обычная процедура (функция) в языке программирования, то есть в основной программе (прерываемом процессе) отсутствует вызов этой процедуры в явном виде. Ее вызов осуществляется независимо от хода выполнения основной программы. Условием вызова ее является наступление некоторого внешнего по отношению к процессу события (например, поступление входных данных от внешнего устройства). Прерывающая процедура "вклинивается" между любыми последовательными шагами процесса, поэтому она должна обладать ПРОЗРАЧНОСТЬЮ , то есть ее выполнение не должно влиять на прерываемый процесс. Можно сформулировать понятие прерывания и в терминологии процессов. ПРЕРЫВАНИЕ - - приоритетный процесс, выполняемый по внешнему событию. В этом определении учитывается и асинхронный характер процессов, и их прозрачность по отношению друг к другу. Приоритетность обозначает, что основной (прерываемый) процесс не может выполняться до завершения процесса обработки прерывания. Понятие прерывания. http://ermak.cs.nstu.ru/cprog/book_old/bk62-01.htm Привилегированный режим. Классификация прерываний Структурная схема подсистемы прерываний. Контроллер прерываний i8259А. Обработка программного прерывания Взаимодействие прерывающего процесса и основной программы Ввод-вывод данных по прерыванию; Вложенные прерывания Отложенное прерывание ( Fork-обработка) ОРГАНИЗАЦИЯ ПРЕРЫВАНИЙ В ЭВМ Характеристики систем прерывания Примеры систем прерываний Векторное прерывание, Векторы прерываний Динамический выбор уровня прерываний. Маскирование сигналов прерывания Альтернатива опросу, применяемая практически во всех современных процессорах, называется прерываниями (interrupt), и состоит в значительном усложнении логики обработки команд процессором. Процессор имеет один или несколько входов, называемых сигналами или линиями запроса прерывания. При появлении сигнала на одном из входов, Процессор дожидается завершения исполнения текущей команды и, вместо перехода к исполнению следующей команды, инициирует обработку прерывания. Обработка состоит в сохранении счетчика команд и, возможно, некоторм других регистров (практически всегда сохраняется также слово состояния процессора. В процессорах с виртуальной памятью иногда сохраняются и регистры диспетчера памяти), и в передаче управления на адрес, определяемый типом прерывания. По этому адресу размещается программа, обработчик прерывания, которая и осуществляет реакцию на соответствующее прерыванию событие. Перед завершением обработчик восстанавливает регистры, и исполнение основной программы возобновляется с той точки, где она была прервана. Как правило, адреса программ, соответствующих различным прерываниям собраны в таблицу, называемую таблицей векторов прерываний, размещаемую в определенном месте адресного пространства. У микроконтроллеров каждому возможному сигналу прерывания обычно соответствует свой вектор. Процессоры общего назначения часто используют более сложную схему, в которой устройство, запрашивающее прерывание, передает процессору номер прерывания или сразу адрес обработчика. Прерывания в PDP-11 Для примера рассмотрим организацию прерываний в машинах семейства PDP-11. Процессоры данной архитектуры сейчас практически не используются в машинах общего назначения, но производятся и применяются в качестве микроконтроллеров. Ряд архитектурных решений PDP-11, разработанной в начале 70-х годов, не потерял актуальности и поныне. В частности, подход к реализации прерываний считается классическим [Кейслер 1986]. Процессоры семейства PDP-11 различают 128 типов прерываний и исключений (чем прерывание отличается от исключения, см. далее). Каждому типу соответствует процедура-обработчик. Адреса точек входа всех процедур собраны в таблицу векторов прерываний. Эта таблица занимает 256 слов физической памяти, начиная с нулевого адреса. Каждый элемент таблицы (вектор) содержит адрес обработчика и новое слово состояния процессора. Позже будет объяснено, для чего это сделано. Процессор узнает о возникновении прерывания, если на один из входов запроса подан сигнал. Обычно этот сигнал генерируется одним из внешних устройств. Например, прерывание может сигнализировать о завершении операции перемещения головки дисковода или передачи данных в режиме ПДП. Каждый вход соответствует определенному уровню приоритета. PDP-11 имеет восемь уровней приоритета прерывания. Прерывание происходит только когда уровень приоритета процессора ниже приоритета запрашиваемого прерывания. Если у процессора установлен приоритет, равный 7, внешние прерывания запрещены. Приоритет процессора задается его словом состояния. Получив запрос, процессор завершает исполнение текущей команды и выставляет сигнал готовности к прерыванию. После этого внешнее устройство выставляет на шине данных номер вектора прерывания. Процессор считывает номер и вызывает соответствующую процедуру из таблицы. При этом вызов обработчика прерывания отличается от вызова обычной процедуры: при обычном вызове в стеке сохраняется только адрес команды, на которую следует возвратить управление. При прерывании же в стеке сохраняются два значения: адреса команды и слова состояния процессора. Новое слово состояния берется из таблицы векторов. При этом приоритет процессора автоматически устанавливается равным тому значению, которое разработчик программы обработки считает правильным. Обратите внимание: не равным приоритету обрабатываемого прерывания, а тому, которое требует разработчик. При завершении процедуры обработки вызывается команда RTI (ReTurn from Interrupt- возврат из прерывания). Эта команда выталкивает из стека адрес прерванной команды и старое слово состояния, тем самым и продолжая исполнение прерванной программы, и восстанавливая приоритет процессора. [Кичев/Некрасов 1988]. Для сравнения: в процессорах семейства 180x86 вектор прерывания содержит только адрес программы-обработчика, а приоритет процессора задается не словом состояния процессора, а регистром внешнего устройства- контроллера прерываний. Контроллер прерываний обычно устанавливает приоритет, равным приоритету прерывания, обрабатываемого в данный момент. Чтобы повысить или понизить этот уровень, обработчик прерывания должен программировать контроллер. Перед завершением обработчика необходимо вернуть контроллер прерываний в исходное состояние, выполнив над ним серию магических команд - эпилог прерывания. Обработка прерываний в системах с виртуальной памятью несколько усложняется: ведь кроме адреса обработчика нам надо еще задать адресное пространство, в котором этот адрес определен. В моделях PDP-11, имеющих диспетчер памяти, эта проблема решается просто: для процессора в каждый момент времени заданы два адресных пространства: пользовательское и системное. Все прерывания обрабатываются в системном адресном пространстве. Для реализации этого процессор имеет два набора регистров диспетчера памяти. Их наличие, с одной стороны, снимает с обработчика прерывания обязанность переключать адресные пространства, а с другой позволяет ядру при обработке системных вызовов обращаться к сегменту данных пользовательского процесса. В защищенном режиме процессоров 180x86 использован более гибкий механизм установки адресного пространства для обработчика. По существу, с каждым обработчиком может быть ассоциировано свое виртуальное адресное пространство. О способе, которым это достигается, лучше прочитать в литературе по соответствующим процессорам, например [Паппас/Марри 1993]. Прерывания лишены недостатков, которые мы указали и выше для обработки событий при помощи опроса: ожидая события, процессор может заниматься какой-либо другой полезной работой, а когда событие произойдет, он приступит к обработке, не дожидаясь полного завершения этой работы. Однако этот механизм имеет и собственные недостатки. В частности, обработка прерывания сопряжена с гораздо большими накладными расходами чем проверка флага и условный переход в режиме ожидания. У оптимизированных для обработки событий микроконтроллеров разница невелика или даже может быть в пользу механизма прерываний: приведенный в примере 6.1 цикл опроса занимает 5 циклов процессора, а обработчик прерывания у PIC вызывается в течение 3-4 циклов ([www.microchip.com PICMicro] утверждает, что средняя задержка прерывания составляет 3,75 цикла). Таким образом, среднее время реакции на событие в режиме опроса составляет 2,5 цикла (по среднему времени опрос в выигрыше), а максимальное -5 циклов (в данном случае преимущество на стороне прерываний). Однако у процессоров общего назначения, которые при обработке прерывания вынуждены сохранять несколько регистров и осуществлять относительно сложный диалог с вызвавшим прерывание устройством, задержка между установкой сигнала прерывания и исполнением первой команды его обработчика - этот интервал и называется задержкой прерывания (interrupt latency) - составляет десятки тактов. Современные суперскалярные процессоры при обработке прерываний вынуждены сбрасывать очередь предварительной выборки команд и, по крайней мере, часть кэшей команд и данных, поэтому у .них накладные расходы еще больше. Задержка прерывания у современных реализаций архитектуры х86 лишь ненамного лучше, чем у 80386 хотя по скорости исполнения последовательных программ современные процессоры превосходят 80386 на несколько порядков. Поэтому младшие модели процессоров с архитектурой х86, 8086 и даже 8085, хотя и не находят применения в персональных компьютерах, но продолжают выпускаться для использования во встраиваемых приложениях или в качестве периферийных процессоров. Так, например, "марсоход" Sojoumer использовал в качестве управляющего процессора 8085 на сапфировой подложке (для обеспечения радиационной устойчивости). Это же обстоятельство является дополнительным доводом в пользу включения в систему канальных процессоров, в данном случае с целью освобождения центрального процессора не от опроса, а от обработки прерываний. Разработчики больших компьютеров часто реализовывали канальные процессоры старших моделей на основе центральных процессоров младших моделей той же серии. Исключения Многие процессоры используют механизм, родственный прерываниям, для обработки не только внешних, но и внутренних событий: мы с вами уже сталкивались с исключительными ситуациями (exception) отсутствия страницы и ошибки доступа в процессорах с виртуальной памятью, а также некоторыми другими - ошибкой шины при доступе к невыровненным словам, заполнению и очистке регистрового окна у SPARC и т. д. Большинство современных процессоров предоставляют исключения при неизвестном коде операции, делении на ноль, арифметическом переполнении или, например, выходе значения операнда за допустимый диапазон в таких операциях, как вычисление логарифма, квадратного корня или арксинуса. Исключительные ситуации обрабатываются аналогично внешним прерываниям: исполнение программы останавливается, и управление передается на процедуру-обработчик, адрес которой определяется природой исключения. Отличие состоит в том, что прерывания обрабатываются после завершения текущей команды, а возврат из обработчика приводит к исполнению команды, следующей за прерванной. Исключение же приводит к прекращению исполнения текущей команды (если в процессе исполнения команды мы уже успели создать какие-то побочные эффекты, они отменяются), и сохраненный счетчик команд указывает на прерванную инструкцию. Возврат из обработчика, таким образом, приводит к попытке повторного исполнения операции, вызвавшей исключение. Благодаря этому, например, обработчик страничного отказа может подкачать с диска содержимое страницы, вызвавшей отказ, перенастроить таблицу дескрипторов и повторно исполнить операцию, которая породила отказ. Обработчик исключения по неопределенному коду операции может использоваться для эмуляции расширений системы команд. Например, при наличии арифметического сопроцессора операции с плавающей точкой исполняются им, а при отсутствии - пакетом эмулирующих подпрограмм. Благодаря этому может обеспечиваться полная бинарная совместимость между старшими (имеющими сопроцессор) и младшими (не имеющими его) моделями одного семейства компьютеров. Исключения, возникающие при исполнении привилегированных команд в пользовательском режиме, могут использоваться системой виртуальных машин. Работающее в виртуальной машине ядро ОС считает, что исполняется в системном режиме. На самом же деле оно работает в пользовательском режиме, а привилегированные команды (переключения режима процессора, настройка диспетчера памяти, команды ввода/вывода) приводят к вызову СВМ. При грамотной реализации обработчиков таких исключений их обработка Произойдет полностью прозрачно для породившей эти исключения программы. Конечно, "подкачка" страницы с диска или программная эмуляция плавающего умножения займет гораздо больше времени, чем простое обращение к памяти или аппаратно реализованное умножение, но, наверное, Потребитель вычислительной системы знал, что делал, когда устанавливал недостаточное количество памяти или приобретал машину без сопроцессора. Многие другие исключения, такие, как деление на ноль, обычно бессмЬ1сленно обрабатывать повторной попыткой деления на какое-то другое число В этом случае целесообразно возвратить управление не на команду, вызвав шую исключение, а в какую-то другую точку. Вопрос, впрочем, в том, куда именно следует возвращаться. Понятно, что код, который может восстано виться в случае деления на ноль, сильно зависит от контекста, в котором произошла ошибка (пример 6.2). Пример 6.2. Обработка исключения Floating underflow (антипереполние при операциях с плавающей точкой) #tinclude static jmp_buf fpe_retry; void fpe_handler (int sig) { 4> __fpreset () ; longjmp (fpe__retry, -1) ; int compare_pgms (Image * imgO, Image * img1) { int xsize=256, ysize=256; int i, j , pO, pi, pd; double avg, avgsq, scale, smooth; scale= (double) xsize* (double) ysize; avg = 0.0; avgsq = 0.0; /* Подавить возможные антипереполнения */ signal (SIGFPE, fpe_handler) ; for(i=0; ipicture [i*xsize] -imgl->picture [i*xsize] ) ; for(j=0; jpicture [ j+i*xsize] ; pl=imgl->picture [ j+i*xsize] ; pd=(pO-pl) ; if (setjmp (fpe_retry) == 0) { smooth = smooth* (1 . 0-SMOOTH_FACTOR) + (double) pd*SMOOTH_FACTOR; vq += smooth; avgsq += smooth*smooth; eise smooth=0 . 0 ; if (Setjmp(fpe_retry) == 0) Aspersion = avgsq/scale-avg*avg/ (scale*scale) ; else dispersion = 0.0; signal (SIGFPE, SIGJDFL) ; } При программировании на ассемблере это может быть реализовано простой подменой адреса возврата в стеке. Многие языки высокого уровня (ЯВУ) реализуют те или иные средства для обработки исключений. Уровень этих средств различен в разных языках, начиная от пары функций setjmp и longjmp в С [Керниган-Ритчи 2000] (пример 6.3) и заканчивая операторами try/catch и throw C++ [Страуструп 1999] и Java [Вебер 1999]. Пример 6.3. Исходный текст функций set jmp/ longjmp. / setjmp. s (emx+gcc) - Copyright (c) 1990-1996 by Eberhard Mattes # include .globl _setjmp, _longjmp .text ALIGN # define J_EBX 0 # define J_ESI 4 # define J_EDI 8 #define J_ESP 12 #define J_EBP 16 # define J_EIP 20 # define J_XCP 24 / Слова со смещениями 28.. 44 зарезервированы / int setjmp (jmp_buf here) _setjmp: PROFILE__NOFRAME movl l*4(%esp), %edx /* here */ raovl %ebx, J_EBX(%edx) movl %esi, J_ESI(%edx) movl ledi, J_EDI(%edx) movl %ebp, J_EBP(%edx) movl %esp, J_ESP(%edx) movl 0*4(%esp), %eax /* Адрес возврата */ movl %eax, J_EIP(%edx) cmpb $0, __osmode /* OS/2? */ je If /* No -> skip */ fs movl 0, leax /* handler Обработчик исключений */ movl %eax, J_XCP(%edx) 1: xorl %eax, leax EPILOGUE(setjmp) ALIGN / void longjmp (jmp_buf there, int n) _longjmp: PROFILE_NOFRAME cmpb $0, __osmode /* OS/2? */ je 2f /* No -> skip */ movl 1*4(%esp), %eax /* there */ pushl J_XCP(%eax) call ___unwind2 /* восстановить обработчики сигналов */ addl $4, %esp 2: movl l*4(%esp), ledx /* there */ movl 2*4(%esp), leax /* n */ testl %eax, leax jne 3f incl %eax 3: movl J_EBX(%edx), %ebx movl J_ESI(ledx), lesi raovl J_EDI(%edx), %edi movl J EBP(%edx), %ebp J_ESP(%edx) , J_EIP(%edx>, %edx %edx, 0*4(%espj /* адрес возврата */ EPILOGUE(longjmp) /* well, ... */ Исключения в ЯВУ часто позволяют избежать использования нелюбимого структурными программистами оператора goto. В объектно-ориентированных (ОО) языках этот механизм играет еще более важную роль: в большининстве таких языков - это единственный способ сообщить о неудаче при исполнении конструктора объекта. Важно подчеркнуть, впрочем, что исключения в смысле ЯВУ и аппаратные исключения процессора - разные вещи. В многозадачной ОС пользовательская программа не имеет непосредственного доступа к обработке прерываний и исключений. ОС предоставляет сервис, позволяющий программисту регистрировать обработчики для тех или иных событий, как соответствующих аппаратным исключениям, так и порождаемых самой операционной системой, но вызов таких обработчиков всегда осуществляется в два этапа: сначала исполняется обработчик, зарегистрированный ядром (пример 6.4), а он, если сочтет нужным и возможным, переключается в пользовательский контекст и вызывает обработчик, зарегистрированный пользователем. Среда исполнения ЯВУ, в свою очередь, может реализовать и свои обработчики между сервисом операционной системы и средствами, доступными программисту. Пример 6.4. Обработчик арифметических исключений в ядре Linux I /* * Iinux/arch/i386/traps.c * * Copyright (С) 1991, 1992 Linus Torvalds * * Поддержка Pentium III FXSR, SSE * Gareth Hughes , May 2000 */ void die(const char * str, struct pt_regs * regs, long err) I console_verbose(); spin_lock_irq(&die_lock); Printk("%s: %041x\n", str, err & Oxffff}; show_registers(regs); sPin_unlock_irq(&die_lock); do_exit (SIGSEGV) ; static inline void die_if_kernel (const char * str, struct pt_regs * regs long err) { if ( ! (regs->eflags & VM_MASK) && ! (3 & regs->xcs) ) die (str, regs, err); static inline unsigned long get_cr2 (void) { unsigned long address; /* получить адрес */ _ asm _ ("movl %%cr2, %0" : "=r" (address)); return address; static void inline do_trap(int trapnr, int signr, char *str, int vm86, struct pt_regs * regs, long error_code, siginfo_t *info) { if (vm86 && regs->eflags & VM_MASK) goto vm86_trap; if ( ! (regs->xcs & 3) ) goto kernel_trap; trap_signal: { struct task_struct *tsk = current; tsk->thread. error_code = error_code; tsk->thread. trap_no = trapnr; if (info) force_sig_info (signr, info, tsk) ; else force_sig (signr, tsk) ; return; kernel_trap: unsigned long fixup = search_exception_table(regs->eip); if (fixup) regs->eip = fixup; else die(str, regs, error_code); return; vm86_trap: { int ret = handle_vm86_trap((struct kernel_vm86_regs *) regs, er-ror_code, trapnr); if (ret) goto trap_signal; return; fldefine DO_ERROR(trapnr, signr, str, name) \ asmlinkage void do_tt#name(struct pt_regs * regs, long error_code) \ { \ do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \ Idefine DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ asmlinkage void do_t#name(struct pt_regs * regs, long error_code) \ { \ siginfo_t info; \ info.si_signo = signr; \ info.si_errno =0; \ info.si_code = sicode; \ info.si_addr = (void *)siaddr; \ do^trap(trapnr, signr, str, 0, regs, error_code, Sinfo); \ } ttdefine DO_VM86_ERROR(trapnr, signr, str, name) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ ( \ do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \ } ttdefine DO_VM86__ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ I asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ siginfo_t info; \ info.si_signo = signr; \ info.si_errno =0; \ info.si_code = sicode; \ info.si_addr = (void *)siaddr; \ do_trap(trapnr, signr, str, 1, regs, error_code, sinfo); \ ' " DO_VM86_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->eip) DO_VM86_ERROR( 3, SIGTRAP, "int3", int3) DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow) DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds) DO_ERROR_INFO( 6, SIGILL, "invalid operand", invalid_op, ILL_ILLOPN, regs->eip) DO_VM86_ERROR( 7, SIGSEGV, "device not available", device_not_available) DO_ERROR( 8, SIGSEGV, "double fault", double_fault) DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coproces-sor_segment_overrun) DO_ERROR(10, SIGSEGV, "invalid TSS", invalidJTSSl DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) DO_ERROR(12, SIGBUS, "stack segment", stack_segment) DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, get_cr2 () )