Как вызываются подпрограммы прерываний из bios
Сегодня мы поговорим о прерываниях процессоров семейства x86 (-64). Подробнее под катом.
Прерывания — это как бы сигнал процессору, что надо прервать выполнение (их поэтому и назвали прерываниями) текущего кода и срочно сделать то, что указано в обработчике.
- 0b0101: 32-битный гейт задачи, при появлении такого прерывания происходит хардверное переключение задачи (да-да, есть и такое, но его уже давно не используют)
- 0b0110: 16-битный гейт прерывания
- 0b0111: 16-битный гейт trap'a (я не знаю, как это перевести на русский язык, извините)
- 0b1110: 32-битный гейт прерывания
- 0b1111: 32-битный гейт trap'a
- Поиск вектора №0 в IDT.
- Сравнение уровня привилегий дескриптора и текущего уровня привилегий процессора.
- Если текущий уровень привилегий процессора меньше уровня привилегий дескриптора, то просто вызвать генеральную ошибку защиты и не вызывать прерывание.
- Происходит сохранение адреса возвращения, регистра (E)FLAGS и другой информации.
- Происходит переход на адрес, указанный в векторе №0 IDT.
- После выполнения обработчика инструкция iret возвращает управление прерванному коду.
Существует особый тип прерываний — IRQ (Interrupt ReQuest), или же аппаратные прерывания, но я буду их для краткости называть просто IRQ. Технически они почти не отличаются от любых других прерываний, но генерируются не процессором или самим кодом, а устройствами, подключенными к компьютеру. К примеру, IRQ №0 генерируется PIT (таймер с программируемым интервалом), IRQ 1 генерируется при нажатии клавиши на клавиатуре, а IRQ 12 — при действии с PS/2-мышью.
Еще есть так называемые программные прерывания. Их, как понятно из названия, программа должна вызывать сама — никто их за нее не вызывает. Таковыми являются, например, системные вызовы в некоторых системах. В Linux, например, они висят на векторе 0x80. Во многих хобби-ОС они тоже висят на векторе 0x80. Теперь немного отсебятины — я думаю, что сисвызовы сделаны в виде прерываний из-за того, что 1) их так очень легко вызывать, 2) их можно вызвать из любого кода, работающего в ОС — IDT-то одна на всю систему.
Информация взята с OSDev Wiki.
Вызовы прерывания BIOS - это средство, которое операционные системы и прикладные программы используют для вызова средств программного обеспечения базовой системы ввода-вывода на компьютерах, совместимых с IBM PC . Традиционно вызовы BIOS в основном используются программами DOS и некоторым другим программным обеспечением, таким как загрузчики (включая, как правило, относительно простое прикладное программное обеспечение, которое загружается напрямую и запускается без операционной системы, особенно игровое программное обеспечение). BIOS работает в режиме реального адреса (Real Mode) процессора x86, поэтому программы, вызывающие BIOS, должны либо работать в реальном режиме, либо должны переключаться из защищенного режима в реальный режим перед вызовом BIOS и последующим переключением обратно. По этой причине современные операционные системы, которые используют ЦП в защищенном режиме или в длительном режиме, обычно не используют вызовы прерывания BIOS для поддержки системных функций, хотя они используют вызовы прерывания BIOS для проверки и инициализации оборудования во время загрузки . Реальный режим имеет ограничение памяти 1 МБ , современные загрузчики (например, GRUB2 , Windows Boot Manager ) используют нереальный режим или защищенный режим (и выполняют вызовы прерывания BIOS в режиме Virtual 8086 , но только для загрузки ОС) для доступа к 4 ГБ объем памяти.
На всех компьютерах программные инструкции управляют физическим оборудованием (экраном, диском, клавиатурой и т. Д.) С момента включения питания. В ПК BIOS, предварительно загруженный в ПЗУ на материнской плате, берет на себя управление сразу после сброса ЦП, в том числе во время включения питания, при нажатии кнопки аппаратного сброса или при критическом программном сбое ( тройная ошибка ). заставляет схему материнской платы автоматически запускать аппаратный сброс. BIOS проверяет оборудование и инициализирует его состояние; находит, загружает и запускает загрузочную программу (обычно загрузчик ОС и исторический ROM BASIC ); и обеспечивает базовый аппаратный контроль для программного обеспечения, работающего на машине, которое обычно представляет собой операционную систему (с прикладными программами), но может быть непосредственно загружаемым отдельным программным приложением.
Со стороны IBM они предоставили всю информацию, необходимую для полного использования BIOS или прямого использования оборудования и полного отказа от BIOS при программировании ранних моделей IBM PC (до PS / 2). С самого начала у программистов был выбор: использовать или нет BIOS в зависимости от оборудования и периферии. IBM настоятельно поощряла создание программ с хорошим поведением, которые обращались к оборудованию только через вызовы BIOS INT (и вызовы служб DOS), чтобы поддерживать совместимость программного обеспечения с текущими и будущими моделями ПК, имеющими разное периферийное оборудование, но IBM понимала, что для некоторых Разработчики программного обеспечения и заказчики оборудования требовали от пользовательского программного обеспечения возможности напрямую управлять оборудованием. Частично это было связано с тем, что значительная часть всех аппаратных функций и функций не была предоставлена службами BIOS. В двух примерах (среди многих) адаптеры MDA и CGA могут выполнять аппаратную прокрутку, а последовательный адаптер ПК может передавать данные с прерываниями, но IBM BIOS не поддерживает ни одну из этих полезных технических функций.
Сегодня BIOS в новом ПК по-прежнему поддерживает большинство, если не все, вызовы функций прерывания BIOS, определенные IBM для IBM AT (представленного в 1984 году), а также многие новые, а также расширения некоторых оригинальных ( например, расширенные диапазоны параметров), опубликованные различными другими организациями и совместными отраслевыми группами. Это, в сочетании с аналогичной степенью совместимости оборудования, означает, что большинство программ, написанных для IBM AT, все еще могут правильно работать на новом ПК сегодня, предполагая, что более высокая скорость выполнения приемлема (что обычно для всех, кроме игр, использующих Время на основе ЦП). Несмотря на значительные ограничения служб, доступ к которым осуществляется через прерывания BIOS, они оказались чрезвычайно полезными и устойчивыми к технологическим изменениям.
СОДЕРЖАНИЕ
Назначение вызовов BIOS
Вызовы прерывания BIOS выполняют функции аппаратного управления или ввода-вывода, запрошенные программой, возвращают программе информацию о системе или выполняют и то, и другое. Ключевым элементом назначения вызовов BIOS является абстракция: вызовы BIOS выполняют обычно определенные функции, а конкретные детали того, как эти функции выполняются на конкретном оборудовании системы, инкапсулируются в BIOS и скрыты от программы. Так, например, программе, которая хочет читать с жесткого диска, не нужно знать, является ли жесткий диск приводом ATA , SCSI или SATA (или ранее - приводом ESDI , либо приводом MFM или RLL с возможно, контроллер Seagate ST-506 , возможно, один из нескольких типов контроллеров Western Digital или другой проприетарный контроллер другой марки). Программе нужно только идентифицировать определенный BIOS номер диска, к которому она хочет получить доступ, и адрес сектора, который она должна читать или записывать, и BIOS позаботится о переводе этого общего запроса в конкретную последовательность требуемых элементарных операций. для выполнения задачи через конкретное оборудование контроллера диска, подключенное к этому диску. Программа избавлена от необходимости знать, как управлять на низком уровне каждым типом жесткого диска (или видеоадаптера, или интерфейса порта, или периферийных устройств часов реального времени), к которым может потребоваться доступ. Это и упрощает программирование операционных систем и приложений, и уменьшает размер программ, уменьшая дублирование программного кода, поскольку функции, включенные в BIOS, не нужно включать в каждую программу, которая в этом нуждается; Вместо этого в программы включены относительно короткие вызовы BIOS. (В операционных системах, где не используется BIOS, служебные вызовы, предоставляемые самой операционной системой, обычно выполняют ту же функцию и цель.)
BIOS также освобождает разработчиков компьютерного оборудования (в той степени, в которой программы написаны для использования исключительно BIOS) от необходимости поддерживать точную совместимость оборудования со старыми системами при разработке новых систем, чтобы поддерживать совместимость с существующим программным обеспечением. Например, аппаратное обеспечение клавиатуры на IBM PCjr работает совсем иначе, чем аппаратное обеспечение клавиатуры на более ранних моделях ПК IBM, но для программ, которые используют клавиатуру только через BIOS, эта разница почти незаметна. (Хорошим примером другой стороны этой проблемы является то, что значительная часть программ для ПК, используемых на момент выпуска PCjr, не использовала клавиатуру исключительно через BIOS, поэтому IBM также включила в PCjr аппаратные функции для эмуляции как работает оригинальное аппаратное обеспечение клавиатуры IBM PC и IBM PC XT . Эмуляция оборудования неточна, поэтому не все программы, которые пытаются напрямую использовать аппаратное обеспечение клавиатуры, будут правильно работать на PCjr, но все программы, которые используют только службы клавиатуры BIOS, будут .)
Вызов BIOS: программные прерывания BIOS
Операционные системы и другое программное обеспечение взаимодействуют с программным обеспечением BIOS для управления установленным оборудованием через программные прерывания. Программное прерывание - это особая разновидность общей концепции прерывания. Прерывание - это механизм, с помощью которого ЦП может быть направлен на то, чтобы остановить выполнение основной программы и вместо этого немедленно выполнить специальную программу, называемую процедурой обслуживания прерывания (ISR). После завершения ISR ЦП продолжает выполнение основной программы. В процессорах x86, когда происходит прерывание, ISR для вызова находится в таблице адресов начальной точки ISR (называемых «векторами прерывания») в памяти: Таблица векторов прерываний (IVT). Прерывание вызывается по номеру его типа, от 0 до 255, и номер типа используется в качестве индекса в таблице векторов прерываний, и в этом индексе в таблице находится адрес ISR, который будет запущен в ответ на прерывание. Программное прерывание - это просто прерывание, которое запускается программной командой; поэтому программные прерывания функционируют как подпрограммы, с той разницей, что программе, которая выполняет вызов программного прерывания, не требуется знать адрес ISR, а только номер прерывания. Это дает преимущества модульности, совместимости и гибкости конфигурации системы.
Программное обеспечение BIOS обычно возвращается вызывающему абоненту с кодом ошибки в случае неудачи или с кодом состояния и / или запрошенными данными в случае успеха. Сами данные могут иметь размер от одного бита или до 65 536 байтов целых необработанных секторов диска (максимум, который может поместиться в один сегмент памяти реального режима). BIOS многократно расширялся и улучшался на протяжении многих лет многими различными корпоративными организациями, и, к сожалению, результатом этого развития является то, что не все функции BIOS, которые можно назвать, используют согласованные соглашения для форматирования и передачи данных или для отчетности о результатах. Некоторые функции BIOS сообщают подробную информацию о состоянии, в то время как другие могут даже не сообщать об успехе или неудаче, а просто молча возвращаются, оставляя вызывающему объекту предположить успех (или проверить результат каким-либо другим способом). Иногда также может быть сложно определить, поддерживается ли конкретный вызов функции BIOS на определенном компьютере или каковы ограничения параметров вызова на этом компьютере. (Для некоторых недопустимых номеров функций или допустимых номеров функций с недопустимыми значениями ключевых параметров - особенно с ранней версией IBM BIOS - BIOS может ничего не делать и возвращать без кода ошибки; тогда это [неудобная, но неизбежная] ответственность вызывающий абонент либо избегает этого случая, не выполняя такие вызовы, либо положительно проверяет ожидаемый эффект вызова, а не предполагает, что вызов был эффективным. одна версия BIOS от определенного поставщика может быть недействительной в более ранней или другой версии BIOS от того же поставщика или в версии BIOS - любого относительного возраста - от другого поставщика.)
Поскольку в вызовах прерывания BIOS используется передача параметров на основе регистров ЦП, вызовы ориентированы на выполнение из языка ассемблера и не могут выполняться напрямую из большинства языков высокого уровня (HLL). Однако язык высокого уровня может предоставлять библиотеку подпрограмм-оболочек, которые переводят параметры из формы (обычно на основе стека), используемой языком высокого уровня, в форму на основе регистров, требуемую BIOS, а затем обратно в соглашение о вызовах HLL после BIOS возвращается. В некоторых вариантах C вызовы BIOS могут выполняться с использованием встроенного языка ассемблера в модуле C. (Поддержка встроенного языка ассемблера не является частью стандарта ANSI C, но является расширением языка; поэтому модули C, использующие встроенный язык ассемблера, менее переносимы, чем чистые стандартные модули C.)
Вызов прерывания
Вызов прерывания может быть выполнен с помощью инструкции языка ассемблера INT x86 . Например, чтобы вывести символ на экран с помощью прерывания BIOS 0x10, можно выполнить следующие инструкции языка ассемблера x86:
Таблица прерываний
Список общих классов прерываний BIOS можно найти ниже. Обратите внимание, что некоторые BIOS (особенно старые) не реализуют все эти классы прерываний.
INT 18h : выполнить BASIC
INT 18h традиционно перешли к реализации Cassette BASIC (предоставляемой Microsoft), хранящейся в дополнительных ПЗУ . Этот вызов обычно вызывается, если BIOS не может идентифицировать какие-либо тома загрузочного диска при запуске.
В то время, когда в 1981 году был выпущен оригинальный IBM PC (тип машины IBM 5150), ключевой особенностью был BASIC в ПЗУ. Современные популярные персональные компьютеры, такие как Commodore 64 и линейка Apple II, также имели Microsoft Cassette BASIC в ПЗУ (хотя Commodore переименовал их лицензионную версию в Commodore BASIC), поэтому на значительной части предполагаемого рынка IBM PC требовал BASIC для конкуренции. Как и в других системах, ROM BASIC IBM PC служил примитивной бездисковой операционной системой, позволяя пользователю загружать, сохранять и запускать программы, а также писать и уточнять их. (Оригинальный ПК IBM был также единственной моделью ПК от IBM, которая, как и его два вышеупомянутых конкурента, включала аппаратное обеспечение интерфейса кассеты. Базовая модель ПК IBM имела только 16 Кбайт ОЗУ и не имела дисковых накопителей [ любого типа ], поэтому кассета интерфейс и BASIC в ПЗУ были важны для того, чтобы можно было использовать базовую модель. ПК IBM с объемом ОЗУ менее 32 КБ не может загружаться с диска. Из пяти микросхем ПЗУ по 8 КБ в исходном ПК IBM, общим объемом 40 КБ, четыре содержат BASIC, и только один содержит BIOS; когда установлено только 16 KiB RAM, ROM BASIC составляет более половины всей системной памяти [4/7, если быть точным].)
Компания Digital Rainbow 100 B INT 18h называла свой BIOS, несовместимый с IBM BIOS. Turbo Pascal , Turbo C и Turbo C ++ перепрофилировали INT 18 для выделения памяти и подкачки. Другие программы также повторно использовали этот вектор в своих целях.
Перехватчики BIOS
В системах DOS IO.SYS или IBMBIO.COM перехватывают INT 13 для обнаружения смены гибких дисков, отслеживания вызовов форматирования, исправления ошибок границ DMA и решения проблем в BIOS ROM IBM "01/10/84" с кодом модели 0xFC перед первый звонок.
Обход BIOS
Многие современные операционные системы (например, Linux и Windows NT ) обходят вызовы прерывания BIOS после запуска, ядро ОС переключает ЦП в защищенный режим или длительный режим при запуске, предпочитая использовать свои собственные программы (например, драйверы ядра ) для управления подключенное оборудование напрямую. Причина этого заключалась прежде всего в том, что эти операционные системы запускают процессор в защищенном режиме или в длительном режиме, тогда как для вызова прерывания BIOS требуется переключение в реальный режим или нереальный режим или использование режима Virtual 8086 . Реальный режим, нереальный режим и виртуальный режим 8086 работают медленно. Однако существуют также серьезные причины для безопасности, чтобы не переключаться в реальный режим, а код BIOS реального режима имеет ограничения как по функциональности, так и по скорости, что побуждает разработчиков операционных систем искать ему замену. Фактически, ограничения скорости BIOS сделали его обычным даже в эпоху DOS, чтобы программы обходили его, чтобы избежать ограничений производительности, особенно для отображения видеографики и быстрой последовательной связи. Проблемы с функциональностью BIOS включают ограничения в диапазоне определенных функций, несогласованность в подмножествах этих функций, поддерживаемых на разных компьютерах, и различия в качестве BIOS (то есть некоторые BIOS являются полными и надежными, другие сокращены и содержат ошибки). Взяв дело в свои руки и не полагаясь на BIOS, разработчики операционных систем могут устранить некоторые риски и сложности, с которыми они сталкиваются при написании и поддержке системного программного обеспечения. С другой стороны, поступая таким образом, разработчики берут на себя ответственность за предоставление программного обеспечения драйверов «на чистом железе» для каждой системы или периферийного устройства, с которыми они намерены работать в своей операционной системе (или за побуждение производителей оборудования предоставлять эти драйверы). Таким образом, должно быть очевидно, что компактные операционные системы, разработанные с небольшим бюджетом, будут склонны интенсивно использовать BIOS, в то время как большие операционные системы, созданные огромными группами инженеров-программистов с большими бюджетами, чаще предпочитают писать свои собственные драйверы вместо использования BIOS, то есть , даже без учета проблем совместимости BIOS и защищенного режима.
Вызовы прерывания BIOS - это средство, которое операционные системы и прикладные программы используют для вызова средств программного обеспечения базовой системы ввода-вывода на компьютерах, совместимых с IBM PC . Традиционно вызовы BIOS в основном используются программами DOS и некоторым другим программным обеспечением, таким как загрузчики (включая, как правило, относительно простое прикладное программное обеспечение, которое загружается напрямую и запускается без операционной системы, особенно игровое программное обеспечение). BIOS работает в режиме реального адреса (Real Mode) процессора x86, поэтому программы, вызывающие BIOS, должны либо работать в реальном режиме, либо должны переключаться из защищенного режима в реальный режим перед вызовом BIOS и последующим переключением обратно. По этой причине современные операционные системы, которые используют ЦП в защищенном режиме или в длительном режиме, обычно не используют вызовы прерывания BIOS для поддержки системных функций, хотя они используют вызовы прерывания BIOS для проверки и инициализации оборудования во время загрузки . Реальный режим имеет ограничение памяти 1 МБ , современные загрузчики (например, GRUB2 , Windows Boot Manager ) используют нереальный режим или защищенный режим (и выполняют вызовы прерывания BIOS в режиме Virtual 8086 , но только для загрузки ОС) для доступа к 4 ГБ объем памяти.
На всех компьютерах программные инструкции управляют физическим оборудованием (экраном, диском, клавиатурой и т. Д.) С момента включения питания. В ПК BIOS, предварительно загруженный в ПЗУ на материнской плате, берет на себя управление сразу после сброса ЦП, в том числе во время включения питания, при нажатии кнопки аппаратного сброса или при критическом программном сбое ( тройная ошибка ). заставляет схему материнской платы автоматически запускать аппаратный сброс. BIOS проверяет оборудование и инициализирует его состояние; находит, загружает и запускает загрузочную программу (обычно загрузчик ОС и исторический ROM BASIC ); и обеспечивает базовый аппаратный контроль для программного обеспечения, работающего на машине, которое обычно представляет собой операционную систему (с прикладными программами), но может быть непосредственно загружаемым отдельным программным приложением.
Со стороны IBM они предоставили всю информацию, необходимую для полного использования BIOS или прямого использования оборудования и полного отказа от BIOS при программировании ранних моделей IBM PC (до PS / 2). С самого начала у программистов был выбор: использовать или нет BIOS в зависимости от оборудования и периферии. IBM настоятельно поощряла создание программ с хорошим поведением, которые обращались к оборудованию только через вызовы BIOS INT (и вызовы служб DOS), чтобы поддерживать совместимость программного обеспечения с текущими и будущими моделями ПК, имеющими разное периферийное оборудование, но IBM понимала, что для некоторых Разработчики программного обеспечения и заказчики оборудования требовали от пользовательского программного обеспечения возможности напрямую управлять оборудованием. Частично это было связано с тем, что значительная часть всех аппаратных функций и функций не была предоставлена службами BIOS. В двух примерах (среди многих) адаптеры MDA и CGA могут выполнять аппаратную прокрутку, а последовательный адаптер ПК может передавать данные с прерываниями, но IBM BIOS не поддерживает ни одну из этих полезных технических функций.
Сегодня BIOS в новом ПК по-прежнему поддерживает большинство, если не все, вызовы функций прерывания BIOS, определенные IBM для IBM AT (представленного в 1984 году), а также многие новые, а также расширения некоторых оригинальных ( например, расширенные диапазоны параметров), опубликованные различными другими организациями и совместными отраслевыми группами. Это, в сочетании с аналогичной степенью совместимости оборудования, означает, что большинство программ, написанных для IBM AT, все еще могут правильно работать на новом ПК сегодня, предполагая, что более высокая скорость выполнения приемлема (что обычно для всех, кроме игр, использующих Время на основе ЦП). Несмотря на значительные ограничения служб, доступ к которым осуществляется через прерывания BIOS, они оказались чрезвычайно полезными и устойчивыми к технологическим изменениям.
СОДЕРЖАНИЕ
Назначение вызовов BIOS
Вызовы прерывания BIOS выполняют функции аппаратного управления или ввода-вывода, запрошенные программой, возвращают программе информацию о системе или выполняют и то, и другое. Ключевым элементом назначения вызовов BIOS является абстракция: вызовы BIOS выполняют обычно определенные функции, а конкретные детали того, как эти функции выполняются на конкретном оборудовании системы, инкапсулируются в BIOS и скрыты от программы. Так, например, программе, которая хочет читать с жесткого диска, не нужно знать, является ли жесткий диск приводом ATA , SCSI или SATA (или ранее - приводом ESDI , либо приводом MFM или RLL с возможно, контроллер Seagate ST-506 , возможно, один из нескольких типов контроллеров Western Digital или другой проприетарный контроллер другой марки). Программе нужно только идентифицировать определенный BIOS номер диска, к которому она хочет получить доступ, и адрес сектора, который она должна читать или записывать, и BIOS позаботится о переводе этого общего запроса в конкретную последовательность требуемых элементарных операций. для выполнения задачи через конкретное оборудование контроллера диска, подключенное к этому диску. Программа избавлена от необходимости знать, как управлять на низком уровне каждым типом жесткого диска (или видеоадаптера, или интерфейса порта, или периферийных устройств часов реального времени), к которым может потребоваться доступ. Это и упрощает программирование операционных систем и приложений, и уменьшает размер программ, уменьшая дублирование программного кода, поскольку функции, включенные в BIOS, не нужно включать в каждую программу, которая в этом нуждается; Вместо этого в программы включены относительно короткие вызовы BIOS. (В операционных системах, где не используется BIOS, служебные вызовы, предоставляемые самой операционной системой, обычно выполняют ту же функцию и цель.)
BIOS также освобождает разработчиков компьютерного оборудования (в той степени, в которой программы написаны для использования исключительно BIOS) от необходимости поддерживать точную совместимость оборудования со старыми системами при разработке новых систем, чтобы поддерживать совместимость с существующим программным обеспечением. Например, аппаратное обеспечение клавиатуры на IBM PCjr работает совсем иначе, чем аппаратное обеспечение клавиатуры на более ранних моделях ПК IBM, но для программ, которые используют клавиатуру только через BIOS, эта разница почти незаметна. (Хорошим примером другой стороны этой проблемы является то, что значительная часть программ для ПК, используемых на момент выпуска PCjr, не использовала клавиатуру исключительно через BIOS, поэтому IBM также включила в PCjr аппаратные функции для эмуляции как работает оригинальное аппаратное обеспечение клавиатуры IBM PC и IBM PC XT . Эмуляция оборудования неточна, поэтому не все программы, которые пытаются напрямую использовать аппаратное обеспечение клавиатуры, будут правильно работать на PCjr, но все программы, которые используют только службы клавиатуры BIOS, будут .)
Вызов BIOS: программные прерывания BIOS
Операционные системы и другое программное обеспечение взаимодействуют с программным обеспечением BIOS для управления установленным оборудованием через программные прерывания. Программное прерывание - это особая разновидность общей концепции прерывания. Прерывание - это механизм, с помощью которого ЦП может быть направлен на то, чтобы остановить выполнение основной программы и вместо этого немедленно выполнить специальную программу, называемую процедурой обслуживания прерывания (ISR). После завершения ISR ЦП продолжает выполнение основной программы. В процессорах x86, когда происходит прерывание, ISR для вызова находится в таблице адресов начальной точки ISR (называемых «векторами прерывания») в памяти: Таблица векторов прерываний (IVT). Прерывание вызывается по номеру его типа, от 0 до 255, и номер типа используется в качестве индекса в таблице векторов прерываний, и в этом индексе в таблице находится адрес ISR, который будет запущен в ответ на прерывание. Программное прерывание - это просто прерывание, которое запускается программной командой; поэтому программные прерывания функционируют как подпрограммы, с той разницей, что программе, которая выполняет вызов программного прерывания, не требуется знать адрес ISR, а только номер прерывания. Это дает преимущества модульности, совместимости и гибкости конфигурации системы.
Программное обеспечение BIOS обычно возвращается вызывающему абоненту с кодом ошибки в случае неудачи или с кодом состояния и / или запрошенными данными в случае успеха. Сами данные могут иметь размер от одного бита или до 65 536 байтов целых необработанных секторов диска (максимум, который может поместиться в один сегмент памяти реального режима). BIOS многократно расширялся и улучшался на протяжении многих лет многими различными корпоративными организациями, и, к сожалению, результатом этого развития является то, что не все функции BIOS, которые можно назвать, используют согласованные соглашения для форматирования и передачи данных или для отчетности о результатах. Некоторые функции BIOS сообщают подробную информацию о состоянии, в то время как другие могут даже не сообщать об успехе или неудаче, а просто молча возвращаются, оставляя вызывающему объекту предположить успех (или проверить результат каким-либо другим способом). Иногда также может быть сложно определить, поддерживается ли конкретный вызов функции BIOS на определенном компьютере или каковы ограничения параметров вызова на этом компьютере. (Для некоторых недопустимых номеров функций или допустимых номеров функций с недопустимыми значениями ключевых параметров - особенно с ранней версией IBM BIOS - BIOS может ничего не делать и возвращать без кода ошибки; тогда это [неудобная, но неизбежная] ответственность вызывающий абонент либо избегает этого случая, не выполняя такие вызовы, либо положительно проверяет ожидаемый эффект вызова, а не предполагает, что вызов был эффективным. одна версия BIOS от определенного поставщика может быть недействительной в более ранней или другой версии BIOS от того же поставщика или в версии BIOS - любого относительного возраста - от другого поставщика.)
Поскольку в вызовах прерывания BIOS используется передача параметров на основе регистров ЦП, вызовы ориентированы на выполнение из языка ассемблера и не могут выполняться напрямую из большинства языков высокого уровня (HLL). Однако язык высокого уровня может предоставлять библиотеку подпрограмм-оболочек, которые переводят параметры из формы (обычно на основе стека), используемой языком высокого уровня, в форму на основе регистров, требуемую BIOS, а затем обратно в соглашение о вызовах HLL после BIOS возвращается. В некоторых вариантах C вызовы BIOS могут выполняться с использованием встроенного языка ассемблера в модуле C. (Поддержка встроенного языка ассемблера не является частью стандарта ANSI C, но является расширением языка; поэтому модули C, использующие встроенный язык ассемблера, менее переносимы, чем чистые стандартные модули C.)
Вызов прерывания
Вызов прерывания может быть выполнен с помощью инструкции языка ассемблера INT x86 . Например, чтобы вывести символ на экран с помощью прерывания BIOS 0x10, можно выполнить следующие инструкции языка ассемблера x86:
Таблица прерываний
Список общих классов прерываний BIOS можно найти ниже. Обратите внимание, что некоторые BIOS (особенно старые) не реализуют все эти классы прерываний.
INT 18h : выполнить BASIC
INT 18h традиционно перешли к реализации Cassette BASIC (предоставляемой Microsoft), хранящейся в дополнительных ПЗУ . Этот вызов обычно вызывается, если BIOS не может идентифицировать какие-либо тома загрузочного диска при запуске.
В то время, когда в 1981 году был выпущен оригинальный IBM PC (тип машины IBM 5150), ключевой особенностью был BASIC в ПЗУ. Современные популярные персональные компьютеры, такие как Commodore 64 и линейка Apple II, также имели Microsoft Cassette BASIC в ПЗУ (хотя Commodore переименовал их лицензионную версию в Commodore BASIC), поэтому на значительной части предполагаемого рынка IBM PC требовал BASIC для конкуренции. Как и в других системах, ROM BASIC IBM PC служил примитивной бездисковой операционной системой, позволяя пользователю загружать, сохранять и запускать программы, а также писать и уточнять их. (Оригинальный ПК IBM был также единственной моделью ПК от IBM, которая, как и его два вышеупомянутых конкурента, включала аппаратное обеспечение интерфейса кассеты. Базовая модель ПК IBM имела только 16 Кбайт ОЗУ и не имела дисковых накопителей [ любого типа ], поэтому кассета интерфейс и BASIC в ПЗУ были важны для того, чтобы можно было использовать базовую модель. ПК IBM с объемом ОЗУ менее 32 КБ не может загружаться с диска. Из пяти микросхем ПЗУ по 8 КБ в исходном ПК IBM, общим объемом 40 КБ, четыре содержат BASIC, и только один содержит BIOS; когда установлено только 16 KiB RAM, ROM BASIC составляет более половины всей системной памяти [4/7, если быть точным].)
Компания Digital Rainbow 100 B INT 18h называла свой BIOS, несовместимый с IBM BIOS. Turbo Pascal , Turbo C и Turbo C ++ перепрофилировали INT 18 для выделения памяти и подкачки. Другие программы также повторно использовали этот вектор в своих целях.
Перехватчики BIOS
В системах DOS IO.SYS или IBMBIO.COM перехватывают INT 13 для обнаружения смены гибких дисков, отслеживания вызовов форматирования, исправления ошибок границ DMA и решения проблем в BIOS ROM IBM "01/10/84" с кодом модели 0xFC перед первый звонок.
Обход BIOS
Многие современные операционные системы (например, Linux и Windows NT ) обходят вызовы прерывания BIOS после запуска, ядро ОС переключает ЦП в защищенный режим или длительный режим при запуске, предпочитая использовать свои собственные программы (например, драйверы ядра ) для управления подключенное оборудование напрямую. Причина этого заключалась прежде всего в том, что эти операционные системы запускают процессор в защищенном режиме или в длительном режиме, тогда как для вызова прерывания BIOS требуется переключение в реальный режим или нереальный режим или использование режима Virtual 8086 . Реальный режим, нереальный режим и виртуальный режим 8086 работают медленно. Однако существуют также серьезные причины для безопасности, чтобы не переключаться в реальный режим, а код BIOS реального режима имеет ограничения как по функциональности, так и по скорости, что побуждает разработчиков операционных систем искать ему замену. Фактически, ограничения скорости BIOS сделали его обычным даже в эпоху DOS, чтобы программы обходили его, чтобы избежать ограничений производительности, особенно для отображения видеографики и быстрой последовательной связи. Проблемы с функциональностью BIOS включают ограничения в диапазоне определенных функций, несогласованность в подмножествах этих функций, поддерживаемых на разных компьютерах, и различия в качестве BIOS (то есть некоторые BIOS являются полными и надежными, другие сокращены и содержат ошибки). Взяв дело в свои руки и не полагаясь на BIOS, разработчики операционных систем могут устранить некоторые риски и сложности, с которыми они сталкиваются при написании и поддержке системного программного обеспечения. С другой стороны, поступая таким образом, разработчики берут на себя ответственность за предоставление программного обеспечения драйверов «на чистом железе» для каждой системы или периферийного устройства, с которыми они намерены работать в своей операционной системе (или за побуждение производителей оборудования предоставлять эти драйверы). Таким образом, должно быть очевидно, что компактные операционные системы, разработанные с небольшим бюджетом, будут склонны интенсивно использовать BIOS, в то время как большие операционные системы, созданные огромными группами инженеров-программистов с большими бюджетами, чаще предпочитают писать свои собственные драйверы вместо использования BIOS, то есть , даже без учета проблем совместимости BIOS и защищенного режима.
3. ОБРАБОТКА ПРЕРЫВАНИЙ В ЗАЩИЩЁННОМ РЕЖИМЕ
Механизм обработки прерываний в защищённом режиме сильно отличается от механизма реального режима. До сих пор мы ничего не говорили о прерываниях, в приведённом выше примере программы перед переходом в защищённый режим мы просто замаскировали все прерывания. Однако такой способ "решения" проблемы прерываний подходит не всегда.
В этой главе мы расскажем вам о том, как надо работать с прерываниями в защищённом режиме и приведём соответствующий пример программы. Вы научитесь обрабатывать в защищённом режиме не только программные прерывания, но и аппаратные, что необходимо, в частности, для создания драйверов.
В главе 4 первой книги первого тома серии "Библиотека системного программиста", который называется "Операционная система MS-DOS", мы подробно рассказали об особенностях обработки прерываний в реальном режиме.
Напомним только основные моменты.
В реальном режиме имеются программные и аппаратные прерывания. Программные прерывания инициируются командой INT, аппаратные - внешними событиями, асинхронными по отношению к выполняемой программе. Обычно аппаратные прерывания инициируются аппаратурой ввода/вывода после завершения выполнения текущей операции.
Кроме того, некоторые прерывания зарезервированы для использования самим процессором - прерывания по ошибке деления, прерывания для пошаговой работы, немаскируемое прерывание и т.д.
Для обработки прерываний в реальном режиме процессор использует таблицу векторов прерываний. Эта таблица располагается в самом начале оперативной памяти, т.е. её физический адрес - 00000.
Таблица векторов прерываний реального режима состоит из 256 элементов по 4 байта, таким образом её размер составляет 1 килобайт. Элементы таблицы - дальние указатели на процедуры обработки прерываний. Указатели состоят из 16-битового сегментного адреса процедуры обработки прерывания и 16-битового смещения. Причём смещение хранится по младшему адресу, а сегментный адрес - по старшему.
Когда происходит программное или аппаратное прерывание, текущее содержимое регистров CS, IP а также регистра флагов FLAGS записывается в стек программы (который, в свою очередь, адресуется регистровой парой SS:SP). Далее из таблицы векторов прерываний выбираются новые значения для CS и IP, при этом управление передаётся на процедуру обработки прерывания.
Перед входом в процедуру обработки прерывания принудительно сбрасываются флажки трассировки TF и разрешения прерываний IF. Поэтому если ваша процедура прерывания сама должна быть прерываемой, вам необходимо разрешить прерывания командой STI. В противном случае, до завершения процедуры обработки прерывания все прерывания будут запрещены.
Завершив обработку прерывания, процедура должна выдать команду IRET, по которой из стека будут извлечены значения для CS, IP, FLAGS и загружены в соответствующие регистры. Далее выполнение прерванной программы будет продолжено.
В защищённом режиме все прерывания разделяются на два типа - обычные прерывания и исключения (exception - исключение, особый случай).
Обычное прерывание инициируется командой INT (программное прерывание) или внешним событием (аппаратное прерывание). Перед передачей управления процедуре обработки обычного прерывания флаг разрешения прерываний IF сбрасывается и прерывания запрещаются.
Исключение происходит в результате ошибки, возникающей при выполнении какой-либо команды, например, если команда пытается выполнить запись данных за пределами сегмента данных или использует для адресации селектор, который не определён в таблице дескрипторов. По своим функциям исключения соответствуют зарезервированным для процессора внутренним прерываниям реального режима. Когда процедура обработки исключения получает управление, флаг IF не изменяется. Поэтому в мультизадачной среде особые случаи, возникающие в отдельных задачах, не оказывают влияния на выполнение остальных задач.
В защищённом режиме прерывания могут приводить к переключению задач. О задачах и мультизадачности мы будем говорить в следующей главе.
Теперь перейдём к рассмотрению механизма обработки прерываний и исключений в защищённом режиме.
Таблица прерываний защищённого режима
Обработка прерываний и исключений в защищённом режиме по аналогии с реальным режимом базируется на таблице прерываний. Но таблица прерываний защищённого режима является таблицей дескрипторов, которая содержит так называемые вентили прерываний, вентили исключений и вентили задач.
Формат элементов дескрипторной таблицы прерываний IDT показан на рис. 12.
Рис. 12. Формат элементов дескрипторной таблицы прерываний IDT.
Где располагается дескрипторная таблица прерываний IDT?
Её расположение определяется содержимым 5-байтового внутреннего регистра процессора IDTR. Формат регистра IDTR полностью аналогичен формату регистра GDTR, для его загрузки используется команда LIDT. Так же, как регистр GDTR содержит 24-битовый физический адрес таблицы GDT и её предел, так и регистр IDTR содержит 24-битовый физический адрес дескрипторной таблицы прерываний IDT и её предел.
Регистр IDTR обычно загружают перед переходом в защищённый режим. Разумеется, это можно сделать и потом, находясь в защищённом режиме. Однако для этого программа должна работать в привилегированном нулевом кольце.
Исключения в защищённом режиме
Для обработки особых ситуаций - исключений - разработчики процессора i80286 зарезервировали 31 номер прерывания. В таблице 3 приведён полный список зарезервированных прерываний защищённого режима.
Таблица 4. Зарезервированные прерывания защищённого режима.
00h | Ошибка при выполнении команды деления. |
01h | Прерывание для пошаговой работы, используется отладчиками. |
02h | Немаскируемое прерывание. |
03h | Прерывание по точке останова для отладчиков. |
04h | Переполнение, генерируется командой INTO, если установлен флаг OF. |
05h | Генерируется при выполнении машинной команды BOUND, если проверяемое значение вышло за пределы заданного диапазона. |
06h | Недействительный код операции, или длина команды больше 10 байт. |
07h | Отсутствие арифметического сопроцессора. |
08h | Двойная ошибка, вырабатывается в том случае, если при обработке исключения возникло ещё одно исключение. Если во время обработки этого прерывания возникает третье исключение, процессор переходит в состояние отключения, что приводит к перезапуску процессора. |
09h | Превышение сегмента арифметическим сопроцессором. |
0Ah | Недействительный сегмент состояния задачи TSS. |
0Bh | Отсутствие сегмента. Вырабатывается при попытке использовать для адресации дескриптор, у которого бит присуствия сегмента в памяти P сброшен в 0. Это прерывание используется для реализации механизма виртуальной памяти. В этом случае по прерыванию 0Bh операционная система может выполнить подкачку отсутствующего сегмента в память. |
0Ch | Исключение при работе со стеком. Может возникать в случае отсутствия сегмента стека в памяти или в случае переполнения (антипереполнения) стека. |
0Dh | Исключение по защите памяти. Возникает при любых попытках получения доступа к сегментам памяти, если программа обладает недостаточным уровнем привилегий. |
0Eh | Отказ страницы для процессоров i80386 или i80486, зарезервировано для i80286. |
0Fh | Зарезервировано. |
10h | Исключение сопроцессора. |
11h - 1Ah | Зарезервированы. |
Перед тем, как передать управление обработчику исключения, для многих зарезервированных прерываний процессор помещает в стек 16-битовый код ошибки. Этот код ошибки программа может проанализировать и тем самым получить некоторую дополнительную информацию об ошибке.
Формат кода ошибки приведён на рис. 13.
Рис. 13. Формат кода ошибки процессора i80286.
Поле индекса содержит индекс дескриптора, при обращении к которому произошла ошибка. Поле I, равное 1, означает, что этот индекс относится к таблице IDT. В этом случае произошла ошибка при обработке прерывания или исключения.
Если бит I равен 0, поле TI выбирает таблицу дескрипторов (GDT или LDT) по аналогии с соответствующим полем селектора.
Бит EXT устанавливается в том случае, когда ошибка произошла не в результате выполнения текущей команды, а по внешним относительно выполняемой программы причинам. Например, при обработке аппаратного прерывания от устройства ввода/вывода произошло обращение к отсутствующему в памяти сегменту (у которого в дескрипторе сброшен бит присутствия P).
- 08h - двойная ошибка;
- 0Ah - недействительный TSS;
- 0Bh - отсутствие сегмента в памяти;
- 0Ch - исключение при работе со стеком;
- 0Dh - исключение по защите памяти.
Заметим, что аналога коду ошибки для зарезервированных прерываний в реальном режиме нет.
Кроме того, новым при обработке прерываний в защищённом режиме является свойство повторной запускаемости исключений. Свойством повторной запускаемости обладают не все исключения.
Что такое повторная запускаемость?
Поясним это на конкретном примере. Пусть в нашей системе реализована виртуальная память. Программа в некоторый момент времени обратилась к отсутствующему в оперативной памяти сегменту, выдав какую-либо команду, например MOV или ADD.
Возникло исключение 0Bh - отсутствие сегмента в памяти. Обработчик этого исключения, входящий в состав операционной системы выполнил свопинг соответствующего сегмента в оперативную память. Что дальше? А дальше было бы неплохо повторить выполнение прерванной команды!
Это можно сделать, так как для всех повторно запускаемых исключений (кроме 03h - прерывание по точке останова и 04h - переполнение) в стек включается адрес не следующей за прерванной командой, а адрес первого байта команды, которая вызвала исключение. Выполнив команду IRET, программа обработки исключения вновь передаст управление прерванной команде.
- 01h - прерывание для пошаговой работы;
- 08h - двойная ошибка;
- 09h - превышение сегмента сопроцессором;
- 0Dh - исключение по защите памяти;
- 10h - исключение сопроцессора.
Обработка аппаратных прерываний
Но в защищённом режиме номера от 08h до 0Fh зарезервированы для обработки исключений!
К счастью, имеется простой способ перепрограммирования контроллера прерываний на любой другой диапазон номеров векторов аппаратных прерываний. Например, аппаратные прерывания можно расположить сразу за прерываниями, зарезервированными для обработки исключений.
После возврата процессора в реальный режим необходимо восстановить состояния контроллера прерываний. Если при подготовке к возврату в реальный режим мы записали в CMOS-память байт состояния отключения со значением 5, после сброса BIOS сам перепрограммирует контроллер прерываний для работы в реальном режиме и нам не надо об этом беспокоиться. В противном случае программа должна установить правильные номера для аппаратных прерываний реального режима.
Следующая программа, которую мы вам представим, выполняет все необходимые действия, связанные с обработкой прерываний и исключений в защищённом режиме.
Наша первая программа (листинг 1) работала в защищённом режиме с запрещёнными прерываниями. Она как бы пролетала через неизведанное с завязанными глазами и сразу же возвращалась в хорошо освоенный реальный режим.
Теперь же программа имеет возможность "осмотреться" и может реагировать на такие события, как прерывания от клавиатуры и таймера. Кроме того, в случае возникновения исключений вам будет выдана некоторая диагностика, включающая код исключения, код ошибки и содержимое регистров процессора на момент возникновения исключения.
Таблица IDT содержит дескрипторы для обработчиков исключений и аппаратных прерываний. Вентили исключений содержат ссылки на программы с именами exc_00. exc_1F. Вслед за вентилями исключений в таблице IDT следуют вентили аппаратных прерываний. Из них задействованы только IRQ0 и IRQ1 - прерывания от таймера и клавиатуры.
Те аппаратные прерывания, которые нас не интересуют, приводят к выдаче в контроллеры прерывания команды конца прерывания. Для таких прерываний предусмотрены заглушки - процедуры с именами dummy_iret0 и dummy_iret1. Первая заглушка относится к первому контроллеру прерывания, вторая - ко второму.
Вслед за вентилями аппаратных прерываний мы поместили в таблицу IDT вентиль программного прерывания int 30h, предназначенного для организации взаимодействия с клавиатурой на манер прерывания BIOS INT 16h. При выдаче прерывания int 30h вызывается процедура с именем Int_30h_Entry.
После запуска программа переходит в защищённый режим и размаскирует прерывания от таймера и клавиатуры. Далее она вызывает в цикле прерывание int 30h (ввод символа с клавиатуры), и выводит на экран скан-код нажатой клавиши и состояние переключающих клавиш (таких, как CapsLock, Ins, и т.д.).
Если окажется нажатой клавиша ESC, программа выходит из цикла. Далее в тексте программы следует ряд команд, закрытых символом комментария. Эти команды приводят к исключению. Вы можете попробовать их работу, удалив соответствующий символ комментария. При возникновении исключения на экран будет выведена диагностика, о чём позаботится обработчик исключений.
Перед завершением работы программа устанавливает реальный режим процессора и стирает экран.
Обработчик аппаратного прерывания клавиатуры - процедура с именем Keyb_int. После прихода прерывания она выдаёт короткий звуковой сигнал, считывает и анализирует скан-код клавиши, вызвавшей прерывание. Скан-коды классифицируются на обычные и расширенные (для 101-клавишной клавиатуры). В отличие от прерывания BIOS INT 16h, мы для простоты не стали реализовывать очередь, а ограничились записью полученного скан-кода в глобальную ячейку памяти key_code. Причём прерывания, возникающие при отпускании клавиш игнорируются.
Запись скан-кода в ячейку key_code выполняет процедура Keyb_PutQ. После записи эта процедура устанавливает признак того, что была нажата клавиша - записывает значение 0FFh в глобальную переменную key_flag.
Программное прерывание int 30h опрашивает состояние key_flag. Если этот флаг оказывается установленным, он сбрасывается, вслед за чем обработчик int 30h записывает в регистр AX скан-код нажатой клавиши, в регистр BX - состояние переключающих клавиш на момент нажатия клавиши, код которой передан в регистре AX.
Для того чтобы не загромождать программу второстепенными деталями, мы не стали перекодировать скан-код в код ASCII, вы сможете при необходимости сделать это сами.
Обработчик прерываний таймера - процедура с именем Timer_int. Эта процедура примерно раз в секунду выдаёт звуковой сигнал, чем её действия и ограничиваются.
Процедура rdump выводит на экран содержимое регистров процессора и может быть использована для отладки программы.
Обратите внимание на использованный способ возврата процессора в реальный режим:
Регистр IDTR загружается нулями, следовательно, предел дескрипторной таблицы прерываний равен нулю. После этого мы выдаём команду программного прерывания. При обработке прерывания возникает исключение, так как регистр IDTR инициализирован неправильно. Но это исключение не может быть обработано по той же причине, что вызывает новое исключение. Теперь процессор переходит уже в состояние отключения и выполняет рестарт в реальном режиме. Что нам и требовалось получить!
Читайте также: