Ошибка прерывания процессора смартфона
Мы подошли к моменту, когда без изучения прерываний дальнейшее изучение микроконтроллеров будет делом сложным. Но и сами прерывания являются одной из самых сложных для изучения тем.
Поэтому соберитесь и запаситесь терпением. Прерываниям будет посвящено несколько статей, в которых мы рассмотрим и аппаратные, и программные вопросы. И, разумеется, особенности реализации прерываний в различных семействах микроконтроллеров.
Кроме того, будет полезно вспомнить статью " Микроконтроллеры для начинающих. Часть 2. Процессор микроконтроллера ". В ней показано, в частности, как формируется адрес команды, которую будет исполнять процессор. А так же статью " Микроконтроллеры для начинающих. Часть 3. Процессор микроконтроллера. Тактирование и синхронизация. ". Здесь показано, как организована совместная работа узлов процессора.
Что такое прерывания
Прежде всего, нам надо разобраться, что же такое прерывания. Собственно говоря ответ на этот вопрос кроется в самом термине. Прерывание действительно прерывает нормальное выполнение программы. А управление получает процедура обработки (обслуживания) прерывания, которую кратко называют ISR - Interrupt service routine.
После завершения обработки прерывания выполнение программы продолжается как обычно, с того самого места, в котором прерывание возникло.
Очень похоже на вызов подпрограмм? Да, похоже. Но есть одно важнейшее отличие - программа не должна знать, что прерывание вообще возникало. Программа не должна зависеть от того, возникло прерывание, или нет. За исключением случаев, когда программист такую зависимость предусматривает в явном виде.
А это означает, что переход к обработке прерывания требует дополнительных действий, которые могут выполняться или аппаратно, или программно.
Программные прерывания, синхронные
В микроконтроллерах, тех, что мы рассматриваем, программные прерывания есть только в STM8. Это команда TRAP. Но в микроконтроллерах вообще, тем более, в микропроцессорах, может быть несколько различных программных прерываний.
Программные прерывания всегда синхронные. То есть, они возникают синхронно с ходом выполнения программы, всегда в одном и том же месте - при выполнении команды прерывания.
Программные прерывания можно рассматривать как простой вызов подпрограммы, но адрес этой подпрограммы всегда предопределен и изменить его нельзя. И нельзя передать такой подпрограмме параметры, иначе чем заранее предусмотренные программистом переменные, обычно, глобальные.
Поскольку программные прерывания вызываем мы сами, не требуется сохранение состояния (контекста) процессора. Но поведение конкретного процессора при обработке программных прерываний нужно искать в документации.
Мы не будем рассматривать программные прерывания в рамках данного цикла статей.
Аппаратные прерывания, асинхронные
Сегодня аппаратные прерывания есть в подавляющем большинстве микроконтроллеров. Но исключения все таки есть, например, линейка BaseLine микроконтроллеров PIC.
Аппаратные прерывания всегда асинхронные. То есть, момент их возникновения никак не связан с выполнением программы. Может возникнуть вопрос, как так не связан, а, например, АЦП? Мы же сами запрашиваем преобразование, а значит, возникающее при завершении преобразования прерывание вызвано именно нами, синхронно.
Нет, совсем не синхронно и не нами. Да, мы сами запросили преобразование. Но сколько для преобразования потребуется времени мы не знаем, количество тактов преобразования может зависеть от многих параметров. Поэтому и прерывание все равно возникнет асинхронно.
Аппаратные прерывания могут быть вызваны и внутренними модулями микроконтроллера, и внешними цепями (через специальный вход INT). Кроме того, аппаратные прерывания могут возникать и при выполнении программы, команды. Например, деление на 0. И это тоже асинхронное прерывание.
Приоритеты прерываний
Некоторые аппаратные прерывания могут быть более важными, чем другие. Например, готовность байта полученного из канала связи более важна, чем нажатие кнопки. При этом говорят о приоритете прерываний.
Уровней приоритета может быть несколько. Но возможно и полное отсутствие деления на приоритеты. Если одновременно возникает несколько запросов прерывания, то обрабатываться они будут в порядке убывания приоритета. Реализуется приоретизация аппаратно.
Прерывание может возникнуть во время обработки другого прерывания. В этом случае говорят о вложенности прерываний.
Вложенные прерывания
Процедура обработки прерывания тоже может быть прервана новым прерыванием, но только если его приоритет выше, чем у обрабатываемого. То есть, мы получаем обработку прерывания внутри обработки другого прерывания. Это и есть вложенность.
В большинстве случаев с вложенными прерываниями проблем не возникает. После завершения обработчика более высокого приоритета управление вернется в прерванный обработчик.
Контроллер прерываний
Теперь становится понятным, что обработка прерываний не такой простой процесс. Запуск процедуры обработки прерывания, безусловно, будет процессор. Но вот разбираться с приоритетами, запретами (маскированием) прерываний, другой вспомогательной (но важной!) работой будет специальный модуль - контроллер прерываний. Этот контроллер может быть и очень простым, и очень сложным. И может быть выполнен как в виде модуля внутри микроконтроллера, так и быть внешней микросхемой.
И сегодня основное внимание я буду уделять именно контроллеру прерываний.
Контроллер прерываний
И начнем мы с самого простого случая. Сегодня он скорее гипотетический, но зато позволит начать разбираться с тем, что лежит в самой глубине процессов
Единственный источник прерываний
Сейчас мы будем рассматривать собственно процессор. Причем процессор имеющий единственный вход запроса прерывания.
Простейший контроллер прерываний с единственным источником, фиксированным адресом обработчика, без приоритетов. Иллюстрация моя Простейший контроллер прерываний с единственным источником, фиксированным адресом обработчика, без приоритетов. Иллюстрация мояЯ не стал показывать всю функциональную схему процессора. Она есть в статьях, ссылки на которые я дал ранее. Здесь же я показал только регистр адреса команды PC и дополнительные узлы, которые используются для обработки прерывания.
Но сначала о регистре PC. Как Вы уже знаете, этот регистр автоматически инкрементируется для перехода к следующей команде. Так же, в него можно загрузить адрес из команд перехода и вызова. Разумеется, этот регистр можно и прочитать.
Я показал, что запись и чтение регистра выполняется через ALU, подписав соответствующие цепи. Все остальные сигналы просто идут к/от других узлов процессора, которые нам сегодня не важны.
Триггер IE_TRIG отвечает за разрешение/запрет прохождения запроса прерывания в процессор. Он может быть частью регистра состояния процессора или частью иного регистра. В данном случае, если он установлен, прерывания разрешены, а если сброшен запрещены.
Триггер INT_TRIG отвечает за хранение запроса прерывания, так как я показал, что вход INT, собственно вывод на который поступает запрос из внешнего мира, является не потенциальным, а импульсным.
Как все это работает. Когда на вход INT поступает импульс запроса прерывания в INT_TRIG записывается 1 (триггер устанавливается). И это выполняется независимо от того, разрешены прерывания или нет. Если прерывания запрещены, то обработка просто будет отложена до момента разрешения. Триггер будет хранить запрос.
На вход процессора сигнал запроса прерывания IF попадет лишь в том случае, если триггер IE_TRIG будет установлен. То есть, если прерывания будут разрешены.
Теперь в игру вступает процессор. И первым делом он запрещает прерывания сбросив IE_TRIG. Теперь нам не важно состояние INT_TRIG поэтому сбрасывается и он. Заодно это позволяет зафиксировать запрос прерывания, который может придти во время обработки текущего прерывания. Далее, обязательно, сохраняет регистр PC.
Выполнив всю дополнительную работу, например, сохранив состояние процессора, процессор записывает в PC адрес процедуры обработки прерывания. Когда процедура обработки завершится она выполнит не команду RET (возврат), а специальную команду IRET (возврат из прерывания).
Теперь процессор снова выполняет всю дополнительную работу, например, восстанавливает состояние процессора. После чего можно восстановить регистр PC. Остается разрешить прерывания.
Теперь программа продолжит работать с того места, где ее выполнение было прервано.
В документации и книгах часто пишут, что восстанавливается состояние разрешения обработки прерываний. Это верно, но не совсем точно. Дело в том, что если уж мы попали в обработчик прерывания, значит прерывания точно были разрешены. И мы можем просто установить IE_TRIG без дополнительных раздумий.
А теперь начнем усложнять нашу задачу. Для начала увеличим количество источников прерывания, но оставим единственный обработчик.
Несколько источников прерываний, единственный обработчик
Ярким представителем такого подхода являются микроконтроллеры PIC, за исключением BaseLine и PIC18.
Контроллер прерываний для нескольких источников, но с единственным обработчиком.Без приоритетов. Цепи сброса триггеров INT_REG не показаны. Иллюстрация моя Контроллер прерываний для нескольких источников, но с единственным обработчиком.Без приоритетов. Цепи сброса триггеров INT_REG не показаны. Иллюстрация мояОсновное отличие здесь в замене INT_TRIG на INT_REG и появлении дополнительного регистра IE_REG. Кроме того, теперь у нас не IE_TRIG, а GIE_TRIG. Дело в том, что теперь он управляет глобальным разрешением/запретом прерываний. А вот запретить/разрешить конкретный источник мы можем через IE_REG.
В целом, обработка прерываний не изменилась. Автоматически сбрасывается GIE_TRIG, что запрещает все прерывания, глобально. IE_REG автоматически не изменяется, только программно, если это программист это предусмотрел.
А вот со сбросом INT_REG все сложнее и интереснее. Сбросить регистр целиком нельзя, можно только триггер соответствующий обрабатываемому запросу. Но как этот триггер найти? Ответ простой - никак.
Поэтому в подобных контроллерах запросы прерываний от источников не сбрасываются автоматически. Их обязательно нужно сбрасывать вручную.
А как мы можем найти источник запроса, вызвавшего прерывание? У нас ведь обработчик один на всех. Довольно просто - прочитав содержимое INT_REG и проанализировав его биты. Это позволит определить источник и вызвать соответствующую подпроцедуру обработки. Именно она потом и сбросит флаг запроса.
Кстати последовательность анализа битов INT_REG определяет и приоритетность прерывания. Такой вот дополнительный программный бонус. Считаете невозможным, так как прерывания запрещаются автоматически?
Возможно! Достаточно держать прерывания запрещенными глобально. При этом триггеры INT_REG будут фиксировать поступающие запросы. Теперь, разрешив в нужный момент прерывания (глобально) мы можем обработать их все сразу. В нужном нам порядке.
Безусловно, это далеко не универсальный метод. Но это и чистая теория, как может показаться. Дело в том, что несколько запросов (они же асинхронные!) могут придти одновременно. Кроме того, мы можем запрещать прерывания на время выполнения критических участков программы по необходимости. А после их разрешения получить как раз такую вот ситуацию.
Несколько источников, несколько обработчиков
Продолжаем усложнять нашу задачу. Давайте добавим отдельные обработчики для каждого источника прерывания. Это не так просто, как может показаться.
Но сначала нам надо вспомнить, что такое вектор прерывания. В своем первоначальном варианте вектором называлась ячейка памяти хранившая адрес обработчика. Содержимое этой ячейки загружалось в PC, что и приводило к переходу на обработчик. И мы могли спокойно изменять адрес обработчика, просто занеся его в вектор.
Однако, в микроконтроллерах (по крайней мере тех, что мы изучаем) вектор это просто определенный набор ячеек памяти команд на начало которого и передается управление. А программист размещает в векторе команду перехода на нужный обработчик.
Преобразовать номер прерывания (номер источника) в адрес перехода (вектора) достаточно легко. Например, можно сдвинуть номер вектора влево на два разряда и сбросить два младших разряда. И мы получим вектор позволяющий разместить 4 команды.
Фрагмент контроллера прерываний обеспечивающего для каждого источника свой обработчик. Иллюстрация моя Фрагмент контроллера прерываний обеспечивающего для каждого источника свой обработчик. Иллюстрация мояЯ не стал показывать всю функциональную схему контроллера прерываний, для наглядности. Что у нас здесь добавилось? Во первых, шифратор, причем шифратор приоритетный, что бы корректно обрабатывать ситуацию с несколькими конкурирующими запросами прерываний. Во вторых, мультиплексор, который определяет источник адреса для занесения в регистр PC.
Источниками адресам могут быть адрес команды из ALU, для команд перехода, или адрес вектора из нашего контроллера прерываний.
Запрос прерывания из источника с помощью приоритетного шифратора превращается в номер прерывания. У нас 4 источника, поэтому достаточно 2 бит адреса. Но вектор должен вмещать более одной команды. Поэтому номер вектора мы помещаем в биты 3 и 2 адреса, а биты 1 и 0 сбрасываем, что и показано на иллюстрации.
Это позволяет нам разместить в каждом векторе до 4 команд, а адрес вектора (адрес первой команды) будет равен номеру прерывания умноженному на 4.
В остальном обработка прерываний не изменилась. Но теперь у нас появилась возможность автоматически сбрасывать соответствующий триггер в INT_REG, ведь мы теперь знаем его номер. Я не буду показывать, как это выполняется на функциональной схеме.
Контроллер прерываний с приоритетами
Приоритетный шифратор в предыдущем случае не означает, что у прерываний есть приоритет. Да, он позволяет выбрать из нескольких прерываний одно, с наименьшим номером (наибольшим приоритетом). Но это не делает возможным прервать текущий обработчик прерывания с меньшим приоритетом.
Причина проста, при возникновении прерывания у нас прерывания запрещаются глобально. Я не буду приводить иллюстрацию, она сложна для начинающих, я просто расскажу, как это работает.
Вводится дополнительный регистр, который хранит приоритет текущего обрабатываемого прерывания. Причем, в общем случае, приоритет не равен номеру прерывания. Например, прерывания могут быть сгруппированы по несколько штук в пределах одного приоритета.
Прерывания не запрещаются глобально. Прерывания запрещаются для приоритета текущего прерывания и меньших приоритетов. При поступлении нового запроса специальный компаратор сравнивает его приоритет с текущим (хранится в специальном регистре, как я говорил). Если приоритет нового запроса выше, он поступает в процессор, что приводит к прерыванию текущего обработчика.
Причем это простейший случай. Могут быть предусмотрены дополнительные режимы работы. Например, циклическая смена приоритетов. Причем и приоритетов в группе, и групп приоритетов.
Когда мы будет изучать реализацию контроллеров прерываний в конкретных семействам микроконтроллеров, мы вернемся к приоретизации.
Заключение
Возникает, если в командах DIV или IDIV делитель равен нулю или результат операции не может быть представлен в том количестве бит, которыми располагает операнд-назначение. А также, если в команде AAM ее непосредственный операнд задан равным нулю.
Генерируется при ряде условий. Может быть как ошибкой, так и ловушкой в зависимости от причины:
- точка останова по команде – ошибка;
- точка останова по данным – ловушка;
- точка останова по вводу/выводу – ловушка;
- защита от записи в регистры отладки – ошибка;
- пошаговое выполнение – ловушка;
- выполнение команды INT 1 – ловушка;
- точка останова по переключению задач – ловушка.
Процессор не сохраняет код ошибки для этого прерывания. Обработчик должен проверять отладочные регистры для выяснения причины прерывания.
Прерывание 2 — Немаскируемое прерывание (NMI)
Во время обработки немаскируемого прерывания процессор во избежание зацикливания перестает реагировать на запросы на немаскируемое прерывание до поступления команды IRET. Рекомендуется использовать шлюз прерывания для обработчика немаскируемых прерываний с тем чтобы обеспечить автоматическое отключение маскируемых прерываний на время работы обработчика.
Команда INT 3 ни коим образом не влияет на состояние и содержимое регистров процессора. Прерванная программа может быть продолжена, если обработчик прерывания восстановит команду, измененную записью точки останова INT 3, и, уменьшив на единицу сохраненные значения CS:EIP, передаст управление на эту команду.
В процессорах Intel386 и старше для отладки программ и установки точек останова рекомендуется использовать регистры отладки, а команду INT 3 применять только в случаях, когда требуемое количество точек останова превышает возможности этих регистров.
Генерируется при выполнении команды INTO, если установлен флаг OF.
Генерируется, если при выполнении команды BOUND процессор обнаруживает, что операнд выходит за заданные границы.
Возникает, когда в управляющем блоке процессора обнаруживается некорректный код, включая коды MMX, 3DNow! и SIMD-команд в процессорах, которые не поддерживают такие расширения системы команд. Сохраненное значение CS:EIP указывает на недопустимый код или на его префикс. Ошибка может быть обработана в текущей задаче.
Это прерывание также возникает при любом появлении неправильного операнда (например, межсегментный переход, использующий регистровый операнд), при попытке выполнения специальных команд защищенного режима (LLDT, SLDT, LTR, STR, LSL, LAR, VERR, VERW, ARPL) в режиме реальной адресации или в режиме V86 и при попытке выполнить команду RSM, когда процессор не находится в системном режиме SMM (System Management Mode).
Специальные коды D6h и F1h зарезервированы Intel и не вызывают ошибки.
Генерируется в следующих ситуациях:
- процессор выполняет команду FPU, и CR0.EM = 1;
- процессор выполняет команду FPU, MMX, 3DNow! или SIMD и CR0.TS = 1.
- процессор выполняет команду WAIT/FWAIT, когда CR0.MP = 1 и CR0.TS = 1.
Т.е. прерывание генерируется, если поступает команда FPU, а сопроцессор отсутствует или поступают команды FPU, MMX, 3DNow!, SIMD или WAIT/FWAIT, а состояние сопроцессора не отвечает необходимому для данной задачи (произошло переключение задач).
Существует три класса прерываний и особых ситуаций: безопасные, способствующие и страничные. В зависимости от этого класса и порядка возникновения прерываний и особых ситуаций может генерироваться двойная ошибка.
Таблица 3.3. Условия, при которых генерируется двойная ошибка
Особая ситуация, возникшая первой
Особая ситуация, возникшая второй
Код ошибки помещается в стек обработчика двойной ошибки; поэтому этот код всегда нулевой. Вызвавшая ошибку команда не перезапускаема. Если во время перехода на обработчик двойной ошибки возникает еще какая-либо особая ситуация, то процессор переходит в режим останова, откуда может быть выведен только сигналами аппаратных прерываний NMI, SMI или сбросом. Если это происходит в обработчике немаскируемого прерывания NMI, то процессор может быть запущен в работу только сбросом. (На практике оказывается, что даже не все процессоры фирмы Intel ведут себя именно так, некоторые просто сбрасываются, некоторые могут, как ни в чем не бывало, продолжить работу.)
Прерывание 9 — Превышение сегмента сопроцессором : Intel286, Intel386
Это прерывание поддерживается только процессорами Intel286 и Intel386. В Intel486 . прерывание 9 считается зарезервированным и не должно использоваться.
Прерывание генерируется при проверке границ сегмента, производящейся при каждом обращении сопроцессора к памяти, в случае, если произошел выход за пределы сегмента при попытке чтения/записи второго или следующих слов операнда. Прерывание может обрабатываться в той же задаче, но команда, вызвавшая эту ошибку, не перезапускаема. Процессор не сохраняет никакой информации о вызвавшей прерывание команде. Для выяснения причины прерывания необходимо обратиться к специальным регистрам сопроцессора, содержащим последнюю выполненную команду и адрес запрошенного операнда. После возникновения этого прерывания не могут быть выполнены никакие команды типа WAIT или команды FPU (кроме FINIT/FNINIT) до тех пор, пока не будет устранена причина сбоя, или сопроцессор не будет инициализирован.
Генерируется при переключении задач, если новый TSS, на который указывает шлюз задачи, является недопустимым. Недопустимыми считаются случаи, когда не только сам TSS задан не корректоно, но и когда он содержит некорректные описания сегментов кода, стека и данных для новой задачи. Код ошибки, передаваемый обработчику содержит индекс селектора ошибочного сегмента.
Индекс кода ошибки
Предел TSS меньше 67h (2Bh для 16-битного TSS)
Неправильная LDT или LDT не присутствует
Селектор сегмента стека
Селектор стекового сегмента выходит за границы таблицы дескрипторов
Селектор сегмента стека
Сегмент стека не разрешен для записи
Селектор сегмента стека
RPL селектора стекового сегмента не равно CPL
Селектор сегмента стека
DPL стекового сегмента не равно CPL
Селектор кодового сегмента
Селектор кодового сегмента выходит за границы таблицы дескрипторов
Селектор кодового сегмента
Кодовый сегмент не является исполняемым
Селектор кодового сегмента
DPL несогласованного кодового сегмента не равен CPL
Селектор кодового сегмента
DPL согласованного кодового сегмента больше CPL
Селектор сегмента данных
Селектор сегмента данных выходит за границы таблицы дескрипторов
Селектор сегмента данных
Сегмент данных не доступен для чтения
Бит EXT кода ошибки показывает, была ли особая ситуация вызвана событием внешним по отношению к программе (т.е., если внешнее прерывание осуществляет переключение задач через шлюз, задающий некорректный TSS).
Это прерывание может быть вызвано, как в контексте старой задачи, так и уже в новой (т.е. регистр TR уже будет загружен новым селектором TSS). Первый случай возникает при проверке присутствия нового TSS. Если переключения задач еще не произошло, то сохраненные CS:EIP указывают на команду старой задачи, которая инициировала переключение задач, если же ошибка возникла после переключения задач, то сохраненные CS:EIP указывают на первую команду новой задачи.
Обрабока данной ошибки в текущей задаче затруднена. Intel рекомендует использовать шлюз задачи для обработчика этой ошибки.
Генерируется, если процессор обнаруживает, что бит присутствия в дескрипторе сегмента сброшен. Это может произойти в следующих случаях:
Эта ошибка рестартируема и может обслуживаться в рамках породившей ее задачи. Код ошибки помещается в стек. Бит EXT кода ошибки устанавливается, если прерывание вызвано внешним событием. Бит IDT кода ошибки устанавливается, если код ошибки ссылается на элемент IDT (т.е. команда INT ссылается на неприсутствующий шлюз).
Сохраняемые значения CS:EIP в большинстве случаев указывают на команду, приведшую к генерации ошибки. В случае, когда ошибка происходит при переключении задач, сохраняемые CS:EIP указывают на первую команду новой задачи, а если ошибка генерируется при обращении к дескриптору шлюза, то CS:EIP будут указывать на команду, осуществившую такое обращение (например, команда CALL).
Генерируется в следующих случаях:
- при нарушении установленных границ в командах, использующих регистр SS (POP, PUSH, RET, IRET, ENTER, LEAVE, а также команды типа MOV AX,[BP] , MOV AX,SS:[EAX] и т.п.);
- при попытке загрузить SS дескриптором, который помечен как неприсутствующий (может случиться в командах CALL, IRET, LSS, MOV, POP).
При возникновении стековой ошибки, процессор помещает код ошибки в стек обработчика. Если прерывание произошло во время переключения задач посредством межуровнего CALL из-за того, что произошло переполнение стека, или сегмент стека не присутствует, то код ошибки содержит селектор сегмента, ставшего причиной ошибки; в других случаях код ошибки всегда нулевой.
Сохраняемые значения CS:EIP указывают на команду, вызвавшую ошибку. Поскольку сама эта команда не выполнена, а состояние процессора при генерации стековой ошибки остается неизменным, обработчику легко устранить причины, вызвавшие ошибку и перезапустить команду. На практике оказывается, что различные модели процессоров различных производителей могут вести себя неадекватно в реальном режиме работы. При превышении границ стекового сегмента в этом неважном на взгляд некоторых разработчиков режиме, разные процессоры могут сброситься, зависнуть, перейти в режим останова и пр.
- выход за границы сегмента при использовании CS, DS, ES, FS или GS;
- выход за границы сегмента при ссылках на таблицу дескрипторов, кроме случая переключения задач и переключения стека;
- передача управления в сегмент, который не является исполняемым;
- запись в только читаемый сегмент данных или сегмент кода;
- чтение из только исполняемого кодового сегмента;
- загрузка регистра SS селектором только читаемого сегмента (кроме случая, когда это происходит во время переключения задач);
- загрузка SS, DS, ES, FS или GS селектором системного сегмента;
- загрузка DS, ES, FS или GS селектором только исполняемого кодового сегмента;
- загрузка SS селектором исполняемого сегмента или нулевым селектором;
- загрузка CS селектором сегмента данных или нулевым селектором;
- использование DS, ES, FS или GS для обращения к памяти, когда в них загружен нулевой селектор;
- переключение на занятую задачу (кроме команды IRET);
- переключение на свободную задачу при выполнении команды IRET;
- использование при переключении задач селектораTSS, который указывает на текущую таблицу LDT (дескрипторы TSS всегда должны располагаться в GDT);
- обращение к значениям в таблице IDT, которые не являются корректными шлюзами прерывания, ловушки или задачи;
- нарушение правил привилегий, отслеживаемых механизмом защиты;
- попытка выполнения привилегированной команды на уровне привилегий отличном от 0;
- обращение к шлюзу, который содержит нулевой селектор или селектор, который не указывает на исполняемый кодовый сегмент;
- выполнение команды INT n, когда CPL больше DPL используемого шлюза прерывания, ловушки или задачи или в режиме V86, когда IOPL < 3;
- селектор, загружаемый командой LLDT в регистр LDTR, не указывает на дескриптор в таблице LDT, либо этот дескриптор не является дескриптором LDT;
- попытка загрузки в регистр TR командой LTRселектора, который указывает на таблицу LDT или на занятый TSS;
- использование в качестве назначения команд межсегментных переходов и вызовов (CALL, RET и JMP) нулевого селектора;
- попытка обращения к обработчику прерывания через шлюз прерывания или ловушки из режима V86, когда уровень привилегий процедуры обработчика прерываний DPL больше 0 (Intel386 …);
- превышение командой размера 15 байт (Intel386 …), такое может случиться при неправильном использовании префиксов;
- попытка загрузки регистра CR0 значением, в котором флаг PE = 0, а флаг PG = 1 (Intel386 …);
- попытка загрузки регистра CR0 значением, в котором флаг CD = 0, а флаг NW = 1 (Intel486 …);
- если начальный адрес операндов сопроцессора выходит за границу сегмента (Intel486 …);
- попытка записи единицы в зарезервированные биты CR4 (Pentium …);
- поступление внешнего маскируемого прерывания, когда инициализировано расширение CR4.VME или CR4.PVI, а также попытка установки флага EFLAGS.VIF в этом режиме при условии EFLAGS.VIP = 1 (Pentium …);
- попытка записи в зарезервированные биты специальных регистров модели MSR (Pentium …);
- при установленном флаге CR4.PAE, когда процессор обнаруживает, что в любом из зарезервированных битов элементов таблицы указателей на каталог страниц присутствует 1, такая проверка производится процессором всякий раз, когда изменяются значения в регистрах CR0, CR3, CR4 и он производит считывание значений элементов таблицы указателей на каталог страниц из памяти (Pentium Pro …).
При возникновении ошибки общей защиты процессор помещает код ошибки в стек обработчика. Если ошибка произошла при загрузке неправильного дескриптора, то код ошибки — это селектор этого дескриптора, либо его индекс в таблице IDT, во всех остальных случаях код ошибки нулевой. Сохраняемые значения CS:EIP указывают на команду, вызвавшую ошибку. Если ошибка происходит во время переключения задач, то ее генерация может произойти как до, так и после момента переключения задачи. Во втором случае процессор сначала закончит загрузку всех значений в регистры CS, SS, DS, ES, FS, GS без проверки их корректности, а затем передаст управление обработчику ошибки.
Обработчик ошибки общей защиты может произвести перезапуск прерванной программы практически при всех случаях. Однако при этом возможна потеря внешних прерываний, которые явились причиной генерации ошибки общей защиты.
В реальном режиме прерывание 13 генерируется при нарушении границы 0FFFFh в сегментах CS, DS, ES, FS, GS.
Генерируется, если страничный механизм активизирован (CR0.PG = 1) и при трансляции линейного адреса в физический возникает одна из следующих ситуаций:
-
или каталога страниц, используемый при трансляции адреса, имеет нулевой бит присутствия, т.е. нужная таблица страниц или страница не присутствует в физической памяти;
- процедура не располагает уровнем привилегий, достаточным для доступа к выбранной странице или пытается произвести запись в страницу, защищенную от записи для текущего уровня привилегий.
Обработчик страничной ошибки получает информацию о ее причине из двух источников: кода ошибки, помещаемого в стек, и содержимого регистра CR2, который содержит линейный адрес, вызвавший ошибку. Код страничной ошибки имеет специальный формат (рис. 3.7.).
Рис. 3.7. Формат кода страничной ошибки
Прерванная программа после устранения причин, вызвавших страничную ошибку (например, загризки страницы в физическую память), может быть продолжена без каких-либо дополнительных корректировок.
Если страничная ошибка была вызвана в связи с нарушением привилегий страничной защиты, то бит доступа (A) в соответствующем элементе каталога страниц устанавливается. Поведение бита доступа в соответствующем элементе таблиц страниц для этого случая не регламентируется в процессорах Intel и может быть разным в различных моделях.
Это прерывание сигнализирует об ошибке, возникшей во время выполнения команды FPU. Т.е. в результате выполнения команды имело место незамаскированное исключение FPU (с помощью регистра управления FPU можно замаскировать все исключения) .
Поскольку сохраняемый при вызове обработчика указатель CS:EIP не всегда определяет команду, ставшую причиной генерации исключения, обработчик должен анализировать содержимое специального регистра сопроцессора FIP, который и содержит точный указатель.
Важной является синхронизация потока команд FPU с другими командами процессора. Например, если команда процессора использует результат предшевствовавшей ей команды FPU, возможна потеря исключения и использование некорректного результата. Для предотвращения этого необходимо вставить команду WAIT/FWAIT после команды FPU. Обратитесь к специальной литературе для подробного изучения специфики программирования смешанных кодов.
Протокол реакции на исключения FPU имеет некоторые отличия в различных моделях процессоров и сопроцессоров. Отличия эти касаются в первую очередь режима реакции в стиле MS-DOS и момента генерации ошибки сопроцессора (сразу по возникновении или при поступлении следующей команды FPU/MMX/3DNow!). В современных микропроцессорах наиболее универсальным и жестко регламентированным является режим внутренней генерации ошибки сопроцессора (CR0.NE = 1), который является основным, режим реакции в стиле MS-DOS поддерживается для совместимости. Подробное описание механизма реакции на исключения сопроцессора приведено в Intel® 64 and IA-32 Architectures Software Developer’s Manual. Volume 1: Basic Architecture.
Генерируется при попытке доступа к невыровненным операндам. Выравнивание необходимо для следующих типов данных.
Думаю, многие любознательные пользователи, наверняка не раз встречали такое сокращение, как IRQ. Его можно встретить, например, если вы любите заглядывать в программу «Менеджер устройств» в Windows. Если вы выберете любое устройство, к примеру, клавиатуру, выберете при помощи правой кнопки мыши пункт меню «Свойства», и в появившемся окне сделаете активной закладку «Ресурсы», то в списке ресурсов вы увидите надпись IRQ 01.
Для чего нужны IRQ
Что же такое IRQ и для чего оно нужно?
Аббревиатура IRQ расшифровывается как Interrupt ReQuest (запрос на прерывание). Для того, чтобы понять, для чего оно нужно, следует вспомнить подробности организации работы персонального компьютера.
Кровеносной системой компьютера, по которой обмениваются информацией процессор и прочие устройства, является системная шина. Но как вообще процессор способен отличить запросы на обработку информации, поступающие по шине от различных устройств?
Для этого и существует система аппаратных прерываний (IRQ). Каждое прерывание имеет определенный номер (нумерация начинается с 0) и закреплено за определенным устройством. Так, за клавиатурой закреплено прерывание под номером 1, отсюда и обозначение IRQ 01.
При поступлении запроса от устройства компьютер прерывает (отсюда и появился сам термин «прерывание») обработку текущей информации и начинает обработку вновь поступившего. Если прерываний несколько, то они обрабатывается в порядке приоритетов, закрепленных за каждым из них. Как правило, чем меньше номер прерывания, тем больший приоритет для процессора имеет устройство, закрепленное за этим прерыванием, но это правило соблюдается далеко не всегда.
Обслуживает обработку IRQ специальный чип, который носит название контроллера прерываний. Как правило, эта микросхема является частью центрального процессора, а иногда выделяется в отдельный чип на материнской плате. Для обработки каждого прерывания в BIOS существует специальная микропрограмма, называемая обработчиком прерывания. Адреса всех обработчиков хранятся в так называемой таблице векторов прерываний.
Настройка Interrupt ReQuest
Надо сказать, что прерывания, закрепленные за некоторыми устройствами, не является фиксированными и их можно изменить программно. Например, IRQ стандартно использующееся последовательным портом Com 2, может использовать и устанавливаемый в слот расширения модем. В современных компьютерах и операционных системах, поддерживающих стандарт PnP и работающих под управлением ОС Windows, значения IRQ для устройств, подключаемых в слоты шины, подбираются автоматически.
Но не все было так просто в прежние времена, когда пользователь должен был вручную устанавливать значение IRQ во многих программах, работавших под операционной системой DOS. Например, при установке в систему звуковой карты, пользователю требовалось выбрать свободное прерывание из очень небольшого числа доступных (как правило, это было IRQ 5) и указать это значение в запускаемой программе, например, в какой-нибудь игре.
Во многих BIOS имеется возможность поменять стандартные значения IRQ в программе Setup. Обычно эта опция располагается в разделах IRQ Resources или PCI/PNP Configuration.
Установка для устройства значения IRQ, равного значению IRQ, уже занятого каким-либо устройством в большинстве случаев приводит к неработоспособности одного из этих устройств или сразу обоих, а иногда чревато и зависанием компьютера.
В более современной шине PCI система управления прерываниями была кардинально изменена, а возможности управления прерываниями были расширены. Благодаря технологии IRQ Sharing, а также технологии ACPI стало возможным размещение нескольких устройств на одном канале прерывания, а у внешних устройств, подключаемых в слоты PCI, появилась возможность автоматического распределения ресурсов между собой.
Кроме того, в современных компьютерах обычно используется расширенный программируемый контроллер прерываний (APIC, Advanced Programmable Interrupt Controller), поддерживающий 24 канала Interrupt ReQuest. Расширенный контроллер прерываний выполнен в виде двух микросхем, одна из которых расположена в самом процессоре, а другая на материнской плате. Этот контроллер прерываний впервые появился в системах на основе процессоров Pentium. Однако при этом была оставлена поддержка старой системы прерываний в целях совместимости. Очередным шагом в развитии принципов обработки прерываний является технология Message Signaled Interrupts, поддержка которой появилась в линейке ОС Windows, начиная с Windows Vista.
Не следует путать аппаратные прерывания IRQ c программными прерываниями BIOS, о которых речь пойдет в отдельной статье. Программные прерывания BIOS, как правило, используются для организации работы программного обеспечения с устройствами ввода-вывода и обозначаются при помощи сокращения INT. Многие из них аналогичны по своим функциям аппаратным IRQ, но имеют при этом другие номера.
Список номеров Interrupt ReQuest в стандартной схеме для 16-битной шины ISA:
Список дополнительных номеров IRQ, которые использует расширенный контроллер прерываний APIC:
Соответствие номеров IRQ и прерываний BIOS:
Заключение
Итак, в этой статье вы смогли узнать, что означает сокращение IRQ, и что представляют собой аппаратные прерывания. Они являются встроенным механизмом распределения ресурсов компьютера и предназначены для организации доступа устройств к центральному процессору. Правильное распределение и настройка IRQ позволяет избежать конфликтов между устройствами и обеспечить стабильную работу системы.
Прерывание - это изменение естественного порядка выполнения программы, которое связано с необходимостью реакции системы на работу внешних устройств, а также на ошибки и особые ситуации, возникшие при выполнении программы. При этом вызывается специальная программа - обработчик прерываний, специфическая для каждой возникшей ситуации, после выполнения которой возобновляется работа прерванной программы.
Механизм прерывания обеспечивается соответствующими аппаратно-программными средствами компьютера.
Классификация прерываний представлена на рис. 7.1.
Запросы аппаратных прерываний возникают асинхронно по отношению к работе микропроцессора и связаны с работой внешних устройств.
Запрос от немаскируемых прерываний поступает на вход NMI микропроцессора и не может быть программно заблокирован. Обычно этот вход используется для запросов прерываний от схем контроля питания или неустранимых ошибок ввода/вывода.
Для запросов маскируемых прерываний используется вход INT микропроцессора. Обработка запроса прерывания по данному входу может быть заблокирована сбросом бита IF в регистре флагов микропроцессора.
Программные прерывания, строго говоря, называются исключениями или особыми случаями. Они связаны с особыми ситуациями, возникающими при выполнении программы (отсутствие страницы в оперативной памяти, нарушение защиты, переполнение ), то есть с теми ситуациями, которые программист предвидеть не может, либо с наличием в программе специальной команды INT n, которая используется программистом для вызова функций операционной системы либо BIOS , поддерживающих работу с внешними устройствами. В дальнейшем при обсуждении работы системы прерываний мы будем употреблять единый термин " прерывание " для аппаратных прерываний и исключений, если это не оговорено особо.
Программные прерывания делятся на следующие типы.
Нарушение (отказ) - особый случай, который микропроцессор может обнаружить до возникновения фактической ошибки (например, отсутствие страницы в оперативной памяти); после обработки нарушения программа выполняется с рестарта команды, приведшей к нарушению.
Ловушка - особый случай, который обнаруживается после окончания выполнения команды (например, наличие в программе команды INT n или установленный флаг TF в регистре флагов ). После обработки этого прерывания выполнение программы продолжается со следующей команды.
Авария ( выход из процесса) - столь серьезная ошибка, что некоторый контекст программы теряется и ее продолжение невозможно. Причину аварии установить нельзя, поэтому программа снимается с обработки. К авариям относятся аппаратные ошибки, а также несовместимые или недопустимые значения в системных таблицах.
Порядок обработки прерываний
Прерывания и особые случаи распознаются на границах команд, и программист может не заботиться о состоянии внутренних рабочих регистров и устройств конвейера.
Реагируя на запросы прерываний, микропроцессор должен идентифицировать его источник, сохранить минимальный контекст текущей программы и переключиться на специальную программу - обработчик прерывания. После обслуживания прерывания МП возвращается к прерванной программе, и она должна возобновиться так, как будто прерывания не было.
Обработка запросов прерываний состоит из:
- "рефлекторных" действий процессора, которые одинаковы для всех прерываний и особых случаев и которыми программист управлять не может;
- выполнения созданного программистом обработчика.
Для того чтобы микропроцессор мог идентифицировать источник прерывания и найти обработчик, соответствующий полученному запросу, каждому запросу прерывания присвоен свой номер ( тип прерывания ).
Тип прерывания для программных прерываний вводится изнутри микропроцессора; например, прерывание по отсутствию страницы в памяти имеет тип 14. Для прерываний, вызываемых командой INT n, тип содержится в самой команде. Для маскируемых аппаратных прерываний тип вводится из контроллера приоритетных прерываний по шине данных . Немаскируемому прерыванию назначен тип 2.
Всего микропроцессор различает 256 типов прерываний. Таким образом, все они могут быть закодированы в 1 байте.
"Рефлекторные" действия микропроцессора по обработке запроса прерывания выполняются аппаратными средствами МП и включают в себя:
- определение типа прерывания ;
- сохранение контекста прерываемой программы (некоторой информации, которая позволит вернуться к прерванной программе и продолжить ее выполнение). Всегда автоматически сохраняются как минимум регистры EIP и CS , определяющие точку возврата в прерванную программу, и регистр флагов EFLAGS . Если вызов обработчика прерывания проводится с использованием шлюза задачи, то в памяти полностью сохраняется сегмент состояния TSS прерываемой задачи;
- определение адреса обработчика прерывания и передача управления первой команде этого обработчика.
После этого выполняется программа - обработчик прерывания, соответствующая поступившему запросу. Эта программа пишется и размещается в памяти прикладным или системным программистом. Обработчик прерывания должен завершаться командой I RET , по которой автоматически происходит переход к продолжению выполнения прерванной программы с восстановлением ее контекста.
Для вызова обработчика прерывания микропроцессор при работе в реальном режиме использует таблицу векторов прерываний, а в защищенном режиме - таблицу дескрипторов прерываний.
Обращение к IDT аналогично обращению к глобальной таблице дескрипторов, где вместо системного регистра GDT R используется регистр IDTR , который определяет размер и базовый адрес таблицы в памяти.
Физический адрес дескриптора шлюза, находящегося в IDT , определяется как сумма базового адреса таблицы и умноженного на 8 типа прерывания (рис. 7.3).
Рис. 7.3. Порядок обращения к таблице дескрипторов прерываний
Содержимое регистра IDTr не сохраняется в сегментах TSS и не изменяется при переключении задачи. Программы не могут обратиться к IDT , так как единственный бит TI индикатора таблицы в селекторе сегмента обеспечивает выбор только между таблицами GDT и LDT .
Максимальный предел таблицы дескрипторов прерываний составляет 256*8 - 1 = 2047.
Можно определить предел меньшим, но это не рекомендуется. Если происходит обращение к дескриптору вне пределов IDT , процессор переходит в режим отключения до получения сигнала по входу NMI или сброса.
В IDT могут храниться только дескрипторы следующих типов:
- шлюз ловушки ,
- шлюз прерывания, шлюз задачи.
Шлюзы ловушки и прерывания сходны со шлюзом вызова, только в них отсутствует поле счетчика WC (рис. 7.4). Так как прерывание является неожиданным событием и не связано с текущей программой, говорить о передаче параметров их обработчику не приходится.
Бит S = 0 в байте доступа определяет этот дескриптор как системный объект . Если поле ТИП в байте доступа равно 1110, то это шлюз прерывания, если 1111 - то шлюз ловушки.
Поле уровня привилегий дескриптора DPL , как правило, устанавливается равным 3 с тем, чтобы к обработчику прерываний могли обращаться программы с любого уровня привилегий.
Бит присутствия P может быть равен как 0, так и 1.
При входе в обработчик через шлюз прерывания в регистре флагов сбрасывается бит разрешения прерываний IF . В этом случае микропроцессор блокирует все маскируемые аппаратные прерывания. Поэтому в обработчике прерываний этот бит должен быть установлен в 1 как можно раньше с тем, чтобы не блокировать работу программ, которые вызываются, например, при обработке прерываний от системного таймера .
При входе в обработчик через шлюз ловушки флаг IF не меняется.
Вызов обработчика через шлюз ловушки , а не шлюз прерывания, чаще реализуют при обработке исключений , так как на период обслуживания прерывания нежелательно выключать механизм разделения времени, использующий прерывания таймера.
Вызов обработчика через шлюз задачи обычно осуществляется при обработке аппаратных прерываний, так как такая обработка не связана с текущей выполняемой задачей. При этом возможен механизм вложенных прерываний, если прерывания в задаче разрешены. Вызов обработчика прерывания через шлюз задачи осуществляется и при обработке исключений , например, "неразрешенный TSS ", когда поврежденная задача не может вызвать процедуру прерывания. Переключение задач требует примерно в 5 раз больше времени, чем вызов процедуры. Поэтому, если приоритет запроса высок, а программа обслуживания короткая, ее оформляют в виде процедуры.
Читайте также: