Функция самого низкого уровня для обработки пользовательского ввода - PullRequest
0 голосов
/ 26 октября 2019

Следующий код, который я прочитал, введен пользователем, аналогично функции gets на языке C.

section .text
global _start

_start:
    mov eax, 3          ; Read user input into str
    mov ebx, 0          ; |
    mov ecx, str        ; | <- destination
    mov edx, 100        ; | <- length
    int 80h             ; \

    mov eax, 1          ; Return
    mov ebx, 0          ; | <- return code
    int 80h             ; \

section .data
    str: times 100 db 0 ; Allocate buffer of 100 bytes

Я не уверен, как Linux обрабатывает мой код, но мне любопытно, какэтот код обрабатывается на машине Intel изначально (без какой-либо ОС). Насколько я знаю, прерывание 80h ищется в таблице векторов прерываний, и вызывается соответствующая кодовая функция. Но, на шаг ниже, как пишется этот код? Я хочу знать, как работает алгоритм, который обрабатывает такую ​​функциональность?

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

1 Ответ

2 голосов
/ 26 октября 2019

На самом низком уровне (голое железо) нет "функции", которую вы "вызываете" с инструкцией 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 для некоторых вещей.

  • https://github.com/torvalds/linux/tree/master/drivers/input/keyboard/ - это целый каталог драйверов клавиатуры для различных возможных аппаратных средств клавиатуры. (Думаю отдельно от USB).
  • https://github.com/torvalds/linux/tree/master/drivers/usb/host/ драйверы для хост-контроллеров USB. (Также другие каталоги в драйверах / usb /, такие как core/, содержат необходимый код)
  • https://github.com/torvalds/linux/blob/master/drivers/hid/usbhid/usbkbd.c Драйвер клавиатуры USB для Linux для Linux. (Существует стандартный общий протокол для USBУстройства HID, включая клавиатуры, поэтому большинство клавиатур и мышей могут «просто работать», не нуждаясь в специальных драйверах, даже в Windows, где базовая ОС не имеет драйверы для всего, что уже собрано / доступно.)

Это почти наверняка больше кода, чем вы хотите просмотреть, но это ответ на ваш вопрос.

...