Bonjour à tous,

Je suis actuellement, pour raisons ludique et pédagogique, de développer un petit kernel sans autre ambition que d'en savoir plus sur la manière dont fonctionnent ces derniers (et développer un peu mes compétences en programmation). Pour "simplifier" la chose, j'ai choisi de booter avec GRUB dans un premier temps ; je me pencherais sur ce sujet plus tard.
Je tourne sous Linux, compile avec GCC et AS, link avec LD, le tout dans un makefile approprié. Mes essais se font sous virtual-box.

Mon code est écrit en C et ASM (GNU/AT&T), et je m'inspire des différentes sources d'infos que je trouve ça et là. Je précise aussi que mes cours d'assembleur et architecture sont assez lointains et se faisaient plutôt sous la forme INTEL (MASM/NASM).

Mon problème est le suivant : impossible de charger les segments code, data ou encore stack (CS,DS,SS) lors-que je souhaite charger la GDT.
J'en ai donc déduit que cela venait très certainement de la forme de ma gdt, mais je ne trouve pas mon erreur.

Code de formation des descripteurs de segment et de la GDT Registres (*.h et *.c) :
Code : 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
 
#ifndef __GDT_H
#define __GDT_H
 
#include "types.h"
 
#define GDTSIZE 0xFF
#define GDTBASE 0x0
 
//typedef struct segDesc segDesc;
//typedef struct segPtr segPtr;
 
//segment descriptor
struct segDesc {
    uint16_t limit_lb;
    uint16_t base_lb;
    uint8_t base_hb;
    uint8_t type;
    uint8_t granul;         //sinon uint8_t limit:4 et uint8_t flags:4
    uint8_t base_vhb;
 
} __attribute__((packed));
 
//Global Register Descriptor Table
struct segPtr {
    uint16_t limit;     //uint32_t limit();
    uint32_t base;      //uint32_t base();
}__attribute__((packed));
 
//déclaration des segment descriptors...
struct segDesc tSeg[3];
 
//déclaration des seg registers.
struct segPtr gdtr;
 
// initialisation des segments (code, data, stack)
void initSegmentDesc(uint8_t i, uint32_t base, uint32_t limit, uint8_t type, uint8_t flags_hb);
 
//init de la gdt globale avec registres
void init_gdt(void);
 
extern void gdt_load(void);    //fonction présente dans le loader.s
 
 
 
 
#endif
...
Code : 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
 
void initSegmentDesc(uint8_t i, uint32_t base, uint32_t limit,
                     uint8_t type, uint8_t flags)
{
    tSeg[i].limit_lb = (limit & 0xFFFF);
    tSeg[i].base_lb = (base & 0xFFFF);
    tSeg[i].base_hb = (base >> 16) & 0xFF;
    tSeg[i].type = type;
    tSeg[i].granul = (limit >> 16) & 0x0F;          //tSeg[i].limit = (limit >> 16) & 0x0F;
    tSeg[i].granul |= (flags & 0xF0);               //tSeg[i].flags = (flags & 0xF);
    tSeg[i].base_vhb = (base >> 24) & 0xFF;
 
    return;
}
 
void init_gdt(void)
{  
 
    initSegmentDesc(0, 0, 0, 0, 0);                     //null
    initSegmentDesc(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);      //code
    initSegmentDesc(2, 0, 0xFFFFFFFF, 0x92, 0xCF);      //data
    //initSegmentDesc(3, 0x0, 0x0, 0x96, 0x0D);         //stack
 
    gdtr.limit = (sizeof(struct segDesc)*3) - 1;
    gdtr.base = (uint32_t)&tSeg;
 
    //gdtr.limit = GDTSIZE*8;
    //gdtr.base = GDTBASE;
 
    //memcpy((uint8_t*)gdtr.base, (uint8_t*)tSeg, gdtr.limit);
 
    gdt_load();        // <-- bug !!!
Le sections commentées sont les différents essais que j'ai fait en m'inspirant de ce que j'ai trouvé sur le net.

loader.s, avec la fonction gdt_load :
Code : 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
 
.set MAGIC, 0x1badb002	#adresse où doit commencer le kernel (par grub)
.set FLAGS, (1<<0 | 1<<1)   #init à 0x0 marche aussi...
.set CHKSUM, -(MAGIC + FLAGS)
 
.section .multiboot
    .long MAGIC
    .long FLAGS
    .long CHKSUM
 
.section .text
    .extern kernelStart
    .extern kerr
    .extern gdtr
    .extern idtP
    .global loader
    .global gdt_load
    .global idt_load
 
    loader:
        mov $kernel_stack , %esp
        push %eax
        push %ebx
        movl %cr0, %eax
        or $1, %eax
        movl %eax, %cr0             #passage ne mode protégé... useless.
        call kernelStart
 
    gdt_load:
        cli                         # <-- ne change rien
        lgdtl (gdtr)
        movw $0x10, %ax
        movw %ax, %ds                #data segment
        movw %ax, %es                #extra segment
        movw %ax, %fs                #gp     -   general purpose
        movw %ax, %gs                #gp     -   general purpose
        ljmp $0x08, $next            #colle le cs à 0x08
    next:
        movw $0x18, %ax
        movw %ax, %ss               #colle le ss à 0x18
        movl $0x20000, %esp
        ret
 
    idt_load:
        lidt (idtP)
        ret
 
    _stop:
        cli
        hlt
        jmp _stop
 
 
.section .bss
    .space 4096     #Mbi
 
    kernel_stack:
Vous remarquerez que j'ai essayé de forcer le passage en mode protégé (bien qu'inutile car GRUB passe la main sous ce mode). J'ai aussi essayé de limiter les potentiels interupts lors du chargement de la GDT (cli). Celà fait presque une semaine que je refais mon code dans tous les sens donc je ne peut pas vous faire la liste de ce que j'ai testé.

Voilà mon "kernel" se lance, m'affiche mes deux lignes de présentations et.. TRIPLE_FAULT....

Quelqu'un voit d'où vient mon erreur ? Je commence à vraiment sécher...

Merci beaucoup d'avance !