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
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.
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 !!!
loader.s, avec la fonction gdt_load :
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é.
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:
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 !
Partager