Int86, int86x программное прерывание

Имеют ли основные приложения Windows NT доступ к программным прерываниям x86 (например, int 19)?

Скажем, я хочу написать приложение или драйвер, который работает в режиме NT NT (например, использует только функции NTDLL.DLL и запускается при запуске ntoskrnl.exe.

Будет ли это приложение иметь доступ к прерываниям x86? IE, могу ли я написать код следующим образом:

И верните его обратно в меню загрузки? Или это еще не разрешено даже в режиме ядра?

Нет. Есть кое-что неправильное в том, что вы просите.

Прежде всего, «Нативные приложения» (те, которые связаны только с NTDLL.dll), все еще являются пользовательскими режимами (Ring 3). Они не находятся в режиме ядра (Ring 0) — у них нет дополнительных привилегий, поскольку это касается процессора/оборудования. Они не запускаются автоматически при запуске ядра.

Во-вторых, то, о чем вы спрашиваете (например, int 19h — Bootstrap loader), это 16-битные вызовы BIOS, а не только обычные прерывания x86. Поскольку система работает в защищенном режиме, даже ядро не может их вызывать.

В какой-то момент процесса загрузки при переключении в защищенный режим ядро устанавливает свою собственную таблицу векторов прерываний (IVT), которая по существу переопределяет ту, которую BIOS предоставил ранее для вызовов BIOS. Единственные записи в этой таблице, которые полезны для процесса пользовательского режима, — это int 3 для контрольных точек, а одно (число которого меня ускоряет) для системных вызовов старого стиля (в Linux это int 80h ).

Прерывания INT

Циклы

Один из типов программных конструкций, который может быть построен с помощью условных переходов — это цикл. Цикл это ничего более, чем блок кода, который заканчивается условным переходом так, что этот код может выполняться постоянно, до тех пор, пока не выполнится условие окончания.

Циклы используются для обработки массивов, проверки статуса портов ввода-вывода, пока не будет достигнуто определенное состояние, очистки блоков памяти, чтения строк с клавиатуры, вывода строк на экран и т.п. Циклы — это основа для обработки чего-либо, что требует повторяющихся действий. Поэтому они часто используются, и Ассемблер предоставляет несколько специальных инструкций для циклов: LOOP, LOOPE, LOOPNE и JCXZ. В начале посмотрим LOOP. Предположим, что Вы хотите распечатать 17 символов строки TestString. Вы можете сделать это

TestString DB ‘this is a test. ‘

MOV bx,OFFSET TestString

MOV dl,[bx] ;взять следующий символ

INC bx ;указать следующий символ

MOV AH,2 ;# функции DOS для вывода

INT 21h ;вызов DOS для печати символа

DEC CX ;уменьшить счетчик

JNZ PrINTStringLOOP ;делать следующий символ

Однако есть лучший способ. Мы отмечали, как Вы помните, что CX особенно полезен в циклах. Здесь

делает то же, что и

но делает быстрее и на байт короче. Когда Вам нужен цикл, который повторяется до тех пор, пока счетчик не достигнет нуля, загрузите счетчик в CX и используйте инструкцию LOOP.

Если необходим цикл с более сложным условием окончания, чем простое уменьшение счетчика то можно воспользоваться LOOPE и LOOPNE.

LOOPE делает то же самое, что и LOOP за исключением того, что LOOPE будет заканчивать цикл либо, если счетчик в CX достиг 0, либо если флаг нуля установлен в 1. (Вспомним, что флаг нуля устанавливается в 1, если последний арифметический результат был 0, или если 2 операнда последнего сравнения были неравны.) Подобно, LOOPNE будет заканчивать цикл, если счетчик в CX достиг 0, либо если флаг нуля установлен в 0.

Допустим, Вы хотите в цикле читать символы с клавиатуры до тех пор, пока не будет нажат ВВОД или пока не будет считано 128 символов. Следующий пример использует для этого LOOPNE:

KeyBuffer DB 128 DUP (?)

MOV bx,OFFSET KeyBuffer

MOV AH,1 ; функции DOS для ввода

INT 21h ;вызов DOS для чтения символа

MOV [bx],AL ;сохранить символ

INC bx ;указать на следующий символ

CMP AL,0dh ;нажат ВВОД?

LOOPne KeyLOOP ;если нет, взять следующий символ,

;если не считано 128 символов

LOOPE так же известна как LOOPZ, и LOOPNE так же известна, как LOOPNZ (аналогично JE/JZ).

С циклами связана еще одна инструкция — JCXZ. JCXZ осуществляет переход, только если CX=0; это полезный способ, проверять CX в начала цикла. Например, следующий код в котором BX указывает на блок байт, устанавливаемых в 0, а CX содержит длину блока, использует JCXZ для пропуска цикла, если CX — 0:

jCXz SkipLOOP ;если CX=0, ничего не делать

MOV BYTE PTR [SI],0 ;установить следующий байт в 0

INC SI ;указать на следующий байт

LOOP CLearLOOP ;обнулить следующий символ, если он есть

Почему нужно пропустить цикл, если CX — 0? Если Вы выполните LOOP с CX=0, то CX уменьшится до 0FFFFh и инструкция LOOP выполнит переход на метку назначения. Тогда цикл выполнится более 65,535 раз. Когда Вы устанавливали CX в 0, Вы подразумевали, что нет байтов для обнуления, а получилось 65,536 байт. JCXZ позволяет Вам проверить этот случай быстро и эффективно.

Несколько интересных примечаний к инструкциям цикла. Во-первых, запомните, что инструкция цикла как и условный переход, может выполнять переход на метку только в диапазоне 128 байт, до или после инструкции цикла. Циклы, больше 128 байт, требуют использования техники «Условный переход перед безусловным переходом», описанный в разделе «Условные переходы». Во-вторых, важно представлять, что ни одна инструкция цикла не действует на флаги. Это означает, что LOOP LOOPTop не точно такая же, как

поскольку DEC изменяет флаги переполнения, знака, нуля, дополнительного переноса и четности в то время, как LOOP не изменяет флаги вообще. По той же причине инструкция DEC не точно такая же, как

поскольку SUB изменяет флаг переноса, а инструкция DEC нет.

Конечно, это небольшие отличия, но они важны для понимания набора инструкций при программировании на ассемблере.

10.4 Процедуры в языке ассемблера

При составлении и вызове подпрограмм необходимо следить за тем, чтобы команды CALL и RET действовали согласовано — были одновременно близкими или дальними. В Ассемблере эта проблема снимается, если подпрограмму описать как процедуру. Процедуры имеют следующий вид:

имя_процедуры PROC [NEAR или FAR]

Хотя в директиве PROC после имени процедуры не ставится двоеточие, это имя относится к меткам и его можно указывать в командах перехода, в частности в команде CALL, когда надо вызвать процедуру. Это же имя должно быть повторено в директиве ENDP, заканчивающей описание процедуры. Предложения между этими двумя директивами образуют тело процедуры (подпрограмму). Имя процедуры является фактически меткой первой из команд тела, поэтому данную команду не надо специально метить.

Если в директиве PROC указан параметр NEAR или он вообще не указан, то такая процедура считается «близкой» и обращаться к ней можно только из того сегмента команд, где она описана. Дело в том, что ассемблер будет заменять все команды CALL, где указано имя данной процедуры, на машинные команды близкого перехода с возвратом, а все команды RET внутри процедуры — на близкие возвраты. Если же в директиве PROC указан параметр FAR, то это «дальняя» процедура: все обращения к ней и все команды RET внутри нее рассматриваются ассемблером как дальние переходы. Обращаться к этой процедуре можно из любых сегментов команд. Таким образом, достаточно лишь указать тип процедуры (близкая она или дальняя), всю же остальную работу возьмет на себя ассемблер: переходы на нее и возвраты из нее будут автоматически согласованы с этим типом. В этом главное (и единственное) достоинство описания подпрограмм в виде процедур. (Отметим, что метки и имена, описанные в процедуре, не локализуются в ней.)

Например, вычисление AX:=SIgn(AX) можно описать в виде процедуры следующим образом:

SIng proc far ;дальняя процедура

Илон Маск рекомендует:  Пример класса captcha на php (2)

JE sgn1 ;AX=0 — перейти к sgn1

MOV AX,1 ;AX:=1 (флаги не изменились!)

JG sgn1 ;AX>0 — перейти к sgn1

sgn1: RET ;дальний возврат

Возможный пример обращения к этой процедуре:

cALl SIgn ;дальний вызов

Типичная схема организации подпрограмм, обычно используемая трансляторами с языков высокого уровня для реализации процедур и функций (в частности, рекурсивных), следующая.

При обращении к подпрограмме в стек заносятся параметры для нее и адрес возврата, после чего делается переход на ее начало:

PUSH param1 ;запись 1-го параметра в стек

PUSH paramk ;запись последнего (k-го) параметра в стек

CALL SUBr ;переход с возвратом на подпрограмму

(Замечание: если необходимо вычислить параметр или если его размер отличен от слова, тогда для записи параметра в стек нужно, конечно, несколько команд, а не одна.)

Команда INT прерывает обработку программы, передает управление в DOS или BIOS для определенного действия и затем возвращает управление в прерванную программу для продолжения обработки. Наиболее часто прерывание используется для выполнения операций ввода или вывода.

Для выхода из программы на обработку прерывания и для последующего возврата команда INT выполняет следующие действия:

— уменьшает указатель стека на 2 и заносит в вершину стека содержимое флагового регистра;

— очищает флаги TF и IF;

— уменьшает указатель стека на 2 и заносит содержимое регистра CS в стек;

— уменьшает указатель стека на 2 и заносит в стек значение командного указателя;

— вычисляет адрес вектора прерывания, умножая тип_прерывания на 4;

— загружает второе слово вектора прерываний в регистр CS;

— загружает в IP первое слово вектора прерывания;

— обеспечивает выполнение необходимых действий;

— восстанавливает из стека значение регистра и возвращает управление в прерванную программу на команду, следующую после INT.

Этот процесс выполняется полностью автоматически. Необходимо лишь определить сегмент стека достаточно большим для записи в него значений регистров.

В данной главе рассмотрим два типа прерываний: команду BIOS INT 10H и команду DOS INT 21H для вывода на экран и ввода с клавиатуры. В последующих примерах в зависимости от требований используются как INT 10H так и INT 21H.

Не нашли то, что искали? Воспользуйтесь поиском:

Лучшие изречения: Сдача сессии и защита диплома — страшная бессонница, которая потом кажется страшным сном. 8773 — | 7145 — или читать все.

188.64.174.135 © studopedia.ru Не является автором материалов, которые размещены. Но предоставляет возможность бесплатного использования. Есть нарушение авторского права? Напишите нам | Обратная связь.

Отключите adBlock!
и обновите страницу (F5)

очень нужно

интереснейшее программное прерывание

Добавлено через 3 минуты
а вот скелет подпрограммы № 2, которая должна будет обрабатывать ошибки (это нам дал преподаватель):
Подпрограмму обработки ошибок можно организовать как програм-
му обработки прерывания. В следующем примере выводится сообщение о
причине ошибки, по значению кода возврата в регисте AX.

Вызов такой программы обработки ошибочных ситуаций делает-
ся командой int n2, например

Добавлено через 3 минуты
вопросов у меня несколько:
1. как подключить подпрограмму № 2 к главной программе
2. как прочитать число с экрана (и как дать возможность пользователю ввести это число)
3. как вывести результаты подсчета факториала в подпрограмме

Добавлено через 16 минут
приведу нить своих суждений:
как я понял,слово может принимать значения от 0 до 65535 или от -32768 до 32767. Два слова образуют двойное слово (обозначается DWORD или DD). Двойное слово может принимать значения от 0 до 4294967295 или от -2147483648 до 2147483647
в моем случае, вводимое значение (N) имеет формат- слово, и имеет знак, поэтому принимает значения
от -32768 до 32767, но мы должны отсечь отрицальное число, поэтому оно будет от 0 до 32 767
а результат F (F=N!) имеет формат — двойное слово, поэтому принимает значения -2147483648 до 2147483647, но мы должны вызвать прерывание, если значение не выходит за размер слова, т.е. в пределах 32 767.
вывод такой: результат F должен быть в промежутке от 32 767 до 2 147 483 647

я правильно рассуждаю? если что-то неверно, прошу поправить меня

Виртуальный режим (V86)

Читайте также:

  1. AOA в режима предупреждения
  2. B. С использованием режима J3E или H3E, что удобнее.
  3. F51.2 . Расстройство режима сна-бодрствования неорганической природы
  4. F51.2 . Расстройство режима сна-бодрствования неорганической природы.
  5. II. Режим работы школы во время организации образовательного процесса.
  6. III. Организация гарнизонной службы в период особого противопожарного режима
  7. III. Режим Б. Муссолини и католическая церковь.
  8. III. Санитарно-эпидемиологические требования к режиму эксплуатации бассейнов и аквапарков.
  9. IV. ПРОПУСКНОЙ РЕЖИМ
  10. VI Режим у контрольних пунктах
  11. VIII. НОРМЫ ТЕХНОЛОГИЧЕСКОГО РЕЖИМА
  12. X. Собор Нотр-Дам де Пари — Центральный портик. Ход процесса — Цвета и режимы Великого Делания.

При виртуальном режиме происходит эмуляция (моделирование) функционирования процессора 8086 в операционной среде основного процессора i386+, работающего в многозадачном режиме, как одной из его возможных задач. При этом обеспечивается ряд средств защиты и возможность страничной организации памяти. Поэтому, часто говорят, что в режиме V86 микропроцессор работает как виртуальный процессор 8086, состоящий из аппаратных средств основного процессора i386+, системного программного обеспечения, представляющего собой специальную программу – монитор V86 в среде основной ОС и прикладного программного обеспечения, разработанного для 8086. Сам же монитор V- режима (V86) представляет собой программу Р — режима, которая выполняется на уровне привилегий 0.

Таким образом, задача в виртуальном режиме имеет сложную структуру: обычная пользовательская программа 8086, вложена в программу-монитор V86, которая, в свою очередь, является задачей защищенного режима базового процессора i386+, выполняемой на уровне привилегий 0. Но программа-монитор V86 может, например, эмулировать средства MS-DOS. В этом случае структура задачи получается еще более сложной: обычная задача 8086 вкладывается в MS-DOS, а сама MS-DOS – в монитор V86.

Все задачи виртуального режима V86 выполняются на уровне привилегий 3 (CPL = 3). Этим виртуальный режим отличается от реального режима работы, при котором всем программам представляется наиболее привилегированный уровень CPL = 0. Поскольку в виртуальном режиме, как и в реальном дескрипторы не используются, то в нем определены только некоторые способы защиты, а именно:

· При использовании страничной организации памяти, в случае нарушения правил доступа к странице, реализуется прерывание типа 14 (отказ страницы).

· При появлении привилегированных команд, которые выполняются в защищенном режиме только при CPL = 0 (команды LIDT, LGDT, LMSW, CLTS, HLT, а также команда MOV при обращении к регистрам управления, тестирования и отладки), возникает прерывание типа 13 (нарушение защиты).

· При появлении других привилегированных команд (LLDT, SIDT, LTR, STR, LAR, LSL, ARPL, VERR, VERW) возникает прерывание типа 6 (неразрешенный код команды).

В задачу, работающую в виртуальном режиме можно войти двумя основными способами:

1. Выполнив команду CALL или JMP к TSS, у которого установлен в единичное состояние бит VM (Virtual Machine) в копии регистра EFLAGS, т.е. осуществить операцию переключения задач.

2. При возврате из прерывания, с использованием команды IRET в ходе выполнения программы с CPL=0, если в загружаемом при этом из стека содержимом регистра EFLAGS, бит VM установлен в 1.

Выход процессора из режима V86 может произойти только при обработке прерываний или исключений, когда:

1. В результате прерывания происходит переход на процедуру с высшим уровнем привилегий (с CPL=0). При этом текущее состояние регистра EFLAGS заносится в стек, а бит VM сбрасывается в 0. То есть, вызванная процедура будет выполняться в защищенном режиме.

2. Прерывание вызывает переключение задачи командой JMP на задачу с TSS, в котором значение бита VM, в поле EFLAGS, равно нулю.

Следует заметить, что в процессорах определен также расширенный виртуальный режим EV86 (Extended V86), который включается дополнительной установкой в единичное состояние бита VME в управляющем регистре CR4. В этом режиме процессор имеет возможность управлять флагом IF (с помощью инструкций CLI и STI) не только при IOPL=3, но и при IOPL

На программные прерывания, вызываемые иным образом, а также особые случаи и внешние аппаратные прерывания карта перенаправления действия не оказывает.

В заключение приведем таблицу возможностей рассмотренных режимов работы процессоров i386+, при выполнении задач (табл.IX.1).

Возможности различных режимов процессоров i386+.

Возможности Реальный режим (PE = 0) Защищенный режим (PE=1)
V – режим (VM=1) P- режим (VM=0)
32-битные регистры общего назначения Доступны Недоступны Доступны
Многозадачность Нет Нет Возможна
Защита: — сегментов — страниц — ввода/вывода Нет Нет Есть
Нет Есть Есть
Нет Возможна Есть
Уровни привилегий 0, 1, 2, 3
Доступность команд МП i386+ Не все Не все Все
Память: — общий объем — размер сегмента — страничный механизм — виртуальная память
До 1 Мбайт До 1 Мбайт До 4 (64) Гбайт
До 64 Кбайт До 64 Кбайт До 4 Гбайт
Нет Возможен Возможен
Нет Нет Возможна
Илон Маск рекомендует:  Что такое код winhlp

Дата добавления: 2015-06-28 ; Просмотров: 821 ; Нарушение авторских прав? ;

Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет

BIOS, системные прерывания. int 11h, int 12h в С++ / C

Стоит задача получить информацию о компьютере, используя системное прерывание int 11h , которое записывает в регистр AX слово состояния (конфигурации). Доступ к прерываниям можно получить из заголовка dos.h , однако функция, обеспечивающая работу с прерыванием int86() была найдена только в библиотеках и хедерах компилятора за 1993 год, MS Visual 1.52 (1993 г) 16-битный, что мне не подходит, в виду наличия 64-битной ОС. Был написан следующий код:

который выводит на экран слово состояния в числовом виде, равном -14302 . И вроде все устраивает, но есть несколько но, которые не получилось решить:

  1. Компилируется этот код тоже только выше указанным компилятором (работаю VirtualBox с Win7 (32 bit)). Точнее, скомпилировать получилось еще в MS Visual C++ 2010 Express, а вот при запуске программы она вылетает и проблема в строчке int 11h
  2. Это магическое число -14302 является результатом также и на планшете (Windows 8.1, 32 bit). И на другом компьютере (WinXP, 32 bit).

Второе «но» наталкивает на мысли, что что-то работает неверно. Разве может быть одинаковым слово состояния на 3 абсолютно разных вычислительных устройствах (планшет, ноутбук, компьютер)?
Прошу советов по решению данной задачи.

Руководство по созданию ядра для x86-системы. Часть 2. Система ввода / вывода

В прошлой статье я писал о том, как создать простейшее x86-ядро, использующее GRUB, работающее в защищённом режиме и выводящее на экран строку. В этот раз мы подключим к ядру драйвер клавиатуры, который может считывать символы a–z и 0–9 с клавиатуры и выводить их на экран. Весь используемый код можно найти на GitHub.

Мы общаемся с устройствами ввода / вывода, используя I/O-порты. Эти порты — просто определённые адреса на шине ввода / вывода x86-системы. Операции чтения / записи на этих портах обрабатываются специальными инструкциями, встроенными в процессор.

Чтение из портов и запись в них

Доступ к портам I/O можно получить, используя инструкции in и out , являющиеся частью набора инструкций x86.

В read_port номер порта принимается как аргумент. Когда компилятор вызывает вашу функцию, он пушит все её аргументы в стек. Аргумент копируется в регистр edx по указателю на стек. Регистр dx — это младшие 16 бит edx . Инструкция in читает из порта, номер которого хранится в dx , и помещает результат в al . Регистр al — это младшие 8 бит eax . Если вы помните, чему вас учили, то знаете, что возвращаемые функциями значения передаются через регистр eax register. Таким образом, read_port обеспечивает чтение из I/O-портов.

write_port очень похожа. Мы принимаем два аргумента: номер порта и данные для записи. Инструкция out записывает данные в указанный порт.

Прерывания

Теперь, прежде чем мы продолжим писать какой-либо драйвер устройства, давайте разберемся, как процессор узнаёт о том, что устройство совершило действие.

Самое простое решение — это поллинг, постоянная проверка состояния устройства. По очевидным причинам это не самое практичное решение. Тут в дело вступают прерывания. Прерывание — это сигнал, посылаемый процессору аппаратным или системным обеспечением, который оповещает о событии. Используя прерывания, мы можем действовать только тогда, когда возникает интересующее нас прерывание.

1 июля – 3 декабря, онлайн, беcплатно

Устройство, называемое контроллером прерываний (Programmable Interrupt Controller, PIC), отвечает за обработку аппаратных прерываний и отправку их соответствующим системным прерываниям.

Когда на аппаратном обеспечении происходит какое-то событие, оно отправляет сигнал, называемый запросом прерывания, по свому специальному каналу на контроллер прерываний. Контроллер преобразует запрос в системное прерывание и отправляет его в процессор, где им занимается ядро.

Если бы у нас не было контроллера прерываний, то нам пришлось бы постоянно опрашивать все устройства на наличие произошедших событий.

Рассмотрим случай с клавиатурой. Она работает через I/O-порты 0x60 и 0x64 . Порт 0x60 передаёт данные (о нажатой клавише), а порт 0x64 — состояние. Однако нужно знать наверняка, когда и из какого порта читать данные.

Для этого отлично подходят прерывания. Когда происходит нажатие клавиши, клавиатура посылает сигнал на контроллер прерываний по линии IRQ1. Контроллер обладает значением offset , полученным во время его инициализации. Он добавляет номер входной линии к этому offset и получает число прерывания. Затем процессор обращается к специальной структуре данных, называющейся дескрипторной таблицей прерываний (Interrupt Descriptor Table, IDT), для передачи обработчику прерываний адреса, соответствующего числу прерывания.

После этого запускается код, расположенный по этому адресу, и обрабатывает исключение.

Настраиваем IDT

Мы реализуем IDT как массив структур IDT_entry . Мы обсудим то, как прерывание клавиатуры привязано к своему обработчику, позже. Сперва посмотрим, как работают контроллеры прерываний.

Современные x86-системы имеют два контроллера прерываний по 8 входных линий. Назовём их PIC1 и PIC2. PIC1 получает сигналы с IRQ0 до IRQ7, а PIC2 — с IRQ8 до IRQ15. PIC1 использует порт 0x20 для команд и 0x21 — для данных. PIC2 использует порт 0xA0 для команд и 0xA1 — для данных.

Контроллеры инициализируются 8-битными инициализирующими командными словами (Initialization command words, ICW). Подробный синтаксис этих команд можно изучить здесь.

В защищённом режиме первой командой, которую вы должны передать двум контроллерам прерываний, является инициализирующая команда ICW1 ( 0x11 ). Эта команда заставляет контроллер ждать поступления ещё трёх инициализирующих слов на порт данных.

Эти команды сообщают контроллерам следующее:

  • сдвиг (ICW2);
  • состояние подключения (master/slave) (ICW3);
  • дополнительную информацию об окружении (ICW4).

Вторая инициализирующая команда — это ICW2, которая записывает в порты данных каждого контроллера его сдвиг.

Контроллеры допускают каскадирование выводов и вводов, что настраивается командой ICW3, но мы не будем его использовать, поэтому установим все значения в ноль.

ICW4 устанавливает дополнительные параметры окружения. Мы заполним младший бит, чтобы сказать контроллерам, что мы работаем в режиме 80×86.

Та-дам! Контроллеры прерываний инициализированы!

У каждого контроллера есть внутренний 8-битный регистр, называющийся регистр масок прерывания (Interrupt Mask Register, IMR). Этот регистр хранит битмэп линий IRQ, идущих в контроллер. Если бит установлен, контроллер игнорирует запрос. Это означает, что мы можем включать и выключать любую линию IRQ, меняя соответствующее значение в IMR. Чтение из порта данных возвращает значение из IMR, а запись — задаёт это значение. В нашем коде мы отключаем все линии IRQ, чтобы позже включить ту, что соответствует клавиатуре.

Если линии IRQ включены, наши контроллеры могут получать идущие по ним сигналы и преобразовывать их в числа прерываний, добавляя сдвиг. Теперь нам нужно найти IDT такую, чтобы число прерывания для клавиатуры было привязано к адресу обработчика событий клавиатуры, который мы напишем.

Какое число прерывания должно соответствовать обработчику событий клавиатуры?

Клавиатура использует IRQ1. Это линия ввода 1 контроллера PIC1. Его сдвиг равен 0x20 . Для получения числа прерывания сложим 1 + 0x20 и получим 0x21 . Таким образом, адрес обработчика событий должен быть связан с прерыванием 0x21 в IDT.

Теперь нам нужно определить IDT для прерывания 0x21 . Мы привяжем это прерывание к функции keyboard_handler , которую запишем в ассемблерном файле.

Каждое значение в IDT состоит из 64 битов. В значении IDT для прерывания мы не храним адрес функции-обработчика целиком, а делим его на 2 части по 16 бит. Младшие биты хранятся в первых 16 битах значения IDT, а старшие 16 битов — в последних. Это сделано в целях совместимости с 286. Да, такие костыли от Intel можно встретить часто!

В значении IDT мы также должны задать тип — это нужно для того, чтобы поймать исключение. Нам также нужно передать коду ядра смещение. GRUB создаст для нас глобальную таблицу дескрипторов, каждое значение которое занимает 8 байт. Дескриптор кода ядра — это второй сегмент, поэтому его сдвиг равен 0x08 . Окно прерывания равно 0x8e . Оставшиеся посередине 8 бит должны быть заполнены нулями. Таким образом, мы заполнили значение IDT в соответствии с прерыванием клавиатуры.

Илон Маск рекомендует:  Что такое код signal

После того, как мы закончили все махинации с IDT, мы сообщаем процессору её адрес, используя инструкцию lidt , принимающую один операнд, который должен быть указателем на структуру дескрипторов, описывающую IDT.

Дескриптор достаточно прост. Он содержит размер IDT в байтах и её адрес. Для хранения значений я использовал массив, но вы можете воспользоваться структурой.

У нас есть указатель в переменной idt_ptr , который мы передаём в lidt , используя функцию load_idt() .

Кроме того, функция load_idt() включает прерывания, используя инструкцию sti .

Когда IDT настроена, мы можем включить линию IRQ клавиатуры, используя маску прерываний, о которой мы говорили ранее.

Функция обработки прерываний клавиатуры

Итак, наши прерывания клавиатуры привязаны к функции keyboard_handler через значение IDT для прерывания 0x21 . Каждый раз, когда мы нажимаем клавишу, мы можем быть уверены, что функция будет вызвана.

Эта функция просто вызывает другую функцию, написанную на Си, и возвращает значение, используя класс инструкций iret . Мы могли бы написать здесь весь необходимый код, но на Си писать безусловно приятнее. iret / iretd используются вместо ret при работе с прерываниями.

Сперва мы отправляем сигнал EOI (конец прерывания), записывая его в порт команд контроллера. Только после этого контроллер принимает следующие прерывания. Нам нужно читать два порта — порт данных 0x60 и порт команд / данных 0x64 .

Сперва мы читаем порт 0x64 для получения состояния. Если младший бит состояния равен 0 , то буфер пуст, и данных для чтения нет. В обратном случае мы читаем порт данных 0x60 . Этот порт даёт нам код каждой нажатой клавиши. Мы используем простой массив символов в файле keyboard_map.h для связывания кодов и символов.

В этой статье мы обрабатываем только строчные буквы и цифры. Конечно, можно настроить и обработку других клавиш, а также их сочетаний.

Вы можете собрать ядро и запустить его на реальной машине или в эмуляторе (QEMU) так же, как и в прошлой статье.

помогите с int86

Цитата (Andrey44 @ 31.1.2008, 10:51 )
и int64 — никогда не встречал
Цитата
typedef signed __int64 INT64;
Цитата (BorisVorontsov @ 31.1.2008, 13:25 )
Знакомься:

typedef signed __int64 INT64;

по моему было написано

Цитата (EnergoHokum @ 31.1.2008, 10:40 )
Может быть, потому, что он знает int64?
Цитата (Nerex @ 30.1.2008, 23:12)
Почему у меня компилятор Visual C++ 6.0 говорит что он не знает int86?

int86 — это не тип данных, а вызов команды int процессора

int86 — это не тип данных, а вызов команды int процессора

интереснейшее программное прерывание

Добавлено через 3 минуты
а вот скелет подпрограммы № 2, которая должна будет обрабатывать ошибки (это нам дал преподаватель):
Подпрограмму обработки ошибок можно организовать как програм-
му обработки прерывания. В следующем примере выводится сообщение о
причине ошибки, по значению кода возврата в регисте AX.

Вызов такой программы обработки ошибочных ситуаций делает-
ся командой int n2, например

Добавлено через 3 минуты
вопросов у меня несколько:
1. как подключить подпрограмму № 2 к главной программе
2. как прочитать число с экрана (и как дать возможность пользователю ввести это число)
3. как вывести результаты подсчета факториала в подпрограмме

Добавлено через 16 минут
приведу нить своих суждений:
как я понял,слово может принимать значения от 0 до 65535 или от -32768 до 32767. Два слова образуют двойное слово (обозначается DWORD или DD). Двойное слово может принимать значения от 0 до 4294967295 или от -2147483648 до 2147483647
в моем случае, вводимое значение (N) имеет формат- слово, и имеет знак, поэтому принимает значения
от -32768 до 32767, но мы должны отсечь отрицальное число, поэтому оно будет от 0 до 32 767
а результат F (F=N!) имеет формат — двойное слово, поэтому принимает значения -2147483648 до 2147483647, но мы должны вызвать прерывание, если значение не выходит за размер слова, т.е. в пределах 32 767.
вывод такой: результат F должен быть в промежутке от 32 767 до 2 147 483 647

я правильно рассуждаю? если что-то неверно, прошу поправить меня

Прерывания. В процессорах х86 используются аппаратные прерывания, программные преры­вания и исключения

В процессорах х86 используются аппаратные прерывания, программные преры­вания и исключения. Аппаратные прерывания были описаны выше; кроме того, к ним относится и специфичное (и неиспользуемое прикладными программами) прерывание SMI для входа в режим системного управления (SMM). Программные прерывания по сути прерываниями и не являются — это лишь короткая форма дальнего вызова ограниченного количества процедур, выполняемая инструкцией Int N (N=0-255). Программные прерывания, в частности, используются для вы­зовов сервисов BIOS и DOS. Исключения генерируются процессором и сопроцес­сором, когда при исполнении инструкций возникают особые условия (например, деление на ноль или срабатывание защиты). Исключения занимают векторы пре­рываний 0-31, которые частично пересекаются с векторами аппаратных преры­ваний ведущего контроллера и NMI, а также с векторами сервисов BIOS. В про­цессорах 8086/88 исключения назывались внутренними прерываниями, их было совсем мало. По мере «взросления» процессоров добавлялись новые исключения; исключениями особо богаты современные процессоры при работе в защищенном режиме. На исключениях строится защита и виртуальная память в многозадач­ных ОС защищенного режима.

В реальном режиме прерывания работают довольно просто, и их обработчики могут находиться в любом месте физически адресуемой памяти (ОЗУ или ПЗУ). В таблице прерываний, начинающейся с нулевого адреса, каждый вектор преры­ваний представляется дальним указателем на процедуру обработки (16-байтные смещение и сегмент). Внедрение собственных обработчиков прерываний пред­ставляет собой несложную задачу, если прерывание используется монопольно одним устройством и соответствующим ему единственным модулем ПО. В реаль­ном режиме любая программа может управлять флагом разрешения аппаратных прерываний; некорректное управление флагом может приводить к различным неприятностям — от сбоя системного времени до «зависания» компьютера.

В защищенном режиме прерывания работают гораздо сложнее. Таблица преры­ваний здесь содержит 8-байтные дескрипторы прерываний. Их обработчики долж­ны быть подключены к ядру ОС, постоянно присутствующему в физической па­мяти. Иначе возможна ситуация, когда, например, аппаратное прерывание вызовет обработчик, выгруженный в данный момент на диск менеджером виртуальной памяти. Обработка такого прерывания будет чрезвычайно долгой (потребуется подкачка страницы). Позволять любой программе управлять флагом разрешения прерываний для многозадачных ОС нельзя из соображений общей устойчивости системы. Сам процесс обработки прерываний (и исключений) в защищенном ре­жиме существенно отличается от прерываний реального режима, и в современных процессорах и ОС имеются средства виртуализации прерываний, о чем подроб-

476______ Глава 12. Архитектурные компоненты IBM PC-совместимого компьютера

нее можно прочитать в [6,7]. Заметим, что в ОС Windows 9x каждое окно MS-DOS представляет собой отдельную виртуальную машину с собственной таблицей пре­рываний «реального» вида, и работа с прерываниями в ней практически не отли­чается от работы в «чистой» MS-DOS. Для установки обработчиков прерываний, требуемых программам защищенного режима, используются вызовы специальных сервисов ОС, и обработчик оформляется особым образом в соответствии с согла­шениями этой ОС (не так, как для MS-DOS).

BIOS, системные прерывания. int 11h, int 12h в С++ / C

Стоит задача получить информацию о компьютере, используя системное прерывание int 11h , которое записывает в регистр AX слово состояния (конфигурации). Доступ к прерываниям можно получить из заголовка dos.h , однако функция, обеспечивающая работу с прерыванием int86() была найдена только в библиотеках и хедерах компилятора за 1993 год, MS Visual 1.52 (1993 г) 16-битный, что мне не подходит, в виду наличия 64-битной ОС. Был написан следующий код:

который выводит на экран слово состояния в числовом виде, равном -14302 . И вроде все устраивает, но есть несколько но, которые не получилось решить:

  1. Компилируется этот код тоже только выше указанным компилятором (работаю VirtualBox с Win7 (32 bit)). Точнее, скомпилировать получилось еще в MS Visual C++ 2010 Express, а вот при запуске программы она вылетает и проблема в строчке int 11h
  2. Это магическое число -14302 является результатом также и на планшете (Windows 8.1, 32 bit). И на другом компьютере (WinXP, 32 bit).

Второе «но» наталкивает на мысли, что что-то работает неверно. Разве может быть одинаковым слово состояния на 3 абсолютно разных вычислительных устройствах (планшет, ноутбук, компьютер)?
Прошу советов по решению данной задачи.

Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL
Цитата (jonie @ 31.1.2008, 21:54)