diff --git a/Makefile b/Makefile
index 6ed38d0..97dea92 100644
--- a/Makefile
+++ b/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 \
diff --git a/include/gdt.h b/include/gdt.h
new file mode 100644
index 0000000..9eb56f6
--- /dev/null
+++ b/include/gdt.h
@@ -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);
diff --git a/kmain.c b/kmain.c
index e706548..1420d57 100644
--- a/kmain.c
+++ b/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));
 }
diff --git a/src/gdt.c b/src/gdt.c
new file mode 100644
index 0000000..cd42df2
--- /dev/null
+++ b/src/gdt.c
@@ -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);
+}
diff --git a/src/load_gdt.s b/src/load_gdt.s
new file mode 100644
index 0000000..2049533
--- /dev/null
+++ b/src/load_gdt.s
@@ -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
diff --git a/src/serial.c b/src/serial.c
index 0430fd6..c30bbca 100644
--- a/src/serial.c
+++ b/src/serial.c
@@ -1,4 +1,5 @@
 #include "io.h"
+#include "serial.h"
 
 void serial_set_baud(unsigned short port, unsigned short div)
 {