Board.KolibriOS.org

Official KolibriOS board
It is currently Sat May 25, 2019 11:03 pm

All times are UTC+03:00




Post new topic  Reply to topic  [ 33 posts ]  Go to page 1 2 3 Next
Author Message
PostPosted: Sat Apr 07, 2007 1:18 pm 
Offline
Kernel Developer
User avatar

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

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


Top
   
 Post subject:
PostPosted: Sat Apr 07, 2007 5:22 pm 
Offline
Kernel Developer

Joined: Wed Mar 08, 2006 6:25 pm
Posts: 3952
Есть два дополнения.

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

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

Code:
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 коды внутренних ошибок драйвера


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


Top
   
 Post subject:
PostPosted: Sat Apr 07, 2007 6:59 pm 
Offline

Joined: Thu Jan 25, 2007 4:45 pm
Posts: 135
diamond, спасибо за интересную статью.


Top
   
 Post subject:
PostPosted: Sat Apr 07, 2007 7:39 pm 
Offline
Kernel Developer
User avatar

Joined: Mon Nov 28, 2005 8:00 pm
Posts: 1601
Serge
Спасибо, будет исправлено (к понедельнику).


Top
   
 Post subject:
PostPosted: Sat Apr 07, 2007 10:08 pm 
Offline
Kernel Developer

Joined: Wed Mar 08, 2006 6:25 pm
Posts: 3952
diamond
Хорошая статья, но есть ещё замечание.
По собственному опыту я бы переписал вызов драйвера в mainloop
Code:
           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 и страниц памяти на присутствие/запись/право доступа. Сейчас передав неправильный указатель можно обрушить всю систему.


Top
   
 Post subject:
PostPosted: Mon Apr 09, 2007 5:59 pm 
Offline
Kernel Developer
User avatar

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


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


Top
   
 Post subject:
PostPosted: Tue Apr 10, 2007 7:33 am 
Offline
Kernel Developer

Joined: Wed Mar 08, 2006 6:25 pm
Posts: 3952
diamond

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

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

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

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


Last edited by Serge on Wed Sep 28, 2011 4:16 pm, edited 1 time in total.

Top
   
 Post subject:
PostPosted: Wed Apr 11, 2007 6:01 pm 
Offline
Kernel Developer
User avatar

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


Top
   
 Post subject:
PostPosted: Sat Apr 21, 2007 11:32 am 
Offline
Kernel Developer
User avatar

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


Top
   
 Post subject:
PostPosted: Mon Apr 23, 2007 5:19 pm 
Offline
Kernel Developer
User avatar

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


Top
   
 Post subject:
PostPosted: Fri May 11, 2007 2:05 pm 
Offline

Joined: Fri Mar 03, 2006 1:53 pm
Posts: 42
Кто как и когда эти драйверы запускает?

Я скомпилировал текст
Code:
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 , но никакого эффекта не увидел.


Top
   
 Post subject:
PostPosted: Fri May 11, 2007 2:34 pm 
Offline

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


Top
   
 Post subject:
PostPosted: Fri May 11, 2007 5:23 pm 
Offline

Joined: Fri Mar 03, 2006 1:53 pm
Posts: 42
k@sTIg@r wrote:
Есть 2 варианта.


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


Top
   
Display posts from previous:  Sort by  
Post new topic  Reply to topic  [ 33 posts ]  Go to page 1 2 3 Next

All times are UTC+03:00


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Limited