На самом низком уровне (голое железо) нет "функции", которую вы "вызываете" с инструкцией int xx
. int xx
может вызывать только другой код, работающий на ЦП, но не вызывать каких-либо особых событий.
Обращение к оборудованию подразумевает выполнение кода, который использует нагрузки или хранилища для генерации транзакций PCI / PCIe, или in
/ out
инструкции для доступа к месту ввода / вывода. (Или, по крайней мере, некоторый доступ к особым физическим адресам; на старых компьютерах это не обязательно был PCI, и несколько адресов MMIO на современных процессорах фактически не выходят из-под контроля, поэтому PCI на самом деле не задействован.)
Насколько я знаю, прерывание 80h ищется в таблице векторов прерываний, и вызывается соответствующая кодовая функция. Но, на шаг ниже, как пишется этот код?
Да, ядро Linux (написанное на C и ассемблере) настраивает IDT, чтобы пользовательское пространство int 80h
входило в ядро вего точка входа обработчика int80
.
int 80h
/ eax=3
в пользовательском пространстве просто отправляет функцию sys_read
в ядре Linux, которая реализует функцию / системный вызов POSIX read()
,(См. Что произойдет, если вы будете использовать 32-битный int 0x80 Linux ABI в 64-битном коде? , чтобы немного рассказать о стороне ядра этой диспетчеризации в таблице системных вызовов).
Представьте себе int 0x80
(или более эффективные инструкции sysenter
и syscall
) как способы вызова функции через границу привилегий. Вся магия (как вы уже догадались) в реализацииэтой функции внутри ядра и других функций, которые он вызывает. (И вся модель Unix «все это файл»; это тот же системный вызов, который вы использовали бы для чтения файла на диске.)
В вашем случае требуется аргумент дескриптора файла, в вашем случае stdin
= 0. Это просто файл, часто TTY или псевдо-tty, подключенный к эмулятору терминала, который обращается к серверу X11 для получения событий клавиатуры. Вы могли бы работать на текстовой консоли Linux (ctrl + alt + f2), и в этом случае ядро запускает эмулятор терминала с клавиатурным вводом, поступающим с любой физической клавиатуры (-ей), подключенной / подключенной. Или вы могли бы перенаправить ввод из любого типа файла.
Если я перенаправил ввод из /dev/input/by-id/usb-Logitech_USB_Receiver-if02-event-kbd
в моей системе, я могу получить некоторые необработанные события нажатия клавиш, но не в текстовом формате ASCII. (Вы можете безопасно sudo cat
этот файл; ввод по-прежнему поступает на ваш X-сервер , а также , чтобы вы могли контролировать его). Это более прямой способ общения с драйвером клавиатуры, но вы по-прежнему проходите через HID (Human Interface Device) Linux и подсистему событий, прежде чем вы на самом деле получите код, который обращается к хост-контроллеру USB, подключенному к вашей клавиатуре.
Ничего подобного нельзя сделать на голом металле ;вы бы использовали in
/ out
или MMIO для загрузки / сохранения, чтобы общаться с клавиатурой через контроллер хост-управления USB (например, eHCI или xHCI). https://wiki.osdev.org/Universal_Serial_Bus
(С эмуляцией BIOS клавиатуры PS / 2 или на старой машине с реальным контроллером клавиатуры PS / 2, вы могли бы общаться с этим гораздо легче. Различные программы, работающие в реальном режиме, напрямую взаимодействуют с аппаратным обеспечением, поэтому существуют более простые стандарты доступа к нему, часто с инструкциями in
и out
для известных номеров портов. Никакого перечисления шины PCI или чего-либо еще необходимого.
На современных ПК вы все еще можете это делать, но в основном это подделано программным обеспечением, фиксирующим доступ. Эмуляция BIOS по определению не голая металлическая. Только разработчики прошивок материнской платы действительно Программа «голый металл». Режим управления системой позволяет встроенному ПО устанавливать перехватчики, которые могут запускаться даже после загрузки ОС. К счастью, большинство систем ничего не делают / ничего из этого, хотя все еще существуют таблицы ACPI, которые ядро должно читать, а не проверять оборудование. напрямую.)
Если вы загружаете устаревший загрузчик , прошивка переключится обратно в реальный режим и настроит набор «сервисов BIOS», которые вы можете использовать через int 10h
и другие номера прерываний. Подобно тому, как вы работаете под ядром Linux, вы не близки к тому, чтобы разговаривать «напрямую» с реальным оборудованием;все детали драйвера устройства скрыты за стандартным API. https://wiki.osdev.org/BIOS
Если вы загружаете современный загрузчик UEFI, снова у вас есть стандартный API для доступа к экрану / клавиатуре с кодом «драйвера», предоставляемым микропрограммой. Это как минимальное ядро. https://wiki.osdev.org/UEFI
Как только загружается настоящее ядро, такое как Linux, у него есть драйверы устройств для реальных контроллеров USB . Если в BIOS была настроена эмуляция оборудования PS / 2, ядро заменяет / отключает это.
Как я уже сказал, этот код ядра Linux написан на C, с некоторыми встроенными упаковщиками asm для некоторых вещей.
Это почти наверняка больше кода, чем вы хотите просмотреть, но это ответ на ваш вопрос.