Projet système PC : 2018 - BARBE Mathieu, BAGLIOTTO Bastien, BECK Thomas, CARTIER Paul, COMBE François, GRÉGOIRE Louis

De Ensiwiki
Aller à : navigation, rechercher
BarbOS
Screenshot Busic.png
Application Busic permettant de lire une musique sur BarbOS.

Développeurs BARBE Mathieu
BAGLIOTTO Bastien
BECK Thomas
CARTIER Paul
COMBE François
GRÉGOIRE Louis
Dernière version 1.0.0 (le 25/05/2018)

Langue Anglais

Type UNIX

Démonstration

Ici bientôt une vidéo!

Implémentation des spécifications de base

Processus

Pour la gestion des processus, de leur cycle de vie et de l'ordonnancement, nous avons implémenté une structure avec les différentes variables nécessaires pour mettre en place un système en round-robin par priorité. La priorité est donnée statiquement au processus à son lancement. Cette gestion de processus permet de lancement plusieurs tâches en parallèle et la terminaison correcte de celles-ci.

Mémoire et Protection

Nous avons implémenté un système de pagination pour virtualiser la mémoire. Cette virtualisation est nécessaire pour faciliter la gestion de plusieurs processus. Chaque processus possède son propre page directory et sa table de page. Ceux-ci sont donc construit à chaque création de processus. Nous avons opté pour une gestion des pages de type free-list. Nous avons donc implementé un allocateur de mémoire physique. Pour garantir qu'un processus donné n'accède jamais à la mémoire d'un autre, nous avons mis en place un système de protection de la mémoire. Notamment, la mémoire Kernel et la mémoire pour les applications User est complètement séparée. Si un processus user a besoin d'accéder à la mémoire du noyau, il doit passer par un appel système. Ces appels système font le lien entre le kernel et le noyau.

Keyboard, applications user et Shell

Nous avons aussi géré le clavier avec un système de buffer et d'interruptions. Avec le clavier implémenté, il fut possible de créer divers programmes utilisateurs puis d'implémenter un programme Shell qui permet de lancer ceux-ci en ligne de commande. Ces commandes sont les suivantes:

Commandes de base

  • help : Affiche la liste des programmes disponible;
  • clear [ ] : Efface l'ecran actuel;
  • echo_on [ ] : Active l'echo du clavier;
  • echo_off [ ] : Desactive l'echo du clavier;
  • exit [ ] : Sortie du shell;
  • ps [ ] : Affiche la liste des processus en cours;
  • time [ ] : Affiche le temps courant.
  • minfo [ ] : Affiche les informations sur les files de messages en cours
  • sinfo [ ] : Affiche les informations sur les sémaphores en cours

Test

  • select test [ ] : Lance le selectionneur de test;


PCI

  • pcils [ ] : Affiche la liste des périphériques PCI;
  • pci_device [ num ] : Affiche certain registres du périphérique PCI selectionnée.

Busic

  • wavls [ ]: Affiche la liste des fichier audio disponibles
  • busic [ ] : Lance le Juke-box audio Busic(TM);
  • play_wav [ num ] : Lance directement le wav choisi avec Busic;
  • play [ ] : Lance la lecture du fichier audio spécifié en arrière plan, si pas de paramettre, relance la lecture après une pause;
  • pause [ ] : Met en pause la lecture du fichier audio en arrière plan;
  • info_wav [ num ] : Affiche les informations du wav selectionné

Extensions

Sémaphores

  • Les sémaphores ont été implémentés en adéquation avec la spécification;
  • L'ensemble des tests concernant concernant les sémaphores ont été passés avec succès;
  • Ces tests on pu être ajoutés à la liste des tests utilisateurs, mais nous avons du retravailler la chaîne de compilation afin de conserver en parallèle les tests des messages;
  • Les tests 23 à 27 sont donc les tests prévu pour les sémaphores.

PCI

Le choix de la norme intel HDA pour la gestion de la carte son nous a obligé à passer par le bus PCI. Nous avons donc créer un driver simple permettant de contrôler le bus PCI. Plusieurs méthodes peuvent-être employées à cette fin, mais nous avons utilisé le système des ports In et Out du x86. Ce driver peut lister les différents périphériques branchés dessus et lire ou modifier les registres de configuration. L'implémentation de ce driver nous a permise de créer des appels systèmes pour afficher la liste des périphériques du bus PCI et d'obtenir des informations supplémentaire sur eux à l'aide de leur numéro.

Intel HDA

Exploration

Une fois le bus PCI accessible et une carte son HDA Intel ajoutée à QEmu, nous sommmes partie à sa recherche. Nous l'avons belle et bien trouvé grâce à la marque Intel et au numéro de device.

Après avoir lu quelques registres de configuration de la carte, la confirmation était faite. Nous avons récupéré :

  • Le registre de commande;
  • Registre de status;
  • Le pin sur lequel la carte son envoie des interruptions à travers le PIC ou par APIC;
  • La zone d'adresse mémoire de la carte son.


Une fois la zone d'adresse mémoire obtenue, nous l'avons mappée en 1:1 en mémoire virtuelle. Avec grand plaisir, nous avons pu y lire des valeurs non nulle.

Configuration

Pour cette étape nous avons travaillé longuement sur la spécification HDA d'Intel. Il a été nécessaire d'en comprendre l'intégralité afin de parvenir à notre but.

Pour comprendre les informations présente ici, il faut savoir quels sont les mécanisme nécessaires à la configurations d'un stream.

  • La carte en elle même se configure à l'aide des registres précédemment mappés en mémoire;
  • Pour chaque codec (ici un seul) un arbre avec plusieurs branches permet de configurer chaque ampli, DAC, ADC, Volume, prise Jack;
  • Un stream doit également être configuré.

Il faut tout d'abord explorer l'arbre dans le but de trouver les fonctionnalités (node) de la carte audio et de repérer les liens entre les périphériques. Pour configurer chaque nœud, un système de message doit être mis en place. Les commandes avec l'adresse du node est envoyé à la carte son et le node répond à travers un autre registre.

Voici la listes des nodes :

  1. Root, La base de l'arbre qui nous permet de voir que le codec est actif;
  2. Audio fonction , le node de base pour une fonctionnalité audio ( il peut aussi y avoir des modem);
  3. Audio output converter, cela correspond à un convertisseur numérique analogique;
  4. Pin Selector, cela corespond à une connection mécanique (ici prise Jack en sortie);
  5. Audio Input;
  6. Pin Selector, cela corespond à une connection mécanique (ici prise Jack en entrée).

La force du libre devant une impasse

Après avoir tout assimilé, configuré la carte ainsi que l'ensemble des nodes de sortie, créé un stream et rempli les buffer avec un sinus à 440Hz, rien ne marchait, aucun son ne sortait.

Après plusieurs passes sur notre code, de multiples lectures sur la documentation ainsi que sur les sites spécialisés ne nous on pas permis de trouver notre erreur. Nous avons donc mis les mains dans le cambouis :

  • Téléchargement des sources de QEmu;
  • Lecture du code source sur la partie HDA;
  • Compilation des sources avec l'option debug;
  • Lancement de notre OS avec GDB sur un ordi en SSH;
  • QEmu était démaré lui aussi avec GDB;


Cette manipulation nous a permis de vérifier que toute les commandes de configuration que nous avons envoyées sont belle et bien comprises par QEmu comme nous l'avions imaginé. Nous n'avions pas d'erreur de ce côté ci.

  • A l'activation du DMA pour récupérer le son dans les buffer, le bus PCI ne nous renvoyait que des zéro;
  • Avions nous mal configuré le DMA ? Le son est-il belle et bien en mémoire physique?
  • Après avoir regardé des logs de QEmu, une version de HDA sans le DMA avait été utilisée;
  • Après avoir modifié le code de QEmu en le remplaçant par la version sans DMA, nous avons pu récupérer nos donnés;
  • Le DMA ne marchait donc pas;
  • Et effectivement, après quelques lecture sur le bus PCI l'erreur a pu être dénichée : Il fallait autoriser la carte son à devenir maitre du bus PCI pour réaliser le DMA!

Nous avons pu entendre directement la note de musique qui nous informait de la bonne configuration de la carte son.

Importation de musiques dans le kernel

L'import des musiques dans la mémoire de notre os se fait via un script Makefile. Ce script prend tous les fichiers .wav présent dans le dossier wav à la racine du projet et les place dans la mémoire, les pointeurs de début et de fin de chaque morceau sont placés dans la structure sound_library de wav.h.

Transformation des fichiers .wav en fichiers liable

Pour transformer le fichier music_name.wav, on crée un fichiers music_name.wav.o dans lequel on copie les sections de données du fichier empty.c. Puis on y ajoute une sections .music_name contenant les octets du fichier .wav. Sans cette modification des fichiers .wav en fichiers .wav.o le linker ne serait pas capable de copier les données brutes des fichiers dans le binaire final.

Création de la structure sound_library

Une fois les fichiers transformés, un script va créer en C une structure sound_library contenant les pointeurs de début et de fin de chaque musique qui seront donnés par le linker. Lorsque le linker va placer les données des sections .music_name des fichiers music_name.wav.o il leur attribuera une adresse mémoire qui est déclaré en extern dans la structure sound_library. Le linker placera explicitement les données du son dans la section .rodata du binaire.

Nouvelle configuration mémoire

Comme les fichier wave contiennent du son non compressé, cela prend beaucoup de place. Par exemple une musique de 2 minutes en stéréo 16 bits 44,1 kHz pèse 30 Mo. On écrase donc très rapidement le tas kernel qui voit sa taille devenir nulle, voir négative! Nous avons donc décalé la fin du tas kernel à 200Mo, ce qui permet d'avoir :

  • 190 Mo de musique;
  • 10 Mo de tas kernel;
  • 56 Mo de frame de 4ko pour les allocations allignées dynamiques.

Cette nouvelle architecture nous a permise d'avoir de la musique et de continuer à faire fonctionner le kernel correctement. Malheureusement, cette nouvelle configuration mise en place en fin de projet a mis en évidence un bug faisant échouer quelques tests.

En effet, quand on enchaîne l'ensemble des tests, on utilise plus de 56 Mo de frame, dans ces conditions, on réutilise les frame libérés par d’anciens processus. Ce comportement était voulu, mais nous ne supprimions pas les précédentes valeurs, donc catastrophe dans certain cas (et bien sur aléatoire).

Nous avons pu corriger cette erreur avant la soutenance mais après le rendu final pour lequel nous n'avions pas remarqué cet effet de bord.

Busic

Une fois le driver HDA au point et des wave accessible depuis le kernel, il a bien fallu les jouer.

Fonctionnalités

  • Ajouter vos propres wav dans le dossier wav au format CD (44,1kHz / 16 bits / Stéréo);
  • wavls vous permet d'en obtenir la liste;
  • infowav i vous permet d'obtenir des info sur le wav i;
  • Le Jukebox Busic;
  • Lancer de la musique en arrière plan avec play i;
  • Mettre en pause une musique en arrière plan avec pause i;
  • Stopper une musique en arrière plan avec stop i.

Busic

Busic est un lecteur de musique qui va vous permettre de jouer les wav présent dans l'OS. Au lancement, la liste des musiques est affichées. Après le lancement d'une musique, il est possible de la mettre en pause à partir de la touche Espace ou de la stopper avec S afin de revenir à la sélection.

Wave

Après étude de l'en-tête d'un fichier wav, qui est en faite un fichier RIFF, il a été possible d'extraire :

  • La fréquence d’échantillonnage;
  • Le nombre de bits par échantillon;
  • Le nombre de canaux;
  • La durée de la piste;
  • La taille du fichier / en-tête.

Cela nous permet de vérifier que nous avons bien à faire à un fichier wav. Nous n'avons pas eu le temps de rendre la configuration du DAC dynamique en fonction du wav sélectionné. Il faut qu'il soit en 44,1kHz / 16bits / Stéréo.

Chargement et lecture des fichiers audio

Quand une lecture est demandé :

  • Le player récupère le fichier audio dans la mémoire du kernel et vérifie quelques paramètres dans l'en-tête du fichier;
  • Deux tampons sont utilisés dans notre configuration, on les remplis donc avec les échantillon audio;
  • On indique à la carte son que le stream peut commencer.
  • La carte son configure son DMA et prend le contrôle du BUS pour lire le premier buffer;
  • Une fois celui la vidé, la carte son interrompt le processeur;
  • Le handler réveil le player avec une grande prio et repart la ou il en était;
  • Au prochain ordonnancement, le player est réveillé, il rempli le buffer vidé par la carte son et se remêt en attente.


Sur un vrai PC

  • Ajout de Grub à notre OS avec un fichier de configuration et la commande grub-mkrescue;
  • Le boot de l'OS a pu être réalisé sur un PC x86 i3;
  • Nos tests de bases en mode kernel on pu être lancé;


Nous n'avons pas eu le temps d'aller plus loin :

  • Le passage en mode user faisait relancer la machine;
  • Rendre notre driver audio dynamique afin de jouer du son sur l'ordinateur.


Tester le kernel

Pour tester notre kernel vous pouvez télécharger ce binaire : kernel.bin et lancer la commande : /usr/bin/qemu-system-i386 -rtc base=localtime -m 256M -k fr -kernel kernel.bin -soundhw hda

Sources