add gdt
This commit is contained in:
parent
96612591f2
commit
592b974f13
5 changed files with 243 additions and 4 deletions
2
Makefile
2
Makefile
|
@ -1,4 +1,4 @@
|
|||
OBJECTS = loader.o serial.o framebuffer.o io.o kmain.o
|
||||
OBJECTS = loader.o load_gdt.o gdt.o serial.o framebuffer.o io.o kmain.o
|
||||
|
||||
CC = gcc
|
||||
CFLAGS = -m32 -nostdlib -nostdinc -fno-builtin -fno-stack-protector \
|
||||
|
|
144
include/gdt.h
Normal file
144
include/gdt.h
Normal file
|
@ -0,0 +1,144 @@
|
|||
/** @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);
|
14
kmain.c
14
kmain.c
|
@ -1,4 +1,6 @@
|
|||
#include "framebuffer.h"
|
||||
#include "serial.h"
|
||||
#include "gdt.h"
|
||||
|
||||
unsigned int write(char *buf, unsigned int len)
|
||||
{
|
||||
|
@ -27,7 +29,13 @@ int strlen(char *buf)
|
|||
|
||||
void kmain(void)
|
||||
{
|
||||
char *str = "pouet pouet";
|
||||
int len = strlen(str);
|
||||
write(str, len);
|
||||
char *str = "Port série prêt pour la communication.";
|
||||
char *fb_str = "Framebuffer fonctionnel.";
|
||||
int len = strlen(fb_str);
|
||||
write(fb_str, len);
|
||||
|
||||
config_gdt();
|
||||
serial_set_baud(COM1_PORT, 5);
|
||||
serial_config(COM1_PORT);
|
||||
serial_write(COM1_PORT, str, strlen(str));
|
||||
}
|
||||
|
|
65
src/gdt.c
Normal file
65
src/gdt.c
Normal file
|
@ -0,0 +1,65 @@
|
|||
#include "gdt.h"
|
||||
|
||||
unsigned short create_selector(unsigned short index, unsigned char type,
|
||||
unsigned char rpl)
|
||||
{
|
||||
unsigned short ret = 0;
|
||||
ret += index << 3;
|
||||
ret += type & 0x0004;
|
||||
ret += rpl & 0x0003;
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct gdt_entry create_gdt_entry(unsigned int start, unsigned short n)
|
||||
{
|
||||
struct gdt_entry ret;
|
||||
ret.size = ((n * 8) - 1) & 0xFFFF;
|
||||
ret.address = start;
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct segment_descriptor create_descriptor(unsigned int base, unsigned int
|
||||
limit, unsigned char dpl, unsigned char segment_type)
|
||||
{
|
||||
/*
|
||||
unsigned short base_1 = (base & 0x0000FFFF) << 4;
|
||||
unsigned char base_2 = (base & 0x00FF0000) << 2;
|
||||
unsigned char base_3 = (base & 0xFF000000);
|
||||
unsigned short limit_1 = (limit & 0x0000FFFF) << 4;
|
||||
*/
|
||||
|
||||
struct segment_descriptor ret;
|
||||
ret.first_bytes = (base & 0x0000FFFF) + ((limit & 0x0000FFFF) << 16);
|
||||
ret.last_bytes = ((base & 0x00FF0000) >> 16) + (((segment_type & 0x0F) +
|
||||
((dpl & 0x03) << 5) + 0x90) << 8 ) + (limit & 0x000F0000) +
|
||||
(base & 0xFF000000);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void add_in_gdt(unsigned int i, unsigned int start, struct segment_descriptor
|
||||
desc)
|
||||
{
|
||||
int index = i * 8;
|
||||
struct segment_descriptor *ptr = (struct segment_descriptor *) start;
|
||||
|
||||
*(ptr + index) = desc;
|
||||
}
|
||||
|
||||
void config_gdt(void)
|
||||
{
|
||||
/* int base = 0x00000010; */
|
||||
int base = 0x00008f60;
|
||||
struct gdt_entry entry = create_gdt_entry(base, 10);
|
||||
/* unsigned short data_selector = create_selector(2, 0, 0); */
|
||||
struct segment_descriptor null = {0, 0};
|
||||
struct segment_descriptor code_kernel = create_descriptor(0, 0xFFFFFFFF, 0, 0x0A);
|
||||
struct segment_descriptor data_kernel = create_descriptor(0, 0xFFFFFFFF, 0, 0x02);
|
||||
|
||||
load_cs();
|
||||
load_registers();
|
||||
add_in_gdt(0, base, null);
|
||||
add_in_gdt(1, base, code_kernel);
|
||||
add_in_gdt(2, base, data_kernel);
|
||||
load_gdt(&entry);
|
||||
}
|
22
src/load_gdt.s
Normal file
22
src/load_gdt.s
Normal file
|
@ -0,0 +1,22 @@
|
|||
global load_gdt
|
||||
global load_cs
|
||||
global load_registers
|
||||
|
||||
load_gdt:
|
||||
mov eax, [esp + 4]
|
||||
lgdt [eax]
|
||||
ret
|
||||
|
||||
; https://www.felixcloutier.com/x86/jmp
|
||||
load_cs:
|
||||
jmp 0x08:flush_cs
|
||||
flush_cs:
|
||||
ret
|
||||
|
||||
load_registers:
|
||||
;mov ax, [esp + 4]
|
||||
mov ax, 0x0010
|
||||
mov ds, ax
|
||||
mov ss, ax
|
||||
mov es, ax
|
||||
ret
|
Loading…
Reference in a new issue