print · rss · source

< Un système multi-tâches : des appels systèmes préemptibles | TutoOS | Gérer la mémoire physique et la mémoire virtuelle >


Un noyau qui boote avec Grub

Les sources

Le package contenant les sources est téléchargeable ici : kernel_GrubEnable.tgz
Pour naviguer dans l'arborescence : GrubEnable


Le standard multiboot

Le document GNU/Multiboot spec. définit un standard qui uniformise la séquence de boot des différents systèmes d'exploitation. Grub est un boot loader qui permet de démarrer un grand nombre de systèmes différents pour peu qu'ils répondent à ce standard. Pour répondre à ce standard, un noyau doit :

  • être un fichier exécutable 32 bits standard
  • l'image du noyau doit inclure un entête spécial, le multiboot header, dans ses 8192 premiers octets

Un premier noyau minimaliste démarré par Grub

Note : l'utilisation de Grub2 est détaillée en annexe
Pour illustrer le boot avec Grub, le package suivant contient un noyau minimaliste répondant au standard multiboot : kernel_SimpleGrub.tgz
Pour naviguer dans l'arborescence : SimpleGrub

L'entête

global _start, start
extern kmain
   
%define MULTIBOOT_HEADER_MAGIC  0x1BADB002
%define MULTIBOOT_HEADER_FLAGS  0x00000003
%define CHECKSUM -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)


_start:
        jmp start

; The Multiboot header
align 4
multiboot_header:
dd MULTIBOOT_HEADER_MAGIC
dd MULTIBOOT_HEADER_FLAGS
dd CHECKSUM    
; ----- Multiboot Header Ends Here -----

start:
        push ebx
        call kmain

        cli ; stop interrupts
        hlt ; halt the CPU

Le programme principal

Grub permet de fournir au noyau plusieurs informations dont la taille de la mémoire physique disponible Cette information est transmise au noyau via la structure de données struct mb_partial_info :

void printk(char*, ...);

struct mb_partial_info {
        unsigned long flags;
        unsigned long low_mem;
        unsigned long high_mem;
        unsigned long boot_device;
        unsigned long cmdline;
};
       
void kmain(struct mb_partial_info *mbi)
{
        printk("Grub example kernel is loaded...\n");
        printk("RAM detected : %uk (lower), %uk (upper)\n", mbi->low_mem, mbi->high_mem);
        printk("Done.\n");
}

Compiler et linker le noyau

La compilation et le linkage pour obtenir le nouveau noyau changent car il faut que l'en-tête du multiboot se trouve au début de la zone texte. Plusieurs méthodes sont possibles :

  1. décrire une section pour l'en-tête et utiliser un script pour le linkage avec ld
  2. décrire une section pour l'en-tête et utiliser ld en ligne de commande avec des paramètres approximatifs
  3. lors du linkage, mettre le fichier objet boot.o en premier afin qu'il soit relogé au début du noyau :
ld -Ttext=100000 --entry=_start boot.o kernel.o screen.o printk.o -o kernel

La commande shell mbchk permet de vérifier la compatibilité du noyau généré avec le standard multiboot :

$ mbchk kernel
kernel: The Multiboot header is found at the offset 4104.
kernel: Page alignment is turned on.
kernel: Memory information is turned on.
kernel: Address fields is turned off.
kernel: All checks passed.

On peut aussi vérifier où sont relogés les différents objets avec la commande shell nm :

$ nm -n kernel
00100000 T _start
00100008 t multiboot_header
00100014 T start
0010001c T kmain
0010005c T scrollup
001000ec T putcar
00100218 T strlen
00100243 T itoa
00100309 T printk
001016e0 D kY
001016e1 D kattr
001016e4 A __bss_start
001016e4 A _edata
001016e4 B kX
001016e8 A _end

Créer et mettre à jour une image de disquette avec Grub

La création d'une telle image nécessite la permission de root.

Attention !
Le script ci-dessous est potentiellement dangereux et chaque commande exécutée en tant que root sur un système UNIX doit être bien comprise. Si une commande du script ci-dessous ne vous semble pas claire, je vous conseille de prendre le temps qu'il faut pour étudier la documentation accessible via la commande shell man. Même si cet effort vous semble futile et n'a en apparence pas de rapport avec le développement d'un noyau, je vous garanti que les connaissances acquises vous seront très utiles. Pour ceux qui débutent en administration système, je recommande l'excellentissime Guide du Rootard :

# creation d'une image vide avec ext2fs
dd if=/dev/zero of=floppyA bs=1024 count=1440
mkfs floppyA

sudo -s

# montage de l'image
mkdir /mnt/loop
mount -o loop -t ext2 floppyA /mnt/loop

# creation de l'arborescence initiale
mkdir /mnt/loop/grub

cp /boot/grub/stage* /mnt/loop/grub

cat > /mnt/loop/grub/menu.lst << EOF
title=Pepin
root (fd0)
kernel /kernel
boot
EOF

cp kern/kernel /mnt/loop
umount /mnt/loop

# installation de grub
grub --device-map=/dev/null << EOF
device (fd0) floppyA
root (fd0)
setup (fd0)
quit
EOF

Une fois l'image construite, la mise-à-jour du noyau est plus simple :

mount -o loop -t ext2 floppyA /mnt/loop
cp kern/kernel /mnt/loop
umount /mnt/loop

Booter Pépin avec Grub

Le noyau est chargé par Grub en 0x100000.

Certaines plages d'adresses sont réservées par le noyau ou pour le hardware :

0x00xFFFGDT et IDT
0x10000x9FFFFlibre
0xA00000xFFFFFréservé pour le hardware
0x1000000x1FFFFFréservé pour le noyau
0x200000maxlibre

< Un système multi-tâches : des appels systèmes préemptibles | TutoOS | Gérer la mémoire physique et la mémoire virtuelle >

print · rss · source
Page last modified on September 05, 2012, at 01:03 PM