Dans cette série de Tutorials, je présumerai que le lecteur soit
déjà familier avec les opérations des processeurs Intel 80x86 à propos des modes protégés tels que le mode
virtuel 8086, la pagination, GDT, LDT, IDT. Si vous ne savez pas de quoi je parle, lisez d'abord la
documentation d'Intel à l'adresse http://developer.intel.com/design/pentium/manuals/
Contenu:
Windows 95 est un système d'exploitation multi-taches
fonctionnant au niveau le plus haut (privilégié), le Ring 0. Toutes les applications normales donc
les autres programmes possèdent un privilège de type Ring 3, c'est le niveau de moindre privilège.
De cette manière, ces applications sont limitées dans ce qu'elles peuvent faire au système. Elles ne
peuvent pas employer les instructions privilégiées du CPU, Ces programmes ne peuvent pas avoir
directement accès au port d'entrée-sortie et cetera. Vous connaissez sans aucun doute ces trois
composants du système: gdi32, kernel32 et user32. Vous pensiez vu leur importance qu'ils fonctionnaient
en Ring 0. Et bien...en réalité, ils fonctionnent en Ring 3, comme toutes les autres applications. Ainsi ils
n'ont pas plus de privilège que, disons, la calculette de Windows ou le jeu du démineur. En réalité, la
puissance du système est dans le contrôle de l'administrateur de machine
virtuelle (VMM) (virtual machine manager) et des Drivers de
Dispositifs Virtuals (VxD) (virtual device drivers).
Tous ça n'aurait pas pu arriver si DOS n'avait pas rendu
le tableau plus compliqué. Durant l'ère de Windows 3.x, il y a eu des tas de bons programmes sous DOS
sur le marché. Windows 3.x a été capable de les faire fonctionner
à côté d'autres programmes Windows normaux, sinon ça auraient été des échecs commercialement.
Ce dilemme n'a pas été facile à résoudre. Les programmes DOS
et les programmes de Windows diffèrent résolument les uns des autres. Les programmes DOS sont
NULS dans le sens qu'ils pensent êtres un
tout unique dans le système : clavier, CPU, mémoire, disque
etc. Ils ne savent pas comment coopérer avec d'autres programmes tandis que les programmes Windows
(en ce temps-là) reposaient sur la multi-gestion coopérative, c'est-à-dire que chaque programme Windows
devait rapporter le contrôle à d'autres programmes grâce à la fonction GetMessage ou PeekMessage.
La solution c'est de faire tourner chaque programme DOS
dans une machine virtuelle 8086 tandis que tous les autres programmes de Windows tournent dans une autre
machine virtuelle appelée system de machine virtuelle
(system virtual machine). Windows est responsable de l'accès au CPU pendant un certain temps pour chaque
machine virtuelle les unes après les autres. Ainsi sous Windows 3.x, les programmes Windows utilisent la
multi-gestion coopérative tandis que les machines virtuelles utilisent la multi-gestion préventive.
Qu'est-ce qu'une machine virtuelle ?
Une machine virtuelle est une machine fictive créée seulement par le
logiciel. Une machine virtuelle réagit aux programmes qui sont en fonctionnement comme une machine réelle.
Ainsi un programme sait qu'il tourne dans une machine virtuelle mais il ne s'en soucie pas. Puisque la
machine virtuelle répond au programme exactement comme une machine
réelle, alors elle peut être traité comme étant une chose réelle.
Vous pouvez vous représenter l'interface entre la machine réelle et son logiciel un peu comme une
sorte d'API. Cet API peu commun consiste à intercepter, les appels du BIOS et des ports d'entrée-sortie.
Si Windows peut d'une façon ou d'une autre parfaitement simuler cet API, alors les programmes tournant
dans la machine virtuelle se comporteront exactement comme s'ils fonctionnaient dans la machine réelle.
c'est là qu'entrent en scène les VMM et les VxDs. Pour coordonner et surveiller des machines
virtuelles (VMs), Windows a besoin d'un programme qui se consacre à cette tâche. Ce programme est le
Manager de Machine Virtuelle.
Le Manager de Machine Virtuelle : (Virual Machine Manager)
VMM est un programme 32 bits en mode
protégé. Sa responsabilité principale est d'ériger et d'entretenir la structure qui soutient des machines
virtuelles. Comme tel, il est responsable de la création, du fonctionnement et de la fin des VMs
(Machines Virtuelles). Le VMM (le Manager) est un des nombreux systèmes VxDs qui est stocké dans
VMM32.VXD de votre répertoire System. C'est aussi un VxD mais il peut être considéré comme le
'maître surveillant', d'autres VxDs. Voyons plus en détails la séquence de Boot de Windows 95:
- io.sys est chargé en mémoire
- config.sys et autoexec.bat sont exécutés
- win.com est appelé
- win.com lance VMM32.VXD lequel est en fait un simple fichier EXE sous DOS.
- VMM32.VXD charge le VMM en mémoire étendue en utilisant le driver XMS
- VMM initialise lui-même d'autres 'virtual device drivers' par défaut.
- VMM met la machine en mode protégé et crée le 'système de machine virtuelle'
- (Virtual Shell Device) Le Dispositif Shell Virtuel, qui a été chargé précédemment,
fait tourner Windows dans le système VM en lançant krnl386.exe
- krnl386.exe charge d'autres fichiers, pour en finir avec le shell de Windows 95.
Comme vous pouvez le voir, VMM est le premier VxD qui soit chargé en mémoire. Il crée le système de la
machine virtuelle et initialise d'autre VxDs. Il fournit aussi de nombreux services à ces VxDs.
Le VMM (le manager de Machine virtuelle) et le mode d'opération des VxDs diffèrent de celui des
programmes réels. Ils sont, la plupart du temps, inertes.
Pendant que les applications tournent dans le système, ces VxDs ne sont pas actifs. Ils seront réveillés
quand une quelconque interruption/faute/événement se produit et a besoin de leur attention.
Le VMM n'est pas le décideur. Ça signifie que les VxDs doivent synchroniser leurs accès aux services
du VMM. Il y a quelques situations pour lesquelles il peut être dangereux d'appeler les services du VMM
tel que lorsque une interruption matériel est en service. Pendant ce temps-là, le VMM ne peut pas tolérer
un autre accès de la part d'un autre VxD. Vous en tant que concepteur de nouveaux VxDs devez être extrêmement prudents à ce
que vous faites. Rappelez-vous qu'il n'y a personne pour s'occuper des erreurs de votre code à votre
place. Vous êtes absolument seul dans le Ring 0. Ici vous êtes sur le fil du rasoir, il n'y aura personne
pour vous dire ou non si vous faites des conneries.
Driver de Dispositif Virtuel: (Virtual Device Driver)
L'abréviation du 'Virtual Device Driver' est VxD.
x est
le placeholder pour le nom du dispositif utilisé, comme Virtual Keyboard Driver,
ou Virtual Mouse Driver et cetera. Les VxDs sont les clefs de la
réussite pour virtualiser le matériel. Souvenez-vous, les programmes sous DOS pensent qu'ils possèdent
tout dans le système, qu'ils sont seuls sur la machine et que la souris le clavier et le reste sont
directement et uniquement à leur service. Quand ils tournent sur des machines virtuelles, Windows doit
leur fournir des remplaçants de dispositifs réels. C'est ça les VxDs, ce sont des remplaçants de souris,
clavier… mais virtuels. Les VxDs d'habitude virtualisent quelques dispositifs matériel. Ainsi, par exemple,
quand un programme DOS pense qu'il communique avec le clavier, en réalité c'est le dispositif virtuel du
clavier qui travaille avec lui. Un VxD prend d'habitude le contrôle du dispositif (du matériel) réel et
gère la division de ce dispositif entre plusieurs VMs.
(En fait votre ordinateur est divisé en plusieurs 'ordinateurs virtuels' ou 'Machines Virtuelles (VMs)'.
Vous n'avez qu'un clavier mais pour que chaque Machine Virtuelle puisse l'utiliser, un VxD (un clavier
virtuel) est calé entre chaque Machine Virtuelle et le vrai clavier physique. Le Manager de Machines
Virtuelles (VMM) octroie un laps de temps machine à tour de rôle à chacune des Machines Virtuelles où un
seul programme tourne dessus.)
Cependant, il n'y a aucune règle pour qu'un VxD DOIVENT forcément
être associé à un dispositif de matériel précis. Il est vrai que les VxDs soient conçus pour virtualiser
des dispositifs matériel (normalement réels) mais nous pouvons aussi considérer les VxDs comme étant des DLL
de priorité Ring-0. Par exemple, si vous souhaitez utiliser quelques particularités qui ne peuvent
seulement être réalisées qu'en Ring 0, vous pouvez coder un VxD qui exécute ce travail pour vous. À cet
égard, vous pouvez vous représenter le VxD comme étant l'extension de votre programme puisque il
virtualise un quelconque dispositif(Device) matériel.
Avant d'aller plus loin et d'essayer de créer vos propres VxDs, laissez-moi d'abord faire le
point à propos de certaines choses sur eux.
-
Les VxDs sont spécifique à Windows 9x. Ils ne peuvent pas fonctionner sur Windows NT. Ainsi si votre
programme dépend de VxDs, il ne sera pas compatible sur une plate-forme Windows NT.
-
Les VxDs sont les entités les plus puissantes du système. Puisqu'ils sont capables de tout vis à vis du
système, ils sont aussi extrêmement dangereux. Un VxD mal conçu peut faire s'effondrer le système. Il n'y
a aucun garde-fou contre les VxDs mal faits.
-
Habituellement, il y a des tas de façons d'arriver au but désirez sans recourir à aucun VxD. Pensez et
pensez deux fois avant d'opter pour une solution de type VxD. S'il y a une autre façon d'exécuter la
tâche en Ring 3, préférez-la.
Il y a deux types de VxD sous Windows 95
-
Les 'VxDs Statics'
-
Et les 'VxDs Dynamic'
Les VxDs Statiques sont ces VxDs qui sont chargés pendant le bootup (le démarrage) du système et reste
chargé jusqu'à l'arrêt du système. Ce type de VxD provient des vieux jours de Windows 3.x. Les VxDs
Dynamiques sont uniquement disponibles sous Windows 9x. Les VxDs Dynamiques peuvent être chargés/déchargés
si nécessaires. La plupart d'entre eux sont des VxDs qui contrôlent les Plug and Play Devices
(des périphériques qui sont automatiquement détectés par Windows au moment de leur installation).
Ces VxDs là, sont chargés par le 'Manager de Configuration et le 'Superviseur d'Entrée/Sortie'.
Vous pouvez aussi charger/décharger ces VxDs dynamiques pour vos applications win32.
Communication Entre les VxDs :
Les VxDs (Les Virtuals Devices, tels que le clavier virtuel) et le VMM (le Manager de Machine Virtuelle),
communiquent entre eux de trois façons possibles :
- Par Messages Windows de Control
- Par Services APIs
- Par Callbacks
Les Messages de Control:
Le VMM envoie des messages de contrôle au système vers TOUS les VxDs
chargés dans le système quand certains événements intéressants se produisent. Dans ce cas précis,
considérez que les messages de contrôle sont un peu comme de simples 'Messages de Fenêtres' en Ring-3
dans des applications Win32. Chaque VxD a une fonction qui reçoit et traite
les messages de contrôle appelée device control procedure. Il y a un
peu moins de 50 systèmes de 'Messages de Contrôle'. La raison pour qu'il n'y ait pas beaucoup de messages
de contrôle c'est qu'il y a souvent beaucoup de VxDs chargés dans le système et que chacun d'entre eux
obtient un accès dans chaque message de contrôle, s'il y a trop de messages de contrôle, le système
rectifiera avec une halte. Ainsi vous trouverez seulement les messages vraiment importants liés aux VMs
comme quand une VM (Machine Virtuelle) est créée, détruite ou autre. En plus du système de 'Messages de
Contrôle', un VxD peut définir ses propres 'Messages de Contrôle' sur mesures qu'il peut utiliser pour
communiquer avec d'autres VxDs qui les comprend.
Service
APIs: Un VxD (un Device Virtuel), y compris le VMM (le Manager de Machine Virtuelle),
exporte d'habitude un jeu des fonctions publiques qui peuvent être appelées par d'autres VxDs. Ces
fonctions sont appelées des services VxD. Le mécanisme d'appel de ces services VxD diffère tout à fait de
celui des applications en Ring-3. Chaque VxD qui exporte des services VxD
DOITpossèder un numéro ID unique. Vous pouvez obtenir un tel n°ID de
Microsoft. Le n°ID est un nombre sur 16 bits qui identifie uniquement un VxD. Par exemple,
UNDEFINED_DEVICE_ID EQU 00000H
VMM_DEVICE_ID
EQU 00001H
DEBUG_DEVICE_ID
EQU 00002H
VPICD_DEVICE_ID
EQU 00003H
VDMAD_DEVICE_ID
EQU 00004H
VTD_DEVICE_ID
EQU 00005H
Vous pouvez voir que le VMM (Manager de Machine Virtuelle) possède le n°ID 1, le VPICD a l'ID n°3 et ainsi
de suite. Le VMM emploie cet ID unique pour trouver le VxD qui exporte les 'services VxD' demandés. Vous
devez aussi choisir le service que vous voulez appeler par son index dans la table de branche de service.
Quand un VxD exporte des services VxD, il stocke les adresses de ces services dans une table. Le VMM
emploiera l'index fourni pour placer l'adresse du service souhaité dans la table de service. Par exemple,
si vous voulez appeler GetVersion qui est le premier service, vous devez spécifier 0 (qui est l'index
zéro-basé). Le mécanisme réel d'appel des 'services VxD' implique l'interruption 20 (int 20h). Dans votre
code paraîtra l'instruction int 20h suivi d'une valeur de type dword qui sera composée du n°ID du
dispositif (du clavier par exemple) et de l'index du service. Par exemple, si vous voulez appeler le
service numéro 1 étant exporté par un VxD qui a le n°ID de dispositif de 000Dh, le code sera le
suivant :
Le mot de poids fort du dword qui suit l'instruction int 20h contient le n°ID du Device. Le mot de poids
faible est l'index zéro-basé dans la table de service.
Quand int 20h est exécuté, le VMM prend le contrôle et examine le dword qui suit immédiatement cet
instruction. Il en extrait alors le n°ID du dispositif et s'en sert pour localiser le VxD et emploie
ensuite l'index de service pour y placer l'adresse du service désirée appartenant au VxD.
Vous pouvez remarquer que cette opération prend un certain temps. Le VMM (Manager de Machine
Virtuelle) doit gaspiller du temps en localisant le VxD et l'adresse du service désiré. Ainsi le
VMM triche un peu. Après que la première opération int 20h se
soit passé, le VMM rompt la liaison. En rompant la liaison, ça
signifie que le VMM remplace l'int 20h ainsi que le dword qui le suivit par un appel direct au service.
Donc ce petit bout de code int 20h sera transformé en : call dword ptr [VxD_Service_Address]
Ce tour de passe passe marche parce que int 20h+dword prend 6 octets,
qui est exactement de la mêmes taille que l'instruction call dword ptr.
Donc les appels suivants sont rapides et efficaces.
Cette méthode a son pour et son contre. Son bon côté, c'est de réduire le travail de chargement du VMM et du VxD
parce qu'ils ne doivent pas fixer TOUS les appels de service de VxDs
quand on les charge. Les appels qui ne sont jamais exécutés resteront non modifiés. Le mauvais côté, c'est
qu'il est impossible de décharger un VxD statique une fois qu'on à fait appel à ses services et q'on s'y
soit lié. Depuis que le VMM fixe les appels avec les adresses réelles des services VxD, si le VxD qui
fournit ces services est déchargé de la mémoire, alors d'autres VxDs qui dépendent de ces services
'crasheront' probablement le système en faisant appel à des adresses mémoire invalides. Il n'y a aucun
mécanisme pour assurer les liaisons. Le preuve c'est que les VxDs
dynamiques ne sont pas appropriés comme les VxDs service providers.
Callbacks:
Les fonctions callbacks ou callback sont des fonctions du VxD qui existent pour être appelés par d'autre
VxDs. Ne faîtes pas la confusion entre les 'callbacks' et les 'VxD services'. Les callbacks ne sont pas
publiques comme les services. Ce sont des fonctions privées que les adresses d'un VxD donnent à d'autres
VxDs specifiques dans certaines situations. Par exemple, quand un VxD
entretient une interruption matérielle, puisque le VMM n'est pas reparticipant (il ne traite qu'avec 1
seul), le VxD ne peut pas employer de 'VxD services' lesquels peuvent provoquer des fautes de page
(en essayant de recommuniquer avec le VMM). Le VxD peut donner l'adresse de sa propre fonction
(le callback) au VMM pour que celui-ci puisse appeler la fonction quand le VMM est capable de tolérer des
fautes de page. Le VxD peut alors reprendre son travail quand sa fonction callback est appelée. Le
concepte de callback n'est pas spécifique aux VxDs. Beaucoup d'APIs de Windows les emploient aussi. Le
meilleur exemple est peut-être la 'procédure de fenêtre'. Vous spécifiez l'adresse d'une procédure de
fenêtre dans la structure WNDCLASS ou WNDCLASSEX et la passez à Windows grâce à l'Appel de RegisterClassEx
ou RegisterClass. Windows appellera votre procédure de fenêtre quand il y aura des messages destinés à
cette fenêtre. Un autre exemple est la procédure de Hook. Votre application donne l'adresse de la
procédure de Hook à Windows pour que celui-ci puisse l'appeler quand des événements intéressant pour votre
application se produisent.
Ces trois méthodes servent à la communication entre VxDs. Il y a aussi les interfaces pour V86, le
mode protégé et les applications Win32. Je couvrirai l'interface VxD pour les applications Win32 dans les
Tutorials suivants.