Всем доброго вечера! Вот я практически добрался до такого момента, когда уже пора прощаться с R-Mode. И вот раз я покидаю R-Mode, то мне нужно будет написать два драйвера: драйвер для дисковода гибких дисков и драйвер клавиатуры. Проблема не понимания у меня заключается в том, что адрес, где будет лежать в памяти (в страничной памяти) драйвер, точно не известен. То есть драйвера будут загружать куда-то по адресу, ближе к ядру операционной системы. Но чёткого адреса нет. Тогда вот я и думаю, как же тогда проектировать такие драйвера в коде. Вот например буду я писать так драйвер: Код (Text): use64 org 0x0000000000000000 ; Код драйвера И таким образом у меня будет начинаться каждый драйвер. Но ведь этот драйвер потом может попасть на любую страничку, но точно не на страничку с индексом 0. В связи с этим будут рассчитаны не правильно смещения. Я вижу два вариант решения проблемы. ПЕРВЫЙ ВАРИАНТ Писать драйвера так, чтобы у них было своё адресное пространство процесса. То есть свои таблицы страниц, загрузка в CR3. ВТОРОЙ ВАРИАНТ Вводить какую-нибудь переменную: Код (Text): use64 org 0x0000000000000000 jmp startDriver driverAddress dq 0x0000000000000000 startDriver: ; Код драйвера При загрузке драйвера в память подставлять значение в поле driverAddress. А в самом коде драйвера делать обращения от базы driverAddress. В общем это то, что было в голове. Как делаете Вы?
s3dworld Драйвер грузится самой ОС, у него есть своя точка входа. ОС сама ищет точку входа, и передает ей управление.
s3dworld ну в винде же драйвера таблицу релокаций имеют, это и позволяет им загружаться по произвольным адресам. поэтому и в вашем случае надо сделать некий загрузчик, настраивающий смещение по таблице релоков. хотя можно и самонастраивающиеся драйвера сделать, поместив в точку входа базонезависимый код, выполняющий настройку.
Если нужно именно 64-битный драйвер то можно и без релокаций обойтись. Код можно легко сделать базонезависимым. При получение аддресса для фасм. вместо Код (Text): mov rax,driverAddress используй всегда lea Код (Text): lea rax,[driverAddress] ;опкод с rip-аддрессацией В 32-битных релоки более нужные т. к. базонезависимыми их труднее делать.
s_d_f Спасибо, большое! Я про оператор lea до этого времени вообще не знал. То есть получается что lea загружает смещение от начала кода до того места, куда указывает метка. Я вот начал делать вчера по такому принципу: Код (Text): use64 org 0x0000000000000000 addressGetPower dq GetPower addressSetEngineOn dq SetEngineOn addressSetEngineOff dq SetEngineOff ; ************************************************************************************* ; Ф У Н К Ц И И Д Р А Й В Е Р А Г И Б К О Г О Д И С К А ; ************************************************************************************* ; ------------------------------------------------------------------------------------- ; Формат: bool GetPower(void); ; Описание: Проверка подачи питания дисководу ; Результат: false - нет питания, true - питание есть ; ------------------------------------------------------------------------------------- GetPower: xor AL,AL mov DX,0x03F1 in AL,DX test AL,00000001b je _getPower_Off mov RAX,1 jmp _getPower_Exit _getPower_Off: xor RAX,RAX _getPower_Exit: ret ; ------------------------------------------------------------------------------------- ; Формат: bool SetEngineOn(unsigned char _drive); ; Описание: Включение мотора дисковода ; Параметры: _drive - номер дисковода (1 либо 2) ; Результат: false - ошибка, true - всё нормально ; ------------------------------------------------------------------------------------- SetEngineOn: ; [RBP+16] - _drive push RBP mov RBP,RSP mov RAX,[RBP+16] test RAX,RAX jz _setEngineOn_Error cmp RAX,2 jg _setEngineOn_Error mov DX,0x03F2 mov AL,0 out DX,AL cmp [RBP+16],word 1 je _setEngineOn_Drive1 jmp _setEngineOn_Drive2 _setEngineOn_Drive1: mov AL,0x1C jmp _setEngineOn_DriveC _setEngineOn_Drive2: mov AL,0x2D _setEngineOn_DriveC: out DX,AL mov CX,8000 _setEngineOn_Delay: loop _setEngineOn_Delay jmp _setEngineOn_Complete _setEngineOn_Error: xor RAX,RAX jmp _setEngineOn_Exit _setEngineOn_Complete: mov RAX,1 _setEngineOn_Exit: mov RSP,RBP pop RBP ret 8 ; ------------------------------------------------------------------------------------- ; Формат: bool SetEngineOff(unsigned char _drive); ; Описание: Выключение мотора дисковода ; Параметры: _drive - номер дисковода (1 либо 2) ; Результат: false - ошибка, true - всё нормально ; ------------------------------------------------------------------------------------- SetEngineOff: ; [RBP+16] - _drive push RBP mov RBP,RSP mov RAX,[RBP+16] test RAX,RAX jz _setEngineOff_Error cmp RAX,2 jg _setEngineOff_Error mov DX,0x03F2 cmp [RBP+16],word 1 je _setEngineOff_Drive1 jmp _setEngineOff_Drive2 _setEngineOff_Drive1: mov AL,0x0C jmp _setEngineOff_DriveC _setEngineOff_Drive2: mov AL,0x0D _setEngineOff_DriveC: out DX,AL jmp _setEngineOff_Complete _setEngineOff_Error: xor RAX,RAX jmp _setEngineOff_Exit _setEngineOff_Complete: mov RAX,1 _setEngineOff_Exit: mov RSP,RBP pop RBP ret 8 Раз смещение 0, то и проблем меньше. В самом верху находятся адреса функции, которые указывают смещение именно от самого начала. Таким образом, когда ядро загрузит драйвер по определённому адресу, оно этот адрес внесёт в таблицу. И когда нужно будет вызвать какую-то функцию из драйвера, ядро возьмём адрес расположения драйвера и сложит его с адресом начала функции. На полученный адрес и будет передано управление. А за lea ещё раз огромное спасибо! Это ведь благодаря ей я смогу в драйвере хранить локальные переменные (именно не локальные переменные функции, а статические/глобальные переменные драйвера), к которым будут обращаться функции.
Вот тут я описал свои сложности: http://dubrovkin.h18.ru/TPD.htm Надеюсь кто-нибудь поможет их решить.