2013-06-04 5 views
2

Introduction:noyau Linux flush_cache_range() appel semble ne rien faire

Nous avons une application dans laquelle Linux fonctionnant sur un processeur ARM accepte les données d'un processeur externe DMA les données dans l'espace mémoire de l'ARM. L'ARM doit ensuite accéder à ces données à partir du code en mode utilisateur.

La plage d'adresses doit être physiquement contiguë car le moteur DMA du processeur externe ne prend pas en charge la diffusion/collecte. Cette plage de mémoire est initialement allouée à partir du noyau ARM via un appel __get_free_pages (GFP_KERNEL | __GFP_DMA, order) car cela nous assure que la mémoire allouée sera physiquement contiguë. Ensuite, un appel à virt_to_phys() sur le pointeur retourné nous donne l'adresse physique qui est ensuite fournie au processeur externe au début du processus.

Cette adresse physique est également connue du code du mode utilisateur Linux qui l'utilise (en mode utilisateur) pour appeler l'API mmap() afin d'obtenir un pointeur en mode utilisateur sur cette zone de mémoire. Notre pilote de noyau Linux voit alors un appel correspondant à sa routine mmap dans la structure file_operations du pilote. Le pilote conserve ensuite le pointeur "vma" vm_area_struct qui lui est passé dans l'appel de sa routine mmap pour une utilisation ultérieure. Lorsque le code du mode utilisateur reçoit un signal indiquant que de nouvelles données ont été DMA à cette adresse mémoire, il doit alors y accéder depuis le mode utilisateur via le pointeur en mode utilisateur obtenu à partir de l'appel à mmap() mentionné ci-dessus. Avant que le code du mode utilisateur le fasse bien sûr, le cache correspondant à cette plage de mémoire doit être vidé. Pour ce faire, le code du mode utilisateur appelle le pilote (via un ioctl) et en mode noyau un appel à flush_cache_range() est effectué:

flush_cache_range (vma, start, end); Les arguments passés à l'appel ci-dessus sont le "vma" que le pilote avait capturé quand sa routine mmap a été appelée et "start" et "end" sont les adresses de mode utilisateur passées dans le driver à partir du code de mode utilisateur dans. une structure fournie à l'appel ioctl().

Problème:

Ce que nous voyons est que la mémoire tampon ne semblent pas se rincée que nous voyons ce qui semble être données périmées lorsque les accès du mode utilisateur sont faits. En tant que test plutôt que d'obtenir l'adresse du mode utilisateur à partir d'un appel mmap() à notre pilote, nous appelons l'API mmap() à/dev/mem. Dans ce cas, nous obtenons un accès non-attaché au tampon (pas de rinçage nécessaire) et tout fonctionne parfaitement.

Notre version du noyau est 3.8.3 et fonctionne sur un ARM 9. Y a-t-il un eror logique dans l'approche que nous essayons?

Merci!

+0

Un indice supplémentaire est que si au lieu d'appeler flush_cache_range (vma, start, end); J'appelle flush_cache_mm (vma-> vm_mm); alors le code fonctionne parfaitement. – user1967844

Répondre

0

J'ai quelques questions après lesquelles je pourrais être en mesure de répondre: 1) Comment utilisez-vous l'adresse "PHYSIQUE" dans votre appel mmap()? mmap ne devrait rien avoir à faire avec les adresses physiques. 2) Que faites-vous exactement pour obtenir des adresses virtuelles d'utilisateur dans votre pilote? 3) Comment mappez-vous ces adresses virtuelles d'utilisateurs aux adresses physiques et où faites-vous? 4) Puisque vous préférez pré-allouer en utilisant get_free_pages(), est-ce que vous le mappez à l'espace du noyau en utilisant ioremap_cache()?