T@LC : on développe notre système d’exploitation, avec moins de 10 lignes de code !
Parfait pour s’occuper cet été !
Et si pendant les mois d’été vous en profitiez pour découvrir un peu l’assembleur et créer votre propre OS ? Promis, cela prendra moins de 10 lignes de code (on pourrait même faire moins). Il marche certes, mais il est totalement inutile (et donc indispensable ? Pas sûr…).
Le 07 juillet 2025 à 11h51
7 min
Logiciel
Logiciel
Il y a quelques mois, nous vous avions proposé de créer et entrainer votre propre intelligence artificielle avec seulement 10 lignes de code. De quoi un peu démystifier les IA et surtout en comprendre les tenants et aboutissants.
Savez-vous qu’il est possible de développer un système d’exploitation avec encore moins de lignes de code ? Alors autant le dire tout de suite, il ne servira pas à grand-chose en l’état… mais n’est-ce pas un peu le but des « Tests à la con » (T@LC) ?
Un OS avec détection du clavier en 9 lignes ? Facile !
Cela permet par contre de toucher du bout des doigts un peu d’assembleur et de mieux comprendre comment fonctionne un OS. Rassurez-vous, Next ne va pas développer son propre système d’exploitation.
On y va doucement avec un OS minimaliste qui ne fait qu’afficher les touches pressées sur le clavier à l’écran. Le code fait moins d’une dizaine de lignes.
[BITS 16]
[ORG 0x7C00]
l: mov ah, 0
int 0x16
mov ah, 0x0E
int 0x10
jmp l
times 510 -($-$$) db 0
dw 0xAA55
La première ligne est assez explicite : nous allons travailler en 16 bits, c’est plus que suffisant pour nos tests.
Explication du code, ligne par ligne
La seconde, indique que le code sera chargé à l’adresse 0x7C00 (0x pour préciser que le nombre qui suit est en hexadécimal). C’est une convention, c’est là que le BIOS va chercher les informations de démarrage.
On passe directement aux deux dernières lignes. « times 510 -($-$$) db 0 » permet de créer un fichier de 510 octets exactement, avec des 0 pour remplir les vides. La dernière ajoute 0xAA55 (0x indique de l’hexadécimal, pour rappel) sur les deux derniers octets. Là encore, c’est un passage obligé pour que le BIOS identifie bien notre OS. On obtient donc au final un fichier de 512 octets exactement.
Mes cours d’assembleur à la fac ayant déjà plus de 25 ans, je me suis aidé de l’intelligence artificielle Claude pour certains morceaux de code. Il n’est par contre pas super à l’aise en assembleur et à parfois tendance à se tromper, surtout sur la ligne « times 510 -($-$$) db 0 » ou il écrit régulièrement « times 510 -($-$) db 0 ». Forcément, le fichier ne fait pas la bonne taille et notre OS ne démarre pas.
Passons au cœur du programme. Si vous avez déjà fait un peu de développement, vous avez certainement identifié une boucle qui débute par « l: » et se termine par « jmp l ». En clair, ça tourne en rond.
On commence par « int 0x16 » qui correspond à une interruption clavier, puis on termine par « int 0x10 » avec un affichage vidéo (sur l’écran). Cette partie du code intercepte donc des touches du clavier pour les afficher à l’écran.
C’est déjà la fin de notre système d’exploitation. Il ne fait rien de plus qu’afficher à l’écran les touches pressées sur le clavier. C’est totalement inutile, mais vous pouvez dire « c’est moi qui l’ai fait ».
nasm et Qemu pour tester votre OS maison
Peut-être vous demandez-vous comment tester ce système d’exploitation, aussi inutile soit-il ? Après tout, vous n’avez pas de raison de nous croire sur parole. Il faut d’abord le compiler avec nasm (Netwide Assembler, un assembleur pour architecture x86).
Plusieurs solutions sont possibles, nous choisissons d’utiliser Winget en ligne de commande dans un Powershell (avec des droits administrateur).
winget install NASM.NASM
Nous installons ensuite Qemu pour lancer des machines virtuelles afin de tester notre système d’exploitation aussi inutile que rapide à démarrer. Dans notre cas, le programme s’installe dans le répertoire Program Files, nous ajoutons donc une variable d’environnement pour ne pas avoir à saisir à chaque fois le chemin complet.
winget install SoftwareFreedomConservancy.QEMU
$env:PATH +=";C:\Program Files\qemu"
Une fois les deux programmes installés, on peut commencer à jouer. Dans un fichier texte portant le nom MonOS.asm (attention, l’extension est bien en .asm) on copie les quelques lignes de notre OS.
Ensuite, on exécute les deux commandes suivantes. La première va créer un fichier .bin, la seconde permet de l’utiliser dans Qemu pour lancer une machine virtuelle avec cet OS :
nasm -f bin .\MonOS.asm -o MonOS.bin
qemu-system-x86_64 -drive format=raw,file=MonOS.bin
On ajoute un prompt à notre OS
C’est bien beau, mais n’est-il pas possible d’améliorer un peu le système ? Bien sûr ! Il faudra à chaque fois coller le code dans votre fichier .asm, utiliser nasm pour refaire le .bin et enfin lancer Qemu
Première étape, ajouter un prompt sous la forme d’un « > ». Il s’affiche une fois, puis tous les caractères saisis au clavier.
[BITS 16]
[ORG 0x7C00]
mov al, '>'
mov ah, 0x0E
int 0x10
l: mov ah, 0
int 0x16
mov ah, 0x0E
int 0x10
jmp l
times 510 -($-$$) db 0
dw 0xAA55
On prend en charge le retour à la ligne
Soyons fou, prenons en charge le retour à la ligne avec la création d’un nouveau prompt à chaque fois (c’est la commande newline qui s’en occupe). La détection de la touche entrée (code ASCII 13) se fait via la ligne « cmp al, 13 » :
[BITS 16]
[ORG 0x7C00]
mov al, '>'
mov ah, 0x0E
int 0x10 l: mov ah, 0
int 0x16
cmp al, 13
je newline
mov ah, 0x0E
int 0x10
jmp l
newline:
mov al, 10
mov ah, 0x0E
int 0x10
mov al, 13
mov ah, 0x0E
int 0x10
mov al, '>'
mov ah, 0x0E
int 0x10
jmp l
times 510 -($-$$) db 0
dw 0xAA55
Amazing : notre OS donne l’heure !
Transformer maintenant notre super machine virtuelle en horloge hors de prix, avec ce nouvel OS qui intercepte la touche « t » pour afficher l’heure courante de la machine :
[BITS 16]
[ORG 0x7C00]
mov al, '>'
mov ah, 0x0E
int 0x10
l: mov ah, 0
int 0x16
cmp al, 13
je newline
cmp al, 't'
je show_time
mov ah, 0x0E
int 0x10
jmp l
newline:
mov al, 10
mov ah, 0x0E
int 0x10
mov al, 13
mov ah, 0x0E
int 0x10
mov al, '>'
mov ah, 0x0E
int 0x10
jmp l
show_time:
mov ah, 2
int 0x1A
mov al, ch
call print_bcd
mov al, ':'
mov ah, 0x0E
int 0x10
mov al, cl
call print_bcd
mov al, ':'
mov ah, 0x0E
int 0x10
mov al, dh
call print_bcd
jmp l
print_bcd:
push ax
shr al, 4
add al, '0'
mov ah, 0x0E
int 0x10
pop ax
and al, 0x0F
add al, '0'
mov ah, 0x0E
int 0x10
ret
times 510 -($-$$) db 0
dw 0xAA55
Un dernier pour la route : afficher un simple message
On peut aussi se passer de la détection du clavier et n’afficher qu’un message :
[BITS 16]
[ORG 0x7C00]
mov si, msg
mov ah, 0x0E
.loop:
lodsb
or al, al
jz $
int 0x10
jmp .loop
msg db 'Hello World, Next est dans la place !', 0
times 510 -($-$$) db 0
dw 0xAA55
L’air de rien, vous touchez au cœur du réacteur des systèmes d’exploitation, enfin ceux d’il y a des dizaines d’années quand la ligne de commande régnait en maitre.
Mais on se rend vite compte de la difficulté de développer en assembleur. Fort heureusement, ce n’est pas utile dans la vie de tous les jours.
T@LC : on développe notre système d’exploitation, avec moins de 10 lignes de code !
-
Un OS avec détection du clavier en 9 lignes ? Facile !
-
Explication du code, ligne par ligne
-
nasm et Qemu pour tester votre OS maison
-
On ajoute un prompt à notre OS
-
On prend en charge le retour à la ligne
-
Amazing : notre OS donne l’heure !
-
Un dernier pour la route : afficher un simple message
Commentaires (31)
Le 07/07/2025 à 12h02
Le 07/07/2025 à 12h25
import os
import sys
if __name__ == '__main__':
command = [shutil.which('cc')] + sys.argv[1]
os.execve(command[0], command)
Le 07/07/2025 à 12h28
Le 07/07/2025 à 13h43
Le 07/07/2025 à 12h52
Le 07/07/2025 à 16h22
Le 07/07/2025 à 13h03
Rappelons tout de même que Linux ne devait être qu'un hobby et pas un projet professionnel.
Le 07/07/2025 à 13h06
Le 07/07/2025 à 20h57
Le 07/07/2025 à 14h00
Mon père avait écrit un gestionnaire de fichiers très puissant et réactif en assembleur, des milliers de lignes de code.
Mais il faut avouer que ce genre de codage optimisé n'a d'avenir que dans des domaines spécifiques : les firmwares ou l'aviation/l'embarqué.
Les micro-controleurs à la rigueur, ou on optimise chaque clock cycle.
PS: j'ai tenté d'utiliser le PIO des raspberry, sans succès.
L'idée était de récupérer un signal d'une telco RC, j'y arrive avec une boucle qui compte le temps passé pour le CPU, mais ça serait mieux d'utiliser ces contrôleurs.
Ca serait plus précis.
Le 08/07/2025 à 12h57
Le 07/07/2025 à 14h23
Le 07/07/2025 à 14h27
Le 07/07/2025 à 14h38
Le 08/07/2025 à 16h49
Le 09/07/2025 à 09h30
Modifié le 07/07/2025 à 14h51
[edit] il ne passe pas. Je l'avais fait en Whitespace
Le 07/07/2025 à 15h43
https://www.minix3.org/
Le 07/07/2025 à 16h56
(spoiler : pas besoin d'ASM ou d'interruptions !)
Le 07/07/2025 à 17h07
Le 07/07/2025 à 18h08
Merci :)
Le 07/07/2025 à 19h32
Le 07/07/2025 à 21h54
.exe.efi ?Le .elf, ça sera pour l'épisode encore après sur le bootloader. Ah, on me souffle qu'il existe déjà un PoC.
Le 08/07/2025 à 21h38
Le 10/07/2025 à 13h44
Le 08/07/2025 à 16h26
https://uefi.org/specs/UEFI/2.10/08_Services_Runtime_Services.html
Et on compile un exécutable au format PE de mémoire, et non un bout de code machine à coller dans le secteur 0.
Le 08/07/2025 à 16h33
Le 07/07/2025 à 19h50
Le 07/07/2025 à 23h57
Modifié le 08/07/2025 à 09h54
J'en avait même fait un article de blog ensuite, car certains point m'avait bien fait cogité.
C'est assez amusant comment faire un noyau est à la fois "pas tant un truc de fou" et en même temps terriblement compliqué, en particulier quand tu veut un truc "sérieux".
Le 08/07/2025 à 11h14
Une véritable variante infiniment "plus", sur tous les aspects.
Valable pour tout, tout le temps.
Signaler un commentaire
Voulez-vous vraiment signaler ce commentaire ?