From 9bd548c4bd62dac4ced9cf93b368f1c9e38198ae Mon Sep 17 00:00:00 2001 From: Piotr Tworek Date: Wed, 1 Jul 2020 00:11:27 +0200 Subject: [PATCH] os: add platform_drv config generator for virt_qemu The VirtIO device configuration on Qemu is dynamic. The order and presence of different command line switches affects base address and interrupt assignment of each device. One could probably hard-code the necessary switches and resulting XML ARM platform driver configuration in each run script, but this seems like troublesome and hard to maintain solution. This patch explores an alternative approach to the problem. It implements a ROM driver which probes the address space region Qemu virt machines assign to VirtIO MMIO devices and exposes the result as XML via a ROM session. This XML output can be fed directly as config to the generic ARM platform driver. Ref #3825 --- repos/os/recipes/src/virtdev_rom/content.mk | 2 + repos/os/recipes/src/virtdev_rom/hash | 1 + repos/os/recipes/src/virtdev_rom/used_apis | 2 + repos/os/src/drivers/virtdev_rom/README | 31 +++ repos/os/src/drivers/virtdev_rom/main.cc | 200 ++++++++++++++++++++ repos/os/src/drivers/virtdev_rom/target.mk | 3 + 6 files changed, 239 insertions(+) create mode 100644 repos/os/recipes/src/virtdev_rom/content.mk create mode 100644 repos/os/recipes/src/virtdev_rom/hash create mode 100644 repos/os/recipes/src/virtdev_rom/used_apis create mode 100644 repos/os/src/drivers/virtdev_rom/README create mode 100644 repos/os/src/drivers/virtdev_rom/main.cc create mode 100644 repos/os/src/drivers/virtdev_rom/target.mk diff --git a/repos/os/recipes/src/virtdev_rom/content.mk b/repos/os/recipes/src/virtdev_rom/content.mk new file mode 100644 index 0000000000..9307f711ae --- /dev/null +++ b/repos/os/recipes/src/virtdev_rom/content.mk @@ -0,0 +1,2 @@ +SRC_DIR = src/drivers/virtdev_rom +include $(GENODE_DIR)/repos/base/recipes/src/content.inc diff --git a/repos/os/recipes/src/virtdev_rom/hash b/repos/os/recipes/src/virtdev_rom/hash new file mode 100644 index 0000000000..d0356ead5d --- /dev/null +++ b/repos/os/recipes/src/virtdev_rom/hash @@ -0,0 +1 @@ +2020-07-03 e1c0e261929b71468814fdbcba02c7e0f6455c25 diff --git a/repos/os/recipes/src/virtdev_rom/used_apis b/repos/os/recipes/src/virtdev_rom/used_apis new file mode 100644 index 0000000000..ec3bf565df --- /dev/null +++ b/repos/os/recipes/src/virtdev_rom/used_apis @@ -0,0 +1,2 @@ +base +os diff --git a/repos/os/src/drivers/virtdev_rom/README b/repos/os/src/drivers/virtdev_rom/README new file mode 100644 index 0000000000..5daf22ecc8 --- /dev/null +++ b/repos/os/src/drivers/virtdev_rom/README @@ -0,0 +1,31 @@ +This driver probes available VirtIO MMIO devices on Qemu's virt platform and +exports the results in XML format via a ROM session. The exported ROM module +is suitable as configuration for the generic ARM platform driver. + +This driver can currently recognize NIC, block, console, RNG, GPU, and +input devices. When a device of a given type is detected, it is assigned a +name based on its type and index on a bus. For example, if the system has +two VirtIO NIC devices, their names will be "nic0" and "nic1". + +To simplify probing devices of the same type, each XML device node has +an additional "type" property node. The value of this property is simply +set to a string indicating device type, without any extra indices, e.g., +"nic", "gpu", "input", etc. + +! +! +! +! + +Configuration +~~~~~~~~~~~~~ + +The virtdev_rom component appends the unmodified content of its own configuration +ROM to its output. This makes it possible to easily append extra policies +to the device configuration produced by the driver, e.g.,: + +! +! +! +! +! diff --git a/repos/os/src/drivers/virtdev_rom/main.cc b/repos/os/src/drivers/virtdev_rom/main.cc new file mode 100644 index 0000000000..b7dc07ebe6 --- /dev/null +++ b/repos/os/src/drivers/virtdev_rom/main.cc @@ -0,0 +1,200 @@ +/* + * \brief Virt Qemu device config generator for ARM platform driver + * \author Piotr Tworek + * \date 2020-07-01 + */ + +/* + * Copyright (C) 2020 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Virtdev_rom { + using namespace Genode; + class Session_component; + class Root; + struct Main; +}; + + +class Virtdev_rom::Session_component : public Rpc_object +{ + private: + + /* + * Noncopyable + */ + Session_component(Session_component const &) = delete; + Session_component &operator = (Session_component const &) = delete; + + Rom_dataspace_capability const _rom_cap; + + public: + + Session_component(Rom_dataspace_capability cap) : _rom_cap(cap) + { } + + Rom_dataspace_capability dataspace() override { return _rom_cap; } + + void sigh(Signal_context_capability) override { } +}; + + +class Virtdev_rom::Root : public Root_component +{ + private: + + /* + * Noncopyable + */ + Root(Root const &) = delete; + Root &operator = (Root const &) = delete; + + Env &_env; + Ram_dataspace_capability _ds; + + Session_component *_create_session(const char *) override + { + auto cap = static_cap_cast(_ds); + return new (md_alloc()) Session_component( + static_cap_cast(cap)); + } + + public: + + Root(Env &env, Allocator &md_alloc, Ram_dataspace_capability &cap) + : Root_component(env.ep(), md_alloc), + _env(env), + _ds(cap) + { } +}; + + +struct Virtdev_rom::Main +{ + enum { + /* Taken from include/hw/arm/virt.h in Qemu source tree. */ + NUM_VIRTIO_TRANSPORTS = 32, + /* Taken from hw/arm/virt.c in Qemu source tree. */ + BASE_ADDRESS = 0x0A000000, + DEVICE_SIZE = 0x200, + IRQ_BASE = 48, + VIRTIO_MMIO_MAGIC = 0x74726976, + }; + + enum { MAX_ROM_SIZE = 4096, DEVICE_NAME_LEN = 64 }; + + Env &_env; + Ram_dataspace_capability _ds { _env.ram().alloc(MAX_ROM_SIZE) }; + Sliced_heap _heap { _env.ram(), _env.rm() }; + Virtdev_rom::Root _root { _env, _heap, _ds }; + + struct Device : public Attached_mmio + { + struct Magic : Register<0x000, 32> { }; + struct Id : Register<0x008, 32> { + enum Value { + INVALID = 0, + NIC = 1, + BLOCK = 2, + CONSOLE = 3, + RNG = 4, + GPU = 16, + INPUT = 18, + MAX_VAL = INPUT, + }; + }; + + Device(Env &env, addr_t base, size_t size) + : Attached_mmio(env, base, size, false) { } + }; + + static char const *_name_for_id(unsigned id) + { + switch (id) { + case Device::Id::NIC : return "nic"; + case Device::Id::BLOCK : return "block"; + case Device::Id::CONSOLE : return "console"; + case Device::Id::RNG : return "rng"; + case Device::Id::GPU : return "gpu"; + case Device::Id::INPUT : return "input"; + default: { + warning("Unhandled VirtIO device ID: ", Hex(id)); + return "virtio"; + } + } + } + + void _probe_devices() + { + Attached_dataspace ds(_env.rm(), _ds); + Attached_rom_dataspace config { _env, "config" }; + + Xml_generator xml(ds.local_addr(), ds.size(), "config", [&] () + { + uint8_t device_type_idx[Device::Id::MAX_VAL] = { 0 }; + + for (size_t idx = 0; idx < NUM_VIRTIO_TRANSPORTS; ++idx) { + addr_t addr = BASE_ADDRESS + idx * DEVICE_SIZE; + Device device { _env, BASE_ADDRESS + idx * DEVICE_SIZE, DEVICE_SIZE }; + + if (device.read() != VIRTIO_MMIO_MAGIC) { + warning("Found non VirrtIO MMIO device @ ", addr); + continue; + } + + auto id = device.read(); + if (id == Device::Id::INVALID) + continue; + + xml.node("device", [&] () + { + static char name[DEVICE_NAME_LEN]; + snprintf(name, sizeof(name), "%s%u", _name_for_id(id), device_type_idx[id - 1]++); + xml.attribute("name", name); + xml.node("io_mem", [&] () { + xml.attribute("address", addr); + xml.attribute("size", DEVICE_SIZE); + }); + xml.node("irq", [&] () { + xml.attribute("number", IRQ_BASE + idx); + }); + xml.node("property", [&] () { + xml.attribute("name", "type"); + xml.attribute("value", _name_for_id(id)); + }); + }); + } + + config.xml().with_raw_content([&] (char const *txt, size_t sz) { + xml.append(txt, sz); + }); + }); + } + + Main(Env &env) : _env(env) + { + _probe_devices(); + env.parent().announce(_env.ep().manage(_root)); + } + + ~Main() { _env.ram().free(_ds); } +}; + + +void Component::construct(Genode::Env &env) +{ + static Virtdev_rom::Main main(env); +} diff --git a/repos/os/src/drivers/virtdev_rom/target.mk b/repos/os/src/drivers/virtdev_rom/target.mk new file mode 100644 index 0000000000..b4a142362a --- /dev/null +++ b/repos/os/src/drivers/virtdev_rom/target.mk @@ -0,0 +1,3 @@ +TARGET = virtdev_rom +SRC_CC = main.cc +LIBS = base