Proj-2011-2012-qemu

From air
Jump to: navigation, search

Émulation de la carte STM32L-Discovery avec Qemu

schéma 1 : Interface entre Qemu et l'UI‎

Enseignant:

  • Olivier Richard

Etudiants:

  • CLAVELIN Aurélien <clavelin.aurelien at gmail.com>
  • EID Timothée <timothee.eid at gmail.com>
  • MERCIER Michael <michael_mercier at orange.fr>

Le but de ce projet est de d'ajouter le support de la carte STM32L-Discovery dans le logiciel de virtualisation Qemu. Il fait suite au projet de l'année dernière (fiche projet) basé lui aussi sur Qemu mais portant sur la carte Stellaris Luminary Lm3s6965.

Qemu

Voir Qemu

Fichiers

Téléchargement

Voici un lien vers le dépot github du projet.

N'hésiter pas à nous contacter (voir au dessus) en cas de problème d'accès aux dépôt ou d'utilisation du code.

Description

Afin d'émuler la carte STM32L-Discovery les fichiers suivant ont été ajoutés au dossier src/hw de Qemu :

  • stm32.c pour décrire la carte dans son ensemble
  • stm32_gpio.c pour les GPIOs
  • stm32_button.c pour les boutons
  • stm32_led.c pour les LEDs
  • stm32_rcc.c pour le module RCC (ce module n'est que très partiellement émulé et donc non fonctionnel)

Composants émulés

Processeur et Mémoire

Le processeur utilisé par la carte est un processeur Cortex-M3 r1p1 (doc) déjà supporté par Qemu.

Pour initialiser celui-ci, il est nécessaire d'utiliser la fonction

MemoryRegion *address_space_mem = get_system_memory();
pic = armv7m_init(address_space_mem, flash_size, sram_size, kernel_filename, cpu_model);

où pic est un tableau de qemu_irq (voir Qemu#Assemblage) correspondant aux fils d'entrée dans le processeur. Dans notre cas les tailles des différentes mémoires sont :

  • RAM: 16 KBits
  • Flash: 128 Kbits

GPIO

L'émulation des GPIOs est gérée par le fichier stm32_gpio.c. Les GPIOs sont les connecteurs de base de la carte. Ils permettent de communiquer avec le bouton USER 0 et les LEDs.

Périphériques

L'émulation ne porte pour l'instant que sur les deux LEDs (stm32_led.c) et le bouton USER0 (stm32_button.c) qui communiquent avec l'extérieur de Qemu grâçe à chardev .

Exemple

Nous allons détailler la composition d'un composant à partir de l'exemple de stm32_gpio

  • Tout d'abord il faut inclure sysbus
#include "sysbus.h"
  • Les registres utilisés par le composant sont ensuite placés dans une structure :
typedef struct {
   SysBusDevice busdev;

   /* Registres GPIO (Reference Manual p119 */
   uint32_t mode; /* Mode */
   uint16_t otype; /* Output type */
   uint32_t ospeed; /* Output speed */
   uint32_t pupd; /* Pull-up/Pull-down */
   uint16_t ind; /* Input data */
   uint16_t outd; /* Output data register */
   uint16_t outd_old; /* Output data register */
   uint32_t bsr; /* Bit set/reset */
   uint32_t lck; /* Lock */
   uint32_t afrl; /* Alternate function low */
   uint32_t afrh; /* Alternate function high */
   
   qemu_irq irq_out[NB_PIN];
   unsigned char id;
} stm32_gpio_state;
  • Cette structure est décrite sous la forme d'une VMStateDescription permettant à Qemu de l'enregistrer correctement
static const VMStateDescription vmstate_stm32_gpio = {
   .name = "stm32_gpio",
   .version_id = 1,
   .minimum_version_id = 1,
   .fields = (VMStateField[])
   {
       VMSTATE_UINT32(mode, stm32_gpio_state),
       VMSTATE_UINT16(otype, stm32_gpio_state),
       VMSTATE_UINT32(ospeed, stm32_gpio_state),
       VMSTATE_UINT32(pupd, stm32_gpio_state),
       VMSTATE_UINT16(ind, stm32_gpio_state),
       VMSTATE_UINT16(outd, stm32_gpio_state),
       VMSTATE_UINT16(outd_old, stm32_gpio_state),
       VMSTATE_UINT32(bsr, stm32_gpio_state),
       VMSTATE_UINT32(lck, stm32_gpio_state),
       VMSTATE_UINT32(afrl, stm32_gpio_state),
       VMSTATE_UINT32(afrh, stm32_gpio_state),
       VMSTATE_END_OF_LIST()
   }
};
  • Une structure SysBusDeviceInfo renseigne la fonction d'initialisation, le nom, la taille de la structure des registres ainsi que la VMStateDescription.
static SysBusDeviceInfo stm32_gpioA_info = {
   .init = stm32_gpio_init_A,
   .qdev.name = "stm32_gpio_A",
   .qdev.size = sizeof (stm32_gpio_state),
   .qdev.vmsd = &vmstate_stm32_gpio,
};
  • Elle est passée en paramètre à la fonction sysbus_register_withprop elle même passée en paramètre de la macro device_init
static void stm32_gpio_register_devices(void) {
   sysbus_register_withprop(&stm32_gpioA_info);
}
device_init(stm32_gpio_register_devices)
  • Voici la fonction d'initialisation du composant :
static int stm32_gpio_init(SysBusDevice *dev, const unsigned char id) {
   int iomemtype;
   stm32_gpio_state *s = FROM_SYSBUS(stm32_gpio_state, dev);
   s->id = id;
   
   //Initialisation de la plage mémoire
   iomemtype = cpu_register_io_memory(stm32_gpio_readfn, stm32_gpio_writefn, s, DEVICE_NATIVE_ENDIAN);
   sysbus_init_mmio(dev, 0x24, iomemtype);

   //Initialisation des pins
   qdev_init_gpio_in(&dev->qdev, stm32_gpio_in_recv, NB_PIN);
   qdev_init_gpio_out(&dev->qdev, s->irq_out, NB_PIN);

   //Initialisation
   stm32_gpio_reset(s);
   vmstate_register(&dev->qdev, -1, &vmstate_stm32_gpio, s);

   return 0;
}

les structures stm32_gpio_readfn et stm32_gpio_writefn sont respectivement une CPUReadMemoryFunc et une CPUWriteMemoryFunc et contiennent les fonctions de lecture et d'écriture sur les registres déclarés dans le stm32_gpio_state. Ces fonctions sont de la forme :

static uint32_t stm32_gpio_read(void *opaque, target_phys_addr_t offset) {
   stm32_gpio_state *s = (stm32_gpio_state *) opaque;

   switch (offset) {
       case 0x00: /* Mode */
           return s->mode;
       case 0x04: /* oType */
           return s->otype;
       case 0x08: /* oSpeed */
           return s->ospeed;
       ...

Le fichier stm32_gpio.c complet est disponible File:Stm32 gpio.txt

Interface graphique

Une interface graphique utilisateur (UI) a été développée afin de permettre à l'utilisateur une meilleure prise en main. Qemu se connecte à l'UI par des sockets fournis par les modules des deux LEDs et du bouton via chardev. Le schéma 1 résume ce fonctionnement.


STM32qemu.jpeg

L'UI a été développée en Python2.7 avec la bibliothèque tkinter.

Glossaire des acronymes

Vous trouverez le glossaire ici