ALLOCATE_LDT_DESCRIPTORS |
Alloue un descripteurs LDT |
Free Pascal |
go32 |
Syntaxe
Function allocate_ldt_descriptors(count:Word):Word;
|
Paramètres
Nom |
Description |
count |
Ce paramètre permet d'indiquer le nombre de descripteurs uniques demandés. |
Retour
Valeur |
Description |
entier |
Ces valeurs permettent d'indiquer un sélecteur de base. |
Description
Cette fonction permet d'allouer un certain nombre de descripteurs.
Remarques
- Les descripteurs alloués doivent être initialisés par l'application avec d'autres appels de fonction. Cette fonction renvoie des descripteurs dont la limite et la taille sont définies
à zéro. Si plusieurs descripteurs sont demandés, la fonction renvoie un sélecteur de base référençant le premier d'un tableau contigu de descripteurs. Les valeurs de sélecteur des
descripteurs suivants du tableau peuvent être calculées en additionnant la valeur renvoyée par la fonction get_next_selector_increment_value.
- En cas d'erreurs : Vérifiez la variable int31error.
- Allocation dynamique des descripteurs : La fonction allocate_ldt_descriptors permet d'allouer dynamiquement un ou plusieurs descripteurs LDT
(Local Descriptor Table) dans l'environnement DPMI (DOS Protected Mode Interface). Cela permet de manipuler directement des segments de mémoire protégée,
ce qui est essentiel pour certaines opérations bas niveau.
- Retour d'un sélecteur valide ou d'une erreur : Lorsque l'appel à allocate_ldt_descriptors réussit, il renvoie un sélecteur utilisable immédiatement. En cas
d'échec, il retourne 0, ce qui indique que l'allocation a échoué. Il est donc impératif de toujours vérifier la valeur de retour avant de poursuivre l'exécution du programme.
- Possibilité d'allouer plusieurs descripteurs à la fois : Cette fonction prend en paramètre le nombre de descripteurs à allouer. Si on en demande plusieurs, elle
retourne uniquement le premier sélecteur alloué. Pour obtenir les suivants, il faut utiliser get_next_selector_increment_value et incrémenter le sélecteur de retour.
- Importance du paramètre DPMI : L'appel à allocate_ldt_descriptors repose sur les services DPMI, permettant d'accéder à la mémoire protégée depuis un programme
fonctionnant en mode réel étendu. Il est donc indispensable de s'assurer que l'environnement DPMI est bien disponible, par exemple via CWSDPMI sous
DOS.
- Utilisation conjointe avec d'autres fonctions : Une fois le descripteur LDT alloué, il est souvent utilisé avec set_segment_base_address et set_segment_limit
pour définir respectivement l'adresse de base et la limite de la mémoire qu'il décrit. Ces étapes sont essentielles pour manipuler correctement la mémoire associée au sélecteur.
- Risque de fuite de descripteurs: Chaque allocation de descripteur consomme une entrée dans la table LDT. Si un programme alloue trop de descripteurs sans les
libérer via free_ldt_descriptor, il risque d'épuiser les entrées disponibles, ce qui peut provoquer des erreurs ou un comportement imprévisible.
- Compatibilité et limitations : La gestion des descripteurs LDT dépend du mode d'exécution du programme. Sous DOS natif
avec DPMI, elle fonctionne bien, mais sous certains environnements comme Windows modernes, l'exécution de programmes en mode
DPMI peut être limitée ou nécessiter un émulateur comme DOSBox.
- Utilisation avancée pour la gestion mémoire : L'allocation de descripteurs LDT permet une gestion mémoire avancée, notamment pour créer des segments dédiés à des
tampons vidéo, des zones de partage entre tâches ou des accès directs à la mémoire haute. Elle offre ainsi un contrôle plus fin que la simple allocation mémoire standard en
Free Pascal.
Exemple
- { Cet exemple démontre l'utilisation des descripteurs et les effets
- du changement de leur limite et de leur adresse de base.
-
- Plus en détail, le programme remplit la région décrite par un
- descripteur alloué dans la mémoire écran en mode texte avec divers
- caractères. Avant de faire cela, il sauvegarde l'intégralité du contenu
- de l'écran dans le tas et le restaure ensuite.
-
- Quelques informations supplémentaires :
-
- L'écran texte d'une carte VGA a son espace mémoire à l'adresse $B800:0 ;
- la mémoire écran est organisée de manière linéaire, c'est-à-dire que la
- deuxième ligne vient directement après la première, où chaque cellule
- occupe 2 octets de mémoire (1 octet pour le caractère, 1 octet pour
- les attributs). Elle a une taille de 32 Ko.
-
- Ainsi, le décalage d'une seule cellule mémoire par rapport à son origine est :
-
- Y * colonnes * 2 + X * 2
-
- où X et Y désignent le point, et colonnes est le nombre de cellules
- caractères par ligne.
- }
-
- {$mode delphi}
-
- Uses
- Crt,go32;
-
- Const
- { Dimensions de l'écran en X et Y }
- maxx = 80;
- maxy = 25;
- { Nombre d'octets utilisés pour chaque cellule de caractères }
- bytespercell = 2;
- { Taille de l'écran en octets }
- screensize = maxx * maxy * bytespercell;
-
- { Adresse linéaire de $B800:0 }
- linB8000 = $B800 * 16;
-
- Type
- string80 = string[80];
-
- Var
- { Contient l'ancien contenu de l'écran }
- Text_Save:Array[0..screensize-1] of Byte;
- { Anciennes coordonnées du curseur X et Y }
- Text_oldx,Text_oldy:Word;
-
- { Sélecteur vers l'écran en mode texte }
- Text_sel:Word;
-
- { Affiche un message d'état sur la première ligne de l'écran puis attend une pression de touche }
- Procedure status(s : string80);Begin
- GotoXY(1, 1);
- ClrEol;
- Write(s);
- ReadKey;
- End;
-
- { Affiche des informations sur le descripteur sur les 2 dernières lignes }
- Procedure selinfo(sel:Word);Begin
- GotoXY(1, 24);
- ClrEol;
- WriteLn('Adresse de base du descripteur : $',hexstr(get_segment_base_address(sel), 8));
- ClrEol;
- Write('Limite du descripteur : ',get_segment_limit(sel));
- End;
-
- { Retourne une cellule de caractère de 2 octets, incluant les données du caractère et ses attributs de couleur }
- Function makechar(ch:char;color:byte):Word;Begin
- makechar:=byte(ch) or (color shl 8);
- End;
-
- BEGIN
- { Sauvegarde le contenu original de l'écran dans une variable, cette fois en utilisant seg_move() et la variable dosmemselector }
- seg_move(dosmemselector, linB8000, get_ds, longint(@text_save),screensize);
- { Nous devons également sauvegarder les anciennes coordonnées du curseur sur l'écran }
- text_oldx := WhereX;
- text_oldy := WhereY;
- { Efface entièrement l'écran }
- seg_fillword(dosmemselector, linB8000, screensize div 2,
- makechar(' ', Black or (Black shl 4)));
- { Affiche un message }
- status('Création du sélecteur ''text_sel'' pour une partie de la mémoire écran en mode texte');
- { Alloue un descripteur }
- text_sel := allocate_ldt_descriptors(1);
- { Définit son adresse de base à l'adresse linéaire de l'écran texte la taille en octets d'une ligne (=maxx * bytespercell * 1) }
- set_segment_base_address(text_sel,linB8000 + bytespercell * maxx * 1);
- { Définit la limite à la taille de l'écran réduite d'un octet (obligatoire) et du nombre de lignes à ne pas modifier (première ligne + les 2 dernières lignes) }
- set_segment_limit(text_sel, screensize - 1 - bytespercell * maxx * 3);
- { Affiche les informations du descripteur }
- selinfo(text_sel);
- status('et effacement de toute la mémoire sélectionnée par le descripteur ''text_sel''');
- { Remplit toute la mémoire sélectionnée avec des caractères uniques }
- seg_fillword(text_sel, 0, (get_segment_limit(text_sel)+1) div 2,makechar(' ', LightBlue shl 4));
- status('Remarquez que seule la mémoire décrite par le descripteur a changé, rien d''autre');
- status('Réduction maintenant de sa limite et de sa base, et définition de sa mémoire décrite');
- { Modifie l'adresse de base du descripteur (l'augmente de la taille en octets d'une ligne) }
- set_segment_base_address(text_sel,get_segment_base_address(text_sel) + bytespercell * maxx);
- { Réduit la limite de la taille en octets de 2 lignes (1 ligne car l'adresse de base a changé, une autre ligne en bas) }
- set_segment_limit(text_sel,get_segment_limit(text_sel) - bytespercell * maxx * 2);
- { Affiche les informations du descripteur }
- selinfo(text_sel);
- status('Remarquez que l''adresse de base a augmenté d''une ligne mais que la limite a diminué de 2 lignes');
- status('Cela devrait vous donner un indice sur le fait que la limite est relative à la base');
- { Remplit la zone du descripteur }
- seg_fillword(text_sel, 0, (get_segment_limit(text_sel)+1) div 2,makechar(#176, LightMagenta or Brown shl 4));
- status('Maintenant, faisons quelque chose de plus fou : ' +
- 'copier 10 lignes de données de l''écran précédemment sauvegardé');
- { Copie la mémoire du segment de données vers l'écran }
- seg_move(get_ds, longint(@text_save), text_sel,maxx * bytespercell * 2, maxx * bytespercell * 10);
- status('Enfin, libération du descripteur et restauration du contenu de l''écran...');
- status('J''espère que ce petit programme vous donnera des ' +
- 'indices sur la manipulation des descripteurs');
- { Libère le descripteur pour qu'il puisse être utilisé pour autre chose }
- free_ldt_descriptor(text_sel);
- { Restaure l'état précédent }
- seg_move(get_ds, longint(@text_save), dosmemselector,linB8000, screensize);
- GotoXY(text_oldx, text_oldy);
- END.
-
Dernière mise à jour : Dimanche, le 23 Août 2020