640 | | - Le code de boot ne fait que sauter dans la fonction kinit avec l'instruction `j`, |
641 | | il n'y a pas de retour, ce n'est donc pas un `jal`, mais pourquoi ne pas avoir utilisé |
642 | | `j init` et donc pourquoi passer par un registre ? |
643 | | {{{#!protected ------------------------------------------------------------------------------------ |
644 | | ''''''''''''''' |
645 | | - On ne sait pas le code de boot est en `0xBFC00000`. |
646 | | L'instruction `j imm26` permet de sauter à n'importe quelle adresse d'instruction `0xB.......` |
647 | | (dans le memento MIPS `j imm26` : `PC <- PC[31:28] || imm26*4` |
648 | | ''''''''''''''' |
649 | | }}} |
650 | | - Dans `kernel.ld`, la définition de la mémoire est plus complète, elle contient 3 régions : |
651 | | pour le code de boot `boot_region` pour le code du noyau `ktext_region` et |
652 | | pour les données globales du noyau `kdata_region`. |
653 | | Ces régions ne contiennent qu'une section de sorties (resp. `.boot`, `.ktext` et `.kdata`) |
654 | | remplies avec les sections d'entrées produites par le compilateur.\\ |
655 | | Que signifie `*(.*data*)` ? |
656 | | {{{#!protected ------------------------------------------------------------------------------------ |
657 | | ''''''''''''''' |
658 | | - C'est une manière de désigner toutes les sections nommées `.*data*` avec `*` = n'importe quoi |
659 | | présentes dans n'importe quel fichier objets reçu par le compilateur. |
660 | | ''''''''''''''' |
661 | | }}} |
662 | | - Quelle est la valeur de `__kdata_end` ? Pourquoi, selon vous, mettre 2 «`_`» au début des variables ? |
663 | | {{{#!protected ------------------------------------------------------------------------------------ |
664 | | ''''''''''''''' |
665 | | - `__kdata_end` est l'adresse du premier octet placé juste après la région data. |
666 | | - les 2 «`_`» permettent d'éviter les conflits avec les noms des symboles (fonction, variable, type, etc.) |
667 | | présents dans le programme. |
668 | | ''''''''''''''' |
669 | | }}} |
670 | | - |
671 | | {{{#!protected ------------------------------------------------------------------------------------ |
672 | | ''''''''''''''' |
673 | | - |
674 | | ''''''''''''''' |
675 | | }}} |
676 | | - |
677 | | {{{#!protected ------------------------------------------------------------------------------------ |
678 | | ''''''''''''''' |
679 | | - |
680 | | ''''''''''''''' |
681 | | }}} |
682 | | - |
683 | | {{{#!protected ------------------------------------------------------------------------------------ |
684 | | ''''''''''''''' |
685 | | - |
686 | | ''''''''''''''' |
687 | | }}} |
688 | | - |
689 | | {{{#!protected ------------------------------------------------------------------------------------ |
690 | | ''''''''''''''' |
691 | | - |
692 | | ''''''''''''''' |
693 | | }}} |
694 | | |
695 | | |
696 | | |
697 | | |
698 | | == 3. Saut dans la fonction kinit() du noyau en langage C |
699 | | |
700 | | Dans ce troisième programme, nous faisons la même chose que pour le deuxième mais `kinit()` est désormais écrit en |
701 | | langage C. Cela change peu de choses, sauf une chose importante `kinit()` est une fonction et donc il faut absolument |
702 | | une pile d'exécution. |
703 | | \\\\ |
704 | | **Objectifs** |
705 | | - Savoir comment et où déclarer la pile d'exécution du noyau. |
706 | | - Savoir comment afficher un caractère sur un terminal depuis un programme C. |
707 | | |
708 | | **Fichiers** |
| 642 | 2. Le code de boot ne fait que sauter à l'adresse `kinit avec l'instruction `j`, |
| 643 | il n'y a pas de retour, ce n'est donc pas un `jal`. Où est définit `kinit` ? |
| 644 | Comment le code de boot connait cette adresse ? |
| 645 | Pourquoi ne pas avoir utilisé `j init` et donc pourquoi passer par un registre ? |
| 646 | {{{#!protected ------------------------------------------------------------------------------------ |
| 647 | ''''''''''''''' |
| 648 | - `kinit` est défini dans la `kinit.S`. |
| 649 | - `hcpu.S` ne connait pas cette adresse, mais grâce au `.globl kinit`, l'éditeur de lien saura compléter `hcpu.o`, dans l'exécutable. |
| 650 | - Le code de boot est en `0xBFC00000`, `kinit` est en `0x80000000`, ces deux adresses ne partagent pas les 4 bits de poids fort, c'est trop loin pour un simple `j`. |
| 651 | ''''''''''''''' |
| 652 | }}} |
| 653 | 1. Dans `kernel.ld`, que signifie `*(.*data*)` ? |
| 654 | {{{#!protected ------------------------------------------------------------------------------------ |
| 655 | ''''''''''''''' |
| 656 | - C'est une manière de désigner toutes les sections nommées `.*data*` avec `*` = n'importe quoi |
| 657 | présentes dans n'importe quel fichier objets reçu par le compilateur. |
| 658 | ''''''''''''''' |
| 659 | }}} |
| 660 | 1. Quelle est la valeur de `__kdata_end` ? Pourquoi mettre 2 «`_`» au début des variables du `ldscript` ? |
| 661 | {{{#!protected ------------------------------------------------------------------------------------ |
| 662 | ''''''''''''''' |
| 663 | - `__kdata_end` est l'adresse du premier octet placé juste après la région data. |
| 664 | - les 2 «`_`» permettent d'éviter les conflits avec les noms des symboles (fonction, variable, type, etc.) |
| 665 | présents dans le programme. |
| 666 | ''''''''''''''' |
| 667 | }}} |
| 668 | |
| 669 | **Exercices** |
| 670 | |
| 671 | - Exécutez le programme sur le simulateur. Est-ce différent de l'étape 1 ? |
| 672 | {{{#!protected ------------------------------------------------------------------------------------ |
| 673 | ''''''''''''''' |
| 674 | * Non, c'est le même comportement. |
| 675 | ''''''''''''''' |
| 676 | }}} |
| 677 | - Modifiez le code, comme pour l'étape 1, afin d'afficher un second message ? |
| 678 | {{{#!protected ------------------------------------------------------------------------------------ |
| 679 | ''''''''''''''' |
| 680 | * C'est très semblable, voire identique, à l'étape 1, l'idée est qu'ils ouvrent le code... |
| 681 | ''''''''''''''' |
| 682 | }}} |
| 683 | |
| 684 | |
| 685 | |
| 686 | == B3. Saut dans la fonction kinit() du noyau en langage C |
| 687 | |
| 688 | |
| 689 | |
| 690 | Dans ce troisième programme, nous faisons la même chose que pour le deuxième mais `kinit()` est désormais écrit en |
| 691 | langage C. Cela change peu de choses, sauf une chose importante `kinit()` est une fonction et donc il faut absolument |
| 692 | une pile d'exécution. |
| 693 | |
| 694 | **Objectifs** |
| 695 | |
| 696 | - Savoir comment et où déclarer la pile d'exécution du noyau. |
| 697 | - Savoir comment afficher un caractère sur un terminal depuis un programme C. |
| 698 | |
| 699 | **Fichiers** |
| 700 | |
717 | | - **Questions**\\ |
718 | | ''Les réponses sont dans le cours ou dans les fichiers sources''\\\\ |
719 | | - Question ? |
720 | | {{{#!protected ------------------------------------------------------------------------------------ |
721 | | ''''''''''''''' |
722 | | - Réponse |
723 | | ''''''''''''''' |
724 | | }}} |
725 | | |
726 | | |
727 | | |
728 | | |
729 | | == 4. Accès aux registres de contrôle des terminaux `TTY` |
730 | | |
731 | | |
732 | | |
733 | | |
734 | | Le prototype de SoC que nous utilisons pour les TP est configurable. Il est possible par exemple de choisir le nombre |
735 | | terminaux texte (TTY). Par défaut, il y en a un mais, nous pouvons en avoir jusqu'à 4. Nous allons modifier le code du |
736 | | noyau pour s'adapter à cette variabilité. En outre, pour le moment, nous ne faisions qu'écrire sur le terminal, |
737 | | maintenant, nous allons aussi lire le clavier. |
738 | | \\\\ |
739 | | **Objectifs** |
740 | | - Savoir comment compiler un programme C avec du code conditionnel. |
741 | | - Savoir comment décrire en C l'ensemble des registres d'un contrôleur de périphérique et y accéder. |
| 709 | **Questions** |
| 710 | |
| 711 | 1. Quand faut-il initialiser la pile ? Dans quel fichier est-ce ? Quelle est la valeur du pointeur initial ? |
| 712 | {{{#!protected ------------------------------------------------------------------------------------ |
| 713 | ''''''''''''''' |
| 714 | - Il faut initialiser le pointeur avant d'appeler `kinit()` |
| 715 | - C'est dans le fichier `hcpu.S` |
| 716 | - '$29' ← '__kdata_end', c'est-à-dire `0x80400000` |
| 717 | ''''''''''''''' |
| 718 | }}} |
| 719 | |
| 720 | **Exercices** |
| 721 | |
| 722 | - Exécutez le programme sur le simulateur. Est-ce différent de l'étape 1 ? |
| 723 | {{{#!protected ------------------------------------------------------------------------------------ |
| 724 | ''''''''''''''' |
| 725 | * Non, c'est le même comportement :-) |
| 726 | ''''''''''''''' |
| 727 | }}} |
| 728 | - Modifiez le code de `kinit.c`, et comme pour l'étape 1, afficher un second message ? |
| 729 | {{{#!protected ------------------------------------------------------------------------------------ |
| 730 | ''''''''''''''' |
| 731 | * Hormis, qu'il s'agit de code C, il n'y a pas de différence de principe, c'est toujours du copier-coller, l'important c'est qu'ils ouvrent le code |
| 732 | ''''''''''''''' |
| 733 | }}} |
| 734 | |
| 735 | |
| 736 | |
| 737 | == B4. Accès aux registres de contrôle des terminaux `TTY` |
| 738 | |
| 739 | |
| 740 | |
| 741 | Le prototype de SoC que nous utilisons pour les TP est configurable. Il est possible par exemple de choisir le nombre |
| 742 | terminaux texte (TTY). Par défaut, il y en a un mais, nous pouvons en avoir jusqu'à 4. Nous allons modifier le code du |
| 743 | noyau pour s'adapter à cette variabilité. En outre, pour le moment, nous ne faisions qu'écrire sur le terminal, |
| 744 | maintenant, nous allons aussi lire le clavier. |
| 745 | |
| 746 | **Objectifs** |
| 747 | |
| 748 | - Savoir comment compiler un programme C avec du code conditionnel. |
| 749 | - Savoir comment décrire en C l'ensemble des registres d'un contrôleur de périphérique et y accéder. |
752 | | - **Questions**\\ |
753 | | ''Les réponses sont dans le cours ou dans les fichiers sources''\\\\ |
754 | | - Question ? |
755 | | {{{#!protected ------------------------------------------------------------------------------------ |
756 | | ''''''''''''''' |
757 | | - Réponse |
758 | | ''''''''''''''' |
759 | | }}} |
760 | | |
761 | | |
762 | | |
763 | | |
764 | | == 5. Premier petit pilote pour le terminal |
765 | | |
766 | | |
767 | | |
768 | | |
769 | | Dans l'étape 4, nous accédons au registre de périphérique directement dans la fonction `kinit()`, ce n'est pas très |
770 | | simple. C'est pourquoi nous allons ajouter un niveau d'abstraction qui représente un début de pilote de périphérique |
771 | | (device driver). Ce pilote, même tout petit constitue une couche logicielle avec une API. |
772 | | \\\\ |
773 | | **Objectifs** |
774 | | - Savoir comment créer un début de pilote pour le terminal `TTY`. |
775 | | - Savoir comment décrire une API en C |
776 | | |
777 | | **Fichiers** |
| 761 | **Questions** |
| 762 | |
| 763 | 1. ? |
| 764 | {{{#!protected ------------------------------------------------------------------------------------ |
| 765 | ''''''''''''''' |
| 766 | - |
| 767 | ''''''''''''''' |
| 768 | }}} |
| 769 | |
| 770 | **Exercices** |
| 771 | |
| 772 | - Exécutez le programme sur le simulateur. Qu'observez-vous ? |
| 773 | - Modifiez le code pour afficher un message sur le second terminal, il y a toujours une attente sur le premier terminal. |
| 774 | - Modifiez le code pour que le programme attende sur les deux terminaux. L'idée est de ne plus faire d'attente bloquante sur le registre `TTY_STATUS` de chaque terminal. |
| 775 | |
| 776 | |
| 777 | |
| 778 | |
| 779 | == B5. Premier petit pilote pour le terminal |
| 780 | |
| 781 | |
| 782 | |
| 783 | Dans l'étape 4, nous accédons au registre de périphérique directement dans la fonction `kinit()`, ce n'est pas très |
| 784 | simple. C'est pourquoi nous allons ajouter un niveau d'abstraction qui représente un début de pilote de périphérique |
| 785 | (device driver). Ce pilote, même tout petit constitue une couche logicielle avec une API. |
| 786 | |
| 787 | **Objectifs** |
| 788 | |
| 789 | - Savoir comment créer un début de pilote pour le terminal `TTY`. |
| 790 | - Savoir comment décrire une API en C |
| 791 | |
| 792 | **Fichiers** |
| 793 | |