773 | | 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`** |
774 | | {{{#!c |
775 | | 1 #define SYSCALL_EXIT 0 |
776 | | 2 #define SYSCALL_TTY_WRITE 1 |
777 | | 3 #define SYSCALL_TTY_READ 2 |
778 | | 4 #define SYSCALL_CLOCK 3 |
779 | | 5 #define SYSCALL_NR 32 |
| 772 | 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 `47` à `54` 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 `55` et quelle conséquence cela a-t-il?\\- Que font les lignes `57` à `62`?\\- Et enfin que font les lignes `64` à `70` ?\\Les commentaires ont été laissés, vous devez juste mettre à quoi ça sert, sans détailler ligne à ligne.\\ \\**`common/syscalls.h`** |
| 773 | {{{#!c |
| 774 | #define SYSCALL_EXIT 0 /* see exit() in ulib/libc.c */ |
| 775 | #define SYSCALL_READ 1 /* see read() in ulib/libc.c */ |
| 776 | #define SYSCALL_WRITE 2 /* see write() in ulib/libc.c */ |
| 777 | #define SYSCALL_CLOCK 3 /* see clock() in ulib/libc.c */ |
| 778 | #define SYSCALL_NR 32 |
784 | | [0 ... SYSCALL_NR - 1] = unknown_syscall, |
785 | | [SYSCALL_EXIT] = exit, |
786 | | [SYSCALL_TTY_READ] = tty_read, |
787 | | [SYSCALL_TTY_WRITE] = tty_write, |
788 | | [SYSCALL_CLOCK] = clock, |
| 783 | [0 ... SYSCALL_NR - 1] = unknown_syscall, /* default function */ |
| 784 | [SYSCALL_EXIT ] = exit, |
| 785 | [SYSCALL_READ ] = tty_read, |
| 786 | [SYSCALL_WRITE ] = tty_write, |
| 787 | [SYSCALL_CLOCK ] = clock, |
792 | | {{{#!xml |
793 | | 34 ksyscall: |
794 | | 35 |
795 | | 36 addiu $29, $29, -8*4 |
796 | | 37 mfc0 $27, $14 |
797 | | 38 mfc0 $26, $12 |
798 | | 39 addiu $27, $27, 4 |
799 | | 40 sw $31, 7*4($29) |
800 | | 41 sw $27, 6*4($29) |
801 | | 42 sw $26, 5*4($29) |
802 | | 43 sw $2, 4*4($29) |
803 | | 44 mtc0 $0, $12 |
804 | | 45 |
805 | | 46 la $26, syscall_vector |
806 | | 47 andi $2, $2, SYSCALL_NR-1 |
807 | | 48 sll $2, $2, 2 |
808 | | 49 addu $2, $26, $2 |
809 | | 50 lw $2, 0($2) |
810 | | 51 jalr $2 |
811 | | 52 |
812 | | 53 lw $26, 5*4($29) |
813 | | 54 lw $27, 6*4($29) |
814 | | 55 lw $31, 7*4($29) |
815 | | 56 mtc0 $26, $12 |
816 | | 57 mtc0 $27, $14 |
817 | | 58 addiu $29, $29, 8*4 |
818 | | 59 eret |
| 791 | {{{#!asm |
| 792 | 45 syscall_handler: |
| 793 | 46 |
| 794 | 47 addiu $29, $29, -8*4 // context for $31 + EPC + SR + syscall_code + 4 args |
| 795 | 48 mfc0 $27, $14 // $27 <- EPC (addr of syscall instruction) |
| 796 | 49 mfc0 $26, $12 // $26 <- SR (status register) |
| 797 | 50 addiu $27, $27, 4 // $27 <- EPC+4 (return address) |
| 798 | 51 sw $31, 7*4($29) // save $31 because it will be erased |
| 799 | 52 sw $27, 6*4($29) // save EPC+4 (return address of syscall) |
| 800 | 53 sw $26, 5*4($29) // save SR (status register) |
| 801 | 54 sw $2, 4*4($29) // save syscall code (useful for debug message) |
| 802 | 55 mtc0 $0, $12 // SR <- kernel-mode without INT (UM=0 ERL=0 EXL=0 IE=0) |
| 803 | 56 |
| 804 | 57 la $26, syscall_vector // $26 <- table of syscall functions |
| 805 | 58 andi $2, $2, SYSCALL_NR-1// apply syscall mask |
| 806 | 59 sll $2, $2, 2 // compute syscall index (mutiply by 4) |
| 807 | 60 addu $2, $26, $2 // $2 <- & syscall_vector[$2] |
| 808 | 61 lw $2, ($2) // at the end: $2 <- syscall_vector[$2] |
| 809 | 62 jalr $2 // call service function |
| 810 | 63 |
| 811 | 64 lw $26, 5*4($29) // get old SR |
| 812 | 65 lw $27, 6*4($29) // get return address of syscall |
| 813 | 66 lw $31, 7*4($29) // restore $31 (return address of syscall function) |
| 814 | 67 mtc0 $26, $12 // restore SR |
| 815 | 68 mtc0 $27, $14 // restore EPC |
| 816 | 69 addiu $29, $29, 8*4 // restore stack pointer |
| 817 | 70 eret // return : jr EPC with EXL <- 0 |