Comment ajouter un nouveau périphérique dans le code source QEMU?
quelle pourrait être l'approche par étapes pour émuler/ajouter un nouveau dispositif dans qemu
en utilisant l'approche QOM?
quels et où pourraient être les changements concernant DeviceState/BusState et d'autres propriétés?
2 réponses
edu
dans l'arborescence d'enseignement PCI device
- https://github.com/qemu/qemu/blob/v2.7.0/hw/misc/edu.c
- https://github.com/qemu/qemu/blob/v2.7.0/docs/specs/edu.txt
C'est très facile à comprendre et bien documenté, donc je vous recommande de l'étudier.
il expose un dispositif PCI minimal, avec IO de base, génération d'interruption, et DMA.
j'ai écrit un module minimal du noyau Linux + des tests userland pour jouer avec:
- https://github.com/cirosantilli/linux-kernel-module-cheat/blob/6788a577c394a2fc512d8f3df0806d84dc09f355/rootfs_overlay/pci.sh
- https://github.com/cirosantilli/linux-kernel-module-cheat/blob/6788a577c394a2fc512d8f3df0806d84dc09f355/kernel_module/pci.c
Minimal PCI device
j'ai encore réduit edu à un quart de la taille sur ma fourchette QEMU: https://github.com/cirosantilli/qemu/blob/22e7e210d6fbe54c35a5ae32450a4419df25a13b/hw/misc/lkmc_pci_min.c No DMA.
pilote de noyau: https://github.com/cirosantilli/linux-kernel-module-cheat/blob/1cd55ebf53542208f7a614a856066123b93d303d/kernel_module/pci_min.c
mon wrapper Buildroot intègre déjà la fourche QEMU avec un sous-module, il suffit de cloner et ./run
.
BRAS dispositif de plate-forme TYPE_SYS_BUS_DEVICE
SoC-land fabrique la plupart des appareils dans le silicium au lieu de PCI, ici est un exemple de fonctionnement minimal:
- qemu fork:
- dispositif https://github.com/cirosantilli/qemu/blob/144ea94d710c666babd06ed733007377e132ed4a/hw/misc/lkmc_platform_device.c
- insérer le dispositif dans
-M versatilepb
: https://github.com/cirosantilli/qemu/blob/144ea94d710c666babd06ed733007377e132ed4a/hw/arm/versatilepb.c#L302 utilisesysbus_create_simple
, qui attend un dispositif du typeTYPE_SYS_BUS_DEVICE
.
- module du noyau: https://github.com/cirosantilli/linux-kernel-module-cheat/blob/05fa0105eaccf37d6a675f9b2bae833fd78d4270/kernel_module/platform_device.c écrit à la mémoire sur la sonde pour tester les choses, ce qui génère également un IRQ.
- Linux versatile DTS patch: https://github.com/cirosantilli/linux/blob/361bb623671a52a36a077a6dd45843389a687a33/arch/arm/boot/dts/versatile-pb.dts#L42
- informe le noyau où se trouvent les registres et les IRQ, et correspond aux paramètres de QEMU
versatilepb.c
"
-
compatible
correspond auplatform_driver.name
dans le module du noyau, et indique au noyau quel module traitera ce périphérique. - est passé au microprogramme de QEMU avec
-dtb
- informe le noyau où se trouvent les registres et les IRQ, et correspond aux paramètres de QEMU
la fourche Linux avec la modification DTC est un sous-module du repo Buildroot wrapper, donc il suffit de cloner et ./run -a arm
.
Hors de l'arborescence de périphériques
j'ai demandé s'il est possible de créer des périphériques out-of-tree à: comment créer des périphériques out-of-tree QEMU? mais ça n'y ressemble pas.
il y a quelques parties de l'exemple dans" Qom exégèse et apocalypse "2014 Présentation à http://events.linuxfoundation.org/sites/events/files/slides/kvmforum14-qom_0.pdf
créer un objet
Object *o = object_new(TYPE_RNG_BACKEND_RANDOM); object_property_set_str(o, "filename", "/dev/random", NULL); object_property_set_bool(o, "opened", "true", NULL); object_property_add_child(container_get("/somewhere"), "my-rng", o, NULL); object_unref(o);
propriétés intérieures
static bool rng_get_opened(Object *obj, Error **errp) { RngBackend *s = RNG_BACKEND(obj); return s->opened; } static void rng_set_opened(Object *obj, bool value, Error **errp) { RngBackend *s = RNG_BACKEND(obj); RngBackendClass *k = RNG_BACKEND_GET_CLASS(s); ... if (k->opened) { k->opened(s, errp) } } static void rng_backend_init(Object *obj) { object_property_add_bool(obj, "opened", rng_get_opened, rng_set_opened, NULL); } static const TypeInfo rng_backend_info = { .name = TYPE_RNG_BACKEND, .parent = TYPE_OBJECT, .instance_size = sizeof(RngBackend), .instance_init = rng_backend_init, .class_size = sizeof(RngBackendClass), .abstract = true, };
(comparer avec le code réel: http://code.metager.de/source/xref/qemu/backends/rng.c et une mise en œuvre de RNG_BACKEND http://code.metager.de/source/xref/qemu/backends/rng-random.c )
ces deux pages peuvent être utiles aussi: * http://wiki.qemu.org/Features/QOM * http://wiki.qemu.org/QOMConventions
l'après "L'Essentiel QEMU PCI API" par Siro Mugabi: http://nairobi-embedded.org/001_qemu_pci_device_essentials.html ( http://web.archive.org/web/20151116022950/http://nairobi-embedded.org/001_qemu_pci_device_essentials.html ) contient un exemple complet de pilote PCI activé par QOM.
le modèle D'objet QEMU (QOM) fournit un cadre pour enregistrer les Types créables par l'utilisateur. QOM modèles de bus, interfaces, périphériques, etc comme des types. Dans QOM, l'information par type d'utilisateur est utilisée pour créer son instance
ObjectClass
ainsi que son instance objet. Cette information est spécifiée dans une structureTypeInfo
(include/qom/object.h
). Par exemple:/* hw/misc/pci-testdev.c */ static const TypeInfo pci_testdev_info = { .name = TYPE_PCI_TEST_DEV, .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCITestDevState), .class_init = pci_testdev_class_init, };
où:
.name
chaîne de caractères qui indique le type d'utilisateur..parent
chaîne de caractères qui spécifie le Type dont ce type d'utilisateur provient..instance_size
taille de l'instance de L'objet du Type. Sa répartition sera effectuée en interne par QOM. Les objets seront discutés plus en détail dans la section instanciation des objets..class_init
le crochet du constructeur. Cette fonction sera chargée d'initialiser l'instance de TypeObjectClass
.