Proj-2011-2012-qemu
Émulation de la carte STM32L-Discovery avec Qemu
Enseignant:
- Olivier Richard
Etudiants:
- CLAVELIN Aurélien
- EID Timothée
- MERCIER Michael
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écharegement
Lien vers le projet à venir...
Description
Afin d'émuler la carte STM32L-Discovery les fichiers suivant on été ajoutés au dossier src/hw de Qemu :
- stm32.c pour décrire la carte dans son ensemble
- stm32_gpio.c pour les gpio
- stm32_button.c pour les boutons
- stm32_led.c pour les led
- stm32_rcc.c pour le module RCC (ce module n'est que très partiellement émuler 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'entrer dans le processeur. Dans notre cas les taille des différentes mémoires sont :
- RAM: 16 KBits
- Flash: 128 Kbits
GPIO
L'émulation des GPIO est gérée par le fichier stm32_gpio.c. Les GPIO sont les connecteur de base de la carte. Il permet 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 communique avec l'extérieur de Qemu grâçe à chardev .
Exemple
Nous allons détaillé 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é 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'enregistré 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 fonction 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; ...
Interface graphique
Une interface graphique utilisateur (UI) à été développer afin de permettre à l'utilisateur une meilleur prise en main. Qemu se connecte à l'UI par des sockets fournis par les modules des deux LED et du bouton via chardev.Le schéma 1 résume ce fonctionnement.
L'UI à été développer en Python2.7 avec la bibliothèque tkinter.
Glossaire des acronymes
Vous trouverez le glossaire ici