SimpleOS

LXR

Navigation



Site hébergé par : enix

The LXR Cross Referencer for SOS

source navigation ]
diff markup ]
identifier search ]
general search ]
 
 
Article:1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 6.5 ] [ 7 ] [ 7.5 ] [ 8 ] [ 9 ] [ 9.5 ]

001 
002 /*
003  * @(#) $Id: bootsect.S,v 1.12 2005/08/13 13:47:31 d2 Exp $
004  * Description : Bootsecteur en syntaxe AT&T
005  * Auteurs : Thomas Petazzoni & Fabrice Gautier & Emmanuel Marty
006  *           Jerome Petazzoni & Bernard Cassagne & coffeeman
007  *           David Decotigny (SOS integration for kernel size detection)
008  *           Christopher Goyet (RAM size determination through BIOS int 15H)
009  * Bug reports to kos-misc@enix.org
010  */
011 
012 /*
013  * But global de ce bootsecteur :
014  *
015  *              - Initialiser la becane
016  *              - Charger le kernel
017  *              - Passer en mode protege
018  *              - Executer le kernel
019  *
020  * Taille restante : Je vous rappelle qu'un bootsecteur ne peut faire
021  * qu'au maximum 512 octets dont 2 octets obligatoires 0xAA55.  Sur
022  * les 510 octets reellement utilisables, il reste 3 octets dispo (60
023  * si on decide d'enlever le BPB un jour) !!!
024  *
025  * thomas_petazzoni :  - detection des codes d'erreurs de chargement
026  * David_Decotigny  :  - Passage en GNU as
027  * David_Decotigny  :  - Chargement du noyau au-dela du 1er Mega (taille
028  *                       max = 0x9e000 octets = 632ko), pour avoir le
029  *                       meme noyau sous grub et avec le bootsecteur
030  */
031 
032  /*
033   * Sequence d'operations :
034   * - Le BIOS charge le bootsect en 0x7c00 (BOOT_ADRESS). On choisit
035   *   la representation 0x7c0:0000 pour que le .org 0 reste valide
036   * - Le bootsect se deplace de lui-meme en 0x9f000 (COPY_ADRESS). On
037   *   choisit la representation 0x9f00:0000 pour que le .org 0 reste
038   *   valide
039   * - Le bootsect verifie que le processeur est du type 386+
040   * - Il charge le noyau depuis la disquette en memoire a partir de
041   *   0x1000 (LOAD_ADRESS). La place dispo est donc 0x9f000 - 0x1000 , soit
042   *   0x9E000, soit encore 1264 secteurs de 512 octets
043   * - Il passe en pmode flat (apres ouverture a20)
044   * - Il recopie le noyau (situe en LOAD_ADRESS) vers son adresse
045   *   finale (FINAL_ADDRESS = 2Mo). La recopie se fait sur tout l'espace
046   *   LOAD_ADRESS ---> COPY_ADRESS, c'est a dire sur 0x9e000 octets =
047   *   632ko. Le noyau peut donc au max faire 632ko. Le nombre max de
048   *   secteurs de disquette qu'on peut charger est donc 1264
049   */
050 
051 
052 /* La taille de la pile */
053 #define BOOT_STACK_SIZE         0x4000
054 
055         .file   "bootsect.S"
056 
057         /* Tout est place dans une seule section */
058         .section ".bootsect"
059 
060         /* L'essentiel du bootsector (sauf les 1eres instructions)
061            sont a un offset 0. On fait en sorte que le compilo soit
062            d'accord la-dessus. Quand on a des adresse realm exotiques
063            (0x7c00, 0x9f000, ...), on s'arrange toujours pour avoir un
064            offset de 0 => on choisira le segment adapte (0x7c0,
065            0x9f00, ...). Il ne faut pas oublier le ld -Ttext 0 */
066         .org 0
067 
068         /* Pour que gas genere du 16bits, afin que ca marche en realm */
069         .code16
070 
071 /*
072  * Parametres de la disquette. Comme c'est chiant de faire une
073  * procedure de detection auto, et que ca prend de la place, on fait
074  * ca "a la main". Par exemple, une DD 720 Ko a 9 secteurs/piste, une
075  * 1.44 Mo a 18 secteurs/pistes
076  */
077 #define CYLS    80
078 #define HEADS   1
079 #define SECTS   18
080 
081 #define BOOT_ADRESS 0x07C00            /* Adresse de demarrage (lineaire) */
082 #define BOOT_SEG (BOOT_ADRESS>>4)      /* Segment de Boot */
083 #define BOOT_SIZE 512                  /* Taille bu bootsecteur */
084 #define COPY_ADRESS 0x9F000            /* La ou on va copier le
085                                           bootsecteur (lineaire) */
086 #define COPY_SEG (COPY_ADRESS>>4)      /* Segment de la ou on va
087                                           copier le bootsecteur */
088 #define LOAD_ADRESS 0x01000            /* 1er chargement du systeme */
089 #define LOAD_SEG (LOAD_ADRESS>>4)      /* Segment du 1er chargement du */
090 #define MAX_KERN_LEN (COPY_ADRESS-LOAD_ADRESS) /* Taille noyau maxi */
091 #define MAX_KERN_SECTS ((MAX_KERN_LEN + 511) >> 9) /* Nbre de secteurs maxi */
092 
093 /* IMPORTANT : Cette valeur DOIT etre identique a l'adresse presente
094                dans sos.lds ! */
095 #define FINAL_ADDRESS 0x200000         /* Adresse finale (physique de 0 a 4G)
096                                           ou est charge le noyau */
097 
098 #define OP16 .byte 0x66 ;
099 #define OP32 .byte 0x66 ;
100 
101 /*
102  * Procedure qui vide le buffer clavier.
103  */
104 #define WAITKB     \
105   1:               ;\
106     .word 0xeb     ;\
107     .word 0xeb     ;\
108     inb $0x64, %al ;\
109     andb $0x2, %al ;\
110     jnz 1b
111 
112         /* Le point d'entree dans le bootsect */
113 .globl _bsect
114 _bsect:
115 
116         /*
117          * La portion qui suit est situee a un offset 0x7c00 en
118          * memoire. Attention donc aux references memoire dans cette
119          * partie. On choisit de rester en offset 0 (.org 0), mais on
120          * charge correctement les segments a 0x7c0.
121          */
122 
123         movw $BOOT_SEG, %ax /* le bootsecteur est a 0x7C00 en lineaire */
124         movw %ax, %ds      /* on le copie a l'adresse COPY_ADRESS */
125         xorw %si, %si      /* comme cette adresse est la plus haute de la mem */
126         xorw %di, %di      /* on pourra charger un kernel + gros */
127         movw $(BOOT_SIZE>>1), %cx
128         movw $COPY_SEG, %ax
129         movw %ax, %es
130         cld
131         rep ; movsw
132                         
133         /* on continue a executer le bootsecteur, mais maintenant a
134            partir de 0x9F000, qu'on represente sous la forme
135            0x9f00:offset */
136         ljmp $COPY_SEG, $here
137 
138         /*
139          * A partir de maintenant, on est a un offset 0 en memoire
140          * (segment 0x9f00), conformement a ce que veut le compilo.
141          */
142 here:
143         movw %ax, %ds
144 
145         /* Petite pile temporaire (1k - 3.84k en RAM ; les adresses 0-1k
146            correspondent au vecteur d'interruptions). */
147         movw %ax, %ss
148         movw $(LOAD_ADRESS - 0x10), %sp
149         
150         /* Efface l'ecran */
151         movb $0x0, %ah
152         movb $0x3, %al
153         int  $0x10
154 
155         /* Verifie que le noyau n'est pas trop gros a charger */
156         cmpw $(MAX_KERN_SECTS), (load_size)
157         jb sizeOk
158         movw $toobig, %si
159         call message
160         call halt
161 
162 sizeOk: 
163         /* Recupere la taille de la RAM */
164         mov $0xE801, %ax
165         int $0x15
166         movw %ax, (memsize1)
167         movw %bx, (memsize2)
168 
169         /* Affiche les messages d'attente */
170         movw $loadkern, %si
171         call message
172         movw $check, %si
173         call message
174 
175 check386:
176         /*
177          * la attention, plus complexe : on teste si le proc est un
178          * 386+ pour cela, on va essayer de modifier les bits 12 ? 14
179          * du registre E-flag si la modification reste, alors le proc
180          * est un 386+, sinon, c'est =< 286
181          *
182          * Merci a Emmanuel Marty pour la compatibilite avec les 386
183          * "pre-jurassique"
184          */
185 
186         pushf /* on sauvegarde le E-Flag */
187         movb $0x70, %ah
188         pushw %ax
189         popf
190         pushf
191         popw %ax
192         orb %ah, %ah
193         je no386  /* si la modif n'est pas valable, alors on saute a
194                      no386 */
195         popf      /* on les restaure ? la fin ... */
196 
197         /* Message de confirmation de 386+ et d'attente */
198         movw $found386, %si
199         call message
200         movw $loading, %si
201         call message
202 
203 /* Copie du noyau disquette => RAM a partir de 0x1000
204    L'adresse de destination est définie par es:0, où es vaut
205    initialement 0x100 (ie correspond alors à l'adresse 256*16, soit 4
206    ko). Chaque itération incrémente ce registre es de 32, ce qui
207    correspond à un bond de 32*16 en mémoire, soit la taille d'un
208    secteur. De cette façon, puisqu'on joue sur les segments plutôt que
209    sur les offsets, la taille du noyau n'est pas limitée à 64 ko. Elle
210    est limitée par contre à la taille de la mémoire disponible sous
211    les 1Mo, \ie 640 ko (0x9f000 - 0x1000).  */
212 copyKernel:
213         /* Chargement du noyau en LOAD_SEG:0 */
214         /* 3 iterateurs :
215                 - load_size : le nbre de secteurs a charger
216                 - cl : le secteur ou on en est pour le
217                   cylindre en cours (<= SECTS)
218                 - dh : la tete en cours (0/1)
219         */
220         movb $0, %dl
221         movw $LOAD_SEG, %ax
222         movw %ax, %es
223 
224         xorw %bx, %bx
225         xorw %dx, %dx
226         movw $1, %cx     /*  premier secteur */
227 
228 .nextsector:             /* prochain secteur */
229         incb %cl         /* en incrementant CL */
230         cmpb $SECTS, %cl /* si CL =< SECTS (=nbre de secteurs/pistes)
231                             alors on charge */
232         jbe .sector
233         movb $1, %cl     /* sinon on revient au secteur 1 */
234         incb %dh         /* mais sur l'autre tete */
235         cmpb $1, %dh     /* on recompare, si DH =< 1 */
236         je .sector       /* on charge */
237         movb $0, %dh     /* sinon on repasse a la tete 0 */
238         incb %ch         /* mais on change de cylindre */
239 
240 .sector:
241         pushw %es
242         movw $0x0201, %ax /* service 0x2, chargement 0x1 seecteur */
243         int $0x13          /* Go ! */
244         jc halt           /* erreur */
245         popw %ax
246         addw $32, %ax     /* on a charge un secteur, donc on doit
247                              charger 512 bytes plus loin */
248         movw %ax, %es     /* on avance donc le segment du buffer de
249                              32bytes, ie 1 secteur en RAM (car 32*16=512) */
250 
251         movw $(0x0E*256+'.'), %ax /* affiche un point */
252         int $0x10
253 
254         decw (load_size)     /* et on repart pour le prochain secteur
255                              tant qu'on n'a pas fini ! */
256         jnz .nextsector
257 
258 after:
259         movw $0x03f2, %dx
260         inb  %dx, %al  /* stoppe le moteur */
261         andb $0x0f, %al
262         outb %al, %dx
263 
264         cli               /* on interdit les interruptions */
265 
266 fincopie:        
267         pushw %cs
268         popw  %ds
269 
270         /* on ouvre la porte A20 */
271         WAITKB           /* on vide le buffer */
272         movb $0xd1, %al /* on met a jour le port */
273         outb %al, $0x64
274         WAITKB
275         movb $0xdf, %al /* bit 2 = ouverture/fermeture */
276         outb %al, $0x60
277 
278         /*
279          * init gdt
280          */
281 InitGDT:
282         /* Préparation du flat mode */
283         lgdt gdtr
284 
285 GoPMode:
286         /* Passage en mode protégé */
287         movl %cr0, %eax
288         orb  $1, %al /* set PE bit to 1 */
289         movl %eax, %cr0
290 
291         /* we are not yet in Pmode jump 'in' pmode clearing prefetch
292          * queue and loading a new selector */
293         movw $0x10, %ax
294         movw %ax, %ds
295         movw %ax, %es
296         movw %ax, %fs
297         movw %ax, %gs
298 
299 /*
300  * Code 32 bits ============================================================
301  */
302         .code32 
303 
304 JumpToHere32: /* Se deplace a l'endroit actuel, en passant en 32bits
305                  et en utilisant la gdt, et vide la prefetch queue */
306         .byte 0x66 /* Prefixe 32bits : en realite, jusqu'au jmp, on est
307                       encore en 16 bits */
308         ljmp $0x8, $(COPY_ADRESS+(Here32))
309 Here32:
310         /* Et voila : On est en 32 bits vrai */
311 
312 MoveKernelToFinalAddr: /* Deplace le noyau (en LOAD_ADDRESS) vers sa
313                           destination finale (FINAL_ADDRESS) */
314         movl $0x10, %eax
315         movl %eax, %ds   /* Seg Src  = DSeg */
316         movl %eax, %es   /* Sed Dest = DSeg */
317         cld
318         movl $LOAD_ADRESS, %esi    /* On commence la copie au debut du noyau */
319         movl $FINAL_ADDRESS, %edi  /* On copie vers cette adresse */
320         movl $MAX_KERN_LEN, %ecx   /* Taille recopie */
321         shrl $2, %ecx
322         rep
323         movsl
324 
325 LaunchKernel:
326         /* Met en place une pile au niveau du symbole "stack" */
327         movl %eax, %ss
328         movl $(stack + BOOT_STACK_SIZE), %ebp
329         movl %ebp, %esp
330 
331 /* passe les arguments a sos */                                       
332         xor %eax, %eax
333         xor %ebx, %ebx
334         movw (COPY_ADRESS+(memsize2)), %ax /*eax = num de block de 64KB apres 16MB*/
335         movw (COPY_ADRESS+(memsize1)), %bx /*ebx = num de block de 1KB entre 1MB et 16MB*/
336         movl $0x40, %ecx /*ecx=64 */
337         mul %ecx
338         add %ebx, %eax
339         pushl %eax  /* valeur de addr */
340         pushl $0x42244224 /* valeur de magic pour indiquer qu'on a pousse
341                              la taille de la RAM sur la pile */
342         pushl $0 /* normalement call fait un push eip, mais la on a un jmp*/
343         
344         /* Saut vers le noyau. La GDT est en place (flat mode), les
345          * selecteurs aussi, a20 est ouverte, et les interruptions sont
346          * cli + pas de idt. Le PIC n'est pas programme */
347         ljmp $0x8, $sos_main
348 
349 /*
350  * Utilities ============================================================
351  */
352         .code16
353 
354 message:
355         lodsb             /* charge ds:si dans al et incremente si */
356         orb %al, %al      /* si al = 0 */
357         jz 1f
358         movb $0x0e, %ah   /* service 0Eh (affichage d'un caractere) */
359         movw $0x0007, %bx /* Parametres : blanc sur fond noir */
360         int $0x10          /* Appel de l'interruption 10h */
361         jmp message       /* On repart au début ... */
362      1: ret               /* si la chaine est finie alors on retourne
363                              dans la fonction appelante */
364 
365 halt:
366         pushw %cs
367         popw %es
368         movw $haltmsg, %si
369         call message
370         cli
371      1: jmp 1b
372         ret
373 
374 no386:
375         movw $need386, %si
376         call message
377         call halt
378 
379         /*
380          * GDT
381          */
382 
383 gdt:
384 gdtr:
385 NULL_Desc:
386         .word (EndGDT)-(gdt)-1 /* Taille GDT */
387         .long (gdt)+COPY_ADRESS
388 unused: 
389         .word   0
390 
391 CS_Desc: /* 0x8 */
392         .word   0xFFFF, 0
393         .byte   0, 0x9B, 0xCF, 0
394 
395 DS_Desc: /* 0x10 */
396         .word   0xFFFF, 0
397         .byte   0, 0x93, 0xCF, 0
398 
399 EndGDT:
400 
401      /* quelques messages */
402 
403 loadkern:  .string      "This is SOS\r\n"
404 toobig:    .string      "Image too big\r\n"
405 check:     .string      "Checking 386+ processor... "
406 found386:  .string      " [OK]\r\n"
407 need386:   .string      " [FAILED]\r\n"
408 diskerror: .string      "Disk Error\r\n"
409 loading:   .string      "Loading... "
410 haltmsg:   .string      "System Halted\r\n"
411 
412      /* Variables pour stocker la taille de la RAM (int 0x15) */
413 memsize1:  .long        0
414 memsize2:  .long        0
415 
416 /*** Les code/données du boot secteur se terminent ICI. le marqueur de
417  * fin (aa55) est ajouté automatiquement par le script ld
418  * sos_bsect.lds ***/
419 
420 /* La pile de 16k qu'on utilise au niveau de LaunchKernel se trouve
421    declaree avec le noyau, dans sa section ".init_stack", cad HORS du boot
422    secteur ! (sinon ca depasserait 512B, forcément). On aurait pu la
423    définir directement dans le sos_bsect.lds, ou dans un fichier .c
424    auxiliaire pour plus de clarté */
425 /* Here is the stack */
426 .section ".init_stack", "aw", @nobits
427 .p2align 4
428 .size stack, BOOT_STACK_SIZE
429 stack:
430         .space BOOT_STACK_SIZE
431 
432 /* Some data characterizing the stack addresses */
433 .data
434         .globl bootstrap_stack_bottom
435 bootstrap_stack_bottom: .long stack
436 
437         .globl bootstrap_stack_size
438 bootstrap_stack_size: .long BOOT_STACK_SIZE

source navigation ] diff markup ] identifier search ] general search ]