OSDev

для всех
Текущее время: 30 апр 2024, 07:11

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 6 ] 
Автор Сообщение
 Заголовок сообщения: Программирование драйверов
СообщениеДобавлено: 26 янв 2011, 20:50 

Зарегистрирован: 22 окт 2010, 13:22
Сообщения: 92
Откуда: Ртищево
Всем доброго вечера!

Вот я практически добрался до такого момента, когда уже пора прощаться с R-Mode. И вот раз я покидаю R-Mode, то мне нужно будет написать два драйвера: драйвер для дисковода гибких дисков и драйвер клавиатуры.

Проблема не понимания у меня заключается в том, что адрес, где будет лежать в памяти (в страничной памяти) драйвер, точно не известен. То есть драйвера будут загружать куда-то по адресу, ближе к ядру операционной системы. Но чёткого адреса нет. Тогда вот я и думаю, как же тогда проектировать такие драйвера в коде. Вот например буду я писать так драйвер:

Код:
use64
org 0x0000000000000000
; Код драйвера


И таким образом у меня будет начинаться каждый драйвер. Но ведь этот драйвер потом может попасть на любую страничку, но точно не на страничку с индексом 0. В связи с этим будут рассчитаны не правильно смещения. Я вижу два вариант решения проблемы.

ПЕРВЫЙ ВАРИАНТ
Писать драйвера так, чтобы у них было своё адресное пространство процесса. То есть свои таблицы страниц, загрузка в CR3.

ВТОРОЙ ВАРИАНТ
Вводить какую-нибудь переменную:

Код:
use64
org 0x0000000000000000
jmp startDriver

driverAddress dq 0x0000000000000000

startDriver:
    ; Код драйвера


При загрузке драйвера в память подставлять значение в поле driverAddress. А в самом коде драйвера делать обращения от базы driverAddress.

В общем это то, что было в голове. Как делаете Вы?

_________________
Изучаю процессор...


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Программирование драйверов
СообщениеДобавлено: 27 янв 2011, 18:54 

Зарегистрирован: 22 окт 2010, 13:22
Сообщения: 92
Откуда: Ртищево
Вот тут я описал свои сложности: http://dubrovkin.h18.ru/TPD.htm

Надеюсь кто-нибудь поможет их решить.

_________________
Изучаю процессор...


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Программирование драйверов
СообщениеДобавлено: 27 янв 2011, 20:05 

Зарегистрирован: 16 фев 2010, 22:03
Сообщения: 101
Есть как минимум два решения проблемы:
1) Позиционно независимый код. Он вычисляет свой адрес относительно текущей инструкции. В long mode это делается элементарно (адресация относительно RIP. не знаю как другое компиляторы, но fasm точно по умолчанию генерирует именно такой код), в 32-битном режиме несколько сложнее (надо определить базу кода и поместить её в регистр, а потом делать все обращения к переменным относительными. Вызов процедур и так может быть относительным как и прыжки, поэтому с ними проблем не будет). Это позволяет сильно упростить загрузчик драйвера, но придётся следовать некоторым правилам в коде драйвера, если в long mode это очень просто (достаточно заменить все mov rax, address, на lea rax, [address]. Больше изменений не нужно в обычном коде. Хотя есть некоторые ещё нюансы, но и эти проблемы решаются незначительным изменением кода), то в 32-битном режиме не очень то удобно (прямого доступа к EIP нет, один регистр придётся потратить на хранение базы, а регистров не так уж и много, требуется небольшой дополнительный код по определению базы).
2) Релоки. Берёте любой существующий формат исполняемых файлов, который поддерживает релоки (например, ELF) или придумываете свой собственный (только вам придётся думать как получить от ассемблера такой формат, поэтому существующий предпочтительней) и делаете все драйвера в нём. Суть этого метода заключается в том, что в файле есть таблица релоков. Один релок задаёт как надо изменить инструкцию по этому адресу, чтобы она указывала на нужные данные. Например, там могут быть адреса всех mov [address], eax. Загрузчик проходит по таблице и прибавляет базу кода ко всем address. В этом случае вы можете практически не думать в драйвере о том куда он будет загружен - все адрес преобразуются к правильным, когда драйвер будет загружен, но придётся сделать достаточно сложный загрузчик.

Вам решать, что для вас удобнее... Лично мне нравится больше позиционной независимый код, если ОС работает в long mode и компилятор - fasm.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Программирование драйверов
СообщениеДобавлено: 27 янв 2011, 20:54 

Зарегистрирован: 22 окт 2010, 13:22
Сообщения: 92
Откуда: Ртищево
KIV
Спасибо большое! Хорошее описание. Как я понял если использовать релоки, то в ядре должен быть, так скажем свой ассемблер, чтобы потом всё это дело скомпилировать?! Хотя может не так понял. Мне всё равно больше нравится позиционно-независимый код.

А какое смещение может быть для всех инструкций (то есть там сколько в обратном направлении, сколько в прямом)? Я тут эксперимент провёл, а разве обязательно mov на lea менять?

Вот например такую ситуацию описывал:

Я собираюсь писать драйвера для 64-битного режима работы процессора, то есть для L-Mode. буду использовать страничную адресацию (собственно иначе никак), где каждая страничка будет занимать 4096 байт (4 КБ). Вот и получается, что в системе может быть таких страничек 4503599627370496 штук (это 2 в 64 степени и затем разделённое на 4096). Вообще, правильнее было бы указать 68719476736 штук (это 2 в 48 степени и затем разделённое на 4096), так как для адресации используются только 48 младших бит. Вот и получается, что странички с абсолютным индексом ближе к 68719476735 будут отведены под ядро операционной системы. Ниже страничку будут с драйверами. А страничку с нулевого индекса будут заполняться кодом программ пользователя. Странички программ будут переключаться (CR3 регистр меняться), а вот странички с драйверами и ядром всегда будут статические.

Так вот, получается что фактически я могу драйвер запихать в любую из страничек в диапазоне от 0 до 68719476735 (пока забудем про программы и про ядро операционной системы). Ну а если драйвер занимает больше 4 КБ, то его уже в несколько подряд идущих страничек пихать. В общем драйвер никогда не знает где он будет сидеть. А при его загрузке в страничку, операционная система в своей служебной таблице будет помечать какой драйвер куда грузила. Предположим что мы поместили драйвер клавиатуры в страничку с индексом 10000. Ну а в самом драйвере будет такой вот код:

Код:
use64
org 0x0000000000000000

address_FunA dq FunA ; Смещение от начала драйвера до функции FunA
address_FunB dq FunB ; Смещение от начала драйвера до функции FunB

value dw 0x0000 ; Глобальная переменная драйвера

FunA:
    mov AX,4
    mov [value],AX
ret

FunB:
    call FunA
ret


Ну и вот что произойдёт, когда, как я уже говорил, поместили драйвер в страничку с индексом 10000, и решили вызвать подряд обе функции?!

Ядро определяет куда оно загрузило драйвер, потом складывает это значение со значением смещения функции в драйвере и передаёт туда управление (ага, это будет 64-битный адрес). И что произойдёт в коде самого драйвера, когда будет вызвана функция FunA? Будет в страничке 10000 по смещению 16 записано число 4 или будет в страничку с индексом 0 по смещению 16 записано число 4?

Далее. Что произойдёт когда будет вызвана функция FunB? Потом она передаст управление на страницу 10000 по смещению 18 или на страницу 0 по смещению 18?

Вот что меня волнует. Я хочу чтобы все адреса в драйвере были относительными на все инструкции: mov, jmp, nz, ..., call. Но боюсь что будет не так.

_________________
Изучаю процессор...


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Программирование драйверов
СообщениеДобавлено: 28 янв 2011, 15:19 

Зарегистрирован: 16 фев 2010, 22:03
Сообщения: 101
Как я вижу вы используете fasm. Он когда это только возможно генерирует позиционно независимый код. jmp всегда относительный, если не указан сегмент куда прыгать. То есть в команде jmp указывается сколько надо прибавить к EIP/RIP. Так всегда. Хоть в реальном режиме, хоть в protected mode, хоть в long mode. call может быть как абсолютным так и относительным. fasm всегда генерирует относительные. И наконец насчёт mov. fasm генерирует обращение к памяти относительно RIP, если адрес не 64-битный. То есть:
Код:
mov [qword var], rax ; Содержимое RAX будет записано в ячейку памяти var.
mov [var], rax ; Содержимое RAX будет записано в ячейку памяти RIP + (var - $)

Таким образом во втором случае база кода не важна - обращение относительно RIP.
А вот для mov в случае если аргумент - неподсредственное значение такое вычисление адреса разумеется не сработает - это применяется только к тому что в квадратных скобках, поэтому придётся для загрузки адреса в регистр или ячейку памяти использовать lea.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Программирование драйверов
СообщениеДобавлено: 28 янв 2011, 18:36 

Зарегистрирован: 10 май 2007, 11:33
Сообщения: 1206
Внутрисегментный call с непосредственным операндом нигде не может быть абсолютным. Абсолютная адресация может быть только регистровой или косвенной.

В длинном режиме можно использовать не только 64-разрядную, но и 32-разрядную абсолютную адресацию, причем не только при работе с аккумулятором.

Относительное смещение вычисляется относительно адреса конца команды, а символ $ обозначает адрес начала команды.


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 6 ] 

Часовой пояс: UTC + 3 часа


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

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


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

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