Une tentative de fabrication d'un système d'exploitation dans Rust pour un Raspberry Pi 3. En raison de contraintes de temps, j'ai priorisé d'obtenir quelque chose qui fonctionne au lieu d'essayer de nouvelles idées, donc pour l'instant c'est un système d'exploitation monolithique avec une API de type Unix, mais je pourrais changer cela à l'avenir. J'ai largement copié ce que j'avais fait pour Gloworm OS qui est écrit en C.
À l'heure actuelle, il prend en charge la mémoire virtuelle, avec une allocation de page à la demande, mais aucune prise en charge pour échanger la mémoire en disque. Il dispose d'un système de fichiers virtuel avec prise en charge du système de fichiers EXT2, ainsi que de certains systèmes de fichiers en mémoire. Il prend en charge plusieurs processus avec la commutation contextuelle déclenchée par le temporisateur du système, mais ne prend pas encore en charge plusieurs threads.
Actuellement, il n'y a qu'un pilote de console (sous-système TTY) et un pilote de carte SD / EMMC (sous-système de périphérique de bloc). Le sous-système du pilote de bloc fournit un bufcache pour cache des blocs de cache à partir du disque par le système de fichiers. Les blocs qui sont empruntés comme mutables sont marqués sales et seront écrits dans le prochain bloc de blocs. La prise en charge de l'écriture EXT2 n'est pas encore bien testée, donc la validation est désactivée pour l'instant.
Les applications peuvent être écrites en rouille et compilées avec les bibliothèques incluses, qui utilisent l'instruction SVC AARCH64 pour effectuer des appels système au système d'exploitation. Il prend actuellement en charge les opérations de fichiers de base, ainsi que exit , fork et exec . Le système d'exploitation peut charger directement les binaires ELF produits par le fret en tant qu'applications et les exécuter. Un programme de shell simple (lancé par le noyau après initialisation) et la commande ls sont disponibles, mais ne sont qu'à une étape de preuve de concept.
Le système d'exploitation se compose d'un noyau et de quelques applications qui sont toutes compilées séparément. Les applications peuvent être chargées dans une partition EXT2, qui peut être lue par le noyau, mais le noyau doit être chargé séparément, donc il n'est pas inclus dans l'image.
Normalement, lorsqu'un Raspberry Pi bottise, le firmware recherche une partition de graisse sur la carte microSD contenant le fichier kernel8.img , qui est ensuite chargé à l'adresse 0x80000 et s'exécute. Une fois le noyau en cours d'exécution, il peut alors monter d'autres partitions à utiliser comme système de fichiers racine. Lors de l'exécution dans Qemu, l'image du noyau est transmise sur la ligne de commande, ainsi que le nom de fichier d'une image disque qui contient la partition EXT2.
Un makefile est fourni dans la racine du projet pour construire l'image du disque EXT2. Pour faciliter le test du code dans QEMU ou sur matériel, il crée une image disque qui ressemble à la carte microSD (c'est-à-dire une partition de graisse plus une partition EXT2). Lors de l'utilisation de Qemu, la partition de graisse est ignorée.
Pour créer une image, à partir d'un ordinateur Linux RUN:
make create-image
make load-image Cela créera un nouveau fichier d'image de 4 Go, utilisez mkfs.ext2 pour créer un nouveau système de fichiers à l'intérieur, montez-le comme un périphérique de bouclage sur <project>/build , puis compilez et chargez les applications. Il copie également une table de partition à code dur dans l'image, ce qui reproduit les partitions utilisées par le matériel.
Une fois l'image créée, le noyau peut être compilé et exécuté dans Qemu, en utilisant:
cd config/raspberrypi3/
make
./qemu.sh Pour courir sur un Raspberry Pi, il faut actuellement une console série USB. J'utilise le programme Miniload du tutoriel Rust Raspberry Pi OS pour télécharger le noyau sur le port série. Il pourrait être possible de mettre l'image du noyau compilé ( ruxpin.img ) dans la partition de démarrage du fichier créé et de l'écrire sur le disque, mais je n'ai pas encore testé cela.
La sortie suivante a été copiée à partir de la console lors de l'exécution dans QEMU. Il a beaucoup de messages de débogage pour montrer ce qui se passe. Il commence par configurer le tas du noyau et la mémoire de page, enregistre les types de systèmes de fichiers, initialise les pilotes de périphérique et monte la partition Root EXT2. Il effectue ensuite un certain nombre de tests pour vérifier la fonctionnalité de base du système de fichiers, suivi par le lancement du premier processus (le shell). Une commande est ensuite tapée, affichée entre "<>", qui lance le programme ls , imprime une liste des fichiers et répertoires en / , puis sort à l'invite du shell.
starting kernel...
kernel heap: using 0x200000, size 14MiB
virtual memory: using region at PhysicalAddress(0x1000000), size 240 MiB, pages 61438
interrupts: initializing generic arm interrupt controller
fs: registering filesystem tmpfs
fs: registering filesystem devfs
fs: registering filesystem ext2
console: initializing
sd: initializing
sd: found partition 0 at 2000, 256 MiB
sd: found partition 1 at 82000, 740 MiB
fs: mounting ext2 at /, device Some(DeviceID(0, 2))
ext2: magic number ef53, block size 4096
ext2: total blocks 982016, total inodes 245760, unallocated blocks: 963991, unallocated inodes: 245742
ext2: features compat: 38, ro: 3, incompat: 2
ext2: allocating inode 13
fs: mounting devfs at /dev, device None
ext2: looking for "dev", found inode 13
Running some hardcoded tests before completing the startup
Mounting the tmpfs filesystem (simple in-memory file system)
ext2: allocating inode 14
fs: mounting tmpfs at /tmp, device None
ext2: looking for "tmp", found inode 14
Creating a directory and a file inside of it
ext2: allocating inode 15
ext2: looking for "testdir", found inode 15
ext2: allocating inode 16
ext2: allocating block 761 in group 0
ext2: allocating block 762 in group 0
ext2: writing to block 762
Read file 14: This is a test
Opening the console device file and writing to it
ext2: looking for "dev", found inode 13
the device file can write
Opening the testapp binary through the vfs interface and reading some data
ext2: looking for "bin", found inode 32769
ext2: looking for "testapp", found inode 32770
read in 1024 bytes
0xffff00000007f790: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
0xffff00000007f7a0: 02 00 b7 00 01 00 00 00 70 29 21 00 00 00 00 00
0xffff00000007f7b0: 40 00 00 00 00 00 00 00 d0 c8 0d 00 00 00 00 00
0xffff00000007f7c0: 00 00 00 00 40 00 38 00 04 00 40 00 10 00 0e 00
0xffff00000007f7d0: 06 00 00 00 04 00 00 00 40 00 00 00 00 00 00 00
0xffff00000007f7e0: 40 00 20 00 00 00 00 00 40 00 20 00 00 00 00 00
0xffff00000007f7f0: e0 00 00 00 00 00 00 00 e0 00 00 00 00 00 00 00
0xffff00000007f800: 08 00 00 00 00 00 00 00 01 00 00 00 04 00 00 00
0xffff00000007f810: 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 00
0xffff00000007f820: 00 00 20 00 00 00 00 00 60 09 00 00 00 00 00 00
0xffff00000007f830: 60 09 00 00 00 00 00 00 00 00 01 00 00 00 00 00
0xffff00000007f840: 01 00 00 00 05 00 00 00 60 09 00 00 00 00 00 00
0xffff00000007f850: 60 09 21 00 00 00 00 00 60 09 21 00 00 00 00 00
0xffff00000007f860: d8 31 00 00 00 00 00 00 d8 31 00 00 00 00 00 00
0xffff00000007f870: 00 00 01 00 00 00 00 00 51 e5 74 64 06 00 00 00
0xffff00000007f880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xffff00000007f890: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xffff00000007f8a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xffff00000007f8b0: 63 61 6c 6c 65 64 20 60 52 65 73 75 6c 74 3a 3a
0xffff00000007f8c0: 75 6e 77 72 61 70 28 29 60 20 6f 6e 20 61 6e 20
0xffff00000007f8d0: 60 45 72 72 60 20 76 61 6c 75 65 00 00 00 00 00
0xffff00000007f8e0: 60 09 21 00 00 00 00 00 08 00 00 00 00 00 00 00
0xffff00000007f8f0: 08 00 00 00 00 00 00 00 20 10 21 00 00 00 00 00
0xffff00000007f900: 60 09 21 00 00 00 00 00 00 00 00 00 00 00 00 00
0xffff00000007f910: 01 00 00 00 00 00 00 00 94 28 21 00 00 00 00 00
0xffff00000007f920: 61 20 72 65 61 6c 6c 79 20 63 6f 6f 6c 20 6d 65
0xffff00000007f930: 73 73 61 67 65 20 74 68 61 74 20 49 27 64 20 6c
0xffff00000007f940: 69 6b 65 20 74 6f 20 73 65 65 00 00 00 00 00 00
0xffff00000007f950: 90 01 20 00 00 00 00 00 2a 00 00 00 00 00 00 00
0xffff00000007f960: 73 72 63 2f 6d 61 69 6e 2e 72 73 00 00 00 00 00
0xffff00000007f970: d0 01 20 00 00 00 00 00 0b 00 00 00 00 00 00 00
0xffff00000007f980: 0c 00 00 00 05 00 00 00 0a 2f 6d 6e 74 2f 74 65
0xffff00000007f990: 73 74 32 00 00 00 00 00 d0 01 20 00 00 00 00 00
0xffff00000007f9a0: 0b 00 00 00 00 00 00 00 0e 00 00 00 51 00 00 00
0xffff00000007f9b0: d0 01 20 00 00 00 00 00 0b 00 00 00 00 00 00 00
0xffff00000007f9c0: 10 00 00 00 28 00 00 00 d0 01 20 00 00 00 00 00
0xffff00000007f9d0: 0b 00 00 00 00 00 00 00 11 00 00 00 19 00 00 00
0xffff00000007f9e0: d0 01 20 00 00 00 00 00 0b 00 00 00 00 00 00 00
0xffff00000007f9f0: 11 00 00 00 2a 00 00 00 d0 01 20 00 00 00 00 00
0xffff00000007fa00: 0b 00 00 00 00 00 00 00 12 00 00 00 11 00 00 00
0xffff00000007fa10: d0 01 20 00 00 00 00 00 0b 00 00 00 00 00 00 00
0xffff00000007fa20: 17 00 00 00 38 00 00 00 d0 01 20 00 00 00 00 00
0xffff00000007fa30: 0b 00 00 00 00 00 00 00 1a 00 00 00 10 00 00 00
0xffff00000007fa40: 72 65 61 64 20 69 6e 20 00 00 00 00 20 00 00 00
0xffff00000007fa50: 4e 6f 74 41 46 69 6c 65 d0 01 20 00 00 00 00 00
0xffff00000007fa60: 0b 00 00 00 00 00 00 00 1c 00 00 00 31 00 00 00
0xffff00000007fa70: d0 01 20 00 00 00 00 00 0b 00 00 00 00 00 00 00
0xffff00000007fa80: 1d 00 00 00 31 00 00 00 64 6f 6e 65 00 00 00 00
0xffff00000007fa90: f8 02 20 00 00 00 00 00 04 00 00 00 00 00 00 00
0xffff00000007faa0: d0 01 20 00 00 00 00 00 0b 00 00 00 00 00 00 00
0xffff00000007fab0: 2d 00 00 00 05 00 00 00 65 78 65 63 75 74 69 6e
0xffff00000007fac0: 67 20 73 65 6c 66 00 00 28 03 20 00 00 00 00 00
0xffff00000007fad0: 0e 00 00 00 00 00 00 00 d0 01 20 00 00 00 00 00
0xffff00000007fae0: 0b 00 00 00 00 00 00 00 24 00 00 00 15 00 00 00
0xffff00000007faf0: 46 69 6c 65 53 69 7a 65 54 6f 6f 4c 61 72 67 65
0xffff00000007fb00: 4e 6f 53 75 63 68 46 69 6c 65 73 79 73 74 65 6d
0xffff00000007fb10: 2f 6d 6e 74 2f 62 69 6e 2f 74 65 73 74 61 70 70
0xffff00000007fb20: 54 6f 6f 4d 61 6e 79 46 69 6c 65 73 4f 70 65 6e
0xffff00000007fb30: 72 61 6e 67 65 20 65 6e 64 20 69 6e 64 65 78 20
0xffff00000007fb40: 50 0e 21 00 00 00 00 00 08 00 00 00 00 00 00 00
0xffff00000007fb50: 08 00 00 00 00 00 00 00 90 0f 21 00 00 00 00 00
0xffff00000007fb60: 60 0e 21 00 00 00 00 00 50 0f 21 00 00 00 00 00
0xffff00000007fb70: 00 05 0a 0f 14 19 1e 23 28 2d 32 37 3c 41 46 4b
0xffff00000007fb80: 50 55 5a 5f 64 69 6e 73 78 7d 82 87 8c 91 63 61
Opening a new file and writing some data into it
ext2: allocating inode 17
ext2: allocating block 763 in group 0
ext2: writing to block 763
Reading back the data written previously
ext2: looking for "test2", found inode 17
0xffff00000007fba0: 74 68 69 73 20 69 73 20 73 6f 6d 65 20 74 65 73
0xffff00000007fbb0: 74 20 64 61 74 61 00 00 00 00 00 00 00 00 00 00
0xffff00000007fbc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xffff00000007fbd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xffff00000007fbe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xffff00000007fbf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xffff00000007fc00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xffff00000007fc10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Printing the contents of the root directory (ext2 mount)
reading dir . with inode 2
reading dir .. with inode 2
reading dir lost+found with inode 11
reading dir bin with inode 32769
reading dir test with inode 12
reading dir dev with inode 13
reading dir tmp with inode 14
reading dir testdir with inode 15
reading dir test2 with inode 17
Finished tests
loading the first processs (/bin/sh) from elf binary file
ext2: looking for "bin", found inode 32769
ext2: looking for "sh", found inode 32772
program segment 0: 6 4 offset: 40 v:200040 p:200040 size: e0
program segment 1: 1 4 offset: 0 v:200000 p:200000 size: 1870
program segment 2: 1 5 offset: 1870 v:211870 p:211870 size: 53c8
program segment 3: 6474e551 6 offset: 0 v:0 p:0 size: 0
ext2: looking for "dev", found inode 13
timer: initializing generic arm timer to trigger context switch
kernel initialization complete
scheduler: starting multitasking
Instruction or Data Abort caused by Access Flag at address 215a70 (allocating new page)
Instruction or Data Abort caused by Access Flag at address fffffff0 (allocating new page)
Instruction or Data Abort caused by Access Flag at address 21337c (allocating new page)
Instruction or Data Abort caused by Access Flag at address 212190 (allocating new page)
Starting shell...
Instruction or Data Abort caused by Access Flag at address 216c34 (allocating new page)
% <typing in ls>
Instruction or Data Abort caused by Access Flag at address 2140e8 (allocating new page)
executing /bin/ls
child pid is 3
clearing old process space
executing a new process
ext2: looking for "bin", found inode 32769
ext2: looking for "ls", found inode 32774
program segment 0: 6 4 offset: 40 v:200040 p:200040 size: e0
program segment 1: 1 4 offset: 0 v:200000 p:200000 size: 730
program segment 2: 1 5 offset: 730 v:210730 p:210730 size: 2cb8
program segment 3: 6474e551 6 offset: 0 v:0 p:0 size: 0
ext2: looking for "dev", found inode 13
Instruction or Data Abort caused by Access Flag at address 212220 (allocating new page)
Instruction or Data Abort caused by Access Flag at address fffffff0 (allocating new page)
ext2: looking for ".", found inode 2
Instruction or Data Abort caused by Access Flag at address 2133e4 (allocating new page)
Instruction or Data Abort caused by Access Flag at address 2110e4 (allocating new page)
.
..
lost+found
bin
test
dev
tmp
testdir
test2
Exiting process 3
%