Board.KolibriOS.org

Официальный форум KolibriOS
Текущее время: Чт ноя 23, 2017 6:01 pm

Часовой пояс: UTC+03:00




Начать новую тему  Ответить на тему  [ 33 сообщения ]  На страницу 1 2 3 След.
Автор Сообщение
 Заголовок сообщения: Как писать драйвера
СообщениеДобавлено: Сб апр 07, 2007 1:18 pm 
Не в сети
Kernel Developer
Аватара пользователя

Зарегистрирован: Пн ноя 28, 2005 8:00 pm
Сообщения: 1601
Вот, написал статью, демонстрирующую программирование драйвера.
http://diamondz.land.ru/writedrv.htm
Приведённый там пример может быть полезен и безотносительно к обучению - написан фильтр, показывающий все обращения программ к файловой системе.

_________________
Ушёл к умным, знающим и культурным людям.


Вернуться к началу
 Заголовок сообщения:
СообщениеДобавлено: Сб апр 07, 2007 5:22 pm 
Не в сети
Kernel Developer

Зарегистрирован: Ср мар 08, 2006 6:25 pm
Сообщения: 3929
Есть два дополнения.

Это не обязательно, но желательно иметь функцию для получения версии API драйвера. Для этого зарезервирован ioctl.io_code=0

вот пример из недоделанного драйвера uart.

Код:
SRV_GETVERSION equ 0

; retval
;  ebx= service version
;  eax= error code
;    0= no error
;   -1= common error

align 4
init_uart:
           mov eax, 68
           mov ebx, 16
           mov ecx, szUart
           int 0x40

           mov [Uart], eax
           test eax, eax
           jz .fail

           push 0              ;storage for version
           mov eax, esp        ;eax= pointer to output buffer
           xor ebx, ebx

           push 4              ;.out_size
           push eax            ;.output
           push ebx            ;.inp_size
           push ebx            ;.input
           push SRV_GETVERSION ;.code
           push [Uart]         ;.handle

           mov eax, 68
           mov ebx, 17
           mov ecx, esp        ;address of IOCTL in app stack
           int 0x40
           add esp, 24         ;sizeof IOCTL
           pop ebx             ;load version
           ret
.fail:
           or eax, -1
           ret


68.16 получает логический номер драйвера и сохраняет его в переменной Uart. После чего в стеке формируется стрктура IOCTL. Чтобы избежать проблем в будущем рекомендую заполнять все поля структуры. В данном примере это происходит в обратном порядке. Последним в стек помещается логический номер драйвера после чего esp становится указателем на структуру IOCTL. После вызова стек восстанавливается командой add esp,24 а pop ebx загружает возвращённый драйвером номер версии.

Второе замечание по кодам ошибок.
Вызовы 68.17 возвращают в eax коды ошибок. Это 0 в случае успеха и ненулевое значение в случае неудачи, обычно -1 как признак общей ошибки, другие коды неопределены. Поэтому драйвер не должен использовать регистр eax для
возврата значений приложению. Все данные от драйвера должны возвращаться в буфере IOCTL.output

Кстати, есть смысл определить стандартные коды ошибок при вызовах 68.17 Например от -1 коды ошибок ядра: драйвер не установлен, неправильный логический номер драйвера и т.д. от +1 коды внутренних ошибок драйвера


Вернуться к началу
 Заголовок сообщения:
СообщениеДобавлено: Сб апр 07, 2007 5:36 pm 
diamond - очень захватывающая статья, в высоком и живом стиле. :) Думаю еще раз пять перечитаю, и на досуге отважусь с подобными экспериментами c колибри (0.6.5.0).


Вернуться к началу
   
 Заголовок сообщения:
СообщениеДобавлено: Сб апр 07, 2007 6:59 pm 
Не в сети

Зарегистрирован: Чт янв 25, 2007 4:45 pm
Сообщения: 135
diamond, спасибо за интересную статью.


Вернуться к началу
 Заголовок сообщения:
СообщениеДобавлено: Сб апр 07, 2007 7:39 pm 
Не в сети
Kernel Developer
Аватара пользователя

Зарегистрирован: Пн ноя 28, 2005 8:00 pm
Сообщения: 1601
Serge
Спасибо, будет исправлено (к понедельнику).


Вернуться к началу
 Заголовок сообщения:
СообщениеДобавлено: Сб апр 07, 2007 10:08 pm 
Не в сети
Kernel Developer

Зарегистрирован: Ср мар 08, 2006 6:25 pm
Сообщения: 3929
diamond
Хорошая статья, но есть ещё замечание.
По собственному опыту я бы переписал вызов драйвера в mainloop
Код:
           push 0              ;storage for output logsize
           mov eax, esp        ;eax= pointer to output data

           push 16*1024        ;logsize
           push logbuf         ;pointer to log buffer
           mov  ebx, esp       ;pointer to input data
           push 4              ;.out_size
           push eax            ;.output
           push 8              ;.inp_size
           push ebx            ;.input
           push 2              ;.code
           push [handle]       ;.handle

           mov eax, 68
           mov ebx, 17
           mov ecx, esp        ;address of IOCTL in app stack
           int 0x40
           add esp, 24+8       ;sizeof IOCTL+ptr_logbuf+log_size
           pop ecx             ;load output logsize

Так конечно длиннее и выглядит сложнее, но есть смысл рассматривать .input как указатель на структуру содержащую входные данные а .output на структуру содержащую выходные данные. В данном случае входные данные адрес logbuf и его размер, а выходные количество записанных байт. Если передаётся и возвращается только одно двойное слово всегда хочется сделать это в полях .input и .output. Но думаю что лучше так не делать потому что надо добавить в ядро проверку адресов .input и .output и страниц памяти на присутствие/запись/право доступа. Сейчас передав неправильный указатель можно обрушить всю систему.


Вернуться к началу
 Заголовок сообщения:
СообщениеДобавлено: Пн апр 09, 2007 5:59 pm 
Не в сети
Kernel Developer
Аватара пользователя

Зарегистрирован: Пн ноя 28, 2005 8:00 pm
Сообщения: 1601
Serge
Старые замечания учтены, статья обновлена, ссылка та же. Только у меня появился вопрос: номер версии для ioctl=0 следует возвращать в каком-то фиксированном формате или совершенно произвольном? (текущая реализации ядра это вообще игнорирует, но мало ли какие могут быть планы...) В первом случае, возможно, вместо банального dword имеет смысл стандартный формат с возможностью контроля совместимости версий?
По поводу последнего замечания: в статье .input и .output содержат действительно указатели, только на глобальные переменные, а не стековые, как в твоём примере. Конечно, если нужно посылать запросы из разных потоков многопоточной программы, нужен стек, но подобное встречается редко. Соответственно если вставить в ядро проверку на принадлежность приложению буферов, на которые указывают .input/.output, размера .inp_size/.outp_size, то разобранный в статье пример по-прежнему будет работать. А размер передаётся в поле .outp_size (причём как in/out - на входе в драйвер он содержит размер пользовательского буфера, на выходе - размер записанных данных), а иначе зачем вообще нужно это поле?


Вернуться к началу
 Заголовок сообщения:
СообщениеДобавлено: Вт апр 10, 2007 7:27 am 
diamond
Статья конечно интересная и полезная, однако у меня возник вопрос при прочтении - "Та организация, которую некоторые считают ругательным словом, не будет иметь претензии на формат заголовка?" Может быть, использовать другой более свободный вариант?
И еще подменять можно всю функцию целиком или подфункцию тоже можно?


Вернуться к началу
   
 Заголовок сообщения:
СообщениеДобавлено: Вт апр 10, 2007 7:33 am 
Не в сети
Kernel Developer

Зарегистрирован: Ср мар 08, 2006 6:25 pm
Сообщения: 3929
diamond

С этими версиями одна головная боль. Для ядра важно только старшее слово - версия драйверной модели так что младшее может хранить что угодно, например ревизию svn. Для звука там хранится текущая версия API а приложения получают диапазон версий SOUND_VERSION.

SOUND_VERSION equ 0x01000100 ;старшее слово - минимально совместимая, младшее - текущая версия.
version dd (4 shl 16) or (SOUND_VERSION and 0xFFFF)

Если есть идеи по формату и контролю версий, предлагай. У меня идеи уже закончились.

По поводу .input и .output. Глобальные или локальные конечно не важно. Если программа делает много разных вызовов размещение в стеке удобней и уменьшает размер кода. Дело в передаче параметров. Все поля ioctl для драйвера входные данные - указатель на структуру входных данных, размер структуры, указатель на структуру выходных данных, размер структуры.
То есть поля не предназначены для возврата значения. Сейчас все вызовы обрабатываются в контексте вызвавшего потока. Указатель на ioctl передаётся непосредственно. если способ передачи изменится и структура будет копироваться код перестанет работать.


Последний раз редактировалось Serge Ср сен 28, 2011 4:16 pm, всего редактировалось 1 раз.

Вернуться к началу
 Заголовок сообщения:
СообщениеДобавлено: Ср апр 11, 2007 6:01 pm 
Не в сети
Kernel Developer
Аватара пользователя

Зарегистрирован: Пн ноя 28, 2005 8:00 pm
Сообщения: 1601
Mario79
Думаю, не будет. Всё-таки базовым для MS COFF (и PE, между прочим) является COFF, а он изначально был под *nix.
Подфункцию подменять тоже можно. Самый простой способ - перехватить всю функцию и в начале обработчика проверить, вызвана ли нужная нам подфункция и если нет, то передать управление ядерному обработчику (в коде из статьи - командой jmp [oldfn70]).
Serge
Ну раз поля не предназначены для возврата значения, тогда надо немного изменить код. Будет исправлено.


Вернуться к началу
 Заголовок сообщения:
СообщениеДобавлено: Сб апр 21, 2007 11:32 am 
Не в сети
Kernel Developer
Аватара пользователя

Зарегистрирован: Пн мар 20, 2006 10:44 am
Сообщения: 557
[offtop]Добавь в статью её адресс, т.к. статья обновляется - всегда можно будет легко проверить соответствие сохранённой и web версий[/offtop]


Вернуться к началу
 Заголовок сообщения:
СообщениеДобавлено: Пн апр 23, 2007 5:19 pm 
Не в сети
Kernel Developer
Аватара пользователя

Зарегистрирован: Пн ноя 28, 2005 8:00 pm
Сообщения: 1601
Да я бы не сказал, что она обновляется - вот сейчас исправил последнее замечание Serge и никаких изменений в будущем не предвидится... А дата последнего обновления всегда указана на http://diamondz.land.ru


Вернуться к началу
 Заголовок сообщения:
СообщениеДобавлено: Пт май 11, 2007 2:05 pm 
Не в сети

Зарегистрирован: Пт мар 03, 2006 1:53 pm
Сообщения: 42
Кто как и когда эти драйверы запускает?

Я скомпилировал текст
Код:
format MS COFF

include 'proc32.inc'
include 'main.inc'
include 'imports.inc'

DEBUG            equ 1

OS_BASE          equ 0
new_app_base     equ 0x60400000
PROC_BASE        equ OS_BASE+0x0080000


struc IOCTL
{  .handle           dd ?
   .io_code          dd ?
   .input            dd ?
   .inp_size         dd ?
   .output           dd ?
   .out_size         dd ?
}

virtual at 0
  IOCTL IOCTL
end virtual

section '.flat' code readable align 16

proc START stdcall, state:dword

        mov    esi,msgStart
        call   boot_log
        mov esi, msgStart
        call SysMsgBoardStr
   jmp $
endp


version       dd 0x00030003

msgStart      db 'start...',13,10,0



Записал полученный объектник в каталог drivers , но никакого эффекта не увидел.


Вернуться к началу
 Заголовок сообщения:
СообщениеДобавлено: Пт май 11, 2007 2:34 pm 
Не в сети

Зарегистрирован: Ср фев 21, 2007 3:03 pm
Сообщения: 188
Есть 2 варианта.
1) В нужном месте в ядре вызываешь ф-цию load_driver , которая принимает один параметр - имя драйвера без .obj (загружает /rd/1/drivers/name.obj)
2) загружаешь драйвер программно с помощью 68.16(смотри подробное описание ф-ции).
Для начала советовал бы 2 вариант.


Вернуться к началу
 Заголовок сообщения:
СообщениеДобавлено: Пт май 11, 2007 5:23 pm 
Не в сети

Зарегистрирован: Пт мар 03, 2006 1:53 pm
Сообщения: 42
k@sTIg@r писал(а):
Есть 2 варианта.


В обоих случаях возвращается 0 в EAX.
С другими драйверами тоже.
Я вставлял диагностику при
stdcall load_driver, szHwMouse
в kernel\video\cursors.inc
возвращается 0.


Вернуться к началу
Показать сообщения за:  Поле сортировки  
Начать новую тему  Ответить на тему  [ 33 сообщения ]  На страницу 1 2 3 След.

Часовой пояс: UTC+03:00


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
Создано на основе phpBB® Forum Software © phpBB Limited
Русская поддержка phpBB