Skip to content
MaximeCheramy edited this page Feb 29, 2012 · 2 revisions

#Syscall

##Définition

Les appels système sont le seul moyen de communication entre le kernel space et l'user space. Il s'agit de fonctions bien spécifiques que l'on peut appeler et qui accordent le temps de leur exécution l'accès aux privilèges kernel. Il faut noter tout de même que les mécanismes utilisés pour exécuter ces appels sont lent, et que leur utilisation est contrainte par le nombre limité de paramètres que l'on peut passer à ces fonction. Cela étant dit, cette contrainte est souvent contournée en passant en paramètre un pointeur vers une structure comprenant autant de paramètres que nécessaire.

##Les appels système dans TacOS

###Fonctionnement

C'est du coté du kernel que les appels systèmes sont gérés. Pour chaque fonction que l'on veut rendre disponible sous forme d'appel système, on associe un identifiant dans une table du kernel. En plus de cela, le kernel dispose d'une fonction syscall_entry qui est en fait un handler d'interruption. Cette fonction a pour but de récupérer les valeurs de eax, ebx, ecx et edx, puis d'appeler la fonction d'appel système dont l'identifiant est eax en lui passant ebx, ecx et edx en paramètres.

Du coté utilisateur, il suffit donc de déclencher l'interruption logiciel correspondant à syscall_entry en ayant préalablement mis les bonnes valeurs dans eax, ebx, ecx et edx.

###Utilisation d'un appel système

Comme on vient de le voir, pour exécuter un appel système il faut paramétrer les registres et déclencher une interruption logicielle. Cependant il est plus simple d'utiliser la fonction

void syscall(uint32_t func, uint32_t param1, uint32_t param2, uint32_t param3);

définie dans syscall.h

En outre, il est conseillé d'ajouter une couche d'abstraction au dessus de cet appel pour permettre par exemple une vérification des types des paramètres.

Par exemple, l'appel système sys_write est réalisé de la manière suivante:

ssize_t write(int fd, const void *buf, size_t count) {

syscall(SYS_WRITE, fd, (uint32_t) buf, (uint32_t)(&count));

return count;

}

###Création d'un appel système

La création d'un nouvel appel système implique deux étapes :

  • Création de la fonction

Par convention, les fonctions correspondant à des appels système s'appellent sys_*. De plus, pour simplifier la définition de telles fonctions, il convient d'utiliser les macro suivantes :

SYSCALL_HANDLER0(name)

SYSCALL_HANDLER1(name, param)

SYSCALL_HANDLER2(name, param1, param2)

SYSCALL_HANDLER3(name, param1, param2, param3)

Par exemple, l'appel système sys_hlt est défini de la manière suivante:

SYSCALL_HANDLER0(sys_hlt)

{

asm("hlt");

}

  • Enregistrement de l'appel auprès du noyau

Il faut à présent préciser au noyau que cette fonction est un handler d'appel système. Pour cela il suffit d'appeler la fonction suivante (depuis le kernel bien entendu, le mieux étant pour le moment dans le cmain de kernel.c):

int syscall_set_handler(uint32_t syscall_id, syscall_handler_t handler);

D'autre part, on trouve dans syscall.h la définition de tous les identifiants d'appel système déja créés. Par défaut, ce sont les identifiant définis dans ce fichier qui servent de référence, et il est donc conseillé de les utiliser partout plutôt que de mettre directement les valeurs.

###Améliorations possibles

Comme expliqué plus haut, le mécanisme d'interruption utilisé pour réaliser les appels système est relativement lent. Il existe une alternative sur architecture x86: SYSENTER/SYSEXIT. Ce sont deux instructions qui permettent de réaliser la même opération mais de manière plus efficace. Il pourrait être intéressant de l'implémenter, tout en gardant si possible le mécanisme d'interruption dans le cas où le processeur ne soit pas compatible.

Clone this wiki locally