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 - NewPic (remplacement de l'image de démarrage de l'Amiga)
(Article écrit par Max et extrait d'Amiga News Tech - octobre 1991)
|
|
Histoire de changer un peu, nous allons vous présenter un programme qui présente la particularité d'être
parfaitement inutile. Quoique, en y regardant de plus près...
Judicieusement baptisé NewPic, ce programme se propose de remplacer la morne et triste
main de l'Amiga -
vous savez, celle qui demande une disquette Workbench - par une image IFF de votre choix. Si le résultat
est purement esthétique, la mise en oeuvre demande quelques connaissances des processus de réinitialisation
et de démarrage de l'ordinateur, un tel programme devant être capable de résister à la réinitialisation
pour resurgir inlassablement à chaque redémarrage.
Séquence frisson
Or donc, lorsque vous appuyez presque machinalement sur le bouton on/off du boîtier d'alimentation, tout
un tas de choses auxquelles on n'auraient même pas pensé se passent. C'est ce que l'on appelle le démarrage
à froid : d'abord, l'électronique chauffe un peu, histoire de pouvoir travailler dans de parfaites conditions.
Ensuite, le logiciel prend la main et commence un véritable travail de titan, qui consiste à s'informer
de la configuration matérielle et à initialiser toutes les couches logicielles du système d'exploitation.
D'un autre côté, une autre séquence de démarrage, semblable à la première pour l'essentiel mais pas
identique, survient lors des démarrages à chaud, c'est-à-dire essentiellement lors d'une réinitialisation,
causé soit par l'appui simultané sur les maintenant célèbres trois touches Control-Amiga gauche-Amiga droite,
soit par la volonté d'un programme quelconque, soit enfin suite à un plantage de la machine. Ce qui se passe à
ce moment-là est fort intéressant, et je vous propose de le découvrir avec moi.
Séquence démarrage
Il faut savoir que lorsque le microprocesseur 68000 se trouve en état de réinitialisation,
un système de recouvrement mémoire fait apparaître une image de la ROM
en bas de mémoire. Ceci est nécessaire parce que justement, le 68000 va chercher l'adresse de la
première instruction à exécuter à l'adresse $00000004 (heu... 4 en décimal) et la valeur initiale
du pointeur de pile à l'adresse $00000000. Or, si de la mémoire occupe cet espace, aucune valeur
valide ne pourra y être trouvée, d'où le recouvrement évoqué plus haut. Le 68000 va chercher
les informations en ce qu'il croit être l'adresse 0, alors qu'il va sans même s'en rendre compte
les trouver en $FC0000.
Bref, le 68000 se retrouve maintenant en $FC00D2, où après quelques tests internes (intégrité de la
ROM, version du système), il supprime le recouvrement mémoire (pour les curieux, c'est le bit 0
du port A du CIA A qui le contrôle). La mémoire est maintenant à nouveau disponible en $00000000
et jusqu'à $0007FFFF (c'est la mémoire Chip ; aucune extension mémoire n'est encore reconnue) et
la table des auto-vecteurs du 68000 peut être mise en place. Ensuite, on construit ExecBase,
on place son adresse en $00000004, et on appelle la routine de démarrage à chaud (je simplifie
un peu, mais c'est ça).
Le démarrage à chaud consiste dans un premier temps à vérifier l'intégrité de la structure ExecBase.
Si ce test échoue, un démarrage "à froid" est provoqué. Un peu plus tard, les premiers programmes
"résidents" (entendez par là, résistant à la réinitialisation) sont appelés, via le
vecteur ColdCapture. Plus tard encore, une fois que la pile aura été initialisée, c'est CoolCapture
qui sera appelé. Après ça, Exec recherche en mémoire toutes les structures résidentes et leur passe
le contrôle du processeur, le temps de leur initialisation. C'est là qu'il nous faudra chercher le
moyen de devenir parfaitement résident, sans embêter les détecteurs de virus qui
recherchent ces affreuses bébêtes dans ColdCapture et CoolCapture, comme VirusX par exemple. Malheureusement,
d'autres antivirus recherchent également les structures résidentes et les éliminent impitoyablement de
la mémoire si elles ont le malheur de ne pas pointer sur une adresse en ROM.
Contre ceux-là, impossible de se protéger.
Séquence structure
Comme vous devez commencer à en avoir l'habitude, un module résident est défini par une structure que
l'on peut trouver dans "exec/resident.i" :
avec :
Le premier mot est donc la constante $4AFC qui permet à Exec de reconnaître une structure résidente lorsqu'il
parcourt la mémoire. Le second élément, RT_MATCHTAG, pointe sur la structure elle-même (donc, sur RT_MATCHWORD)
et sert de deuxième vérification quant à la validité de cette structure. Parmi les champs réellement importants,
on trouve également RT_ENDSKIP, qui indique la fin de la structure. Ce pointeur permet de la rallonger à volonté,
afin par exemple de maintenir résidentes d'autres données. En général, le programme résident sera lui aussi
logé entre la structure et l'adresse pointée par RT_ENDSKIP. L'adresse de ce programme est placée dans le
champ RT_INIT.
La priorité de la structure indique dans quel ordre elle sera initialisée. Plus la priorité est élevée, plus
l'initialisation arrivera tôt. Par exemple, exec.library présente une priorité de 120, celle du trackdisk.device
est de 14, celle du strap (le module qui affiche la main Workbench et charge le bloc d'amorce
de la disquette en DF0:), de -60 et celle de la dos.library, de 0. En général, on utilisera une priorité négative,
afin d'être sûr que le système complet est initialisé. J'ai arbitrairement choisi -59, au cas
où d'autres programmes résidents voudraient s'installer avant la lecture du bloc d'amorce,
mais -1 aurait amplement suffit. Attention toutefois à ne pas descendre en dessous de -59, étant donné que
le strap ne rend pas la main ; c'est toujours le dernier module appelé.
Seuls deux drapeaux sont possibles : d'abord, RTF_COLDSTART que l'initialisation de la structure devra
être effectuée devinez quand ? Lors du démarrage à froid, oui. Ensuite, RTF_AUTOINIT indique que RT_INIT
pointe non pas sur une routine personnelle, mais sur une table de données qu'Exec initialisera en appelant
la fonction InitStruct(). Cela est plus particulièrement utile dans le cas de bibliothèques et de périphériques
logiques et ne nous intéresse pas aujourd'hui. Nous nous contenterons donc de positionner RTF_COLDSTART.
Une dernière remarque, mais de taille, concernant les structures résidentes : elles doivent absolument se
trouver en mémoire Chip pour avoir une chance d'être reconnues. Un bogue, ou plutôt une omission dans
Exec limite en effet la recherche à la zone de données $00000000 à $0007FFFF.
Séquence résidente
Pour une fois, Exec ne présente aucune fonction destinée à rendre résidente une structure.
Il faut tout faire par soi-même. Rassurez-vous, cela n'est pas très compliqué.
On utilise pour cela les champs KickMemPtr, KickMemTag et KickCheckSum de la structure ExecBase.
KickMemPtr pointe sur une liste de structures MemList (NDLR : voire l'excellent
article de Philippe Vautrin à ce sujet)
dont on comprend vite l'utilité : dès que son gestionnaire de mémoire est prêt, c'est-à-dire bien
avant la recherche et l'initialisation des structures résidentes, Exec alloue, via AllocAbs(),
toutes les zones désignées par ces MemLists, cela pour éviter qu'elles ne soient allouées par
d'autres, au risque d'écraser les données qui s'y trouvent. Cela n'est bien entendu utile que
pour les modules résidents en mémoire. Donc, pour se protéger contre toute atteinte à notre
vie privée, nous devrons initialiser correctement une MemList et l'insérer dans ce tableau.
KickTagPtr est un pointeur sur une liste des structures résidentes trouvées lors du démarrage à froid.
Ensuite, lors d'un démarrage à chaud, Exec recherchera les structures résidentes via cette liste, et
uniquement ainsi. Donc, pour être sûr qu'à la prochaine réinitialisation notre structure soit toujours
présente, il faudra nous y insérer nous-mêmes. Nous verrons un tout petit plus loin le format un peu
particulier de cette liste.
KickCheckSum est devinez quoi ? Une somme de contrôle, oui, qu'Exec utilise pour tester l'intégrité
des données pointées par KickMemPtr et KickTagPtr. Si cette somme de contrôle est incorrecte,
un démarrage à froid est provoqué, et adieu le petit programme résident. Or, en nous insérant dans ces
deux listes, nous faussons la somme de contrôle. Il faudra donc la recalculer, à l'aide de la
fonction SumKickData().
Enfin, un quatrième champ d'ExecBase, falcutatif celui-là et nommé ResModules, peut être utilisé.
Il pointe également sur une liste des structures résidentes en mémoire, aussi bien ROM que mémoire,
et est utilisé par la fonction FindResident() pour rechercher un module par son nom. Si on ne
s'insère pas dans cette liste, FindResident() sera incapable de trouver notre module, mais celui-ci
sera tout de même bel et bien là, et actif de surcroît.
Les formats des listes pointées par KickTagPtr et ResModules sont absolument identiques une entrée nulle
indique la fin de la liste et une entrée avec le bit 31 positionné indique qu'il s'agit d'un pointeur
sur une seconde liste (il faut donc effacer ce bit 31 pour obtenir l'adresse de la nouvelle liste). Toute
autre valeur est considérée comme l'adresse d'une structure résidente.
Comment faire son trou dans toutes ces listes ? Deux méthodes sont possibles : soit on recherche la première
entrée vide, qui représente donc la fin de la liste, et on y insère un pointeur sur une liste créée par
nous-mêmes et qui ne contient que notre structure ; soit on s'insère directement au premier rang en faisant
pointer KickTagPtr sur nous-mêmes. Notre liste à nous contiendra dans ce cas deux pointeurs : le premier
sur notre structure résidente, le second sur la liste que pointait originellement KickTagPtr. Le
raisonnement est bien entendu strictement identique en ce qui concerne ResModules.
Séquence bloc d'amorce
Nous en arrivons maintenant au point où notre code résident est appellé par Exec. Je vous rappelle qu'à
ce stade, tout le système est correctement initialisé, et qu'on peut donc appeler la graphics.library
pour afficher la nouvelle image (en créant non pas un écran au sens Intuition du terme, mais un bon
vieux View et tutti quanti) et le trackdisk.device pour lire le bloc d'amorce.
Une fois le bloc d'amorce lu, on vérifie qu'il s'agit bien d'une disquette amorçable
et si c'est le cas, on termine gentiment notre programme, après avoir libéré toutes les
ressources allouées. Le véritable strap sera alors appelé à son tour ; il trouvera une disquette amorçable
dans le lecteur et n'aura pas besoin d'afficher sa petite main potelée. Le reste ne concerne plus
que lui. Tiens, juste une précision pendant que j'y pense saviez-vous que cette fameuse main n'est
pas une image au sens propre du terme, gravée dans la ROM, mais un dessin réalisé par une suite de
Move(), Draw(), FloodFill() et autres BltTemplate() ? Étonnant, non ?
Listing 1
;
; NewPic - Remplace la main du WB par une image IFF au choix.
; © 1991, Max pour ANT
;
; Usage : 'NewPic I image' pour installer
; 'NewPic R' pour dé-installer
;
; *******************************************************
; * ATTENTION : Un minimum de vérifications sont faites *
; * sur la validité de l'image IFF. *
; *******************************************************
opt o+,ow-
incdir "include:"
include "exec/memory.i"
include "exec/ports.i"
include "exec/resident.i"
include "exec/execbase.i"
include "devices/trackdisk.i"
include "devices/bootblock.i"
include "graphics/gfx.i"
include "graphics/view.i"
include "graphics/gfxbase.i"
include "libraries/dos.i"
include "exec/exec_lib.i"
include "graphics/graphics_lib.i"
include "libraries/dos_lib.i"
; ************************************
CALL MACRO
jsr _LVO\1(a6)
ENDM
DEFBSTR MACRO
.len\@ dc.b .end\@-.str\@
.str\@ dc.b \1,10
.end\@ even
ENDM
; Codes d'erreur renvoyés par LoadPic
E_NOERR EQU 0 ; Pas d'erreur à signaler
E_FILE EQU 1 ; Fichier non trouvé
E_IFF EQU 2 ; Pas un fichier IFF
E_ILBM EQU 3 ; Pas un fichier ILBM
E_BAD EQU 4 ; Fichier IFF corrompu
; ************************************
rsreset
args rs.l 2 ; Variables du programme principal
DosBase rs.l 1
stdout rs.l 1
picadr rs.l 1
readbuf rs.b 12
VARSIZE rs.w 0
rsreset
MyMem rs.b 0 ; Variables du programme résident
mm_port rs.b MP_SIZE ; MsgPort
mm_tdio rs.b IOTD_SIZE ; IoExtED
mm_buff rs.b 2*TD_SECTOR ; Buffer pour le trackdisk.device
mm_chng rs.l 1 ; Nb de changements de disquette
gfxbase rs.l 1 ; GfxBase
mm_oldv rs.l 1 ; OldView
mm_view rs.b v_SIZEOF ; View
mm_vp rs.b vp_SIZEOF ; ViewPort
mm_bmap rs.b bm_SIZEOF ; BitMap
mm_rinf rs.b ri_SIZEOF ; RasInfo
mm_SIZE rs.w 0
; ************************************
Start movea.l $4.w,a6
lea VARS(pc),a5
movem.l d0/a0,args(a5)
lea dosname(pc),a1
moveq #0,d0
CALL OpenLibrary
move.l d0,DosBase(a5)
beq.s NoDos
movea.l d0,a6
CALL Output
move.l d0,stdout(a5)
movem.l args(a5),d0/a0
clr.b -1(a0,d0.w)
move.b (a0)+,d0
beq.s NoArgs
andi.b #$df,d0 ; Conversion majuscule
cmpi.b #'I',d0 ; Installation demandée ?
beq.s InstallTag
cmpi.b #'R',d0 ; Dé-installation ?
beq RemoveTag
NoArgs lea usage.txt(pc),a0
bsr Print
Exit movea.l DosBase(a5),a1
movea.l $4.w,a6
CALL CloseLibrary
NoDos moveq #0,d0
rts
; ************************************
InstallTag:
move.l a0,-(sp)
bsr FindMe ; Déjà intallé ?
beq.s InstallIt ; non
addq.l #4,sp
lea deja_la.txt(pc),a0
bsr Print
bra.s Exit
InstallIt:
movea.l (sp)+,a0
.space cmpi.b #' ',(a0)+
beq.s .space
subq.l #1,a0
bsr LoadPic ; Charge l'image IFF
beq.s .PicOk
lea erreurs(pc),a0
subq.l #1,d0 ; Le code d'erreur sert d'indice
lsl.l #2,d0 ; dans le tableau
movea.l 0(a0,d0.l),a0
bsr Print
bra.s Exit
.PicOk movea.l $4.w,a6 ; Alloue la mémoire nécessaire
move.l #RESSIZE,d0
moveq #MEMF_CHIP|MEMF_PUBLIC,d1 ; CHIP !!!
CALL AllocMem
tst.l d0
bne.s .MemOk
lea memoire.txt(pc),a0
bsr Print
bra.s Exit
.MemOk movea.l d0,a4 ; a4 pointe cette mémoire
lea RomTag(pc),a0
lea (RESSIZE).w,a1 ; Copie les données du programme
exg d0,a1 ; dans la mémoire réservée
CALL CopyMem
CALL Disable ; Qu'on ne me dérange pas !
move.l a4,RT_MATCHTAG(a4) ; Le RomTag pointe sur lui
lea RESSIZE(a4),a0
move.l a0,RT_ENDSKIP(a4) ; Fin des données résidentes
lea TagName-RomTag(a4),a0
move.l a0,RT_NAME(a4) ; Nom pour FindResident()
lea ResCode-RomTag(a4),a0
move.l a0,RT_INIT(a4) ; Routine Init
lea TagPtrs-RomTag(a4),a0 ; Insère notre RomTag
move.l a4,(a0)
move.l KickTagPtr(a6),4(a0) ; dans ExecBase.KickTagPtr
beq.s .1
bset #7,4(a0) ; Positionne le bit 31 bu mot long
.1 move.l a0,KickTagPtr(a6)
lea Modules-RomTag(a4),a0 ; Insère notre module
move.l a4,(a0)
move.l ResModules(a6),4(a0) ; dans ExecBase.ResModules
beq.s .2
bset #7,4(a0) ; Positionne le bit 31 du mot long
.2 move.l a0,ResModules(a6)
lea memList-RomTag(a4),a0 ; Initialise et insère
move.l a4,ML_ME+ME_ADDR(a0) ; notre MemList dans
move.l KickMemPtr(a6),LN_SUCC(a0) ; ExecBase
move.l a0,KickMemPtr(a6)
CALL SumKickData
move.l d0,KickCheckSum(a6) ; checksum
CALL Enable
lea ok_inst.txt(pc),a0 ; Et c'est tout !
bsr Print
bra Exit
; ************************************
RemoveTag:
bsr.s FindMe
bne.s RemoveIt
lea pas_la.txt(pc),a0
bsr.s Print
bra Exit
RemoveIt:
movea.l d0,a4 ; a4 pointe le RomTag
CALL Disable
lea memList-RomTag(a4),a1 ; Recherche NOTRE MemList...
lea KickMemPtr(a6),a0
.loop move.l LN_SUCC(a0),d0
cmpa.l d0,a1
beq.s .found
movea.l d0,a0
bra.s .loop
.found move.l LN_SUCC(a1),LN_SUCC(a0) ; ...et l'enlève de ExecBase
move.l TagPtrs-RomTag+4(a4),KickTagPtr(a6)
bclr #7,KickTagPtr(a6) ; Enlève notre KickTagPtr
move.l Modules-RomTag+4(a4),ResModules(a6)
bclr #7,ResModules(a6) ; Enlève notre ResModule
CALL SumKickData
move.l d0,KickCheckSum(a6) ; checkum
CALL Enable
movea.l BODYadr-RomTag(a4),a1 ; Libère la mémoire du
move.l BODYlen-RomTag(a4),d0 ; BODY de l'image IFF
CALL FreeMem
movea.l a4,a1
move.l #RESSIZE,d0 ; Libère la mémoire des
CALL FreeMem ; données résidentes
lea ok_rem.txt(pc),a0 ; Et c'est tout !
bsr.s Print
bra Exit
; ************************************
FindMe lea TagName(pc),a1
movea.l $4.w,a6
CALL FindResident
tst.l d0
rts
; ************************************
Print move.l a6,-(sp)
moveq #0,d3
move.b (a0)+,d3
move.l a0,d2
move.l stdout(a5),d1
movea.l DosBase(a5),a6
CALL Write
movea.l (sp)+,a6
rts
; ************************************
include "LoadPic.s" ; Routine de chargement IFF
; ************************************
VARS dcb.b VARSIZE
dosname dc.b "dos.library",0
even
usage.txt dc.b .1-*-1
dc.b "NewPic V 1.0 - © 1991, Max pour ANT",10
dc.b "Usage : NewPic [I=INSTALL|R=REMOVE]",10
.1 even
deja_la.txt DEFBSTR <"NewPic est déjà installé.">
pas_la.txt DEFBSTR <"NewPic n'est pas installé.">
memoire.txt DEFBSTR <"Pas assez de mémoire !">
ok_inst.txt DEFBSTR <"NewPic v1.0 installé.">
ok_rem.txt DEFBSTR <"NewPic v1.0 dé-installé.">
erreurs dc.l fichier.txt,form.txt,ilbm.txt,reading.txt
fichier.txt DEFBSTR <"Fichier non trouvé.">
form.txt DEFBSTR <"Ce n'est pas un fichier IFF.">
ilbm.txt DEFBSTR <"Ce n'est pas un fichier ILBM.">
reading.txt DEFBSTR <"Erreur en lecture du fichier IFF.">
; ************************************
include "Resident.s" ; Données et code résident
; ************************************
END
|
Listing 2
; LoadPic.s - Routine de chargement de l'image IFF
LoadPic movem.l d2-d7/a2-a6,-(sp)
movea.l DosBase(a5),a6
lea readbuf(a5),a4
moveq #E_FILE,d7 ; Ouvre le fichier
move.l a0,d1
move.l #MODE_OLDFILE,d2
CALL Open
move.l d0,d4
beq nofile
moveq #E_IFF,d7
move.l d4,d1
move.l a4,d2
moveq #12,d3
CALL Read
cmpi.l #'FORM',(a4) ; Vérifie le 'FORM'
bne noiff
moveq #E_ILBM,d7
cmpi.l #'ILBM',8(a4) ; Vérifie le 'ILBM'
bne noiff
iff move.l d4,d1
move.l a4,d2
moveq #8,d3
CALL Read
subq.l #8,d0 ; Réellement 8 octets lus ?
bne loaded
movem.l (a4),d5-d6 ; d5=ChunkName, d6=ChunkSize
cmpi.l #'BMHD',d5
beq.s bmhd
cmpi.l #'CAMG',d5
beq.s camg
cmpi.l #'CMAP',d5
beq.s cmap
cmpi.l #'BODY',d5
beq.s body
seek move.l d4,d1 ; Saute les Chunks inconnus
move.l d6,d2 ; (d6 = longueur du chunk)
moveq #OFFSET_CURRENT,d3
CALL Seek
bra.s iff
bmhd bsr LoadChunk ; Charge le chunk en mémoire
lea width(pc),a0
move.w 0(a3),0(a0) ; Largeur de l'image
move.w 2(a3),2(a0) ; Hauteur de l'image
move.b 8(a3),4+1(a0) ; Nb plans
move.b 10(a3),8(a0) ; Compression
bsr FreeChunk ; Libère le chunk
bset #16,d7 ; Flag BMHD ok
bra.s iff ; Chunk suivant
camg bsr.s LoadChunk ; Charge le chunk en mémoire
lea modes(pc),a0
move.w 2(a3),(a0) ; ViewModes
bsr FreeChunk ; Libère le chunk
bset #17,d7 ; Flag CAMG ok
bra.s iff ; Chunk suivant
cmap bsr.s LoadChunk ; Charge le chunk en mémoire
movea.l a3,a0
lea palette(pc),a1 ; Buffer de destination
move.l d6,d0
divu #3,d0
subq.w #1,d0 ; d0 = nb. couleurs - 1
cmpi.w #31,d0
ble.s .loop
moveq #31,d0 ; 32 couleurs maximum !
.loop moveq #0,d1
move.b (a0)+,d1 ; Composante Rouge
lsl.w #4,d1
or.b (a0)+,d1 ; Composante Verte
lsl.w #4,d1
or.b (a0)+,d1 ; Composante Bleue
lsr.w #4,d1
move.w d1,(a1)+ ; La couleur est dans la palette
dbra d0,.loop ; Couleur suivante
bsr.s FreeChunk ; Libère le chunk
bset #18,d7 ; Flag CMAP ok
bra iff ; Chunk suivant
body bsr.s LoadChunk ; Charge le chunk en mémoire
lea BODYadr(pc),a0
move.l a3,(a0)+ ; Adresse et taille dans la MemList
move.l d6,(a0) ; (qui restera résidente)
bset #19,d7 ; Flag BODY ok
bra iff ; ON NE LIBERE PAS LE CHUNK !!!
loaded moveq #E_NOERR,d6
swap d7
cmpi.w #%1111,d7 ; Tous les chunks chargés ?
beq.s .iffok
moveq #E_BAD,d6 ; Non, y'a une erreur...
.iffok exg d7,d6
noiff move.l d4,d1 ; Ferme le fichier
CALL Close
nofile move.l d7,d0 ; d0 = code d'erreur
movem.l (sp)+,d2-d7/a2-a6
rts
LoadChunk:
movea.l $4.w,a6
move.l d6,d0 ; d0 = d6 = sizeof(Chunk)
moveq #MEMF_CHIP,d1 ; En CHIP si ça doit rester résident
CALL AllocMem ; Allocation mémoire
movea.l d0,a3 ; a3 = adresse du Chunk
move.l d4,d1
move.l d0,d2
move.l d6,d3
movea.l DosBase(a5),a6
CALL Read ; et lecture du chunk
sub.l d6,d0 ; Z=1 si erreur
rts
FreeChunk:
movea.l $4.w,a6
movea.l a3,a1 ; a1 = a3 = adresse du chunk
move.l d6,d0 ; d0 = d6 = taille du chunk
CALL FreeMem ; Libération mémoire
movea.l DosBase(a5),a6 ; (DosBase sert encore !)
rts
|
Listing 3
; Resident.s - Données et code résident (initialisés ailleurs)
RomTag dc.w RTC_MATCHWORD ; = $4afc
dc.l 0,0 ; MatchTag, EndSkip
dc.b RTF_COLDSTART ; Flags
dc.b 1,0,-59 ; Version, Type, Pri
dc.l 0,0,0 ; Name, IDString, Init
TagName dc.b "NewPic 1.0",0
even
memList dcb.b LN_SIZE
dc.w 2 ; ML_NUMENTRIES
dc.l 0,RESSIZE ; ML_ADR, ML_LENGTH
BODYadr dc.l 0
BODYlen dc.l 0
TagPtrs dc.l 0,0
Modules dc.l 0,0
width ds.w 1
height ds.w 1
depth ds.w 1
modes ds.w 1
compr ds.w 1
palette ds.w 32
tdname TD_NAME
gfxname dc.b "graphics.library",0
even
ResCode movem.l d0-d7/a0-a6,-(sp)
movea.l $4.w,a6
move.l #mm_SIZE,d0 ; Alloue les variables dynamiques
move.l #MEMF_CHIP|MEMF_CLEAR,d1
CALL AllocMem
tst.l d0
beq NoVars ; Raté (ce serait étonnant !)
movea.l d0,a5 ; a5 pointe les vatriables
lea mm_port(a5),a2 ; Initialise le MsgPort
move.b #NT_MSGPORT,LN_TYPE(a2)
moveq #-1,d0
CALL AllocSignal
move.b d0,MP_SIGBIT(a2)
bmi NoSig
suba.l a1,a1
CALL FindTask
move.l d0,MP_SIGTASK(a2)
lea mm_tdio(a5),a1 ; Initialise l'IOExtTD
move.b #NT_MESSAGE,IO+MP+LN_TYPE(a1)
move.l a2,IO+MP+MN_REPLYPORT(a1)
lea tdname(pc),a0 ; Ouvre le trackdisk.device (DF0:)
moveq #0,d0
moveq #0,d1
CALL OpenDevice
tst.b d0
bne.s NoTD
lea mm_tdio(a5),a3
lea mm_buff(a5),a4
movea.l a3,a1
move.w #TD_CHANGENUM,IO_COMMAND(a1)
CALL DoIO
move.l IO_ACTUAL(a3),mm_chng(a5)
bsr.s ChkDsk ; Y'a un disk bootable ?
beq.s ResExit ; Oui -> on s'casse
bsr Image ; Non -> on affiche l'image
ChkChng btst #6,$bfe001 ; (on quitte avec la souris)
beq.s .oui
movea.l a3,a1 ; Disque changé ?
move.w #TD_CHANGENUM,IO_COMMAND(a1)
CALL DoIO
move.l IO_ACTUAL(a3),d0
cmp.l mm_chng(a5),d0
beq.s ChkChng ; Pas encore
bsr.s ChkDsk ; Le nouveau disque est bootable ?
bne.s ChkChng ; Non -> boucle
.oui bsr UnloadImg ; Enlève l'image
ResExit movea.l a3,a1 ; Ferme le trackdisk.device
CALL CloseDevice
NoTD moveq #0,d0
move.b mm_port+MP_SIGBIT(a5),d0
CALL FreeSignal
NoSig movea.l a5,a1
move.l #mm_SIZE,d0
CALL FreeMem
NoVars movem.l (sp)+,d0-d7/a0-a6
rts
ChkDsk movea.l a3,a1
move.w #TD_CHANGESTATE,IO_COMMAND(a1)
CALL DoIO
tst.l IO_ACTUAL(a3)
bne.s .non ; Pas de disque dans le drive !
movea.l a3,a1
move.w #TD_CHANGENUM,IO_COMMAND(a1)
CALL DoIO
move.l IO_ACTUAL(a3),mm_chng(a5)
movea.l a3,a1 ; Démarre le moteur
move.w #TD_MOTOR,IO_COMMAND(a1)
addq.l #1,IO_LENGTH(a1)
CALL DoIO
movea.l a3,a1 ; ...et lit les 2 secteurs boot
move.w #ETD_READ,IO_COMMAND(a1)
move.l #2*TD_SECTOR,IO_LENGTH(a1)
move.l a4,IO_DATA(a1)
clr.l IO_OFFSET(a1)
move.l mm_chng(a5),IOTD_COUNT(a1)
CALL DoIO
move.w d0,-(sp) ; (sauve le code d'erreur)
movea.l a3,a1 ; Arrête le moteur
move.w #TD_MOTOR,IO_COMMAND(a1)
clr.l IO_LENGTH(a1)
CALL DoIO
tst.w (sp)+ ; Erreur de lecture ?
bne.s .non
movea.l a4,a0
cmpi.l #BBNAME_DOS,(a0) ; Disquette est bootable ?
bne.s .non
moveq #0,d0
move.w #((TD_SECTOR*2)/4)-1,d1 ; Calcule son checksum
.chksum add.l (a0)+,d0
bcc.s .1
addq.l #1,d0
.1 dbra d1,.chksum
not.l d0 ; Z = 1 si le disque est bootable
.non rts
; ************************************
Image movem.l a2-a6,-(sp) ; Affichage de l'image IFF
lea gfxname(pc),a1
moveq #0,d0
CALL OpenLibrary
move.l d0,gfxbase(a5)
beq .failed
movea.l d0,a6
move.l gb_ActiView(a6),mm_oldv(a5)
lea mm_view(a5),a2 ; a2 pointe le View
lea mm_vp(a5),a3 ; a3 pointe le ViewPort
lea mm_bmap(a5),a4 ; a4 pointe la bitmap
movea.l a2,a1 ; Initialise le View
CALL InitView
move.l a3,v_ViewPort(a2)
move.w modes(pc),v_Modes(a2)
movea.l a3,a0 ; Initialise le ViewPort
CALL InitVPort
move.w width(pc),vp_DWidth(a3)
move.w height(pc),vp_DHeight(a3)
move.w modes(pc),vp_Modes(a3)
lea mm_rinf(a5),a0
move.l a0,vp_RasInfo(a3)
move.w depth(pc),d1
moveq #1,d0
lsl.l d1,d0
CALL GetColorMap
move.l d0,vp_ColorMap(a3)
beq .failed
movea.l a4,a0 ; Initialise la BitMap
move.w depth(pc),d0
move.w width(pc),d1
move.w height(pc),d2
CALL InitBitMap
move.w depth(pc),d2
subq.w #1,d2
moveq #0,d3
move.b compr(pc),d0 ; Si l'image n'était pas compressée,
beq.s .norast ; pas besoin d'allouer des plans de bits !
.planes move.w width(pc),d0
move.w height(pc),d1
CALL AllocRaster
move.l d0,bm_Planes(a4,d3.l)
beq.s .failed
addq.l #4,d3
dbra d2,.planes
bra.s .initRI
.norast movea.l BODYadr(pc),a0
move.w width(pc),d0
lsr.w #3,d0
mulu height(pc),d0
.noras1 move.l a0,bm_Planes(a4,d3.l)
adda.l d0,a0
addq.l #4,d3
dbra d2,.noras1
.initRI lea mm_rinf(a5),a0 ; Initialise le RasInfo
move.l a4,ri_BitMap(a0)
movea.l a2,a0 ; Construit le View
movea.l a3,a1
CALL MakeVPort
movea.l a2,a1
CALL MrgCop
move.b compr(pc),d0 ; Décompresse au besoin l'image
beq.s .nopack
bsr.s UnpackIFF
.nopack movea.l a3,a0 ; ...et affiche le résultat
lea palette(pc),a1
moveq #1,d0
move.w depth(pc),d1
lsl.l d1,d0
CALL LoadRGB4
movea.l a2,a1
CALL LoadView
CALL WaitTOF
.failed movem.l (sp)+,a2-a6
rts
UnpackIFF:
movem.l d0-d7/a0-a6,-(sp) ; Décompactage IFF
move.l BODYadr(pc),a4
lea mm_bmap(a5),a3
move.w bm_BytesPerRow(a3),d5
moveq #0,d0
Lignes lea bm_Planes(a3),a2
move.w depth(pc),d1
subq.w #1,d1
Planes movea.l (a2)+,a0
move.w d0,d2
mulu d5,d2
adda.l d2,a0
moveq #0,d2
Comp moveq #0,d3
move.b (a4)+,d3
bmi.s Crunch
ext.w d3
add.w d3,d2
addq.w #1,d2
CompL move.b (a4)+,(a0)+
dbra d3,CompL
bra.s NextByte
Crunch cmpi.b #$80,d3
beq.s NextByte
neg.b d3
ext.w d3
add.w d3,d2
addq.w #1,d2
move.b (a4)+,d4
CrunchL move.b d4,(a0)+
dbra d3,CrunchL
NextByte:
cmp.w d5,d2
blt.s Comp
NextPlane:
dbra d1,Planes
addq.w #1,d0
cmp.w bm_Rows(a3),d0
blt.s Lignes
movem.l (sp)+,d0-d7/a0-a6
rts
UnloadImg:
move.l gfxbase(a5),d0 ; Libère la mémoire utilisée
beq.s .nogfx
movea.l d0,a6
movea.l mm_oldv(a5),a1 ; est-ce vraiment utile ?
CALL LoadView
CALL WaitTOF
move.l mm_vp+vp_ColorMap(a5),d0
beq.s .1
movea.l d0,a0
CALL FreeColorMap
move.b compr(pc),d0
beq.s .norast
.1 move.w depth(pc),d2
subq.w #1,d2
lea mm_bmap+bm_Planes(a5),a2
.planes move.l (a2)+,d0
beq.s .2
movea.l d0,a0
move.w width(pc),d0
move.w height(pc),d1
CALL FreeRaster
.2 dbra d2,.planes
.norast lea mm_vp(a5),a0
tst.l vp_DspIns(a0)
beq.s .3
CALL FreeVPortCopLists
.3 move.l mm_view+v_LOFCprList(a5),d0
beq.s .4
movea.l d0,a0
CALL FreeCprList
.4 move.l mm_view+v_SHFCprList(a5),d0
beq.s .5
movea.l d0,a0
CALL FreeCprList
.5 movea.l a6,a1
movea.l $4.w,a6
CALL CloseLibrary
.nogfx rts
RESSIZE EQU *-RomTag ; Taille des données résidentes
|
|