Changes between Version 91 and Version 92 of Archi-1-TP10
- Timestamp:
- Nov 28, 2021, 10:41:03 AM (3 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
Archi-1-TP10
v91 v92 204 204 205 205 206 1. En assembleur, vous utilisez les sections prédéfinies `.data` et `.text` pour placer respectivement les data et le code, mais vous pouvez créer vos propres sections avec la directive `.section` (nous avons utilisé cette possibilité pour la section `.boot`). Il est aussi possible d'imposer ou de créer des sections en langage C avec la directive `__attribute__ `. Cette directive du C permet de demander certains comportements au compilateur. Il y a beaucoup d'attributs possibles (si cela vous intéresse vous pouvez regarder dans la [https://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Variable-Attributes.html doc de GCC sur les attributs]. En cours, nous avons vu un attribut permettant de désigner ou créer une section dans laquelle est mise la fonction concernée. Quelle est la syntaxe de cet attribut?206 1. En assembleur, vous utilisez les sections prédéfinies `.data` et `.text` pour placer respectivement les data et le code, mais vous pouvez créer vos propres sections avec la directive `.section` (nous avons utilisé cette possibilité pour la section `.boot`). Il est aussi possible d'imposer ou de créer des sections en langage C avec la directive `__attribute__((section("section-name")))`. La directive du C `__attribute__` permet de demander certains comportements au compilateur. Ici, c'est la création d'une section, mais il y a beaucoup d'attributs possibles (si cela vous intéresse vous pouvez regarder dans la [https://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Variable-Attributes.html doc de GCC sur les attributs]. Comment créer la section `.start` en C ? 207 207 {{{#!protected ------------------------------------------------------------------------------------ 208 208 '' 209 209 Cours 10 / slide 38 210 - `__attribute__ ((section (".start")))`\\ Remarquez la syntaxeun peu curieuse avec les doubles underscore et les doubles parenthèses.210 - `__attribute__ ((section (".start")))`\\La syntaxe est un peu curieuse avec les doubles underscore et les doubles parenthèses. 211 211 '' 212 212 }}} … … 378 378 **mais** comme `EXL`=`1`, alors on reste en mode `kernel` avec interruptions masquées. L'exécution de l'instruction `eret` mettra `EXL` à `0` pour rendre les bits `UM` et `IE` actifs et passer en mode `user` (ici avec interruptions masquées). 379 379 - Le registre GPR `$29` reçoit l'adresse de la première adresse après la section `.data`. C'est le haut de la pile. 380 '' '''''''''''''380 '' 381 381 }}} 382 382 1. Que faire avant l'exécution de la fonction `main()` du point de vue de l'initialisation? Et au retour de la fonction `main()`? 383 383 {{{#!protected ------------------------------------------------------------------------------------ 384 ''''''''''''''' 384 '' 385 Cours 10 / slide 38 385 386 - Comme dans la fonction `kinit()`, il faut explicitement initialiser les variables globales non initialisées dans le programme C. 386 - Si on sort de la fonction `main()`, l'application s'achève. Cela signifie qu'il faut appeler la fonction `exit()` qui effectue l'appel système EXIT. Cette appel est réalisé au cas où l'application n'aurait pas explicitement exécuté `exit()`.387 '' '''''''''''''387 - Si on sort de la fonction `main()`, l'application s'achève. Cela signifie qu'il faut appeler la fonction `exit()` qui effectue l'appel système SYSCALL_EXIT. Cette appel est réalisé au cas où l'application n'aurait pas explicitement exécuté `exit()`. Dans ce cas la valeur rendue par l'application est la valeur de retour de la fonction `main()`. 388 '' 388 389 }}} 389 390 1. Nous avons vu que le noyau est sollicité par des événements, quels sont-ils? Nous rappelons que l'instruction `syscall` initialise le registre `c0_cause`, comment le noyau fait-il pour connaître la cause de son appel? 390 391 {{{#!protected ------------------------------------------------------------------------------------ 391 ''''''''''''''' 392 '' 393 Cours 10 / slide 17 392 394 - Il y en a 3 (si on excepte le signal `reset` qui redémarre tout le système: 393 395 1. Les appels système donc l'exécution de l'instruction `syscall`. … … 395 397 1. Les interruptions qui sont des demandes d'intervention provenant des périphériques. 396 398 - L'instruction `syscall` initialise les 4 bits `XCODE` du registre `c0_cause` avec un code indiquant la raison de l'entrée dans le noyau. Le noyau doit analyser ce champ `XCODE`. 397 '' '''''''''''''398 }}} 399 1. `$26` et `$27` sont deux registres temporaires que le noyau se réserve pour faire des calculs sans qu'il ait besoin de les sauvegarder dans la pile. Ce ne sont pas des registres système comme `c0_sr` ou `c0_epc`. En effet, l'usage de ces registres (`$26` et `$27`) par l'utilisateur ne provoque pas d'exception du MIPS. Toutefois si le noyau est appelé alors il modifie ces registres et donc l'utilisateur perd leur valeur.\\Le code assembleur ci-après contient les instructions exécutées à l'entrée dans le noyau, quelle que soit la cause. Les commentaires présents dans le code ont été volontairement retirés (ils sont dans les fichiers du TP). La section `.kentry` est placée à l'adresse `0x80000000` par l'éditeur de lien. La directive `.org` (ligne 16) permet de déplacer le pointeur de remplissage de la section courante du nombre d'octets donnés en argument, ici `0x180`. Pouvez-vous dire pourquoi ? Expliquer les lignes 25 à 28.\\ \\**`kernel/hcpu.S`**399 '' 400 }}} 401 1. `$26` et `$27` sont deux registres temporaires que le noyau se réserve pour faire des calculs sans qu'il ait besoin de les sauvegarder dans la pile. **Ce ne sont pas des registres système** comme `c0_sr` ou `c0_epc`. En effet, l'usage de ces registres (`$26` et `$27`) par l'utilisateur ne provoque pas d'exception du MIPS. Toutefois si le noyau est appelé alors il modifie ces registres et donc l'utilisateur perd leur valeur.\\Le code assembleur ci-après contient les instructions exécutées à l'entrée dans le noyau, quelle que soit la cause. Les commentaires présents dans le code ont été volontairement retirés (ils sont dans les fichiers du TP). La section `.kentry` est placée à l'adresse `0x80000000` par l'éditeur de lien. Ligne 16, la directive `.org DEP` (`.org` pour `origine`) permet de placer le pointeur de remplissage de la section courante à `DEP` octets du début de la section, ici `DEP = 0x180`. Aurait-on pu remplacer le `.org 0x180` par `.space 0x180` ? Expliquer les lignes 25 à 28.\\ \\**`kernel/hcpua.S`** 400 402 {{{#!c 401 403 15 .section .kentry,"ax" … … 410 412 }}} 411 413 {{{#!protected ------------------------------------------------------------------------------------ 412 ''''''''''''''' 413 - La section `kentry` est placée à l'adresse `0x80000000` or l'entrée du noyau est `0x80000180`, il faut donc déplacer le pointeur de remplissage de la section `ktentry` de `0x180`. Remarquez qu'on aurait pu utiliser une directive `.space 0x180`. 414 '' 415 Cours 10 / slide 41 (mais il n'y a pas ces détails) 416 - La section `kentry` est placée à l'adresse `0x80000000` or l'entrée du noyau est `0x80000180` (l'entrée du noyau est l'adresse à laquelle le processeur ''saute'' lors de l'exécution `syscall`), il faut donc déplacer le pointeur de remplissage de la section `ktentry` de `0x180`. La directive `.space 0x180` réserve `0x180`, si on met cette directive au tout début de la section, c'est équivalent. 414 417 - Commentaire du code 415 418 - Ligne 25 : `$26` **←** `c0_cause`\\⟶ donc le registre `$26`GPR réservé au kernel prend la valeur du registre de cause. … … 417 420 - Ligne 27 : `$27` **←** `0b00100000`\\⟶ On initialise le registre GPR réservé au kernel $27 avec la valeur attendue dans $26 s'il s'agit d'une cause `syscall`. 418 421 - Ligne 28 : si `$26` ≠ `$27` goto not_syscall\\⟶ Si ce n'est pas un `syscall`, on va plus loin, sinon on continue en séquence. 419 '' '''''''''''''420 }}} 421 1. Le gestionnaire de `syscall` est la partie du code qui gère le comportement du noyau lors de l'exécution de l'instruction `syscall`. C'est un code en assembleur présent dans le fichier `kernel/hcpu .S` que nous allons observer. Pour vous aider dans la compréhension de ce code, vous devez imaginer que l'instruction `syscall` est un peu comme un appel de fonction. Ce code utilise un tableau de pointeurs de fonctions nommé `syscall_vector` définit dans le fichier `kernel/ksyscalls.c`. Les lignes `36` à `43` sont chargées d'allouer de la place dans la pile.\\Dessinez l'état de la pile après l'exécution de ces instructions. Que fait l'instruction ligne `44` et quelle conséquence cela a-t-il? Que font les lignes `46` à `51`? Et enfin que font les lignes `53` à `59` sans détailler ligne à ligne.\\ \\**`common/syscalls.h`**422 '' 423 }}} 424 1. Le gestionnaire de `syscall` est la partie du code qui gère le comportement du noyau lors de l'exécution de l'instruction `syscall`. C'est un code en assembleur présent dans le fichier `kernel/hcpua.S` que nous allons observer. Pour vous aider dans la compréhension de ce code, vous devez imaginer que l'instruction `syscall` est un peu comme un appel de fonction. Ce code utilise un tableau de pointeurs de fonctions nommé `syscall_vector[]` définit dans le fichier `kernel/ksyscalls.c`. Les lignes `36` à `43` sont chargées d'allouer de la place dans la pile.\\Dessinez l'état de la pile après l'exécution de ces instructions. Que fait l'instruction ligne `44` et quelle conséquence cela a-t-il? Que font les lignes `46` à `51`? Et enfin que font les lignes `53` à `59` sans détailler ligne à ligne.\\ \\**`common/syscalls.h`** 422 425 {{{#!c 423 426 1 #define SYSCALL_EXIT 0 … … 437 440 }; 438 441 }}} 439 **`kernel/hcpu .S`**442 **`kernel/hcpua.S`** 440 443 {{{#!xml 441 444 34 ksyscall: … … 525 528 $(OD) -D $@ > $@.s 526 529 527 obj/hcpu .o : hcpu.S hcpu.h530 obj/hcpua.o : hcpua.S hcpu.h 528 531 $(CC) -o $@ $(CFLAGS) $< 529 532 $(OD) -D $@ > $@.s … … 533 536 - La `cible` finale est : `kernel.x` 534 537 - Les `cibles` intermédiaires sont : `kernel.ld`, `obj/hcpu.o`, `obj/kinit.o`, `obj/klibc.o` et `obj/harch.o`. 535 - La `source` est : `hcpu .S`538 - La `source` est : `hcpua.S` 536 539 - Les variables automatiques servent à extraire des noms dans la définition de la dépendance (`cible : dépendances`) 537 540 - dans la première règle : … … 540 543 - dans la seconde règle : 541 544 - `$@` = `cible` = `obj/hcpu.o` 542 - `$<` = la première des dépendances = `hcpu .S`545 - `$<` = la première des dépendances = `hcpua.S` 543 546 ''''''''''''''' 544 547 }}} … … 632 635 ├── harch.c : code dépendant de l'architecture du SoC 633 636 ├── hcpu.h : prototype de la fonction clock() 634 ├── hcpu .S: code dépendant du cpu matériel en assembleur637 ├── hcpua.S : code dépendant du cpu matériel en assembleur 635 638 ├── kernel.ld : ldscript décrivant l'espace d'adressage pour l'éditeur de lien 636 639 ├── klibc.h : API de la klibc … … 648 651 {{{#!make 649 652 kernel.x : kernel.ld obj/hcpu.o obj/kinit.o obj/klibc.o obj/harch.o 650 obj/hcpu .o : hcpu.S653 obj/hcpua.o : hcpua.S 651 654 obj/kinit.o : kinit.c klibc.h 652 655 obj/klibc.o : klibc.c klibc.h harch.h … … 659 662 {{{#!protected ------------------------------------------------------------------------------------ 660 663 ''''''''''''''' 661 - Ils sont dans le fichier `hcpu .S`664 - Ils sont dans le fichier `hcpua.S` 662 665 ''''''''''''''' 663 666 }}} … … 667 670 668 671 669 * Le numéro du processeur est dans les 12 bits de poids faible du registre $15 (`c0_cpuid`) du coprocesseur système (à côté des registres `c0_epc`, `c0_sr`, etc.). Ajoutez la fonction `int cpuid(void)` qui lit le registre `c0_cpuid` et qui rend un entier contenant juste les 12 bits de poids faible.\\Vous pouvez vous inspirez fortement de la fonction `int clock(void)`. Comme il n'y a qu'un seul processeur dans cette architecture, `cpuid` rend toujours `0`.\\Ecrivez un programme de test (vous devrez modifier les fichiers `hcpu.h`, `hcpu .S` et `kinit.c`)672 * Le numéro du processeur est dans les 12 bits de poids faible du registre $15 (`c0_cpuid`) du coprocesseur système (à côté des registres `c0_epc`, `c0_sr`, etc.). Ajoutez la fonction `int cpuid(void)` qui lit le registre `c0_cpuid` et qui rend un entier contenant juste les 12 bits de poids faible.\\Vous pouvez vous inspirez fortement de la fonction `int clock(void)`. Comme il n'y a qu'un seul processeur dans cette architecture, `cpuid` rend toujours `0`.\\Ecrivez un programme de test (vous devrez modifier les fichiers `hcpu.h`, `hcpua.S` et `kinit.c`) 670 673 671 674 {{{#!protected 672 **hcpu .S**675 **hcpua.S** 673 676 {{{#!asm 674 677 .globl cpuid … … 710 713 │ ├── harch.c : code dépendant de l'architecture du SoC 711 714 │ ├── hcpu.h : prototype de la fonction clock() 712 │ ├── hcpu .S: code dépendant du cpu matériel en assembleur715 │ ├── hcpua.S : code dépendant du cpu matériel en assembleur 713 716 │ ├── klibc.h : API de la klibc 714 717 │ ├── klibc.c : fonctions standards utilisées par les modules du noyau … … 788 791 │ ├── harch.c : code dépendant de l'architecture du SoC 789 792 │ ├── hcpu.h : prototype de la fonction clock() 790 │ ├── hcpu.S : code dépendant du cpu matériel en assembleur 793 │ ├── hcpua.S : code dépendant du cpu matériel en assembleur 794 │ ├── hcpuc.c : code dépendant du cpu matériel en c 791 795 │ ├── klibc.h : API de la klibc 792 796 │ ├── klibc.c : fonctions standards utilisées par les modules du noyau … … 822 826 {{{#!protected ------------------------------------------------------------------------------------ 823 827 ''''''''''''''' 824 - Il est dans le fichier `kernel/hcpu .S`.828 - Il est dans le fichier `kernel/hcpua.S`. 825 829 ''''''''''''''' 826 830 }}} … … 830 834 831 835 832 - Vous allez ajouter un appel système nommé `SYSCALL_CPUID` qui rend le numéro du processeur. Nous allons lui attribuer le numéro 4 (notez que ces numéros de services n'ont rien à voir avec les numéros utilisés pour le simulateur MARS). Pour ajouter un appel système, vous devez modifier les fichiers : `common/syscalls.h`, `kernel/ksyscall.c`, `kernel/hcpu .S` et `kernel/hcpu.h`.cpuid(void)`.836 - Vous allez ajouter un appel système nommé `SYSCALL_CPUID` qui rend le numéro du processeur. Nous allons lui attribuer le numéro 4 (notez que ces numéros de services n'ont rien à voir avec les numéros utilisés pour le simulateur MARS). Pour ajouter un appel système, vous devez modifier les fichiers : `common/syscalls.h`, `kernel/ksyscall.c`, `kernel/hcpua.S` et `kernel/hcpu.h`.cpuid(void)`. 833 837 834 838 … … 863 867 │ ├── harch.c : code dépendant de l'architecture du SoC 864 868 │ ├── hcpu.h : prototype de la fonction clock() 865 │ ├── hcpu.S : code dépendant du cpu matériel en assembleur 869 │ ├── hcpua.S : code dépendant du cpu matériel en assembleur 870 │ ├── hcpuc.c : code dépendant du cpu matériel en c 866 871 │ ├── klibc.h : API de la klibc 867 872 │ ├── klibc.c : fonctions standards utilisées par les modules du noyau