Changes between Version 13 and Version 14 of Archi-1-TP10


Ignore:
Timestamp:
Dec 29, 2020, 6:11:38 PM (4 years ago)
Author:
franck
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Archi-1-TP10

    v13 v14  
    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, ou une adresse de tableau d'entiers, ou encore une structure.
     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. 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`:
    222222{{{#!c
    223223__tty_regs_map   = 0xd0200000 ; /* tty's registers map, described in devices.h */
    224224}}}
    225 {{{#!protected ------------------------------------------------------------------------------------
    226 '''''''''''''''
    227 -
    228 '''''''''''''''
    229 }}}
    230 1. inclusion de code assembleur en C?
    231 {{{#!protected ------------------------------------------------------------------------------------
    232 '''''''''''''''
    233 -
    234 '''''''''''''''
    235 }}}
    236 1. appel de code assembleur depuis le code C?
     225   Dans le fichier `harch.c` :
     226{{{#!c
     227 12 struct tty_s {
     228 13     int write;          // tty's output address
     229 14     int status;         // tty's status address something to read if not null)
     230 15     int read;           // tty's input address
     231 16     int unused;         // unused address
     232 17 };
     233 18
     234 19 extern volatile struct tty_s __tty_regs_map[NTTYS];
     235}}}
     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` ?
     237{{{#!protected ------------------------------------------------------------------------------------
     238'''''''''''''''
     239- `extern` : informe le compilateur que la variable définie existe ailleurs. Grâce à son type, le compilateur sait s'en servir.
     240- `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}}}
     2441. Certaines parties du noyau sont en assembleur, il y au moins les toutes premières instructions du code de boot 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. Si le gestionnaire de syscall connait l'adresse de la fonction C qu'il veut appeler et qu'il la place dans un registre, par exemple `$2`, il suffit qu'il exécuter l'instruction `jal $2`. Que doivent contenir les registres `$4` à `$7` et comment doit-être la pile?
     245{{{#!protected ------------------------------------------------------------------------------------
     246'''''''''''''''
     247-
     248'''''''''''''''
     249}}}
     2501. 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`. Combien vaut cette adresse? Dans quelle section se trouve-t-elle? Quelle fonction est à cette adresses? Pourquoi doit-on écrire ce code en assembleur?
     251{{{#!c
     252  9 void kinit (void)
     253 10 {
     254 11     kprintf (0, banner);
     255 12     __asm__ volatile (          // this code allows to exit the kernel to go to user code
     256 13                          "la     $26,    __crt0         \n"     // get first address of user cod    e
     257 14                          "mtc0   $26,    $14            \n"     // put it in c0_EPC
     258 15                          "li     $26,    0b00010010     \n"     // next status [UM,0,ERL,EXL,IE]     
     259 16                          "mtc0   $26,    $12            \n"     // UM <- 1, IE <- 0, EXL <- 1
     260 17                          "la     $29,    __data_end     \n"     // define new user stack pointer
     261 18                          "eret                          \n");   // j EPC and EXL <- 0
     262 19 }
     263}}}
    237264{{{#!protected ------------------------------------------------------------------------------------
    238265'''''''''''''''