IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Programmation d'OS Assembleur Discussion :

Etrange compilation d'un kernel en C


Sujet :

Programmation d'OS Assembleur

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2008
    Messages : 10
    Par défaut Etrange compilation d'un kernel en C
    Bonjour,

    Je suis en train d'essayer de créer un mini-kernel en C, lancé à partir d'un bootloader en assembleur. Le bootloader fonctionne (il est inspiré d'un tutoriel), j'ai réussi à le tester avec un noyau en assembleur. Son rôle est simplement de charger le code du noyau à l'adresse 0x1000, de passer en mode protégé (je n'initialise pas la ligne A20 pour le moment, mais je ne pense pas que ce soit nécessaire puisque je n'excède pas les 1Mb) puis d'appeler le noyau.

    Le problème est au niveau du noyau. Pas de problème de compilation, mais quand je teste le tout (Bochs), les variables globales de mon prgrammes en C semblent foirer.

    Je vous mets le code complet :
    Code boot.asm : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
     
     
    %include "gdtnasm.inc"
     
    [BITS 16]       ; We need 16-bit intructions for Real mode
     
    [ORG 0x7C00]    ; The BIOS loads the boot sector into memory location 0x7C00
     
    reset_drive:
            mov [bootdrive], dl     ; saving boot drive
            mov ah, 0               ; RESET-command
            int 13h                 ; Call interrupt 13h
            or ah, ah               ; Check for error code
            jnz reset_drive         ; Try again if ah != 0
            mov ax, 0
            mov es, ax
            mov bx, 0x1000          ; Destination address = 0000:1000
            mov ah, 02h             ; READ SECTOR-command
            mov al, 02h             ; Number of sectors to read = 1
            mov ch, 0               ; Cylinder = 0
            mov cl, 02h             ; Sector = 2
            mov dh, 0               ; Head = 0
            int 13h                 ; Call interrupt 13h
            or ah, ah               ; Check for error code
            jnz reset_drive         ; Try again if ah != 0
     
            cli                     ; Disable interrupts, we want to be alone
            xor ax, ax
            mov ds, ax              ; Set DS-register to 0 - used by lgdt
            lgdt [gdt_desc]         ; Load the GDT descriptor
            mov eax, cr0            ; Copy the contents of CR0 into EAX
            or eax, 1               ; Set bit 0
            mov cr0, eax            ; Copy the contents of EAX into CR0
            jmp 08h:clear_pipe      ; Jump to code segment, offset clear_pipe
     
    [BITS 32]                       ; We now need 32-bit instructions
     
    clear_pipe:
            mov ax, 10h             ; Save data segment identifyer
            mov ds, ax              ; Move a valid data segment into the data segment register
            mov fs, ax
            mov gs, ax
            mov ss, ax              ; Move a valid data segment into the stack segment register
            mov esp, 090000h        ; Move the stack pointer to 090000h
            mov ax, 18h
            mov es, ax
            call 08h:01000h          ; Jump to section 08h (code), offset 01000h
    end:
            jmp end
     
    ; Variables
     
    bootdrive: db 0
     
    gdt:                    ; Address for the GDT
    ; Null Segment
    gdt_null	desc	0,0,0
    ; Code Segment
    gdt_code	desc	0, 0xFFFFF, D_CODE + D_READ + D_BIG + D_BIG_LIM
    ; Data Segment
    gdt_data	desc	0, 0xFFFFF, D_DATA + D_WRITE + D_BIG + D_BIG_LIM
    ; Video Segment
    gdt_video	desc	0x0B8000, 0xFA0, D_DATA + D_WRITE + D_BIG
    gdt_end:                ; Used to calculate the size of the GDT
     
    gdt_desc:                       ; The GDT descriptor
            dw gdt_end - gdt - 1    ; Limit (size)
            dd gdt                  ; Address of the GDT
     
    times 510-($-$$) db 0           ; Fill up the file with zeros
            dw 0AA55h                ; Boot sector identifyer

    Code start.c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
     
     
    unsigned char* video_mem = (unsigned char *)0xB8000;
    void clrscr(void);
     
    void os_main(void)
    {
    	clrscr();
    	*((unsigned char *)0xB8000) = 'A';
    	*((unsigned char *)0xB8001) = 0x1B;
    }
     
    void clrscr(void)
    {
     
    	unsigned char *vidmem = video_mem;
     
    	const long size = 80 * 25;
     
    	long loop;
     
    	// Clear visible video memory
     
    	for (loop=0; loop < size; loop++)
     
    	{
     
    		*vidmem++ = 0;
     
    		*vidmem++ = 0xF;
     
    	}
    }

    Le résultat du truc, c'est qu'il m'affiche le caractère 'P', mais il n'efface pas l'écran. Si je remplace la ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    unsigned char *vidmem = video_mem;
    par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    unsigned char *vidmem = (unsigned char *)0xB8000;
    ça marche. Le problème semble donc venir des variables globales... Et j'avoue que j'ai du mal à l'expliquer.

    Au niveau de la compilation, je fais simplement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
     
    gcc -c start.c
     
    ld --oformat binary -e os_main -Ttext 0x1000 -o kern.bin start.o
    Je travaille sous linux, avec la version par défault de ubuntu.

    Autre chose, qui est sans doute lié, c'est que je ne peux pas déclarer des fonctions dans un autre fichier que je link. Là de nouveau, pas de problème de compilation, mais la fonction ne fait rien (d'apparent) et ne retourne jamais.

    Merci de votre aide

    CalvinGhost

  2. #2
    Membre confirmé
    Inscrit en
    Décembre 2005
    Messages
    225
    Détails du profil
    Informations forums :
    Inscription : Décembre 2005
    Messages : 225
    Par défaut
    Euh une petite remarque, le bootloader que tu utilises ressemble très fort à celui qu'a fait le propriétaire de OnyxKernel, donc veille à ce que la GDT soit bien initialisée

    Puis, pourquoi une variable globale alors qu'une #DEFINE SCREEN 0xB8000 aurait suffit ?

    Enfin, comme tout programmeur d'OS, fait toi un Cross GCC

    Et après ton LD, essaie ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    i586-elf-objcopy -R .note -R .comment -S -O binary kernel.bin kernel
    Le prefixe i586-elf c'est celui que j'ai donné à ma cross Binutils ^^"

    Bon Osdev'ing


    PS : d'où tu sors le Video Segment ? Normalement une GDT contient un segment nul, un segment de code, un segment de données, un segment de code en User Mode et un segment de données en User Mode !!

  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2008
    Messages : 10
    Par défaut
    J'ai été voir OnyxKernel, ce n'est pas de là que je me suis inspiré, mais c'est vrai que ça y ressemble Par contre j'ai vérifié encore et encore ma gdt, et elle a l'air d'être ok.

    Variable globale parce qu'en général c'est toujours pratique :p Mais c'est vrai que j'ai finalement opté pour le #DEFINE SCREEN 0xB8000. Je voulais surtout comprendre le fin fond du problème, histoire que ça ne me gène pas dans la suite... Mais je l'ai résolu en passant l'option -N au linker (même si je ne comprends toujours pas pourquoi ça ne marchait pas ).

    Pour le cross compiler, j'en entends parler partout, mais qu'est ce que c'est censé apporter ? Parce que comme je tourne sur un pc, mon gcc livré avec ubuntu doit être bon, non ? Et est ce que par hasard tu pourrais me renseigner un endroit où trouver une marche à suivre ? Histoire de ne pas m'enrouler les pinceaux

    Un grand merci en tous cas,

    CalvinGhost

    PS : Le Video Segment, je m'en servais dans mon kernel en assembleur, c'était pratique, entre autres pour éviter les débordements. Mais je l'ai retiré maintenant

  4. #4
    Membre confirmé
    Inscrit en
    Décembre 2005
    Messages
    225
    Détails du profil
    Informations forums :
    Inscription : Décembre 2005
    Messages : 225
    Par défaut
    Bonjour,

    http://www.osdev.org/osfaq2/index.ph...Cross-Compiler

    PS : sur mon kernel, j'utilise bien des variables globales, notamment pour initialiser une IDT, TSS ... et elles marchent bien, si tu veux voir mon Makefile, fait-le moi savoir

  5. #5
    Membre expérimenté
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2008
    Messages : 145
    Par défaut
    A la fin de ton kernel, tu as juste oublié une boucle infinie du genre :
    Sans cette instruction, ta fonction principale effectue un 'ret' qui aboutit n'importe où et provoque inéluctablement une erreur de type #GP ou un truc dans le genre.

  6. #6
    Membre confirmé
    Inscrit en
    Décembre 2005
    Messages
    225
    Détails du profil
    Informations forums :
    Inscription : Décembre 2005
    Messages : 225
    Par défaut
    Citation Envoyé par milouz123 Voir le message
    A la fin de ton kernel, tu as juste oublié une boucle infinie du genre :
    Sans cette instruction, ta fonction principale effectue un 'ret' qui aboutit n'importe où et provoque inéluctablement une erreur de type #GP ou un truc dans le genre.
    Bonjour,

    Ce n'est pas tout à fait vrai, il a toujours son "jmp end" dans son boot loader ;-)

Discussions similaires

  1. Erreur de compilation etrange lié a un switch ?
    Par mikebranque dans le forum C++
    Réponses: 3
    Dernier message: 10/07/2012, 13h04
  2. Compilation du linux-kernel-1.0
    Par hebus44 dans le forum Administration système
    Réponses: 4
    Dernier message: 10/06/2009, 22h22
  3. comment compiler un module kernel ?
    Par rufa11 dans le forum RedHat / CentOS / Fedora
    Réponses: 14
    Dernier message: 17/09/2008, 15h32
  4. Problème de compilation d'un kernel
    Par goutbouyo dans le forum Assembleur
    Réponses: 2
    Dernier message: 12/05/2007, 00h52
  5. [Création OS] Comment compiler un bootsector + un kernel ???
    Par Damian dans le forum Programmation d'OS
    Réponses: 3
    Dernier message: 05/07/2005, 22h34

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo