kernel_premier/include/gdt.h
2023-10-05 23:28:32 +02:00

144 lines
5.6 KiB
C

/** @file gdt.h
* @brief Configuration de la Table de Description Globale ou GDT. Utilisée
* pour pouvoir gerer la memoire sous forme de segments.
*
* 1. Il faut en premier initialiser le registre @c gdtr avec l'adresse et la
* taille de la GDT.
* 2. Charger ensuite dans les registres @c cs et @c ds des sélecteurs de
* segments
* 3. Charger dans la GDT des descripteurs de segments. Le premier est toujours
* nul, le deuxième est le segment pour le code du noyau et le troisième pour
* les données.
*
* Références:
* - Documentation Intel (volume 3A):
* https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html
* - De manière globale : les parties 2 et 3
* - Partie 3.4.3 : registres de segments
* - Figure 3-11 : structure à charger dans le registre @c gdtr
* - Figure 3-5 : illustration de la transformation d'une adresse logique
* en adresse linéaire
* - Figure 3-6 : anatomie d'un sélecteur de segment
* - Figure 3-8 : anatomie d'un descripteur de segment
* - Table 3-1 : type de segment (donnée et code)
* - chargement de @c gdtr https://www.felixcloutier.com/x86/lgdt:lidt
* - explication sur les sélecteurs de segments
* https://wiki.osdev.org/Segment_Selector
* - explication sur la segmentation et plus particulièrement les registres de
* segmentation : https://wiki.osdev.org/Segmentation
* - tutoriel pour inialiser la GDT : https://wiki.osdev.org/GDT_Tutorial
* - documentation en français (rapidement survolée) :
* https://wiki.osdev.org/GDT_Tutorial
*/
/** @struct gdt_entry
*
* Structure qui sera passée à la fonction load_gdt(). Elle est utilisée pour
* rassembler la taille et l'adresse de la GDT en un seul type de 6 bytes.
*
* Voir section 3.5.1 du volume 3A du manuel d'Intel.
*/
struct gdt_entry
{
/**
* La taille de la GDT en bytes. Elle doit être éguale à 8N - 1, à cause de
* la taille des segments (1 segment = 8 bytes).
*/
unsigned short size;
/**
* L'adresse de la GDT, doit être alignée sur un multiple de 8 pour avoir
* de meilleures performances.
*/
unsigned int address;
}__attribute__((packed));
/** @struct segment_descriptor
*
* Un descripteur de segment est chargé dans la GDT. Il contient 8 bytes,
* séparés en 2 @c unsigned @c int.
*
* Premier int :
* | 0 - 15 | 16 - 31 |
* |----------------------------|--------------------------|
* | Limite du segment (0 - 15) | Adresse de base (0 - 15) |
*
* Deuxième int :
* | 0 - 7 | 8 - 11 | 12 | 13 - 14 | 15 | 16 - 19 | 20 | 21 | 22 | 23 | 24 - 31 |
* |---------------------------|--------------|-----------------|------------------------------------|-----------------|-----------------------------|---------------|--------------------|------------------------|-------------|----------------------------|
* | Adresse de base (16 - 23) | Segment type | Descriptor Type | Niveau de privilège du descripteur | Segment present | Limite du segment (16 - 19) | Disponibilité | 64bit code semgent | Default operation size | Granularité | Adresse de base (24 - -31) |
*
* @note Cette structure a été codée pour répondre à un besoin : comment
* simplifier la création de descripteurs de segments. Il s'agit d'un choix
* d'implémentation que j'ai fait et qui n'est pas indiqué dans la
* documentation Intel ou dans <EM> The little book about OS development </EM>.
*/
struct segment_descriptor
{
/** Contient les bytes 0 à 3 (base + limite). */
unsigned int first_bytes;
/** Contient les bytes 4 à 7 (base + limite + drapeaux). */
unsigned int last_bytes;
}__attribute__((packed));
/**
* Créer une valeur de sélecteur de segment.
*
* @param index l'index du segment dans la GDT
* @param type le type de table (0 = GDT, 1 = LDT)
* @param rpl le niveau de privilège (0 = le +, 3 = le -)
*/
unsigned short create_selector(unsigned short index, unsigned char type,
unsigned char rpl);
/**
* Va charger la structure passée en paramètre comme GDT au processeur. Appelle
* l'instruction @c lgdt, qui prend en paramètre 6 bytes, d'où l'utilisation de
* la structure.
*
* @param entry les informations de la GDT à charger
*/
void load_gdt(struct gdt_entry *entry);
/**
* Charge dans le registre @c cs le sélecteur 0x08.
*/
void load_cs(void);
/**
* Charge dans les registres @c ds, @c es et @c ss un sélecteur de segment.
*
* @param selector le sélecteur à charger
*/
void load_registers(void);
/**
* Créer une structure gdt_entry.
*
* @param start : l'adresse de départ
* @param n : le nombre d'éléments dedans
*/
struct gdt_entry create_gdt_entry(unsigned int start, unsigned short n);
/**
* Créer un descripteur de segment.
*
* @param base l'adresse de base en mémoire
* @param limit la limite du segment
* @param dpl niveau de privilège du semgent (0 le +, 3 le -)
* @param segment_type les autorisations en écriture / exécution du segment
* (cf. table 3-1)
*/
struct segment_descriptor create_descriptor(unsigned int base, unsigned int
limit, unsigned char dpl, unsigned char segment_type);
/**
* Ajoute un descripteur de segment dans la GDT.
*
* @param i : l'index dans la GDT (sera calculé pour l'insérer au bon endroit)
* @param start : l'adresse du début de la GDT
* @param desc : le descripteur à insérer
*/
void add_in_gdt(unsigned int i, unsigned int start, struct segment_descriptor
desc);
void config_gdt(void);