|
Accueil-->VxD W9x en ASM - Chapitre 3
Structure d’un VxD1 IntroductionMaintenant que vous connaissez les bases concernant le VMM et les VxD, vous êtes capable d’apprendre à écrire du code pour créer un VxD. Vous avez besoin du Windows 95/98 Device Driver Development Kit. Cette acquisition est indispensable. Le DDK de Windows 95 est fourni uniquement aux souscripteurs du MSDN. Toutefois le DDK de Windows 98 DDK est disponible gratuitement grâce au net sur le site de Microsoft. Vous pouvez utiliser le DDK de Windows 98 pour développer des VxD même si ce DDK est plutôt orienté vers les WDM. Vous pouvez télécharger le DDK Windows 98 sur : http://www.microsoft.com/hwdev/ddk/install98ddk.php Vous pouvez télécharger le package complet, environ 30 Mo ou sélectionner seulement les parties qui vous intéressent. Si vous ne téléchargez pas le package complet, n’oubliez pas de télécharger la documentation du DDK Windows 95 DDK documentation incluse dans other.exe. Le DDK Windows 98 contient MASM version 6.11d. Vous pouvez l’upgrader dans sa dernière version en consultant comment faire sur le site de Iczelion's Win32 Assembly Homepage sur : http://members.xoom.com/Iczel/ Le DDK Windows 9x DDK contient plusieurs fichiers d’inclusions indispensables qui ne sont pas inclus dans le package MASM32. Vous pouvez également y télécharger la version originale en anglais de ce document, ainsi que les exemples associés. 2 Le format de fichier LE2.1 DescriptionUn VxD utilise le format exécutable linéaire LE. C’est le format conçu pour OS/2 version 2.0.Il peut contenir à la fois du code 16-bit et 32-bit, ce qui est une exigence des VxD. Souvenez-vous que les VxD datent de l’époque de Windows 3.x. En ce temps, Windows se lançait à partir du DOS, aussi les VxD devaient procéder à certaines initialisations en mode réel avant que la machine ne bascule en mode protégé. Le code 16-bit en mode réel devant être dans le même exécutable que le code 32-bit en mode protégé, le format LE est un choix logique. 2.2 Drivers de NTLes drivers de Windows NT n’ayant pas d’initialisation en mode réel utilisent le format PE et non LE. 3 Classes de segments3.1 GénéralitésLe code et les données dans un fichier LE sont stockés dans différents segments dont les différentes classes sont expliquées ci après. 3.2 LCODE code et données verrouillésCe segment est verrouillé en mémoire, ce qui signifie que ce segment ne peut être paginé sur disque. Le code et les données qui doivent être présents à tout moment, tout particulièrement le gestionnaire d’interruption, doivent être dans ce segment. 3.3 PCODE code paginableCe segment peut être paginé par le VMM. Le code et les données ne sont pas nécessairement présents en mémoire à tout moment. Le VMM peut paginer ce segment sur disque si le manque de mémoire vive physique se fait sentir. 3.4 PDATA données paginables
3.5 ICODE code d’initialisationLe code de ce segment est utilisé durant l’initialisation du VxD seulement. Après initialisation ce segment sera détruit par le VMM pour récupérer de la mémoire physique. 3.6 DBOCODE code et données de déboguageLe code et les données de ce segment sont utilisés quand vous lancez le VxD sous débogueur. Il contient par exemple le gestionnaire du message Debug_Query. 3.7 SCODE code et données statiquesCe segment sera toujours présent en mémoire, même si le VxD est déchargé. Ce segment est tout particulièrement utilisé pour les VxD dynamiques devant être chargés et déchargés de nombreuse fois durant une session Windows et dont vous souhaitez en garder la configuration. 3.8 RCODE initialisation du code et des données en mode réelCode 16-bit en mode réel pour l’initialisation. 3.9 16ICODE données d’initialisation en mode protégé USE16Ce segment est en mode 16-bit et contient le code que le VxD copie du mode protégé au mode V86. Par exemple si vous voulez coller du code V86 dans une VM, le code à transférer doit être dans ce segment. Si vous ne mettez pas ce code dans ce segment, l’assembleur générera un code faux, à savoir 32-bit au lieu de 16-bit. 3.10 MCODE chaînes de caractères verrouilléesCe segment contient les chaînes de caractères qui sont compilées avec l’aide de macros de message du VMM. C’est utile pour créer des versions internationales de driver. 4 Choix des segments4.1 LimitationsCela ne signifie pas que votre VxD doit contenir tous ces segments. Vous pouvez choisir parmi ceux ci les segments qui vous intéressent. Par exemple, si votre VxD n’a pas besoin d’être initialisé en mode réel, il n’y aura pas de segment RCODE. La plupart du temps il y aura les segments LCODE, PCODE et PDATA. C’est aux programmeur de VxD de juger de l’opportunité de tel ou tel segment pour le code et les données. 4.2 ConseilsEn général, vous devriez utiliser le plus souvent possible les segments PCODE et PDATA car la VMM peut déplacer en mémoire les segments si nécessaire. Il faut utiliser LCODE pour stocker les gestionnaires d’interruption hardware. On n’utilise pas les classes directement, mais vous devez utiliser des segments basés sur ces classes. Les déclarations de ces segments sont stockés dans un fichier de définition de module (.def) comme dans l’exemple complet ci après. 5 Exemple5.1 Code
VXD FIRSTVXD 5.2 ExplicationsLa première instruction est la déclaration du nom du VxD, en majuscules. Après vous trouvez la déclaration des segments, constituée de trois parties : le nom du segment, sa classe, et ses propriétés de fonctionnement. Vous constatez que de nombreux segments partagent la même classe. Par exemple,les segments _LPTEXT, _LTEXT, _LDATA sont tous basés sur la classe LCODE et les mêmes propriétés. Ces segments sont déclarés pour rendre le code plus facile à lire et comprendre. Par exemple, LCODE peut contenir du code et des données mais il est plus structuré de stocker les données dans le segment _LDATA et le code dans le segment _LTEXT. Eventuellement les segments partageant la même classe seront combinés dans un seul segment, après mise au point, dans la version finale du VxD. Un VxD exporte un et seulement un symbole, le device descriptor block (DDB).Le DDB est actuellement une structure contenant tout ce que le VMM a besoin de savoir sur le VxD. Vous devez exporter le DDB dans le fichier de définition de module. La plupart du temps, vous pouvez utiliser comme modèle ce fichier .def. Changez seulement le nom du VxD en première et dernière ligne. Les déclarations de segments sont écrasées pour un projet assembleur de VxD. Ils sont prévus pour un projet C , mais il est possible de faire de même en assembleur. Vous obtiendrez beaucoup de warnings mais cela assemble. Vous pouvez vous débarrasser de ces warnings en effaçant les déclarations de segments inutiles au projet. “vmm.inc” contient de nombreuses macros pour déclarer vos segments dans le fichier source.
_LTEXT VxD_LOCKED_CODE_SEG Chaque macro a son pendant de terminaison. Par exemple si vous voulez déclarer un segment _LTEXT dans votre source, procédez ainsi :
VxD_LOCKED_CODE_SEG 6 Squelette d’un VxD6.1 GénéralitésMaintenant que vous connaissez les segments dans un fichier LE, nous pouvons aller au fichier source. Une chose que vous pouvez observer de la programmation de VxD est l'utilisation importante de macros. Vous trouverez des macros partout dans la programmation de VxD. Ces macros sont fournies pour masquer les détails insidieux aux yeux du programmeur et d'une certaine façon rendre le code plus portable. Si vous êtes curieux, vous pouvez voir la définition de ces macros dans divers fichiers include comme "vmm.inc". Voici le squelette du code source :
.386p À première vue, le code source ne ressemble pas à un code source asm. C'est du à l'utilisation de macros. Analysons ce code source et vous le comprendrez bientôt. 6.2 .386Dites à l'assembleur que nous voulons employer le jeu d'instruction 80386 en mode protégé. Vous pouvez aussi employer .486p ou .586p. 6.3 include vmm.incVous devez inclure vmm.inc dans chaque code source VxD parce qu'il contient les définitions de macros que vous employez dans le fichier source. Vous pouvez inclure d'autre include si nécessaire. 6.4 DECLARE_VIRTUAL_DEVICEComme exposé précédemment, le VMM apprend tout ce qu'il doit savoir d'un VxD via le VxD_Desc_Block (DDB). Un bloc de descripteur de VxD est une structure qui contient l'information essentielle sur le VxD comme le nom de VxD, son deviceID, les points d'entrée des services VxD (s'ils existent) etc. Vous pouvez chercher cette structure dans VMM.inc. Elle est déclarée comme VxD_Desc_Block. Vous exporterez cette structure dans le fichier .DEF. Il y a 22 membres dans cette structure, mais vous devrez d'habitude de remplir seulement certains d'entre eux. Ainsi VMM.inc contient une macro qui initialisera et remplira les membres de structure pour vous. Cette macro est DECLARE_VIRTUAL_DEVICE. Elle a le format suivant : Declare_Virtual_Device_Name, MajorVer, MinorVer, CtrlProc, DeviceID, InitOrder, V86Proc, PMProc, RefData Une chose que vous pouvez observer est que, les étiquettes dans le code source VxD sont insensibles à la casse. Vous pouvez employer des majuscules ou des minuscules ou les combiner. 6.5 Paramètres de Declare_Virtual_Device6.5.1 NAME Le nom du VxD. La longueur maximale est de 8 caractères. Cela DOIT ÊTRE en majuscule. Le nom doit être unique parmi les VxD dans le système. La macro emploie aussi le nom pour créer le nom du DDB en ajoutant _DDB au nom du device. Ainsi si vous employez FIRSTVXD comme nom du VxD, la macro Declare_Virtual_Device déclarera le nom du DDB comme FIRSTVXD_DDB. Rappelez-vous que, vous devrez aussi exporter le DDB dans le fichier .DEF. Vous devez faire correspondre l'étiquette dans le fichier source avec celui dans le fichier DEF. 6.5.2 MajorVer et MinorVer Les versions principale et secondaire de votre VxD CtrlProc. Le nom de la procédure de contrôle pour votre VxD. Une procédure de contrôle est une fonction qui reçoit et traite les messages du VxD. Penser qu'une procédure de contrôle est l'équivalent d' une classique procédure de fenêtre. Puisque nous emploierons la macro Begin_Control_Dispatch pour créer notre procédure de contrôle, nous devons employer le nom standard qui est dans la forme de VxDName_Control. 6.5.3 Begin_Control_Dispatch La macro ajoute _Control au nom du VxD passé, aussi devons nous spécifier le nom de notre VxD suivi de _Control dans le paramètre CtrlProc. 6.5.4 DeviceID L'identificateur 16 bits unique de votre VxD. Vous avez besoin de l'ID si et seulement si votre VxD doit utiliser une des situations ci-dessous : Votre VxD exporte des services VxD pour d'autres VxD. Comme l' interruption 20h emploie l' ID pour identifier le VxD, il est impératif que votre VxD ait un identificateur unique. Votre VxD correspond avec des applications en mode réel pendant l'initialisation avec la fonction 1607h de l'interruption 2Fh. Les résidents en mode réel (TSR) employe la fonction 1605h de l'interruption 2Fh pour charger votre VxD. Si votre VxD n'a pas besoin d'un ID unique ID, vous pouvez spécifier UNDEFINED_DEVICE_ID dans ce champ. Si vous avez besoin d'ID unique, vous devez en demander un à Microsoft. 6.5.5 InitOrder L'ordre d'initialisation, ou en bref, l'ordre de chargement. Le VMM charge les VxD dans l'ordre indiqué. Chacun VxD aura un numéro d'ordre de chargement. Par exemple :
VMM_INIT_ORDER EQU 000000000H Vous pouvez voir que VMM, DEBUG et DEBUGCMD sont les premiers VxD chargés, suivi par PERF et APM. Le VxD ayant la plus petite valeur d'ordre d'initialisation est chargé d'abord. Si votre VxD exige les services d'autre VxD pendant l'initialisation, vous devez spécifier une valeur d'ordre d'initialisation qui est plus grande que celui du VxD que vous voulez appeler de manière à ce que le VxD appelé soit déjà en mémoire. Si votre VxD ne se soucie pas de l'ordre d'initialisation, spécifiez UNDEFINED_INIT_ORDER dans ce paramètre. 6.5.6 V86Proc et PMProc Votre VxD peut exporter l'API pour l'utilisation par des programmes en mode protégé et V86. V86Proc et PMProc spécifient les adresses de ces API. Rappelez-vous que les VxD existent principalement pour la supervision de VM. Il est raisonnable pour les VxD de fournir le support API pour les programmes DOS et les programmes en mode protégé. Si vous n'exportez pas d' API, vous pouvez omettre ces champs. 6.5.7 RefData Données de référence employées par l' Input Output Supervisor (IOS). La seule occasion ou vous emploierez ce champ est quand vous programmerez un layer block driver utilisant l'IOS. Vous pouvez omettre ce champ si votre VxD n'est pas un layer block driver. 6.6 La macro Begin_Control_Dispatch
Begin_control_dispatch FIRSTVXD Cette macro et sa contre-partie définissent la procédure de contrôle qui est la fonction que le VMM appelle quand il y a des messages de contrôle pour votre VxD. Vous devez spécifier la première moitié du nom de la procédure de contrôle de dispositif, dans notre exemple nous employons FIRSTVXD. La macro ajoutera _Control au nom que vous avez fourni. Ce nom doit correspondre à celui que vous spécifiez dans le paramètre CtrlProc de la macro. 6.7 Declare_Virtual_DeviceLa procédure de contrôle est toujours dans un segment verrouillé VxD_LOCKED_CODE_SEG. Cette procédure de contrôle ne fait rien. Vous devez spécifier quels messages de contrôle sont nécessaires à votre VxD ainsi que fonctions qui les manipuleront. Vous employez la macro Control_Dispatch à cette fin. 6.8 La fonction Control_DispatchmessagePar exemple, si votre VxD traite seulement le message Device_Init, votre procédure de contrôle ressemblerait à cela :
Begin_Control_Dispatch FIRSTVXD OnDeviceInit est le nom de la fonction qui manipulera le message Device_Init. Vous pouvez nommer votre fonction comme vous le voulez. Vous finissez le code source du VxD avec la directive de fin. 6.9 RécapitulatifPour récapituler, un VxD doit avoir au minimum un device block control et une procédure de contrôle. Vous déclarez un bloc avec la macro Declare_Virtual_Device et une procédure de contrôle avec la macro Begin_Control_Dispatch. Vous devez exporter le bloc en spécifiant son nom sous la directive EXPORTS dans le fichier DEF. 7 Assemblage du VxDLe processus d'assemblage est le même que celui employé dans l'assemblage d'applications normales win32. Vous exécutez ml.exe sur le code source asm et liez ensuite le fichier d'objet avec link.exe. Les différences sont dans les commutateurs de ligne de commande employés par ml.exe et link.exe ml -coff -c -Cx -DMASM6 -DBLD_COFF -DIS_32firstvxd.asm
-D<texte> défini une macro.
Par exemple, -DBLD_COFF défini une macro BLD_COFF utilise pour l’assemblage conditionnel. Si vous êtes intéressé cherchez BLD_COFF dans les fichiers include et voyez par vous-même l’effet sur le processus d’assemblage. Dans une ligne de commande comme celle ci dessous , 3 macros sont définies : BLD_COFF, IS_32, et MASM6. Si vous êtes familier du C, ce procédé est identique à :
#define BLD_COFF Je trouve plus commode d'employer un makefile mais vous pouvez créer un fichier batch pour automatiser le processus d'assemblage si vous n'aimez pas l'approche du makefile. Voici mon makefile.
NAME=firstvxd
Page:
1
2
3
4
5
6
7
8
9
Copyright © Jean-Pierre Fayeulle |