Writing drivers for KolibriOS/ru: Difference between revisions
No edit summary |
(update manual. 1/5 part) |
||
Line 17: | Line 17: | ||
== Драйвер == | == Драйвер == | ||
Специально для желающих написать свой драйвер предоставляется каркас драйвера. Он находится в svn-репозитории вместе с ядром, точнее, в папке {{#svn:/kernel/trunk/drivers|svn://kolibrios.org/kernel/trunk | Специально для желающих написать свой драйвер предоставляется каркас драйвера. Он находится в svn-репозитории вместе с ядром, точнее, в папке {{#svn:/kernel/trunk/drivers|svn://kolibrios.org/kernel/trunk/drivers}}. Ну что же, давайте посмотрим ({{#svn:/kernel/trunk/drivers/sceletone.asm|sceletone.asm из #450|450}}): | ||
<syntaxhighlight lang="asm"> | <syntaxhighlight lang="asm"> | ||
Line 29: | Line 29: | ||
;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", в которой будет располагаться код нашего драйвера, после объявления секции подключаем вспомогательные файлы. {{#svn:/drivers/proc32.inc|proc32.inc}} содержит макросы для определения и вызова стандартных процедур (<tt>proc/endp</tt>, <tt>stdcall/ccall/invoke/cinvoke</tt>, <tt>local</tt> для создания локальных переменных) и находится в той же папке, что и {{#svn:/drivers/sceletone.asm|sceletone.asm}}. Его можно включать или не включать, макросы оттуда можно использовать или не использовать, в этой статье они используются, чтобы не усложнять восприятие (вообще говоря, при стремлении к максимальной эффективности использование макросов может повредить, но это тема отдельных жарких споров). {{#svn:/drivers/peimport.inc|peimport.inc}} содержит объявления для всех экспортируемых функций ядра. Загляните туда, ничего сложного там нет, просто куча стереотипных конструкций. На самом деле (в смысле того, как разрешается импорт при загрузке драйвера) список всех экспортируемых функций и данных ядра находится в файле {{#svn:/kernel/trunk/core/exports.inc|core/exports.inc}} (метка <tt>kernel_export</tt>), так что если вам как программисту ядра вдруг понадобиться что-нибудь своё экспортировать, лезьте туда (ну и {{#svn:/drivers/peimport.inc|peimport.inc}} отредактируйте из вежливости к другим). | ||
Внимание! Здесь появляется возможность несовместимости: если вы используете какие-нибудь функции, которых (ещё или уже) нет в ядре, на которое вы рассчитываете, ядро откажется грузить ваш драйвер (ругнувшись на доске отладки нехорошим словом на ненашем языке "unresolved" с указанием имени функции). | Внимание! Здесь появляется возможность несовместимости: если вы используете какие-нибудь функции, которых (ещё или уже) нет в ядре, на которое вы рассчитываете, ядро откажется грузить ваш драйвер (ругнувшись на доске отладки нехорошим словом на ненашем языке "unresolved" с указанием имени функции). | ||
Line 42: | Line 47: | ||
<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 98: | ||
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"> |
Revision as of 12:55, 5 December 2022
ПРЕДУПРЕЖДЕНИЕ: Данная статья устарела и нуждается в обновлении/переписывании. Сейчас ядро использует для драйверов формат PE вместо MS COFF.
Вступление
Предупреждение 1. Прежде чем писать драйвер, хорошо подумайте, нельзя ли обойтись средствами прикладных API, в частности, функций работы с оборудованием 46 и 62. Во-первых, от ошибки в кривом приложении пострадает только это кривое приложение, а кривой драйвер способен без особого труда обрушить всю систему. Во-вторых, для приложений можно вылавливать баги в отладчике MTDBG, обладающем определёнными возможностями, а для драйверов этот путь закрыт (разве что встроенный отладчик эмулятора Bochs, но он заведомо непригоден для отладки с реальным железом), так что единственным средством остаётся отладочный вывод на доску отладки BOARD со всеми недостатками.
Далее допустим, что вы всё ещё читаете эту статью. Мало ли, может, вы всегда пишете код с первого раза безошибочно (чего только на свете не бывает), или в совершенстве владеете отладкой прямо в мозгу и считаете всякие отладочные средства баловством, или просто считаете, что настоящий мужчина (настоящая леди?) не боится трудностей и несколькими строчками текста вас не напугать.
Предупреждение 2. Драйвера, естественно, тесно связаны с ядром. А в ядро КолибриОС вносятся изменения несколько раз в неделю. Разумеется, большинство изменений никак не касается драйверной подсистемы, но иногда добавляются/исчезают/изменяются важные системные функции, экспортируемые драйверам. Поэтому если вы возьмёте и скомпилируете прилагаемый к статье код, то, возможно, он прямо в таком виде работать не будет. Так что внимательно читайте текст - я постараюсь выделить по возможности все причины неработоспособности в будущем и требуемые модификации. Прилагаемый к статье код рассчитан на ревизию {{#svn_rev:450}}, последнюю на момент написания этих строк (в дистрибутиве 0.6.5.0 работать в таком виде не будет).
Вообще-то основная задача драйверов - обеспечить работу с оборудованием. Но поскольку эта статья ставит своей целью показать принципы работы драйверов, а для реализации основной задачи нужно много кода, работающего именно с железом и не имеющего никакого отношения к драйверной подсистеме, то процесс написания драйвера показан на следующем примере: создадим драйвер, перехватывающий и записывающий все обращения приложений к файловой системе, и управляющую программу, которая получает данные от драйвера и отображает их. В качестве средства разработки используется FASM. Архив к статье находится здесь.
Описание работы с драйверной подсистемой
Драйверная подсистема позволяет загружать драйвера в формате PE и работать с ними. Для загрузки драйверов в ядре придусмотрено 2 сисфункции 68.16 и 68.21 а для управления драйвером сисфункция 68.17. Драйвер должен иметь экспортируемую функцию START, которая должна возвращать хандлер стуктуры драйвера в случае успеха, и ноль в случае, если драйвер не загружен. Для работы с ядром драйверу нужно импортировать некоторые функции ядра, которые экспортируются ядром как core.dll.
Драйвер
Специально для желающих написать свой драйвер предоставляется каркас драйвера. Он находится в svn-репозитории вместе с ядром, точнее, в папке {{#svn:/kernel/trunk/drivers|svn://kolibrios.org/kernel/trunk/drivers}}. Ну что же, давайте посмотрим ({{#svn:/kernel/trunk/drivers/sceletone.asm|sceletone.asm из #450|450}}):
<syntaxhighlight lang="asm">
- ;;
- Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;;
- Distributed under terms of the GNU General Public License ;;
- ;;
- driver sceletone
format PE DLL native 0.05 entry START
section '.flat' code readable writable executable include 'proc32.inc' include 'struct.inc' include 'macros.inc' include 'peimport.inc'
</syntaxhighlight>
Ну, "Copyright" - он и есть копирайт, комментарий в следующей строке извещает нас, куда же мы собственно попали, это неинтересно. Дальше мы должны известить компилятор, какой формат мы хотим получить. Драйвера должны иметь формат PE. В общем, так должно быть для всех драйверов. Дальше идёт указание функции START как точки входа, которую вызовет ядро после загрузки драйвер