Suivez-nous sur X

|
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
ALL
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
A propos d'Obligement
|
|
David Brunet
|
|
|
|
Programmation : Assembleur - Boot Allocator
(Article écrit par Frédéric Mazué et extrait d'Amiga News Tech - septembre 1990)
|
|
Ce mois-ci, je vous propose un petit programme (Boot Allocator) qui vous permettra d'amorcer vos disquettes sur DF1: DF2: ou DF3: à
votre guise. Mais attention, ceci est réservé aux possesseurs de Kickstart 1.3. Autrement dit : place aux jeunes.
Le déroulement d'une séquence de démarrage
Savez-vous comment se déroule une séquence de démarrage sur votre machine préférée ? Peut-être pas, sinon vous
ne seriez pas en train de dévorer goulûment cet article. Voici donc quelques explications succinctes.
Tout d'abord, les circuits électroniques effectuent des tests et s'assurent ainsi eux-mêmes qu'ils sont
en état de fonctionner. Si l'un de ces circuits constate qu'il est en panne, alors une couleur apparaît
et reste sur votre moniteur. La couleur est destinée à informer les spécialistes de l'origine de la panne.
Ce test s'effectue naturellement très vite, puis l'on rentre dans le processus d'initialisation (ou "reset"
en anglais) de l'Amiga. Normalement un microprocesseur 68000 va chercher à l'adresse $0 une valeur pour
le pointeur de pile superviseur puis il charge son PC avec le contenu de l'adresse $4 et c'est parti.
Mais, me direz-vous, que contiennent ces adresses à l'allumage ou lors d'une réinitialisation ?
A l'allumage, ces adresses contiennent toute les deux 0 et lors d'une réinitialisation, la première contient 0
et la deuxième la valeur de execbase qui ne peut évidemment pas être utilisée par le 68000 comme adresse de
démarrage.
Mais alors, comment ça marche ? Très simple : juste après le test des circuits, le bit de la broche PA 0
du CIA A est placé et ceci a pour effet de provoquer le recouvrement de la mémoire Chip par la ROM.
Ainsi, sans même s'apercevoir qu'il s'est fait berner, le 68000 lit le contenu des adresses $f80000 et
$f80004. Si vous êtes curieux et que vous allez examiner vous-même ces adresses, vous constaterez que la
routine reset démarre à l'adresse Sfc00d2. Très tôt dans cette routine, vous rencontrerez l'instruction
move.b #$02,$bfe0001 qui a pour effet à la fois d'éteindre la LED de mise sous tension
et d'annuler le recouvrement mémoire, ce qui ne pose plus de problème maintenant que le 68000 caracole
joyeusement en ROM.
Que se passe-t-il ensuite ? Beaucoup de choses que je résume. L'ordinateur teste de combien de mémoire il
dispose, il commence à construire exec.library, il saute dans le vecteur ColdCapture le cas échéant (n'est-ce
pas messieurs les programmateurs de virus ?), puis et c'est très important, sont installées les structures
résidentes suivant un ordre de priorité que voici et que je suis allé moi-même rechercher en ROM.
Structures |
Priorité |
Commentaires |
exec.library |
120 |
L'installation est totalement terminée |
expansion.library |
110 |
Et non pas exception.library comme mentionné dans La Bible de l'Amiga |
potgo.ressource |
110 |
|
keymap.ressource |
110 |
|
cia.ressource |
80 |
|
disk.ressource |
70 |
|
misc.ressource |
70 |
|
ramlib.library |
70 |
|
graphics.library |
65 |
|
keyboard.device |
60 |
|
gameport.device |
60 |
|
timer.device |
50 |
|
audio.device |
40 |
|
input.device |
40 |
|
layers.library |
31 |
Attention, contient un sorcier extraordinaire ! Videz donc la ROM à l'adresse $fe09a4 et vous verrez |
console.device |
20 |
|
trackdisk.device |
20 |
|
intuition.library |
10 |
|
alert.hook |
5 |
Ça c'est notre fameux Guru ! |
mathffp.library |
0 |
|
workbench.task |
0 |
|
dos.library |
0 |
|
romboot.library |
-40 |
Kickstart 1.3 seulement |
bootstrap |
-60 |
C'est le programme de démarrage |
Une fois ces structures installées, le 68000 saute dans le vecteur CoolCapture le cas échéant (n'est-ce pas
messieurs les programmeurs de virus ?). Ensuite les structures précédemment installées et qui sont un programme
sont exécutées en tant que tel : c'est le cas du démarrage. Pour les curieux qui voudraient tracer
la routine de démarrage eux-mêmes, c'est facile, cette routine commence à l'adresse $fe8444, mais
je vous recommande de sauter les instructions qui trafiquent le DMA sinon gare au plantage.
La routine Boot
Que fait la routine Boot ? Elle commence par examiner si la réinitialisation
provient de l'utilisateur ou du Guru (examen des registres D6 et D7) et agit en
conséquence. Le cas qui nous intéresse étant une réinitialisation utilisateur, je
n'entrerais pas dans de profondes méditations. La routine continue en ouvrant
le trackdisk.device pour lire les secteurs 0 et 1 de la disquette contenue dans
DF0: (s'il y a une disquette). Si à ce moment des "secteurs amorce" (c'est-à-dire
si la disquette est autoamorçable) sont trouvés, l'Amiga démarre imparablement sur DF0:.
Mais s'il n'y a pas de disquette ou si celle-ci n'est pas autoamorçable, alors la routine
ouvre la romboot.library qui, elle, regarde s'il existe en mémoire des structures DosNode
avec priorité au démarrage, si oui elle démarre selon cette structure, si non la romboot.library
recherche d'éventuels périphériques autoamorçables tel qu'un disque dur A590 par exemple.
Maintenant c'est du sérieux, j'ai dit au début de cet article qu'il est possible de démarrer
sur n'importe quel lecteur externe (dûment connecté de préférence) et voilà que je vous révèle
comment. Il faudrait simplement pouvoir entrer en mémoire une de ces fameuses structures DosNode.
Si seulement il était possible d'avoir la main pendant la réinitialisation ! Casse la tienne !
On va s'offrir le luxe d'installer nous-même une structure résidente du type de celles vues
précédemment, mais d'une priorité supérieure au bootstrap et qui nous proposera le choix d'ajouter
ou non un DosNode au système et voilà !
Programmation de la réinitialisation
D'après les Amiga ROM Kernel Manual, qui ne sont pas très bavards sur le sujet (toujours la
peur des programmeurs de virus apparemment), voici comment doit être constituée une structure résidente :
struct resident {
0 UWORD rt_MatchWord;
2 struct Resident *rt_MatchTag;
6 APTR rt_EndSkip;
10 UBYTE rt_Flags;
11 UBYTE rt_Version;
12 UBYTE rt_Type;
13 BYTE rt_Pri;
14 char *rt_Name;
18 char *rt_IdString;
22 APTR rt_Init;
};
|
Les plus observateurs d'entre vous auront remarque que cette structure est donnée en langage C,
mais la transposition en assembleur ne pose aucun problème comme vous le verrez dans le listing.
Quelques explications :
- rt_MatchWord est un mot de passe et doit avoir la valeur $4AFC.
- rt_MatchTag est un pointeur sur la structure elle-même.
- rt_EndSkip est un pointeur sur la fin de ce que l'on veut maintenir en mémoire.
- rt_Flags doit contenir $01 pour que la structure soit initialisée en tant que programme.
- rt_Version : numéro de version avec 0 comme valeur de préférence.
- rt_Type doit contenir $01 -> type process.
- rt_Name : pointeur sur le nom de la structure.
- rt_IdString : pointeur sur un commentaire parfaitement inutile.
- rt_Init : dans notre cas est un pointeur sur le programme qui devra être exécuté.
Maintenant que nous avons cette structure, qu'en faisons-nous ? Réponse : rien. Ce qu'il
faut faire maintenant c'est informer l'Amiga qu'il aura des structures résidentes à initialiser
et pour ce faire, il faut (ce que les livres ne disent pas ou alors ce sont des bêtises) lui
fournir un tableau de pointeur dont chaque élément est un pointeur sur une structure à initialiser.
Dans le listing, ce tableau est appelé "pour_KickTagPtr", comporte un seul élément puisqu'on
ne veut installer qu'une structure et un long mot nul de fin de tableau (très important, les
programmeurs en C me comprendront).
KickTagPtr : qui c'est celui-là ? C'est un pointeur dans execbase qui doit pointer sur le
tableau de structures à initialiser. Vous trouverez dans le listing la valeur de décalage de
KickTagPtr et vous verrez qu'on le fait bien pointer sur le tableau "pour_KickTagPtr".
Mais ce n'est pas tout !
La memory list
En effet, dans execbase se trouve un pointeur nommé "KickMemPtr" et qui doit pointer sur une
"memory list" correspondant à la structure que l'on veut installer. Voyons ça de plus près.
struct MemList {
0 struct Node ml_Node;
14 UWORD ml_NumEntries;
16 struct memEntry ml_ME[1];
};
|
On a donc d'abord une structure de noeud, c'est banal, puis le nombre d'entrées dans la memory
list puis la première entrée.
Ceux qui sont à l'aise en C comprendront que les entrées de la memory list sont rangées dans
un tableau de structures. En fait, la structure memory list est quelque peu hybride car extensible
à l'infini (ou presque), il suffit d'augmenter le nombre d'entrées et le nombre d'éléments du
tableau. Voyons enfin la structure MemEntry.
struct MemEntry {
union {
ULONG meu_Reqs;
APRRT meu_Addr;
} me_Un;
ULONG me_Length;
};
|
Les connaisseurs en C que vous êtes savent que lorsqu'on a affaire à une union, c'est soit l'un
soit l'autre :
- meu_Reqs serait la condition de réservation de mémoire, nous ne l'utiliserons pas.
- meu_Addr est l'adresse de la mémoire réservé. Nous y mettrons tout naturellement l'adresse
de notre structure résidente, plaçant ainsi l'Amiga devant un fait accompli, et l'obligeant à
considérer que cette mémoire nous est reservée (Cf. le listing).
- me_Length est simplement la longueur de la mémoire dont nous venons de forcer la réservation.
Tout ceci étant fait, il suffit d'appeler la routine d'exec.library KickSumData afin de
recalculer une somme d'autocontrôle puis de ranger le résultat en KickCheckSum dans execbase
est c'est prêt.
Il suffit de faire une réinitialisation (après avoir sauvegardé le programme, c'est tout de
même plus prudent) pour admirer le résultat.
Deux remarques
Pour ceux qui utilisent un RAD:, il faut savoir que celui-ci s'installe comme nous venons
de l'expliquer. Ce qui signifie que le lancement de notre programme va impitoyablement
détruire le RAD:. Il y a bien sûr un remède. Modifier notre programme comme suit :
tester la présence du RAD: (ou d'un équivalent), modifier sa memory list et son tableau
de pointeur en y ajoutant notre propre structure. En fait, cela revient à se chaîner au
RAD:. Mais voilà, comme là où il y a de la chaîne, il n'y a pas de plaisir, j'ai laissé
libre cours à ma paresse et préfère laisser les modifications à votre sagacité.
J'ai remarqué que mon programme "rate" quelquefois sur un Amiga 2000 équipé d'un Super Fat Agnus
et donc d'un Mo de mémoire Chip. Comme je travaille habituellement sur Amiga 500, je n'ai
pas eu le temps d'approfondir la question sur l'A2000 d'un collègue. Je soupçonne un bogue
dans la routine AllocEntryd'exec.library. Si un lecteur tire l'affaire au clair il gagnera...
toute mon estime.
Le DosNode
Il m'a fallu lire entre les lignes (en anglais, groumpff !) des Amiga ROM Kernel Manual
pour trouver la solution du problème. Le moins que l'on puisse dire est que la documentation
au niveau du DOS est sibylline. C'est à croire que Commodore préfère qu'on y touche pas à son
DOS. Ceci est pour le moins curieux.
On finit par comprendre qu'il faut appeler la routine MakeDosNode de l'expansion.library.
A cette routine, il faut passer un paquet de paramètres (registre A0) définis (!) comme suit :
Paramètres |
Commentaires |
APTR dosName |
Exemple "DF1" c'est le nom du périphérique logique à monter |
APTR execName |
Le nom de celui qui devra s'occuper du boulot, ici "trackdisk.device" |
ULONG unit |
Numéro d'unté concernée : 1 pour DF1:, etc. |
ULONG flags |
0 le drapeau utilisé lors de l'ouverture du trackdisk.device (il suffisait d'y penser !) |
Vient ensuite une série de longs mots définissant la géométrie du disque réel ou virtuel qui doit être monté :
Paramètres |
Commentaires |
ULONG de_TableSize |
Le nombre de longs mots composant la table ici présente. Dans notre cas : 17 |
ULONG de_SizeBlock |
Le nombre de longs mots dans un bloc, ici 128 |
ULONG de_SecOrg |
Secteur origine, ici 0 |
ULONG de_Surfaces |
Le nombre de têtes, ici 2 |
ULONG de_SectorPerBlock |
1 évidemment ! |
ULONG de_BlocksPerTracks |
Nombre de blocs par piste, ici 11 |
ULONG de_Reserved |
Le nombre de bloc réservés au démarrage, donc 2 |
ULONG de_PreAlloc |
Concerne les disques durs, ici 0 |
ULONG de_Interleave |
Je ne sais ce que c'est. 0 convient très bien |
ULONG de_LowCyl |
Piste de départ, donc 0 |
ULONG de_HighCyl |
Dernière piste, donc 79 |
ULONG de_NumBuffers |
Tout marche très bien avec 5 |
ULONG de_BufMemType |
Type de mémoire, ici 3, soit Chip|Public |
ULONG de_MaxTransfer |
Le nombre d'octets dans un bloc, soit 512 |
ULONG de_Mask |
Masque de mémoire maximum, mettre $00ffffff |
ULONG de_BootPri |
Priorité au démarrage : ici 5 c'est suffisant |
ULONG de_DosType |
Ici OldFileSystem, soit $44F5300 |
A cela j'ajoute un long mot nul car j'ai remarqué qu'à la suite d'un calcul parfaitement hermétique,
le système d'exploitation remplace le dit mot nul par Guru seul sait quoi ! Ce paquet de
paramètres étant traité par MakeDosNode on obtient un pointeur sur un DosNode qu'on insérera dans
le système avec la routine AddDosNode de expansion.library et c'est terminé.
Donc après avoir assemblé ce programme (qui peut être placé dans une startup-sequence),
lancez-le. Il rend la main immédiatement. Retirez votre disquette Workbench de DF0:
et placez-la en DF1: et faites une réinitialisation. Lorsque la requête apparaît, cliquez le
bouton droit de la souris et l'Amiga démarrera en DF1:. Si vous avez tout bien compris, il
vous sera enfantin de modifier ce programme pour démarrer en DF2: ou DF3: si le coeur vous en
dis et moi je vous dit à bientôt.
|