619 | | Nous allons désormais avoir deux exécutables: le noyau et l'application. Dans cette étape, nous allons voir comment le noyau fait pour appeler l'application, alors que celle-ci n'est pas compilée en même temps que le noyau. |
620 | | |
621 | | |
622 | | **Objectifs** |
623 | | |
| 619 | Nous allons désormais avoir deux exécutables: le noyau et l'application. Dans cette étape, nous allons voir comment le noyau fait pour appeler l'application, alors que celle-ci n'est pas compilée en même temps que le noyau. Nous allons passer du noyau à l'application à la fin de la fonction `kinit()`.\\ |
| 620 | En revanche, dans cette étape, nous n'allons pas mettre en place la gestion des syscalls. C'est-a-dire qu'il ne sera pas possible de revenir dans le noyau depuis l'application. C'est bien entendu une étape intermédiaire, parce qu'il faut normalement absolument pouvoir invoquer le noyau depuis l'application pour accéder aux périphériques. |
| 621 | Toutefois, pour pouvoir quand même accéder aux registres de périphériques, nous allons exceptionnellement exécuter l'application en mode kernel. Ainsi, l'application pourra accéder aux adresses de l'espace d'adressages réservées aux mode `kernel`. |
| 622 | |
| 623 | |
| 624 | **Objectifs de l'étape** |
| 625 | |
| 626 | - Ecrire une application en dehors du kernel et voir comment le kernel entre dans l'application. |
649 | | 1. Question ? |
650 | | {{{#!protected ------------------------------------------------------------------------------------ |
651 | | ''''''''''''''' |
652 | | - réponse |
653 | | ''''''''''''''' |
654 | | }}} |
655 | | |
656 | | |
| 652 | 1. Dans quel fichier se trouve la première fonction de l'application et comment s'appelle-t-elle? |
| 653 | {{{#!protected ------------------------------------------------------------------------------------ |
| 654 | ''''''''''''''' |
| 655 | - Dans le fichier `user/crt0.c`, c'est la fonction `_start()` |
| 656 | ''''''''''''''' |
| 657 | }}} |
| 658 | 1. Quelle est la fonction du noyau qui appelle cette fonction et dans quel ? |
| 659 | {{{#!protected ------------------------------------------------------------------------------------ |
| 660 | ''''''''''''''' |
| 661 | - Dans le fichier `kernel/kinit.c` et c'est la fonction `kinit()`. |
| 662 | ''''''''''''''' |
| 663 | }}} |
| 664 | 1. Comment le noyau fait-il pour démarrer l'application en mode `kernel`? (la réponse est dans la fonction de la question précédente). |
| 665 | {{{#!protected ------------------------------------------------------------------------------------ |
| 666 | ''''''''''''''' |
| 667 | - Dans la fonction `kinit()` : ligne 19, on initialise le bit `UM` du registre status `c0_sr` avec `0`. Ainsi, après l'exécution de `eret`, nous serons en mode `kernel`. |
| 668 | {{{#!c |
| 669 | 18 // this code allows to exit the kernel to go to user code |
| 670 | 19 __asm__ volatile ( "la $26, __text_origin \n" // get first address of user code |
| 671 | 20 "mtc0 $26, $14 \n" // put it in c0_EPC |
| 672 | 21 "li $26, 0b00000010 \n" // next status [UM,0,ERL,EXL,IE] |
| 673 | 22 "mtc0 $26, $12 \n" // UM <- 0, IE <- 0, EXL <- 1 |
| 674 | 23 "la $29, __data_end \n" // define new user stack pointer |
| 675 | 24 "eret \n"); // j EPC and EXL <- 0 |
| 676 | }}} |
| 677 | ''''''''''''''' |
| 678 | }}} |
| 679 | |
| 680 | **Exercice** |
| 681 | |
| 682 | - Vous n'allez pas faire grand-chose pour cette étape parce qu'elle n'est pas très utile du fait de l'impossibilité de revenir dans le noyau après l'entrée dans l'application. Affichez juste un second message depuis la fonction `main()` |