{{{ #!html

TP2 : Déploiement de l'application MJPEG sur une architecture SoC monoprocesseur

}}} [[PageOutline]] TP Précédent : [[wiki:TP1_2012_Station]] = 0. Objectif = L'objectif de ce TP est d'appréhender les informations nécessaires au système d'exploitation afin de construire la table des pages et le code binaire d'une application. Nous nous concentrons en particulier sur le mécanisme de mémoire virtuelle pour effectuer le placement physique des objets logiciels. Nous utiliserons pour cela une plateforme décrite à l'aide de SoCLib. = 1. Rappels sur la mémoire virtuelle = L' '''espace d'adressage''' d'une application est l'ensemble des adresses accessibles par cette application. Si les adresses sont sur 32 bits, l'espace d'adressage est de 4Go. Les systèmes avec mémoire virutelle sont dits ''paginés'', c'est-à-dire que l'espace d'adressage est découpé en zone appelées '''pages'''. La taille d'une page varie d'un système à l'autre mais fait généralement 4Ko. Lors de son exécution, le processeur émet des '''adresses virtuelles''' (ou logiques), qui sont celles produites par le compilateur et contenues dans le fichier binaire. Plus précisément, les adresses virtuelles finales des sections d'un programme sont en général définies dans un fichier de ''script ld'' (existant par défaut ou donné par l'utilisateur à ld). Ces adresses sont plus ou moins arbitraires. Ces adresses virtuelles sont ensuite converties en '''adresses physiques'''. On parle de '''traduction d'adresse'''. Une adresse physique est l'adresse réelle d'une case mémoire ou d'un registre adressable d'un périphérique. Dans un programme compilé en natif, un utilisateur ne se préoccuppe en général pas des adresses physiques dans lesquelles son programme va être placé (il n'en a pas la possibilité). En revanche, dans le cas d'un système sur puce ayant une architecture NUMA, on veut pouvoir placer précisément les données dans des bancs mémoire spécifiques afin de favoriser la localité et réduire le temps d'accès à ces données. Le composant qui effectue cette traduction s'appelle la MMU (''Memory Management Unit''). La MMU a de plus une autre fonction, qui consiste à fournir un mécanisme de protection de la mémoire en vérifiant que les pages sont correctement accédées selon les attributs qui leur sont propres. Ces attributs sont principalement : * la page est inscriptible * la page est accessible en mode utilisateur * la page est exécutable (typiquement une page contenant du code) * la page est cachable D'autres attributs peuvent exister selon les architectures et systèmes d'exploitation. Cette traduction d'adresse se fait par page : deux adresses virtuelles consécutives appartenant à la même page seront traduites par deux adresses physiques consécutives appartenant à la même page. On parle alors de '''page virtuelle''', contenu à placer en mémoire, et de '''page physique''', zone mémoire pouvant accueillir un contenu. Ainsi, comme les pages sont alignées, une adresse virtuelle (resp. physique) peut être décomposée en deux parties : le numéro de page virtuelle VPN (''resp.'' physique PPN) et l'offset de l'adresse dans la page. Le '''mapping''' consiste à associer un PPN à chaque VPN. L'espace d'adressage pour une application est ainsi appelé '''espace d'adressage virtuel''' : chaque application possède son propre espace d'adressage virtuel, et tous les espaces d'adressage virtuels cohabitent dans la mémoire physique (ou sur le disque par l'intermédiaire du swap). Pour effectuer sa traduction, la MMU utilise une structure de données appelée '''table des pages'''. La table des pages se situe en mémoire et est cachable. (parler de la TLB ?) = 2. Présentation du mécanisme de mémoire virtuelle dans DSX = Au niveau de DSX, la notion de page est transparente. On définit un '''objet virtuel''' comme étant une partie indissociable de code ou données du programme initial qui est placée de manière contigüe en mémoire. Un objet virtuel peut par exemple être une section ELF ou un buffer. Un ou plusieurs objets virtuels sont regroupés dans un '''segment virtuel'''. Un segment virtuel est un espace contigü de l'espace d'adressage virtuel d'une application. Il contient (entre autres) une adresse de base et une taille. Certains segments virtuels sont spéciaux, car ils sont répliqués dans l'espace d'adressage de toutes les applications : on parle de '''segments globaux'''. Chaque segment virtuel est finalement placé sur un '''segment physique''', c'est-à-dire une zone de la mémoire physique contigüe ayant une adresse de base et une taille. Plusieurs segments virtuels peuvent bien sûr être placés sur le même segment physique. En plus d'effectuer le placement des objets logiciels sur les bancs mémoire, DSX permet par ailleurs d'effectuer le placement des tâches d'une application (définie comme un ensemble de tâches communiquantes par canaux MWMR) sur des processeurs donnés. Pour cela, DSX a besoin de connaitre un certain nombre d'information sur l'architecture sous-jacente (en plus des segments physiques). Cette description conjointe du matériel et du mapping se fait dans DSX par l'intermédiaire d'un format propre à cet outil utilisant le langage XML : la structure d'informations de mapping. Cette structure est défini en détail [[dsx:wiki:DsxvmMappingInfoStructure | ici]]. De plus, cette structure n'est pas parsée directement par le système d'exploitation, mais est transformée en structure binaire équivalente (basée sur des types C) par un petit outil appelé `xml2bin`, et placée dans le binaire final de l'application. Dans la suite, on parlera du fichier `map.xml` pour se référer au fichier xml contenant ces informations. Les informations contenues dans cette structure de données sont utilisées par le système d'exploitation (le giet-vm) pour construire la table des pages. La table des pages dans le giet-vm est statique (i.e. non modifiable pendant l'exécution) et sa construction a lieu lors de la phase de boot. Le schéma ci-dessous résume les différents objets manipulés par l'outil DSX : [[Image(structure_mapping_info.svg)]] Cette structure de mapping est soit donnée par l'utilisateur à DSX, soit produite par DSX à partir des informations concernant l'architecture et le mapping des tâches et objets logiciels. Après compilation par DSX des différentes applications et du giet-vm, on possède autant de fichiers binaires que d'application -- plus un pour le giet-vm -- contenant tous des adresses virtuelles. Ces adresses virtuelles doivent correspondre à celles utilisées dans manière arbitraire par le giet-vm si l'utilisateur fournit lui-même le fichier `map.xml` (pas sûr) (si le fichier `map.xml` est produit par DSX, il contient bien sûr des adresses cohérentes avec celles des binaires). Néanmoins se pose un problème pour le chargement du binaire en mémoire. En effet, le chargement s'effectue traditionnellement dans soclib avec un composant appelé `loader` qui charge les sections en mémoire à partir de leurs adresses dans le binaire. Comme ces adresses sont ici virtuelles, on ne peut pas procéder de la sorte directement. Deux solutions sont possibles : * Écrire un `vloader` qui utilise la structure `map.xml` et effectue la traduction lors du chargement. * Déplacer les sections pour obtenir un binaire avec les adresses de chargement. On peut ensuite utiliser le `loader` de soclib traditionnel. C'est cette dernière solution qui est retenue. Pour cela l'utilisation de DSX est couplée à un outil dont le nom est Memo (MErger and MOver). En plus d'effectuer le déplacement des sections à l'aide de la structure d'information de mapping, Memo effectue aussi la fusion des différents binaires en un seul. Le schéma suivant montre une représentation simplifiée du fonctionnement de DSX : [[Image(dsxvm_overall_working.svg)]] = 3. Spécification des informations de mapping dans DSX = Nous allons pour commencer nous intéresser à l'application !SplitMsg vu au premier TP. Nous nous plaçons dans le cadre d'une plateforme contenant 1 seul cluster de 1 processeur, dans une architecture sans cohérence mémoire. Commencez par récupérer l'archive suivante : [[lien]] et décompressez-là dans un répertoire `tp2` : {{{ $ cp path/to/archive_tp2.tar.gz path/to/tp2/ $ cd !$ $ tar -xvzf archive_tp2.tar.gz }}} Pour ce TP, on ne s'intéresse pas au contenu du fichier décrivant la topcell de l'architecture (`top.cpp`). À la place, on considère la description simplifiée suivante de l'architecture : Note : les questions suivantes contiennent plusieurs sous-questions chacune. Faites bien attention à répondre à la totalité de ces sous-questions. Ouvrez le fichier `map.xml` contenant les informations nécessaires de l'architecture ainsi que les informations de mapping '''''Question 1.1 : Sachant que notre architecture contient un seul cluster, quelles doivent être les valeurs de `cluster_x` et `cluster_y` ?''''' Complétez le fichier en y ajoutant ces valeurs, ainsi que les bases, tailles et types des segments, en n'oubliez pas de vous référer à la page de documentation de ce format présente [[dsx:wiki:DsxvmMappingInfoStructure | ici]]. '''''Question 1.2 : Quel doit être le nom de l'attribut `psegname` pour le périphérique de type ICU ?''''' Complétez le fichier en y ajoutant les valeurs de `psegname` pour les 3 périphériques. '''''Question 1.3 : Quelle doit être la valeur de `vbase` dans le `vseg seg_boot_code` contenant le code de boot ? Pourquoi doit-elle être égale à l'adresse physique à laquelle elle est mappée ? Quelle doit être la valeur de l'attribut `mode` de ce `vseg` ? Enfin, quel est le type du `vobj` contenu dans ce `vseg` ?''''' Complétez le fichier avec ces trois valeurs, ainsi qu'avec la valeur de l'attribut `psegname`. ''Note : les segments `seg_boot_mapping` et `seg_boot_stack` sont un peu particuliers, on ne s'y intéresse pas ici (éventuellement à modifier selon les évolutions). '''''Question 1.4 : Sachant que les périphériques sont en mapping identité, quelle doit être la `vbase` du `vseg seg_icu_icu0` ? Quel est son mode ?''''' Complétez dans le fichier les informations manquantes pour les segments `seg_icu_icu0`, `seg_timer_timer0` et `seg_tty_tty`. ''Note : le segment `seg_dma_dma0` est inutilisé mais nécessaire pour la description''. '''''Question 1.5 : Quelles doivent être les valeurs respectives des attributs `mode` et `type` des segments `seg_kernel_code`, `seg_kernel_data`, `seg_kernel_init` et `seg_kernel_uncdata` ? Même question pour les valeurs des attributs `type` des `vobj` qui leur sont associés. Complétez le fichier avec ces nouvelles informations. '''''Question 1.6 : Qu'est-ce que l'attribut `strat_name` de l'élément `vspace` ? Pourquoi est-il égal à `data_split_msg` ?''''' '''''Question 1.7 : Quel doit être le mode du `vseg seg_code_split_msg` ? Même question pour le `vseg seg_cons_stack`.''''' Complétez dans le fichier les informations manquantes pour les segments `seg_code_split_msg`, `seg_cons_stack` et `seg_data_split_msg` et les vobjs qu'ils contiennent. '''''Question 1.8 : Que contient le `vseg seg_fifo0` ? Pourquoi son attribut `mode` est-il `"__WU"` (en particulier non caché) ?''''' '''''Question 1.9 : Que contient le `vseg seg_ptab_split_msg` ? Pourquoi son attribut `mode` est-il `"C___"` ?''''' Désassemblez le fichier `soft/split_msg/split_msg.elf` avec la commande : {{{ $ mipsel-unknown-elf-objdump -D soft/split_msg/split_msg.elf | less }}} '''''Question xx : Quelle est l'adresse de base de la fonction xxx ? Est-ce une adresse physique ou virtuelle ?''''' => Demander quelque part dans le TP pourquoi une seule passe pose problème (taille des binaires et de map.bin) = 3. Mapping de l'application Mjpeg = + Observation des adresses émises dans soclib avec gdb