Changes between Version 27 and Version 28 of Archi-1-TP10


Ignore:
Timestamp:
Jan 2, 2021, 10:10:05 AM (4 years ago)
Author:
franck
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Archi-1-TP10

    v27 v28  
    126126'''''''''''''''
    127127}}}
    128 1. Le registre `EPC` est un registre 32 bits qui contient une adresse. Vous devriez l'avoir décrit dans la question 2, mais expliquez pourquoi ce doit être l'adresse de l'instruction qui provoque une exception qui doit être stocké dans `EPC`?
     1281. Le registre `EPC` est un registre 32 bits qui contient une adresse. Vous devriez l'avoir décrit dans la question 2, mais expliquez pourquoi ce doit être l'adresse de l'instruction qui provoque une exception qui doit être stockée dans `EPC`?
    129129{{{#!protected ------------------------------------------------------------------------------------
    130130'''''''''''''''
     
    147147{{{#!protected ------------------------------------------------------------------------------------
    148148'''''''''''''''
    149 - C'est `0x80000180`i. Il n'y a qu'un adresse pour toutes les causes syscall, exception et interruption.
     149- C'est `0x80000180`i. Il n'y a qu'une adresse pour toutes les causes syscall, exception et interruption.
    150150- En fait, on peut considérer que `0xBFC00000` permet aussi d'entrer dans le noyau après un reset.
    151151'''''''''''''''
     
    185185{{{#!protected ------------------------------------------------------------------------------------
    186186'''''''''''''''
    187 - `__attribute__ ((section (".crt0")))`. Remarquez la syntaxe un peu curieuse avec les doubles underscore et les doubles parenthèse.
     187- `__attribute__ ((section (".crt0")))`. Remarquez la syntaxe un peu curieuse avec les doubles underscore et les doubles parenthèses.
    188188'''''''''''''''
    189189}}}
     
    211211'''''''''''''''
    212212- La ligne 11 contient `. = ALIGN(4)`, c'est équivalent à la directive `.align 4` de l'assembleur.
    213   cela permet de déplacer le pointeur de remplissage de la section de sortie courante (c'est-à-dire ici `.kdata`)
    214   frontière de 2^4^ octets (une adresse multiple de 16). Cette contrainte est lié au caches que nous ne verrons pas ici.
     213  Cela permet de déplacer le pointeur de remplissage de la section de sortie courante (c'est-à-dire ici `.kdata`)
     214  frontière de 2^4^ octets (une adresse multiple de 16). Cette contrainte est liée aux caches que nous ne verrons pas ici.
    215215- La ligne 12 permet de créer la variable de ldscript `__bss_origin` et de l'initialiser à l'adresse courante,
    216   ce sera donc l'adresse de début du la zone `bss`.
     216  ce sera donc l'adresse de début de la zone `bss`.
    217217- La ligne 15 permet de créer la variable `__bss_end` qui sera l'adresse de fin de la zone `bss`
    218218  (en fait c'est la première adresse qui suit juste `bss`.
     
    239239- `extern` : informe le compilateur que la variable définie existe ailleurs. Grâce à son type, le compilateur sait s'en servir.
    240240- `volatile` : informe le compilateur que la variable peut changer de valeur toute seule et que donc il doit toujours accéder en mémoire à chaque fois que le programme le demande. Il ne peut donc pas optimiser les accès mémoire en utilisant les registres.
    241 - `__tty_regs_map` est un tableau à 2 cases (puisque `NTTYS`=2). Chaque case est une structure de 4 entiers, donc `0x10` octets. `read` est le troisième champs, c'est le troisième entier de la structure, donc en `+8` par rapport au début.\\En conséquence `__tty_regs_map[1].read` est en `0xd0200018`
    242 '''''''''''''''
    243 }}}
    244 1. Certaines parties du noyau sont en assembleur. Il y au moins les toutes premières instructions du code de boot (démarrage de l'ordinateur) et l'entrée dans le noyau après l'exécution d'un syscall. Dans ce dernier cas, le gestionnaire de syscall écrit en assembleur a besoin d'appeler une fonction écrite en langage C. Le gestionnaire de syscall trouve l'adresse de la fonction C qu'il doit appeler puis il place cette adresse dans un registre, par exemple `$2`. Il suffit qu'il exécute l'instruction `jal $2` pour appeler la fonction. Que doivent contenir les registres `$4` à `$7` et comment doit-être la pile?
     241- `__tty_regs_map` est un tableau à 2 cases (puisque `NTTYS`=2). Chaque case est une structure de 4 entiers, donc `0x10` octets. `read` est le troisième champ, c'est le troisième entier de la structure, donc en `+8` par rapport au début.\\En conséquence `__tty_regs_map[1].read` est en `0xd0200018`
     242'''''''''''''''
     243}}}
     2441. Certaines parties du noyau sont en assembleur. Il y a au moins les toutes premières instructions du code de boot (démarrage de l'ordinateur) et l'entrée dans le noyau après l'exécution d'un syscall. Dans ce dernier cas, le gestionnaire de syscall écrit en assembleur a besoin d'appeler une fonction écrite en langage C. Le gestionnaire de syscall trouve l'adresse de la fonction C qu'il doit appeler puis il place cette adresse dans un registre, par exemple `$2`. Il suffit qu'il exécute l'instruction `jal $2` pour appeler la fonction. Que doivent contenir les registres `$4` à `$7` et comment doit-être la pile?
    245245{{{#!protected ------------------------------------------------------------------------------------
    246246'''''''''''''''
    247247- C'est un appel de fonction, il faut donc respecter la convention d'appel des fonctions
    248   - Les registre `$4`à `$7` contiennent les arguments de la fonction
     248  - Les registres `$4`à `$7` contiennent les arguments de la fonction
    249249  - Le pointeur de pile doit pointer sur la case réservée pour le premier argument et les cases suivantes sont réservées
    250250    arguments suivants.
     
    253253'''''''''''''''
    254254}}}
    255 1. Vous avez appris à écrire des programmes assembleur, mais parfois il est plus simple, voire il est nécessaire de mélanger le code C et le code assembleur. Dans l'exemple ci-dessous, nous voyons comment la fonction `kinit()` procède pour entrer dans la fonction placée à l'adresse `__crt0` définie dans le fichier `kernel.ld`. Remarquez la syntaxe, ici `volatile` permet de dire au compilateur d'insérer le code tel que sans le modifier. Notez aussi l'absence de `,` entre les chaînes de caractères. Le premier argument de `__asm__` est une chaîne de caractères unique dans laquelle les instructions sont séparées par de `\n`. Il peut y avoir d'autres arguments, nous ne les verrons pas.\\Dans quelle section se trouve l'adresse `__crt0`? Combien vaut elle? Est-ce que cette valeur est imposée par le processeur MIPS comme l'adresse de boot ou d'entrée dans le kernel? Quelle fonction est à cette adresses? Pourquoi doit-on écrire ce code en assembleur?
     2551. Vous avez appris à écrire des programmes assembleur, mais parfois il est plus simple, voire il est nécessaire de mélanger le code C et le code assembleur. Dans l'exemple ci-dessous, nous voyons comment la fonction `kinit()` procède pour entrer dans la fonction placée à l'adresse `__crt0` définie dans le fichier `kernel.ld`. Remarquez la syntaxe, ici `volatile` permet de dire au compilateur d'insérer le code tel que sans le modifier. Notez aussi l'absence de `,` entre les chaînes de caractères. Le premier argument de `__asm__` est une chaîne de caractères unique dans laquelle les instructions sont séparées par de `\n`. Il peut y avoir d'autres arguments, nous ne les verrons pas.\\Dans quelle section se trouve l'adresse `__crt0`? Combien vaut-elle? Est-ce que cette valeur est imposée par le processeur MIPS comme l'adresse de boot ou d'entrée dans le kernel? Quelle fonction est à cette adresse? Pourquoi doit-on écrire ce code en assembleur?
    256256{{{#!c
    257257  9 void kinit (void)
     
    329329'''''''''''''''
    330330}}}
    331 1. Nous avons vu que le noyau est sollicité par des événements, quels sont-ils?Quel est le comportement exact de l'instruction `syscall`?  Comment le noyau fait-il pour connaitre la cause de son appel?
     3311. Nous avons vu que le noyau est sollicité par des événements, quels sont-ils?Quel est le comportement exact de l'instruction `syscall`?  Comment le noyau fait-il pour connaître la cause de son appel?
    332332{{{#!protected ------------------------------------------------------------------------------------
    333333'''''''''''''''
     
    339339'''''''''''''''
    340340}}}
    341 1. `$26` et `$27` sont deux registres temporaires que le noyau se réserve pour faire des calcul 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 `$26` et `$27` par l'utilisateur ne provoque pas d'exception du MIPS, mais si le noyau est appelé, il modifie ces registres et donc l'utilisateur perd leur valeur. Le code assembleur ci-après contient les instructions exécutées par le noyau quelque-soit la cause. Les commentaires présents dans le code ont été volontairement retirés. La section `.kentry` sera 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`**
     3411. `$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 `$26` et `$27` par l'utilisateur ne provoque pas d'exception du MIPS, mais si le noyau est appelé, il modifie ces registres et donc l'utilisateur perd leur valeur. Le code assembleur ci-après contient les instructions exécutées par le noyau, quelle que soit la cause. Les commentaires présents dans le code ont été volontairement retirés. La section `.kentry` sera 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`**
    342342{{{#!c
    343343 15 .section    .kentry,"ax"     
     
    416416{{{#!protected ------------------------------------------------------------------------------------
    417417'''''''''''''''
    418 - Le rôle principal d'un Makefile est de décrire le mode d'emploi pour construire un fichier dit **`cible`** à partir d'un ou plusieurs fichiers **`source`** dit de dépendance en utilisant des commandes du `shell`. Ce rôle pourrait tout aussi bien être occupé par un script `shell` et d'ailleurs dans le premier TP nous avons vu un usage du Makefile dans lequel nous avions rassembler plusieurs scripts `shell` sous forme de règles.
    419 - Le second rôle d'un Makefile est de permettre la reconstruction efficace du fichier **`cible`** lorsqu'un seul seul fichier **`source`** change. Pour ce rôle, le Makefile exprime toutes les étapes de constructions de la **`cible`** finale et des **`cibles`** intermédiaires sous forme d'un arbre dont les feuilles sont les fichiers **`source`**.
    420 '''''''''''''''
    421 }}}
    422 1. Vous n'allez pas à avoir à écrire un Makefile complètement, toutefois vous allez devoir les modifier en ajoutant des règles. Nous avons vu brièvement la syntaxe utilisée dans les Makefiles de ce TP au cours n°1. Les lignes qui suivent sont des extraits du premier Makefile. Quelles est la cible finale, les cibles intermédiaires et les sources? A quoi servent les variables automatiques de make? Dans ces deux règles, donnez-en la valeur.
     418- Le rôle principal d'un Makefile est de décrire le mode d'emploi pour construire un fichier dit **`cible`** à partir d'un ou plusieurs fichiers **`source`** dits de dépendance en utilisant des commandes du `shell`. Ce rôle pourrait tout aussi bien être occupé par un script `shell` et d'ailleurs dans le premier TP nous avons vu un usage du Makefile dans lequel nous avions rassemblé plusieurs scripts `shell` sous forme de règles.
     419- Le second rôle d'un Makefile est de permettre la reconstruction efficace du fichier **`cible`** lorsqu'un seul seul fichier **`source`** change. Pour ce rôle, le Makefile exprime toutes les étapes de constructions de la **`cible`** finale et des **`cibles`** intermédiaires sous forme d'un arbre dont les feuilles sont les fichiers **`sources`**.
     420'''''''''''''''
     421}}}
     4221. Vous n'allez pas à avoir à écrire un Makefile complètement, toutefois vous allez devoir les modifier en ajoutant des règles. Nous avons vu brièvement la syntaxe utilisée dans les Makefiles de ce TP au cours n°1. Les lignes qui suivent sont des extraits du premier Makefile. Quelles sont la cible finale, les cibles intermédiaires et les sources? A quoi servent les variables automatiques de make? Dans ces deux règles, donnez-en la valeur.
    423423{{{#!make
    424424kernel.x : kernel.ld obj/hcpu.o obj/kinit.o obj/klibc.o obj/harch.o
     
    435435'''''''''''''''
    436436}}}
    437 1.Dans le TP, a partir de la deuxième étape, nous avons trois répertoire de sources
     4371.Dans le TP, à partir de la deuxième étape, nous avons trois répertoire de sources
    438438{{{
    4394394_libc/
    440440├── Makefile        : Makefile racine qui invoque les Makefiles des sous-répertoires et qui exécute
    441 ├── common ────────── répetoire des fichiers commun kernel / user
     441├── common ────────── répertoire des fichiers commun kernel / user
    442442├── kernel ────────── Répertoire des fichiers composant le kernel
    443443│   └── Makefile    : description des actions possibles sur le code kernel : compilation et nettoyage
     
    472472'''''''''''''''
    473473}}}
    474 1. génération de nombres pseudo-aléatoire `rand`?
     4741. génération de nombres pseudoaléatoires `rand`?
    475475{{{#!protected ------------------------------------------------------------------------------------
    476476'''''''''''''''
     
    500500
    501501
    502 == B1. Ajout d'une bibliothèque de fonctions standard pour le kernel (klic)
    503 
    504 
    505 Le noyau gère les ressources matérielles et logicielles utilisées par les applications. Il a besoin de fonctions standards pour réaliser des opérations de base, telles qu'une fonction `print` ou une fonction `rand`. Ces fonctions ne sont pas très originales, mais elles recèlent des subtilités que vous ne connaissez peut-être pas encore. En outre, nous allons utiliser un Makefile définissant un graphe de dépendance explicite entre les fichiers cibles et les fichiers source avec des règles de construction.
     502== B1. Ajout d'une bibliothèque de fonctions standards pour le kernel (klic)
     503
     504
     505Le noyau gère les ressources matérielles et logicielles utilisées par les applications. Il a besoin de fonctions standards pour réaliser des opérations de base, telles qu'une fonction `print` ou une fonction `rand`. Ces fonctions ne sont pas très originales, mais elles recèlent des subtilités que vous ne connaissez peut-être pas encore. En outre, nous allons utiliser un Makefile définissant un graphe de dépendance explicite entre les fichiers cibles et les fichiers sources avec des règles de construction.
    506506
    507507
     
    582582│   └── Makefile    : description des actions possibles sur le code kernel : compilation et nettoyage
    583583└── user ──────────── Répertoire des fichiers composant l'application user
    584     ├── crt0.c      : fonctions d'interface entre kernel et user, pour le momment : crt0()
     584    ├── crt0.c      : fonctions d'interface entre kernel et user, pour le moment : crt0()
    585585    ├── main.c      : fonction principale de l'application
    586586    ├── user.ld     : ldscript décrivant l'espace d'adressage pour l'édition de liens du user
     
    6146143_syscalls/
    615615├── Makefile        : Makefile racine qui invoque les Makefiles des sous-répertoires et qui exécute
    616 ├── common ────────── répetoire des fichiers commun kernel / user
     616├── common ────────── répertoire des fichiers commun kernel / user
    617617│   └── syscalls.h  : API la fonction syscall et des codes de syscalls
    618618├── kernel ────────── Répertoire des fichiers composant le kernel
     
    630630│   └── Makefile    : description des actions possibles sur le code kernel : compilation et nettoyage
    631631└── user ──────────── Répertoire des fichiers composant l'application user
    632     ├── crt0.c      : fonctions d'interface entre kernel et user, pour le momment : crt0()
     632    ├── crt0.c      : fonctions d'interface entre kernel et user, pour le moment : crt0()
    633633    ├── main.c      : fonction principale de l'application
    634634    ├── user.ld     : ldscript décrivant l'espace d'adressage pour l'édition de liens du user
     
    6606604_libc/
    661661├── Makefile        : Makefile racine qui invoque les Makefiles des sous-répertoires et qui exécute
    662 ├── common ────────── répetoire des fichiers commun kernel / user
     662├── common ────────── répertoire des fichiers commun kernel / user
    663663│   └── syscalls.h  : API la fonction syscall et des codes de syscalls
    664664├── kernel ────────── Répertoire des fichiers composant le kernel
     
    679679│   └── Makefile    : description des actions possibles sur le code user : compilation et nettoyage
    680680└── ulib ──────────── Répertoire des fichiers des bibliothèques système liés avec l'application user
    681     ├── crt0.c      : fonctions d'interface entre kernel et user, pour le momment : crt0()
     681    ├── crt0.c      : fonctions d'interface entre kernel et user, pour le moment : crt0()
    682682    ├── libc.h      : API pseudo-POSIX de la bibliothèque C
    683683    ├── libc.c      : code source de la libc