Проблеми с инсталирането на VxD драйвер и как да ги разрешите

Бележки от първо лице за ИТ, новини и технологично остаряване.

Блог → Проблеми с инсталирането на VxD драйвери и как да ги разрешите

Първо, нека разберем какво е VxD. Това са драйвери на Windows на системно ниво (т.е. на ниво системно ядро), които се изпълняват в пръстена с нулева защита в защитения режим и имат всички възможни и немислими привилегии (по-специално правото на достъп до устройства на физическо ниво ). Много хора се интересуват как да създадат и заредят такъв драйвер с помощта на „стандартни инструменти“. Е, те попитаха - ние отговаряме! В този пост ще засегна проблемите с инсталирането, зареждането, регистрирането на VxD драйвера в системата и някои слабо документирани проблеми при тяхното изпълнение.

На първо място, инструментариумът. Най-малко се нуждаем от Microsoft Driver Development Kit (DDK). Той включва набор от заглавни файлове (* .h), библиотеки за импортиране на системен модул (* .lib), изходен код за примери, помощни файлове и няколко специализирани помощни програми. Освен това се нуждаете от компилатор на C от пакета Microsoft Visual C/C ++. Разбира се, никой не си прави труда да използва компилатори от други производители, но след това ще трябва да създадете * .lib файлове сами и да страдате дълго време, така че * .h DDK файловете да бъдат преведени без проклятие.

Откъде да започнем? Трябва да прочетете документацията от DDK и накратко да разберете как работи ядрото на Windows като цяло и драйверите (VxD) по-специално. И така, VxD са разделени на два основни класа: статично натоварени (статично зареждане) и динамично (динамично зареждане). Основната им разлика е, че статично заредените драйвери се четат в RAM при стартиране на системата и остават в нея, докато Windows бъде изключен (във всеки случай не знам как да принудя такива VxD да бъдат разтоварени). Динамично заредените драйвери се четат в RAM при нужда и при желание могат да бъдат премахнати от там.

Сега нека се занимаем с класификацията на устройствата. Те могат да бъдат Plug and Play (PnP) и др. наследство ("наследство" от по-ранни версии). PnP устройствата автоматично се разпознават и конфигурират от операционната система при свързване, докато старите устройства трябва да се инсталират и конфигурират ръчно. PnP устройствата са всички USB и SCSI устройства, модеми, мишки, стандартни COM и LPT портове, както и почти всички съвременни ISA и PCI карти. Е, всичко останало, което не може автоматично да бъде открито и конфигурирано от Windows, принадлежи на стари устройства (нестандартни COM портове и хардуер, прикрепен към тях, стари ISA карти, външно оборудване, което не поддържа спецификацията PnP, както и драйвери, които го правят) не работи директно с физическо оборудване, например - TCP/IP стек).

Е, една последна бележка относно VxD класификацията: Win9x дефинира три типа функционални драйвери: товарачи, изброители и самите драйвери. Устройството за зареждане е почти винаги статичен VxD, целта му е ясно от името, той зарежда драйвери от посочения тип. Обикновено програмистът няма нужда да пише свой собствен буутлоудър, можете да използвате един от стандартните (* IOS - за драйвери на файловата система, * VCOMM - за серийни и паралелни портове, * CONFIGMG - за PnP устройства).

Enumerator е нещо, което постоянно се намира в паметта и търси дали се е появило ново PnP устройство, което му е известно. Или е отишло някъде, което е съществувало преди. В тези ситуации изброяващият (чрез * CONFIGMG - който е и конфигуратор на PnP устройство) зарежда или разтоварва съответния драйвер на устройството. Драйвер на устройство - VxD, който участва пряко в поддръжката на оборудването. Драйверът на устройството може да бъде или статичен, или динамичен (в последния случай той се зарежда при поискване от изброител, приложна програма или друг VxD).

Можете да разберете останалата част от теорията сами, като прочетете документацията от DDK. Така че нека се захващаме с практиката! Малко вероятно е да се наложи да напишете драйвер за устройство, вмъкнато в стандартен ISA или PCI слот на компютър - обикновено такива карти се поддържат от производителите на хардуер на доста прилично ниво. Най-вероятно ще се докопате до нещо, свързано към COM или LPT порт и освен това не поддържа спецификацията PnP. Следователно основната задача ще бъде:
- писане на процедура за правилната инсталация на драйвера, с „менюта“ и „да се види в диспечера на устройствата“;
- определяне на всички COM и LPT портове, налични в системата (защо обърквате потребителя с ненужни въпроси при инсталиране на драйвера?);
- правилно определяне на присъствието на вашето устройство на посочения порт (представете си колко е страхотно, ако в момента на анкетиране на портовете мишката е напълно покрита или принтерът спре да печата);
- правилно улавяне и освобождаване на ресурси, необходими за функционирането на вашето устройство.

Първа стъпка е инсталирането на драйвера. Както вече разбрахме, драйверите могат да бъдат статични и динамични. За да заредите статични драйвери, те могат да бъдат записани в раздела [386Enh] на файла SYSTEM.INI. Но този метод е остарял и всъщност е оставен само за съвместимост със стари версии на Windows (единственото изключение са драйверите, които трябва да бъдат заредени, преди процесорът да бъде поставен в защитен режим на работа - например за достъп до реалния режим Функции на BIOS). Вторият (предпочитан) начин е записването на информация в системния регистър, в клона HKEY_LOCAL_MACHINE \ System \ CurrentControlSet \ Services \ VxD \ DEVICE_NAME, където стойността на DEVICE_NAME може да бъде произволна (по ваш вкус). Този клон трябва да съдържа променлива от тип REG_SZ на име StaticVxD и със стойност, съдържаща името на вашия VxD драйвер. Ако файлът се намира в директорията% SystemRoot% \ SYSTEM, тогава може да се посочи само името му, в противен случай не забравяйте да посочите пълния път. Освен това в същата нишка трябва да създадете начална променлива от тип REG_BINARY със стойност, равна на 0. По принцип променливата Start е предназначена само за съвместимост с следващите версии на Windows.

Съвет: за да заредите VxD, използвайки * IOS като устройство за зареждане на устройства, можете просто да пренапишете своя VxD в директория% SystemRoot% \ SYSTEM \ IOSUBSYS и да зададете разширението на файла * .VXD или * .MPD.

Но използването на статично заредени драйвери без специална нужда не е оправдано, тъй като води до увеличена консумация на RAM, която никога не е достатъчна. Следователно втората опция е за предпочитане - използването на динамично заредени VxD. Ако вашето устройство не поддържа спецификацията PnP, то по дефиниция е наследство. За стари устройства, ядрото на Windows предоставя един вид емулатор на преброител, който зарежда всички драйвери, описани в системния регистър в клона HKEY_LOCAL_MACHINE \ Enum \ Root \. Всъщност, за да може вашето устройство, което не е PnP, да се превърне в аналог на PnP, трябва да заредите VxD-изброителя, който сте написали, който, ако е необходимо, ще зареди и разтовари директно драйвера на физическото устройство. Между другото, по същата причина, изброяващият и драйверът обикновено се изпълняват под формата на два различни VxD (тъй като изброяващият е постоянно в RAM и драйверът на устройството се зарежда при необходимост).

Така че, за да инсталирате написания от вас изброител, трябва да зададете минималната информация за него в системния регистър - например в HKEY LOCAL MACHINE \ Enum \ Root \ DEVICE_NAME \ 0000, където DEVICE_NAME може да бъде всеки низ (например име на вашия изброител), а 0000 означава, че това е първото логическо устройство (защо имате нужда от повече?). От минимално необходимата информация е необходимо да запишете следните променливи в този клон (всички стойности са от типа REG_SZ):

Това е основно това. След рестартиране на системата ще се появи съобщението на Windows „ново устройство е намерено и се търси софтуер за него“, след което ще бъдете подканени да поставите диск от производителя на хардуера - и инсталирането на драйвера ще продължи както обикновено. Възниква въпросът: възможно ли е да се направи без рестартиране на системата? Оказва се - можете! Въпреки че нашето устройство е наследство, самият Windows го емулира като PnP. По принцип можете просто да влезете в диспечера на устройствата и да кликнете върху бутона Обновяване в раздела, който съдържа дървото на устройството, и последствията ще бъдат същите като след рестартиране на системата. Още по-добре, попитайте * CONFIGMG (той е този, който конфигурира PnP устройства), за да провери всички устройства (включително новопоявилите се в системата). За да направите това, след като напишете информация в системния регистър, извикайте функцията ReenumerateDevices ().

За съжаление Win9x няма стандартни инструменти за определяне на броя и имената на COM портовете, налични в системата. Номерирането на портове не трябва да бъде от край до край, системата може да бъде например "COM1", "COM7" и "COM18". Както и да е, серийните портове не трябва да се наричат ​​"COMx", а паралелните портове "LPTx". По принцип имената на портовете могат да бъдат напълно произволни.

За да разрешим този проблем, ще се възползваме от факта, че всички устройства в системата са подредени под формата на дърво на устройството (DevNode дърво). Освен това за всеки сериен и паралелен порт стандартният изброител е драйверът * VCOMM, интерфейсът към който е документиран в DDK. Тъй като броят на портовете в системата може да е различен, не трябва да разпределяте памет за съхраняване на информация за тях под формата на статичен масив - по-добре е да използвате средствата, предвидени за VxD от системното ядро ​​(т.нар. VMM сервизни функции).

След това, когато вече имаме списък на всички физически портове, познати на системата, остава да определим към кой от тях е свързано външното ни оборудване. И определете, ако е възможно, в "горещ" режим, тъй като потребителят може да свързва и изключва нашето оборудване, без да изключва захранването на компютъра и без да рестартира системата.

Разбира се, анкетирането на събития с таймер може да се използва като фронтален метод, като се деактивират прекъсванията за времето на анкетиране с командата CLI и след това се активират с командата STI (тъй като VxD се изпълняват на ниво ядро ​​- командите CLI/STI директно от процесора и не се емулират от операционната система). Но такава тактика може да доведе до загуба на прекъсвания от други устройства и производителността на системата няма да се подобри от това.

От друга страна, не бива да получаваме достъп до хардуерни ресурси в „всеки момент от времето, който ни харесва“ - възможно е някой вече да работи с този порт и ние просто можем да му пречим. За да реши този проблем, VCOMM предлага механизъм, наречен манипулатор на спорове. Идеята му е, че ако се нуждаем от физически ресурси, контролирани от друг драйвер (в този случай сериен или паралелен порт драйвер), тогава се свързваме с входната точка на манипулатора на спорове с искане за изземване на ресурса. Те могат или не могат да ни дадат ресурс. Ако ресурсът ни е бил даден, можем да го използваме напълно свободно и след края на използването се обадете отново на манипулатора на спора и го освободете. Е, ако ресурсът не е наличен, тогава няма какво да се направи, ще трябва да изчакате и да опитате отново да вземете при следващия цикъл на проверка.

Между другото, ако получихме ресурса „за временно ползване“, тогава друг драйвер също може да се опита да го поиска. В този случай ще бъде извикана нашата функция за обратно извикване, в която ние ще решим - да дадем ресурса, или все още имаме нужда от него за изключително използване. За съжаление в тази бъчва мед има и няколко лъжици катран. Първо, манипулаторът на спорове не поддържа повече от две заявки едновременно. Тези. ако нашият драйвер е изпълнил заявка за ресурс, който вече е използван от някого, тогава никой не може да ни отнеме този ресурс, докато не го върнем доброволно.

Е, вашето устройство работи ли? Доволни ли сте? О, на "зелени" дънни платки вашият драйвер или не работи изобщо, или работи три минути и след това обменът с вашето устройство спира без обяснение? По принцип тази глупост се появи за първи път в Windows 98 (в Windows 95 поддръжката на ACPI е внедрена до минимум и не пречи на живота на системния програмист). Факт е, че когато улавяте ресурс чрез достъп до манипулатора на спорове (и още повече, ако го заснемете „незаконно“ между команди CLI/STI), никой дори не мисли да прехвърли порта от „спящ“ в „работен“ режим. Накратко, на него просто няма захранващо напрежение! Между другото, това се отнася както за серийни, така и за паралелни портове (особено ако са интегрирани на "зелена" дънна платка).

Знаете ли как да включите/изключите порта? Лично аз не знам. Но добре познатият CONFIGMG - знае (чудя се откъде?). Можете да се обърнете към него за помощ. По принцип абсолютно не е необходимо да се запазва първоначалното състояние на захранващото напрежение и да се възстановява в края на използването на ресурси; това се прави единствено, за да се осигури "коректност" по отношение на друг драйвер, работещ със същото устройство. Както се казва, „не прави на друг това, което не си пожелаваш“. Като цяло използването на този принцип при писане на драйвери има много положителен ефект върху съвместимостта с друг хардуер и софтуер.

Е, като цяло това е всичко, което исках да кажа. Оборудвайте се с дебъгер, изучете ядрото на системата, вижте примери от DDK. И все пак, дори и психически подготвени, когато започнете да пишете драйвери за платформата Windows NT, ще плюете и ще си спомняте с неприятна тиха дума славната компания на Microsoft - за нейното внедряване на VxD под Windows 9x.