PSE Seance 3

De Ensiwiki
Aller à : navigation, rechercher
AttentionCette page est maintenue uniquement par les enseignants. Afin de ne pas perturber le déroulement des cours, elle n'a pas vocation à être modifiée par les élèves. Mais si vous avez des modifications à proposer, merci d'en discuter ou d'envoyer un e-mail aux auteurs de la page (cf. historique)

Mycomputer.png  Deuxième Année  CDROM.png  Informatique 

Dans cette troisième séance de Pratique du Système, on va implanter la gestion du clavier dans le système commencé pendant les séances précédentes.

Principe général

Le clavier fonctionne grâce au mécanisme d'interruptions déjà utilisé pour l'horloge à la séance précédente. Lorsqu'un évenement à lieu en provenance du clavier (une touche pressée par exemple), le contrôleur d'interruption reçoit l'IRQ 1. Il active en réaction le signal d'interruption externe 33, pour lequel on doit donc avoir écrit un traitant approprié.

C'est ce traitant qui sensé réaliser tout le travail nécessaire au traitement de l'évenement (par exemple, détecter quelle touche a été pressée, convertir le code de la touche (scancode) en code ASCII pour permettre son affichage, etc.). Dans le cadre des TP de PSE, comme il s'agit d'une opération complexe, on vous fourni une partie du code nécessaire au décodage des événements clavier et votre travail consistera principalement à utiliser correctement le code fourni.

Traitement de l'interruption clavier

Le traitant à écrire pour gérer l'interruption 33 doit réaliser les opérations suivantes dans l'ordre spécifié :

  1. sauvegarder le contexte d'exécution, comme ça a dû être fait aussi pour l'interruption horloge ;
  2. acquitter l'interruption auprès du contrôle d'interruption, là encore de la même façon que pour l'interruption 32 ;
  3. lire le code de la touche manipulée, en utilisant les ports d'entrée-sortie : dans ce cas, il suffit de lire un octet sur le port de données 0x60, grâce à l'instruction inb ;
  4. appeler la fonction void do_scancode(int code) fournie, en lui passant en paramètre le code de la touche (attention, on passe bien un entier sur 32 bits et pas juste un octet) ;
  5. restaurer le contexte d'exécution, puis terminer le traitant avec l'instruction iret.

Traitement des caractères reçus

La fonction do_scancode (extraite du noyau Linux) réalise toutes les opérations complexes de décodage de la touche manipulée : vous n'avez pas à comprendre son fonctionnement précis.

Une fois ce traitement terminée, elle appelle la fonction void keyboard_data(char *str) que vous allez devoir écrire. Cette fonction reçoit en argument une chaîne composée des caractères (codes ASCII) correspondant à la touche manipulée : en effet, certaines touches particulières (touches de fonction, etc.) sont représentées par plusieurs codes ASCII.

Pour bien comprendre le fonctionnement de ce mécanisme, on vous recommande de commencer par afficher les codes ASCII contenus dans la chaîne passée en paramètre ainsi que le symbole s'il est imprimable, ce qui peut être fait très simplement en implantant keyboard_data comme suit :

void keyboard_data(char *str)
{
    printf("Codes ASCII de la touche : ");
    for (int i = 0; str[i] != '\0'; i++) {
        printf("%u ", (unsigned)str[i]);
    }
    if ((str[0] >= 32) && (str[0] < 127)) {
        printf(", symbole imprimable : '%c' ", str[0]);
    }
    printf("\n");
}

Testez ce qui se passe en appuyant sur différentes touches du clavier. Pensez à tester les touches de modification (shift, control, etc.). On vous rappelle que vous pouvez voir la table ASCII en tapant man ascii dans un terminal.

Une fois que vous avez bien compris ce fonctionnement, on vous demande de gérer correctement l'affichage des différentes touches :

  • les symboles des touches imprimables (lettres, chiffres, ponctuation, etc.) doivent être affichées à l'écran ;
  • les touches de contrôle doivent provoquer l'effet attendu : par exemple, on doit aller à la ligne quand on appuie sur entrée, avancer d'une tabulation quand on appuie sur tab, effacer le caractère précédent quand on appuie sur backspace, etc ;
  • les touches de fonction peuvent être utilisées pour ajouter le comportement que vous souhaitez, par exemple changer la couleur du texte de l'écran selon la touche appuyée.

Gestion des LEDs

Les LEDs indiquant si le verrouillage des majuscules et le pavé numérique sont activés peuvent aussi être contrôlés. Pour cela, il suffit d'écrire une fonction void kbd_leds(unsigned char leds) qui :

  1. envoie la commande 0xED sur le port de commande 0x60 ;
  2. envoie la valeur de l'octet leds sur le port de données 0x60.

Cette fonction sera utilisée par la gestion du clavier extraite de Linux pour maintenir en cohérence l'état des LEDs. Cependant, comme la LED correspondant à la fonction scroll lock ne fonctionne pas, il est conseillé d'appeler explicitement kbd_leds(0) une fois dans votre fonction kernel_start pour éteindre initialement toutes les LEDs.

Extensions possibles

Une fois que vous avez terminé la partie obligatoire et seulement si tout fonctionne correctement, vous pouvez ajouter des extensions facultative à votre système, par exemple :

  • gérer un interprète de commandes (shell) qui reconnait des suites de caractères comme des commandes et les exécute (par exemple, vous pouvez gérer les commandes « aide » pour afficher la liste des commandes disponibles, « effacer » pour effacer l'écran, « remplir chaine » pour afficher 100 fois la chaîne donnée à l'écran, etc.) ;
  • intégrer l'allocateur mémoire dynamique que vous avez développé en SEPC à votre noyau et l'utiliser dans l'application de votre choix ;
  • pour ceux qui souhaitent aller plus loin, vous pouvez réfléchir à la notion de processus légers vu en SEPC et essayer d'en implanter une gestion simpliste dans votre système (par exemple en gérant deux processus légers se passant explicitement la main) ;
  • etc.

On rappelle que l'évaluation se fera principalement via l'examen de TP final : il est donc très important d'avoir bien compris tout ce qui a été demandé et ne pas chercher à ajouter des fonctions optionnelles si la base obligatoire ne fonctionne pas correctement.