platform_drv: add report facility

By adding a 'report' node to the platform driver's configuration
one can enable either devices or config reports. The devices
report contains all devices and their detailed state, as well as
whether it is already in use or not. The config report contains
one by one the current configuration of the platform driver.
Moreover, this commit adds a README file describing the facilities
of the platform driver.

Fix genodelabs/genode#4386
This commit is contained in:
Stefan Kalkowski 2022-04-28 14:41:17 +02:00 committed by Christian Helmuth
parent d0694b3e0b
commit a1564d1826
7 changed files with 164 additions and 38 deletions

View File

@ -10,6 +10,7 @@ import_from_depot [depot_user]/src/[base_src] \
[depot_user]/src/fs_report \
[depot_user]/src/fs_rom \
[depot_user]/src/platform_drv \
[depot_user]/src/report_rom \
[depot_user]/src/vfs_import \
[depot_user]/src/vfs
@ -75,12 +76,25 @@ install_config {
</route>
</start>
<start name="report_rom">
<resource name="RAM" quantum="3M"/>
<provides>
<service name="ROM"/>
<service name="Report"/>
</provides>
<route>
<any-service> <parent/> </any-service>
</route>
<config verbose="no"/>
</start>
<start name="platform_drv">
<resource name="RAM" quantum="1M"/>
<provides> <service name="Platform"/> </provides>
<route>
<service name="ROM" label="config"> <child name="report_fs_rom"/> </service>
<service name="ROM" label="devices"><child name="report_fs_rom"/> </service>
<service name="ROM" label="config"> <child name="report_fs_rom"/> </service>
<service name="ROM" label="devices"><child name="report_fs_rom"/> </service>
<service name="Report"> <child name="report_rom"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
@ -105,70 +119,70 @@ append qemu_args "-nographic "
set good_string {
[init -> test-platform_drv] <devices version="1">
[init -> test-platform_drv] <device name="0" type="dummy-device">
[init -> test-platform_drv] <device name="0" type="dummy-device" used="false">
[init -> test-platform_drv] <io_mem phys_addr="0x40000000" size="0x1000"/>
[init -> test-platform_drv] <irq number="32"/>
[init -> test-platform_drv] </device>
[init -> test-platform_drv] <device name="1" type="dummy-device">
[init -> test-platform_drv] <device name="1" type="dummy-device" used="false">
[init -> test-platform_drv] <io_mem phys_addr="0x40001000" size="0x1000"/>
[init -> test-platform_drv] <irq number="33"/>
[init -> test-platform_drv] </device>
[init -> test-platform_drv] <device name="2" type="dummy-device">
[init -> test-platform_drv] <device name="2" type="dummy-device" used="false">
[init -> test-platform_drv] <io_mem phys_addr="0x40002000" size="0x1000"/>
[init -> test-platform_drv] <irq number="34"/>
[init -> test-platform_drv] </device>
[init -> test-platform_drv] </devices>
[init -> test-platform_drv] <devices version="2">
[init -> test-platform_drv] <device name="0" type="dummy-device">
[init -> test-platform_drv] <device name="0" type="dummy-device" used="true">
[init -> test-platform_drv] <io_mem phys_addr="0x40000000" size="0x1000"/>
[init -> test-platform_drv] <irq number="32"/>
[init -> test-platform_drv] </device>
[init -> test-platform_drv] <device name="1" type="dummy-device">
[init -> test-platform_drv] <device name="1" type="dummy-device" used="true">
[init -> test-platform_drv] <io_mem phys_addr="0x40001000" size="0x1000"/>
[init -> test-platform_drv] <irq number="33"/>
[init -> test-platform_drv] </device>
[init -> test-platform_drv] </devices>
[init -> test-platform_drv] <devices version="3"/>
[init -> test-platform_drv] <devices version="4">
[init -> test-platform_drv] <device name="0" type="dummy-device">
[init -> test-platform_drv] <device name="0" type="dummy-device" used="false">
[init -> test-platform_drv] <io_mem phys_addr="0x40000000" size="0x1000"/>
[init -> test-platform_drv] <irq number="32"/>
[init -> test-platform_drv] </device>
[init -> test-platform_drv] <device name="1" type="dummy-device">
[init -> test-platform_drv] <device name="1" type="dummy-device" used="false">
[init -> test-platform_drv] <io_mem phys_addr="0x40001000" size="0x1000"/>
[init -> test-platform_drv] <irq number="33"/>
[init -> test-platform_drv] </device>
[init -> test-platform_drv] <device name="2" type="dummy-device">
[init -> test-platform_drv] <device name="2" type="dummy-device" used="false">
[init -> test-platform_drv] <io_mem phys_addr="0x40002000" size="0x1000"/>
[init -> test-platform_drv] <irq number="34"/>
[init -> test-platform_drv] </device>
[init -> test-platform_drv] <device name="3" type="dummy-device">
[init -> test-platform_drv] <device name="3" type="dummy-device" used="false">
[init -> test-platform_drv] <io_mem phys_addr="0x40003000" size="0x1000"/>
[init -> test-platform_drv] <irq number="35"/>
[init -> test-platform_drv] </device>
[init -> test-platform_drv] </devices>
[init -> test-platform_drv] <devices version="5"/>
[init -> test-platform_drv] <devices version="6">
[init -> test-platform_drv] <device name="0" type="dummy-device">
[init -> test-platform_drv] <device name="0" type="dummy-device" used="false">
[init -> test-platform_drv] <io_mem phys_addr="0x40000100" size="0x1000"/>
[init -> test-platform_drv] <irq number="32"/>
[init -> test-platform_drv] </device>
[init -> test-platform_drv] </devices>
[init -> test-platform_drv] Error: Device 0 not valid!
[init -> test-platform_drv] <devices version="7">
[init -> test-platform_drv] <device name="0" type="dummy-device">
[init -> test-platform_drv] <device name="0" type="dummy-device" used="true">
[init -> test-platform_drv] <io_mem phys_addr="0x40000100" size="0x1000"/>
[init -> test-platform_drv] <irq number="32"/>
[init -> test-platform_drv] </device>
[init -> test-platform_drv] <device name="1" type="dummy-device">
[init -> test-platform_drv] <device name="1" type="dummy-device" used="false">
[init -> test-platform_drv] <io_mem phys_addr="0x40001100" size="0x1000"/>
[init -> test-platform_drv] <irq number="33"/>
[init -> test-platform_drv] </device>
[init -> test-platform_drv] <device name="2" type="dummy-device">
[init -> test-platform_drv] <device name="2" type="dummy-device" used="false">
[init -> test-platform_drv] <io_mem phys_addr="0x40002100" size="0x1000"/>
[init -> test-platform_drv] <irq number="34"/>
[init -> test-platform_drv] </device>
[init -> test-platform_drv] <device name="3" type="dummy-device">
[init -> test-platform_drv] <device name="3" type="dummy-device" used="false">
[init -> test-platform_drv] <io_mem phys_addr="0x40003100" size="0x1000"/>
[init -> test-platform_drv] <irq number="35"/>
[init -> test-platform_drv] </device>
@ -177,6 +191,6 @@ set good_string {
[init -> test-platform_drv] Test has ended!
}
run_genode_until "No matching policy for 'test-platform_drv -> ' anymore, will close the session!.*\n" 100
run_genode_until "Test has ended!.*\n" 100
grep_output "init -> test-platform_drv"
compare_output_to $good_string

View File

@ -0,0 +1,64 @@
This directory contains the implementation of Genode's platform driver.
Behavior
--------
Per client a policy must be configured that states which client can
access certain devices to form a virtual bus per client. The client may
iterate through the virtual bus using the devices_rom() function of
the platform_session interface to discover all available devices of the virtual
bus. When identified a specific device its device capability can be obtained
via its unique name. Simple device drivers that drive exactly one device do
not need the devices ROM, but can simply obtain their device capability via
the acquire_single_device() function of the platform session interface.
With the device capability the resources of the devices can be obtained, e.g.
io_port, io_mem and irq of the platform_device interface.
Policy usage
------------
A policy may contain several nodes describing several devices.
!<start name="platform_drv" managing_system="yes">
! <resource name="RAM" quantum="8M"/>
! ...
! <config>
! <policy label_prefix="usb_drv" info="yes">
! <device name="ehci"/>
! <device name="uhci"/>
! </policy>
! </config>
! ...
The managing_system attribute is evaluated by init. If set to "yes" it
permits a component, the platform driver, to restrict the allocation of memory to
specific physical RAM ranges. The platform driver uses this feature to ensure that
the allocation of DMA capable memory consider several restrictions. For
example, some drivers, as the UHCI controller, requires a
physical memory address below 4G. Another example is that on 32bit hosts
physical to virtual identical mappings of DMA memory for the device_pd
(required when IOMMU is used) must be below the kernel memory boundary (3G).
On some systems, e.g., base-hw kernel on certain ARM platforms, it allows the
platform driver to call system management firmware via kernel syscalls.
The 'info' attribute in a policy node describe, whether the client gets
permission to access a devices ROM containing detailed information about
the devices of its virtual bus.
Report facilities
-----------------
The configuration of the platform driver supports different levels of reports.
By default the platform driver does not report anything. But when adding a
report node:
! <config>
! <report devices="yes" config="yes"
! ...
! </config>
it is possible to enable either a devices and/or config report. The first will
open up a Report session to dynamically report all accessible devices and its
state. Whereby the second report states the currently active configuration of
the platform driver.

View File

@ -79,11 +79,15 @@ void Driver::Device::acquire(Session_component & sc)
});
sc.update_devices_rom();
sc.devices().update_report();
}
void Driver::Device::release(Session_component & sc)
{
if (!(_owner == sc))
return;
_reset_domain_list.for_each([&] (Reset_domain & r)
{
sc.devices().resets().apply(r.name, [&] (Driver::Reset &reset) {
@ -102,15 +106,18 @@ void Driver::Device::release(Session_component & sc)
clock.disable(); });
});
if (_owner == sc) _owner = Owner();
_owner = Owner();
sc.update_devices_rom();
sc.devices().update_report();
}
void Driver::Device::report(Xml_generator & xml, Session_component & sc)
void Driver::Device::report(Xml_generator & xml, Device_model & devices)
{
xml.node("device", [&] () {
xml.attribute("name", name());
xml.attribute("type", type());
xml.attribute("used", _owner.valid());
_io_mem_list.for_each([&] (Io_mem & io_mem) {
xml.node("io_mem", [&] () {
xml.attribute("phys_addr", String<16>(Hex(io_mem.range.start)));
@ -135,7 +142,7 @@ void Driver::Device::report(Xml_generator & xml, Session_component & sc)
});
});
_clock_list.for_each([&] (Clock &c) {
sc.devices().clocks().apply(c.name, [&] (Driver::Clock &clock) {
devices.clocks().apply(c.name, [&] (Driver::Clock &clock) {
xml.node("clock", [&] () {
xml.attribute("rate", clock.rate().value);
xml.attribute("name", c.driver_name);
@ -143,7 +150,7 @@ void Driver::Device::report(Xml_generator & xml, Session_component & sc)
});
});
_report_platform_specifics(xml, sc);
_report_platform_specifics(xml, devices);
});
}
@ -157,3 +164,21 @@ Driver::Device::~Device()
if (_owner.valid()) {
error("Device to be destroyed, still obtained by session"); }
}
void Driver::Device_model::update_report()
{
if (_reporter.enabled()) {
Reporter::Xml_generator xml(_reporter, [&] () {
for_each([&] (Device & device) {
device.report(xml, *this); });
});
}
}
void Driver::Device_model::update(Xml_node const & node)
{
_model.update_from_xml(*this, node);
update_report();
}

View File

@ -16,6 +16,7 @@
#include <base/allocator.h>
#include <base/heap.h>
#include <os/reporter.h>
#include <platform_session/device.h>
#include <util/list.h>
#include <util/list_model.h>
@ -166,12 +167,12 @@ class Driver::Device : private List_model<Device>::Element
fn(idx++, ipr.addr, ipr.size); });
}
void report(Xml_generator &, Session_component &);
void report(Xml_generator &, Device_model &);
protected:
virtual void _report_platform_specifics(Xml_generator &,
Session_component &) {}
Device_model &) {}
friend class Driver::Device_model;
friend class List_model<Device>;
@ -202,6 +203,7 @@ class Driver::Device_model :
private:
Heap & _heap;
Reporter & _reporter;
List_model<Device> _model { };
Clocks _clocks { };
Resets _resets { };
@ -209,12 +211,11 @@ class Driver::Device_model :
public:
void update(Xml_node const & node) {
_model.update_from_xml(*this, node);
}
void update_report();
void update(Xml_node const & node);
Device_model(Heap & heap)
: _heap(heap) { }
Device_model(Heap & heap, Reporter & reporter)
: _heap(heap), _reporter(reporter) { }
~Device_model() {
_model.destroy_all_elements(*this); }

View File

@ -21,15 +21,17 @@ struct Driver::Main
void update();
Env & env;
Heap heap { env.ram(), env.rm() };
Sliced_heap sliced_heap { env.ram(), env.rm() };
Attached_rom_dataspace config_rom { env, "config" };
Attached_rom_dataspace devices_rom { env, "devices" };
Device_model devices { heap };
Signal_handler<Main> handler { env.ep(), *this,
&Main::update };
Driver::Root root { env, sliced_heap,
config_rom, devices };
Heap heap { env.ram(), env.rm() };
Sliced_heap sliced_heap { env.ram(), env.rm() };
Attached_rom_dataspace config_rom { env, "config" };
Attached_rom_dataspace devices_rom { env, "devices" };
Reporter cfg_reporter { env, "config" };
Reporter dev_reporter { env, "devices" };
Device_model devices { heap, dev_reporter };
Signal_handler<Main> handler { env.ep(), *this,
&Main::update };
Driver::Root root { env, sliced_heap,
config_rom, devices };
Main(Genode::Env & e)
: env(e)
@ -46,8 +48,22 @@ void Driver::Main::update()
{
config_rom.update();
devices_rom.update();
config_rom.xml().for_each_sub_node("report", [&] (Xml_node const node) {
dev_reporter.enabled(node.attribute_value("devices", false));
cfg_reporter.enabled(node.attribute_value("config", false));
});
devices.update(devices_rom.xml());
root.update_policy();
if (cfg_reporter.enabled()) {
Reporter::Xml_generator xml(cfg_reporter, [&] () {
config_rom.xml().with_raw_content([&] (char const *src, size_t len) {
xml.append(src, len);
});
});
}
}
void Component::construct(Genode::Env &env) {

View File

@ -104,7 +104,7 @@ void Session_component::produce_xml(Xml_generator &xml)
xml.attribute("version", _version);
_devices.for_each([&] (Device & dev) {
if (matches(dev)) dev.report(xml, *this); });
if (matches(dev)) dev.report(xml, _devices); });
}

View File

@ -96,6 +96,12 @@ struct Main
Reporter::Xml_generator cfg(config_reporter, [&] ()
{
cfg.node("report", [&]
{
cfg.attribute("devices", true);
cfg.attribute("config", true);
});
cfg.node("policy", [&]
{
cfg.attribute("label", "test-platform_drv -> ");