Introduction
Un vrai driver matériel doit connaître les ressources assignées à son périphérique : plages de ports, régions mémoire, interruption, canal DMA, etc.
Dans WDM, ces informations arrivent généralement lors de IRP_MN_START_DEVICE.
1. Ressources brutes et ressources traduites
Lors du démarrage du périphérique, le PnP Manager fournit deux listes :
- Raw resources : ressources telles qu'elles existent sur le bus.
- Translated resources : ressources traduites dans un format directement exploitable par le processeur et le HAL.
Code: Select all
stack->Parameters.StartDevice.AllocatedResources
stack->Parameters.StartDevice.AllocatedResourcesTranslated
2. Structures principales
Structures importantes
- CM_RESOURCE_LIST
- CM_FULL_RESOURCE_DESCRIPTOR
- CM_PARTIAL_RESOURCE_LIST
- CM_PARTIAL_RESOURCE_DESCRIPTOR
Code: Select all
PCM_PARTIAL_RESOURCE_LIST list;
for (ULONG i = 0; i < list->Count; ++i)
{
PCM_PARTIAL_RESOURCE_DESCRIPTOR res =
&list->PartialDescriptors[i];
switch (res->Type)
{
case CmResourceTypePort:
break;
case CmResourceTypeMemory:
break;
case CmResourceTypeInterrupt:
break;
case CmResourceTypeDma:
break;
}
}
Une ressource CmResourceTypePort décrit une plage de ports d'E/S.
Informations importantes :
Code: Select all
res->u.Port.Start
res->u.Port.Length
res->Flags
4. Port-mapped I/O
Sur x86/x64, certains périphériques exposent des registres via un espace d'adressage I/O distinct.
Les API classiques sont :
API importantes
- READ_PORT_UCHAR
- READ_PORT_USHORT
- READ_PORT_ULONG
- WRITE_PORT_UCHAR
- WRITE_PORT_USHORT
- WRITE_PORT_ULONG
Code: Select all
UCHAR value = READ_PORT_UCHAR(portBase);
WRITE_PORT_UCHAR(portBase, 0x01);
De nombreux périphériques modernes exposent leurs registres dans une plage d'adresses mémoire.
Le driver mappe la ressource physique avec :
Code: Select all
PVOID regs = MmMapIoSpace(
physicalAddress,
length,
MmNonCached
);
Code: Select all
MmUnmapIoSpace(regs, length);
- READ_REGISTER_UCHAR
- READ_REGISTER_USHORT
- READ_REGISTER_ULONG
- READ_REGISTER_BUFFER_*
- WRITE_REGISTER_UCHAR
- WRITE_REGISTER_USHORT
- WRITE_REGISTER_ULONG
- WRITE_REGISTER_BUFFER_*
Code: Select all
volatile ULONG* statusReg =
(volatile ULONG*)((PUCHAR)regs + STATUS_OFFSET);
ULONG status = READ_REGISTER_ULONG(statusReg);
Un registre matériel n'est pas de la RAM ordinaire. L'ordre des accès, les barrières mémoire, le cache et les contraintes de plateforme peuvent être importants.
Il faut donc préférer les macros prévues par le WDK plutôt qu'un simple :
Code: Select all
*reg = value;
Une ressource CmResourceTypeInterrupt décrit l'interruption assignée au périphérique.
On y retrouve selon le type de ressource :
Code: Select all
res->u.Interrupt.Level
res->u.Interrupt.Vector
res->u.Interrupt.Affinity
res->Flags
8. Ressource DMA
Pour les périphériques utilisant un canal DMA système, on peut recevoir :
Code: Select all
res->u.Dma.Channel
res->u.Dma.Port
9. Stocker les ressources dans DEVICE_EXTENSION
Une pratique classique consiste à conserver les ressources utiles dans l'extension du périphérique.
Code: Select all
typedef struct _DEVICE_EXTENSION
{
PDEVICE_OBJECT LowerDevice;
PUCHAR PortBase;
ULONG PortLength;
PVOID RegisterBase;
ULONG RegisterLength;
PKINTERRUPT InterruptObject;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
Code: Select all
for (ULONG i = 0; i < list->Count; ++i)
{
PCM_PARTIAL_RESOURCE_DESCRIPTOR res =
&list->PartialDescriptors[i];
switch (res->Type)
{
case CmResourceTypePort:
DbgPrint("PORT: %I64x length=%lu\n",
res->u.Port.Start.QuadPart,
res->u.Port.Length);
break;
case CmResourceTypeMemory:
DbgPrint("MEM: %I64x length=%lu\n",
res->u.Memory.Start.QuadPart,
res->u.Memory.Length);
break;
case CmResourceTypeInterrupt:
DbgPrint("IRQ vector=%lu level=%lu\n",
res->u.Interrupt.Vector,
res->u.Interrupt.Level);
break;
}
}
Lorsqu'un périphérique est arrêté ou supprimé, le driver doit libérer ce qu'il a acquis :
- MmUnmapIoSpace pour les régions MMIO.
- IoDisconnectInterrupt / routine moderne équivalente pour l'interruption.
- Libération des objets DMA si nécessaire.
- Arrêt des timers et DPC associés.
Le chemin typique est :
Code: Select all
IRP_MN_START_DEVICE
|
v
CM_RESOURCE_LIST
|
+--> Port
+--> Memory/MMIO
+--> Interrupt
+--> DMA
|
v
DEVICE_EXTENSION
|
v
accès au matériel
