#define GDTBASE 0x800 /* addr. physique ou doit resider la gdt */ #define GDTSIZE 0xFF /* nombre max. de descripteurs dans la table */Puis on definit une structure qui correspond aux descripteurs de segment et une autre qui correspond aux donnees a charger dans le registre GDTR. La directive __attribute__ ((packed)) indique a gcc qu'une structure doit occuper le moins de place possible en memoire. Si on omet cette directive, il y a des chances que le compilateur insere des octets entre les champs de la structure afin de les aligner pour optimiser la vitesse d'acces. Cette optimisation du compilateur est ici enormement genante car on s'attend a ce que chaque structure decrite ci-dessous corresponde a la meme chose en memoire :
/* descripteur de segment */ typedef struct { u16 lim0_15; u16 base0_15; u8 base16_23; u8 acces; u8 lim16_19 : 4; u8 other : 4; u8 base24_31; } gdtdesc __attribute__ ((packed)); /* registre GDTR */ struct gdtr { u16 limite ; u32 base ; } __attribute__ ((packed)); struct gdtr kgdtr;On definit ensuite la table de GDT. On met les champs a zero pour que soit initialise le descripteur nul :
/* table de GDT */ gdtdesc kgdt[GDTSIZE] = {0, 0, 0, 0, 0, 0, 0};La variable kgdtptr correspond au nombre de descripteur initialises dans la GDT. Cette variable commence a 1 car le descripteur nul est initialise :
/* pointeur sur un descripteur libre dans la GDT */ unsigned int kgdtptr = 1;
void scrollup (unsigned int); void putcar(uchar); void print (char*); void dump(uchar*,int);
/* * Cette fonction initialise la GDT apres que le kernel soit charge * en memoire. Une GDT est deja operationnelle, mais c'est celle qui * a ete initialisee par le secteur de boot et qui ne correspond * pas forcement a celle que l'on souhaite pour bosokernel. */ void init_gdt(void) { gdtdesc code, data, stack; /* initialisation des descripteurs de segment */ init_code_desc(0x0, 0xFFFFF, &code); init_data_desc(0x0, 0xFFFFF, &data); init_gdt_desc(0, 0x10, 0x97, 0x0D, &stack); add_gdt_desc(code); add_gdt_desc(data); add_gdt_desc(stack);Les descripteurs sont places dans le tableau 'kgdt' situe quelque part en memoire et une fois que le tableau est correctement rempli, on le recopie a l'endroit en memoire ou il doit resider (definit par GDTBASE). On initialise la structure 'kgdtr' puis on effectue le changement de GDT en chargeant cette structure dans le registre GDTR. On met a jour les selecteurs de segments de donnees (ds, es, fs , gs et ss) puis on fait un "long jump" pour mettre a jour le selecteur du segment de code (cs) :
/* initialisation de la structure pour GDTR */ kgdtr.limite = GDTSIZE*8; kgdtr.base = GDTBASE; /* recopie de la GDT a son adresse */ memcopy(kgdt, kgdtr.base, kgdtr.limite); /* chargement du registre GDTR */ asm("lgdtl (kgdtr)"); /* initialisation des segments */ asm(" movw $0x10,%ax \n \ movw %ax, %ds \n \ movw %ax, %es \n \ movw %ax, %fs \n \ movw %ax, %gs \n \ movw $0x18,%ax \n \ movw %ax, %ss \n \ movl $0x1FFFF,%esp \n \ nop \n \ nop \n \ ljmp $0x08,$next \n \ next: \n"); }