Writing drivers for KolibriOS/ru: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
(Global update of the article, part 1e) |
||
(7 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
{{DISPLAYTITLE:Пишем драйвер для КолибриОС}} | {{DISPLAYTITLE:Пишем драйвер для КолибриОС}} | ||
'''ПРЕДУПРЕЖДЕНИЕ: Данная статья устарела и | |||
''' ВНИМАНИЕ: Данная статья находится в разработке и содержит множество устаревших и непроверенных данных. В данный момент использование этой статьи в качестве справочного материала не рекомендуется. ''' | |||
'''ПРЕДУПРЕЖДЕНИЕ: Данная статья устарела и переписывается. НЕ ИСПОЛЬЗУЙТЕ ЭТУ СТАТЬЮ.''' | |||
== Вступление == | == Вступление == | ||
'''Предупреждение 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]] со всеми недостатками. | '''Предупреждение 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 14: | Line 20: | ||
== Описание работы с драйверной подсистемой == | == Описание работы с драйверной подсистемой == | ||
Драйверная подсистема позволяет загружать драйвера в формате PE и работать с ними. Для загрузки драйверов | Драйверная подсистема позволяет ядру загружать драйвера в формате 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]): | ||
<syntaxhighlight lang="asm"> | <syntaxhighlight lang="asm"> | ||
Line 29: | 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> | </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 42: | Line 54: | ||
<syntaxhighlight lang="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> | </syntaxhighlight> | ||
Это просто объявление | Это просто объявление констант | ||
<syntaxhighlight lang="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> | </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 91: | Line 105: | ||
DEBUG equ 1 | DEBUG equ 1 | ||
STRIDE equ 4 ;size of row in devices table | STRIDE equ 4 ;size of row in devices table | ||
</syntaxhighlight> | </syntaxhighlight> | ||
(из которых первая включает код отладочного вывода в блоках <tt>if DEBUG/end if | (из которых первая включает код отладочного вывода в блоках <tt>if DEBUG/end if</tt>, последняя нужна для красоты и ни для чего больше) и мы наконец-то переходим к изучению кода: | ||
<syntaxhighlight lang="asm"> | <syntaxhighlight lang="asm"> | ||
Line 1,153: | Line 1,165: | ||