Changes between Version 49 and Version 50 of Archi-1-TP10


Ignore:
Timestamp:
Jan 3, 2021, 11:48:02 AM (4 years ago)
Author:
franck
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Archi-1-TP10

    v49 v50  
    219219'''''''''''''''
    220220}}}
    221 1. Nous connaissons les adresses des registres de périphériques. Ces adresses sont déclarées dans le fichier ldscript `kernel.ld`. Ci-après, nous avons la déclaration de la variable de ldscript `__tty_regs_map`. Cette variable est aussi utilisable dans les programmes C, mais pour être utilisable par le compilateur C, il est nécessaire de lui dire quel type de variable c'est. Est-ce une adresse d'entier? Est-ce une adresse de tableau d'entiers? Ou encore, est-ce une structure?\\Dans le fichier `kernel.ld`:
     2211. Nous connaissons les adresses des registres de périphériques. Ces adresses sont déclarées dans le fichier ldscript `kernel.ld`. Ci-après, nous avons la déclaration de la variable de ldscript `__tty_regs_map`. Cette variable est aussi utilisable dans les programmes C, mais pour être utilisable par le compilateur C, il est nécessaire de lui dire quel type de variable c'est, par exemple une adresse d'entier ou une adresse de tableau d'entiers, Ou encore, une adresse de structure.\\ \\Dans le fichier `kernel.ld`:
    222222{{{#!c
    223223__tty_regs_map   = 0xd0200000 ; /* tty's registers map, described in devices.h */
     
    234234 19 extern volatile struct tty_s __tty_regs_map[NTTYS];
    235235}}}
    236   À quoi servent les mots clés `extern` et `volatile` ?\\Si NTTYS est une macro dont la valeur est 2, quelle est l'adresse en mémoire `__tty_regs_map[1].read` ?
     236  À quoi servent les mots clés `extern` et `volatile` ?\\Si `NTTYS` est une macro dont la valeur est `2`, quelle est l'adresse en mémoire `__tty_regs_map[1].read` ?
    237237{{{#!protected ------------------------------------------------------------------------------------
    238238'''''''''''''''
    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 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 }}}
    244 1. 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?
     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. Le gestionnaire de syscall est écrit en assembleur et il a besoin d'appeler une fonction écrite en langage C. Ce que fait le gestionnaire de syscall est:
     245 - trouver l'adresse de la fonction C qu'il doit appeler pour exécuter le service demandé;
     246 - placer cette adresse dans un registre, par exemple `$2`;
     247 - exécuter l'instruction `jal` (ici, `jal $2`) pour appeler la fonction.
     248
     249 Que doivent contenir les registres `$4` à `$7` et comment doit-être la pile?
    245250{{{#!protected ------------------------------------------------------------------------------------
    246251'''''''''''''''
     
    253258'''''''''''''''
    254259}}}
    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 adresse? Pourquoi doit-on écrire ce code en assembleur?
     2601. Vous avez appris à écrire des programmes assembleur, mais parfois il est plus simple, voire 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 n'en aurons pas besoin.\\ \\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?
    256261{{{#!c
    257262  9 void kinit (void)
     
    277282- L'adresse `__crt0` est la première adresse de la section `text` dans laquelle se trouve le code de l'application.
    278283- Elle vaut `0X7F400000`.
    279 - Cette adresse n'est pas imposée par le MIPS. C'est le choix des architectes de SoC. La seule condition est que cette adresse soit
     284- Cette adresse n'est pas imposée par le MIPS. C'est le choix des architectes du SoC. La seule condition est que cette adresse soit
    280285  dans la partie accessible en mode user.
    281286- A cette adresse, on place la fonction `__start()`.
     
    283288'''''''''''''''
    284289}}}
    285 1. Dans le code C de la question précédente, à quoi servent les lignes 12 à 16? Pourquoi faire des déclarations `extern`?
     2901. Dans le code C de la question précédente, à quoi servent les lignes 14 à 16? Pourquoi faire des déclarations `extern`?
    286291{{{#!protected ------------------------------------------------------------------------------------
    287292'''''''''''''''
    288293- Ces lignes servent à mettre à 0 la zone des variables globales non initialisées explicitement par le programme.
    289 - Les déclarations externes permettent d'informer le compilateur que les adresses `__bss_orgin` et `__bss_end`
     294- Les déclarations `extern` permettent d'informer le compilateur que les adresses `__bss_orgin` et `__bss_end`
    290295  existent ailleurs. De fait, elles sont définies dans le fichier `kernel.ld`.
    291296'''''''''''''''