[SOS] Le gestionnaire de pages physiques

David mykeysdavid at gmail.com
Mar 14 Aou 20:32:54 CEST 2007


Bonjour,

C'est mon premier message sur cette liste, qui semble une niche 
d'information.

Merci pour SOS, qui me permet de comprendre certains principes des OS 32 
bits, ce qui me permet d'améliorer mes compétences en C et ASM x86.

Mon but est de faire un OS graphique vers la fin (très simple), ce qui 
signifie que je vais d'abord me rendre à la gestion des threads 
utilisateurs et j'essaierai d'implémenter un simple contrôleur du mode 
v8086. Avec ça, il me semble que je pourrai contrôler efficacement la 
configuration du mode vidéo (obtention des paramètres, définition du 
mode et accès à l'interface du mode protégé VBE) (le bootsecteur me 
permet de faire ça, mais ce n'est pas très bon (aucun contrôle de 
validité)).

Pour l'instant, j'arrive au gestionnaire de pages physiques, dont je 
semble avoir compris le fonctionnement, et j'ai le code suivant (que 
j'ai mis en pièce jointe). Mais, cela génère une boucle infinie sous 
qemu, avec des valeurs totalement loufoques de "i" et "page_descr" 
(fonction physmem_init() ).

Après quelques tests, je me rends compte de ceci (j'ai 32 Mb de RAM sous 
qemu):
start (le début de la mémoire gérée) est à 4096 (correct);
end (la fin de la mémoire gérée) est à 33554432 (32 Mb exact) (correct);
Nombre de pages (end-start)>>PAGE_SHIFT est à 8191 (encore correct);
l'adresse de "i" sur la pile est 2 164 144;
DESCR_START (qui correspond à PALIGNS( & __e_kernel )) est à 2 097 152 
(plus bas que i??) ??

Je ne comprends pas du tout ce qui se passe, pourquoi le symbole 
__e_kernel est-il comme cela ? C'est la source de mes problèmes (car 
dans ce cas page_descr pointera éventuellement vers i et l'écrasera, ce 
qui crée une boucle infinie ...

Je compile avec cygwin et le cross-compilateur que vous avez fourni 
(binutils 2.16, gcc 3.4.4) sous Windows. Le makefile est légèrement 
modifié pour automatiquement utiliser l'image de grub fournie. Je mets 
le zip en pièce jointe et, si ça marche pas (aucune expérience en 
mailing-lists), allez sur 
http://serveur1.archive-host.com/membres/up/1521434322/MyOS.zip .

 >>Merci de m'aider.


P.S Voici certaines fonctions que je juge pratiques, sont-elles bien ?

    Soft_Ramsize: Calcul en C de la taille de la RAM. Utile quand le
    boot sector et grub ne fonctionne pas. Cette fonction doit être
    appelée avant la pagination (car elle cherche à écrire directement
    en mémoire). La taille minimale précisée est égale à 4 Mio - 4 o.
    Cette fonction ne *devrait* pas effacer les données en RAM (elle
    remet les données qu'elle écrase), mais je n'ai pas eu à voir si ça
    le faisait vraiment.
    C'est pour éviter d'écraser le noyau que je mets 4 Mo.
    L'algorithme utilisé est simple (c'est le même principe qu'une
    recherche binaire). "magic" vaut "01111111111111111111111111111111b"
    (c'est un choix personnel). Ça boucle tant que l'espace entre deux
    tests est plus petit qu'un octet.
     
    void soft_ramsize(unsigned long *ramsize){
        volatile unsigned long magic = 2147483647,tmp=0;
        /* minRAM = 4MB (don't blow up the kernel code), maxRAM = 4GB .
    Remove 4 bytes because it's a long (magic do 4 bytes in memory). */
        unsigned long minRAM = 0x3FFFFC, maxRAM = 0xFFFFFFFC;
        register unsigned long ramsz = (maxRAM - minRAM) >> 1;
        volatile unsigned long *tptr;
       
        do{
            tptr = (long*)(ramsz);
            tmp = *tptr;
            *tptr = magic;
            /* Higher! */
            if (*tptr == magic){
                *tptr = tmp;
                tmp = ramsz;
                minRAM = ramsz;
                ramsz += (maxRAM - minRAM) >> 1;
            }
            /* Lower !*/
            else{
                tmp = ramsz;
                maxRAM = ramsz;
                ramsz -= (maxRAM - minRAM) >> 1;
            }
           
        } while (ramsz != tmp); /* While there is another comparison */
        *ramsize = (ramsz + 4) >> 10;
    }

    Tvmem_putstring: affiche une chaîne rapidement à l'écran. Cette
    fonction ne gère pas encore le dépassement (quand on dépasse 24,79).
    Elle est écrite afin d'utiliser les fonctionnalités du processeur
    (lodsb et stosw). On utilise une instruction pour écrire deux octets
    dans la RAM vidéo (stosw), ce qui accélère le traitement. l'attribut
    est dans ah et le caractère dans al (les processeurs intel sont
    little endian).
    /void tvmem_putstring(u8 row, u8 col, u8 a, const char* str){
        /*    Explanations:
            movb %0,%ah    > Sets the attribute into ah ONCE
            1:
            lodsb        > Loads an char into AL from memory at ESI
            orb %al,%al    > Or'd ah and ah. This returns zero only if
    AL is zero.
            jz 2f:        > If the or was zero, jump forward to 2: (end)
            stosw        > Write AX(AH and AL) into memory at EDI
            jmp 1b        > Jump backward at 1: (write char)
            2:
        */
        asm volatile("movb %0,%%ah\n1:  lodsb; orb %%al,%%al; jz 2f;
    stosw; jmp 1b\n2:"
        :
        : "m" (a), "D" (VIDEO + ((row * COLUMNS + col) << 1)), "S" (str)
        : "memory", "ax"
        );
    }/

    mov_blk: transfère des double mots (des blocs de 32 bits) de src à
    dest. Un des exemples de
    http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html .
    c'est de l'ASM inline. cela permet de copier 4 octets à la fois et
    donc de pouvoir accélérer de 400% les traitements !

    /#define mov_blk(src, dest, numwords) \
    asm __volatile__ ("cld\n\t"\
    "rep movsl"\
    :                                        \
    : "S" (src), "D" (dest), "c" (numwords)  \
    )/

    memcpy: version optimisée qui utilise mov_blk pour faire la majorité
    du travail:
    /void * memcpy(void* dest, const void* src, size_t size){
        long dwsize = size >> 2;
        char i;
        char bsize = size & 3;
        long rsize = size - bsize;
        char* dest_r = dest + rsize;
        char* src_r = (char*)(src + rsize);
       
        mov_blk((long*)dest,(long*)src, dwsize);

        for ( i = 0; i<rsize; i++ ) *dest_r++ = *src_r++;
        return dest;
    }/

 


-------------- section suivante --------------
Une pièce jointe HTML a été nettoyée...
URL: http://the-doors.enix.org/pipermail/sos/attachments/20070814/b7c77c77/attachment-0001.html 
-------------- section suivante --------------
Un texte encapsulé et encodé dans un jeu de caractères inconnu a été nettoyé...
Nom : physmem.h
Url : http://the-doors.enix.org/pipermail/sos/attachments/20070814/b7c77c77/attachment-0002.txt 
-------------- section suivante --------------
Un texte encapsulé et encodé dans un jeu de caractères inconnu a été nettoyé...
Nom : physmem.c
Url : http://the-doors.enix.org/pipermail/sos/attachments/20070814/b7c77c77/attachment-0003.txt 
-------------- section suivante --------------
Une pièce jointe non texte a été nettoyée...
Nom: MyOS.zip
Type: application/octet-stream
Taille: 120973 octets
Desc: non disponible
Url: http://the-doors.enix.org/pipermail/sos/attachments/20070814/b7c77c77/attachment-0001.obj 


Plus d'informations sur la liste de diffusion Sos