Writing drivers for KolibriOS/ru: Difference between revisions
Jump to navigation
Jump to search
m (fix links) |
(Global update of the article, part 1e) |
||
(12 intermediate revisions by 4 users not shown) | |||
Line 1: | Line 1: | ||
{{DISPLAYTITLE:Пишем драйвер для КолибриОС}} | {{DISPLAYTITLE:Пишем драйвер для КолибриОС}} | ||
''' ВНИМАНИЕ: Данная статья находится в разработке и содержит множество устаревших и непроверенных данных. В данный момент использование этой статьи в качестве справочного материала не рекомендуется. ''' | |||
'''ПРЕДУПРЕЖДЕНИЕ: Данная статья устарела и переписывается. НЕ ИСПОЛЬЗУЙТЕ ЭТУ СТАТЬЮ.''' | |||
== Вступление == | == Вступление == | ||
'''Предупреждение 1.''' Прежде чем писать драйвер, хорошо подумайте, нельзя ли обойтись средствами прикладных [http://ru.wikipedia.org/wiki/API API], в частности, функций работы с оборудованием | '''Предупреждение 0.''' Данная статья описывает написание драйверов для основной ветки Колибри ОС и не включает в себя исторические моменты. Предыдущая версия статьи находится на форуме по [http://board.kolibrios.org/viewtopic.php?p=10987#p10987 ссылке]. | ||
'''Предупреждение 1.''' Прежде чем писать драйвер, хорошо подумайте, нельзя ли обойтись средствами прикладных [http://ru.wikipedia.org/wiki/API API], в частности, функций работы с оборудованием [[SysFn46/ru|46]] и [[SysFn62/ru|62]]. Во-первых, от ошибки в кривом приложении пострадает только это кривое приложение, а кривой драйвер способен без особого труда обрушить всю систему. Во-вторых, для приложений можно вылавливать баги в отладчике [[Mtdbg/ru|MTDBG]], обладающем определёнными возможностями, а для драйверов этот путь закрыт (разве что встроенный отладчик эмулятора [http://ru.wikipedia.org/wiki/Bochs Bochs], но он заведомо непригоден для отладки с реальным железом), так что единственным средством остаётся отладочный вывод на доску отладки [[Board/ru|BOARD]] со всеми недостатками. | |||
Далее допустим, что вы всё ещё читаете эту статью. Мало ли, может, вы всегда пишете код с первого раза безошибочно (чего только на свете не бывает), или в совершенстве владеете отладкой прямо в мозгу и считаете всякие отладочные средства баловством, или просто считаете, что настоящий мужчина (настоящая леди?) не боится трудностей и несколькими строчками текста вас не напугать. | Далее допустим, что вы всё ещё читаете эту статью. Мало ли, может, вы всегда пишете код с первого раза безошибочно (чего только на свете не бывает), или в совершенстве владеете отладкой прямо в мозгу и считаете всякие отладочные средства баловством, или просто считаете, что настоящий мужчина (настоящая леди?) не боится трудностей и несколькими строчками текста вас не напугать. | ||
Line 10: | Line 17: | ||
Вообще-то основная задача драйверов - обеспечить работу с оборудованием. Но поскольку эта статья ставит своей целью показать принципы работы драйверов, а для реализации основной задачи нужно много кода, работающего именно с железом и не имеющего никакого отношения к драйверной подсистеме, то процесс написания драйвера показан на следующем примере: создадим драйвер, перехватывающий и записывающий все обращения приложений к файловой системе, и управляющую программу, которая получает данные от драйвера и отображает их. В качестве средства разработки используется [http://ru.wikipedia.org/wiki/FASM FASM]. | Вообще-то основная задача драйверов - обеспечить работу с оборудованием. Но поскольку эта статья ставит своей целью показать принципы работы драйверов, а для реализации основной задачи нужно много кода, работающего именно с железом и не имеющего никакого отношения к драйверной подсистеме, то процесс написания драйвера показан на следующем примере: создадим драйвер, перехватывающий и записывающий все обращения приложений к файловой системе, и управляющую программу, которая получает данные от драйвера и отображает их. В качестве средства разработки используется [http://ru.wikipedia.org/wiki/FASM FASM]. | ||
Архив к статье находится здесь. | Архив к статье находится здесь. | ||
== Описание работы с драйверной подсистемой == | |||
Драйверная подсистема позволяет ядру загружать драйвера в формате PE и работать с ними. Для загрузки драйверов предусмотрено 2 системных вызова: 68.16 и 68.21, а для управления драйвером системный вызов 68.17. Драйвер должен иметь точку входа с функцией, которая должна возвращать хандлер структуры драйвера в случае успеха, и ноль в случае, если драйвер не инициализировался. Для работы драйвер импортирует некоторые функции ядра, которые экспортируются ядром как core.dll. | |||
== Драйвер == | == Драйвер == | ||
Специально для желающих написать свой драйвер предоставляется каркас драйвера. Он находится в | Специально для желающих написать свой драйвер предоставляется каркас драйвера. Он находится в git-репозитории в папке [https://git.kolibrios.org/KolibriOS/kolibrios/src/branch/main/drivers drivers]. Ну что же, давайте посмотрим [https://git.kolibrios.org/KolibriOS/kolibrios/src/branch/main/drivers/sceletone.asm sceletone.asm]): | ||
<asm> | <syntaxhighlight lang="asm"> | ||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
;; ;; | ;; ;; | ||
Line 25: | Line 36: | ||
;driver sceletone | ;driver sceletone | ||
format | format PE DLL native 0.05 | ||
entry START | |||
section '.flat' code readable writable executable | |||
include 'proc32.inc' | include 'proc32.inc' | ||
include ' | include 'struct.inc' | ||
</ | include 'macros.inc' | ||
include 'peimport.inc' | |||
</syntaxhighlight> | |||
Ну, "[http://ru.wikipedia.org/wiki/Copyright Copyright]" - он и есть копирайт, комментарий в следующей строке извещает нас, куда же мы собственно попали, это неинтересно. Дальше мы должны известить компилятор, какой формат мы хотим получить. Драйвера должны иметь формат | Ну, "[http://ru.wikipedia.org/wiki/Copyright Copyright]" - он и есть копирайт, комментарий в следующей строке извещает нас, куда же мы собственно попали, это неинтересно. Дальше мы должны известить компилятор, какой формат мы хотим получить. Драйвера должны иметь формат [https://en.wikipedia.org/wiki/Portable_Executable PE]. В общем, так должно быть для всех драйверов. Дальше идёт указание функции START как точки входа, которую вызовет ядро после загрузки драйвера. После этого объявляется секция ".flat", в которой будет располагаться код нашего драйвера, после объявления секции подключаем вспомогательные файлы. [https://git.kolibrios.org/KolibriOS/kolibrios/src/branch/main/drivers/proc32.inc proc32.inc] содержит макросы для определения и вызова стандартных процедур (<tt>proc/endp</tt>, <tt>stdcall/ccall/invoke/cinvoke</tt>, <tt>local</tt> для создания локальных переменных) и находится в той же папке, что и sceletone.asm. Его можно включать или не включать, макросы оттуда можно использовать или не использовать, в этой статье они используются, чтобы не усложнять восприятие (вообще говоря, при стремлении к максимальной эффективности использование макросов может повредить, но это тема отдельных жарких споров). [https://git.kolibrios.org/KolibriOS/kolibrios/src/branch/main/drivers/peimport.inc peimport.inc] содержит объявления для всех экспортируемых функций ядра. Загляните туда, ничего сложного там нет, просто куча стереотипных конструкций. На самом деле (в смысле того, как разрешается импорт при загрузке драйвера) список всех экспортируемых функций и данных ядра находится в файле {{#svn:/kernel/trunk/core/exports.inc|core/exports.inc}} (метка <tt>kernel_export</tt>), так что если вам как программисту ядра вдруг понадобиться что-нибудь своё экспортировать, лезьте туда (ну peimport.inc отредактируйте из вежливости к другим). | ||
Внимание! Здесь появляется возможность несовместимости: если вы используете какие-нибудь функции, которых (ещё или уже) нет в ядре, на которое вы рассчитываете, ядро откажется грузить ваш драйвер (ругнувшись на доске отладки нехорошим словом на ненашем языке "unresolved" с указанием имени функции). | Внимание! Здесь появляется возможность несовместимости: если вы используете какие-нибудь функции, которых (ещё или уже) нет в ядре, на которое вы рассчитываете, ядро откажется грузить ваш драйвер (ругнувшись на доске отладки нехорошим словом на ненашем языке "unresolved" с указанием имени функции). | ||
Line 37: | Line 53: | ||
Ну что же, идём дальше: | Ну что же, идём дальше: | ||
<asm> | <syntaxhighlight lang="asm"> | ||
DEBUG equ 1 ; for debug output in board | |||
API_VERSION equ 0 ;version api this driver | |||
STRIDE equ 4 ;size of row in devices table | |||
SRV_GETVERSION equ 0 ; number function for get api version | |||
</syntaxhighlight> | |||
Это просто объявление констант | |||
<asm> | <syntaxhighlight lang="asm"> | ||
proc START c, state:dword, cmdline:dword | |||
cmp [state], 1 | |||
jne .exit | |||
.entry: | |||
push esi | |||
if DEBUG | |||
mov esi, msgInit | |||
invoke SysMsgBoardStr | |||
end if | |||
call detect | |||
pop esi | |||
test eax, eax | |||
jz .fail | |||
invoke RegService, my_service, service_proc | |||
ret | |||
.fail: | |||
.exit: | |||
xor eax, eax | |||
ret | |||
endp | |||
</syntaxhighlight> | |||
</ | |||
Выше мы создали функцию START, о которой уже говорилось ранее. Данная функция принимает 2 аргумента: state и cmdline и возвращает хэндлер драйвера, полученный при вызове RegService. Если эта функция вернёт 0, то это будет означать, что драйвер по какой-то причине не может работать(либо нет нужного оборудования, с которым бы драйвер работал, либо его что-то не устраивает и чтобы не создавать ошибок, драйвер завершает работу). Параметр cmdline это командная строка в ascii кодировке, state это действие, которое требует от этой функции ядро. Сейчас есть 2 значения этого аргумента: DRV_ENTRY передаваемое при старте драйвера и DRV_EXIT передаваемое при завершении работы драйвера. Эти значения определены в файле {{#svn:/drivers/macros.inc|macros.inc}}. В этом коде вызываются 2 функции импортированные из ядра: SysMsgBoardStr и RegService, функции ядра имеют разные соглашения о вызовах, в одних параметры передаются через стек, в других через регистры. Описание соглашения о вызовах функций можно найти в файле {{#svn:/kernel/trunk/core/exports.inc|exports.inc}} в комментарии возле экспортируемой функции. | |||
Процедура <tt>START</tt> - это процедура, которая вызывается системой при загрузке драйвера и при завершении работы. В первом случае она должна инициализировать драйвер, во втором - наоборот. О ней речь пойдёт чуть позже. | Процедура <tt>START</tt> - это процедура, которая вызывается системой при загрузке драйвера и при завершении работы. В первом случае она должна инициализировать драйвер, во втором - наоборот. О ней речь пойдёт чуть позже. | ||
Line 84: | Line 102: | ||
Последняя порция констант | Последняя порция констант | ||