gems: driver-manager subsystem for PC platforms

This is a drivers subsystem that starts the most fundamental
(framebuffer, input, block) device drivers dynamically, depending on the
runtime-detected devices. The discovered block devices are reported
as a "block_devices" report.
This commit is contained in:
Norman Feske 2017-06-30 13:30:37 +02:00 committed by Christian Helmuth
parent 37b5c9a2c1
commit 6bfd4f4276
14 changed files with 998 additions and 0 deletions

View File

@ -0,0 +1,4 @@
Device-driver subsystem that starts drivers for
framebuffer, input, and block devices on demand

View File

@ -0,0 +1,15 @@
_/src/platform_drv
_/src/acpi_drv
_/src/ps2_drv
_/src/usb_drv
_/src/usb_block_drv
_/src/vesa_drv
_/src/intel_fb_drv
_/src/ahci_drv
_/src/fs_report
_/src/fs_rom
_/src/ram_fs
_/src/input_filter
_/src/init
_/src/driver_manager
_/raw/drivers_managed-pc

View File

@ -0,0 +1 @@
2017-09-06-a d0f1da3a828141f7c8e57557c873a910faa19caf

View File

@ -0,0 +1,10 @@
content: drivers.config fb_drv.config input_filter.config en_us.chargen
drivers.config:
cp $(REP_DIR)/recipes/raw/drivers_managed-pc/$@ $@
fb_drv.config input_filter.config:
cp $(GENODE_DIR)/repos/os/recipes/raw/drivers_interactive-pc/$@ $@
en_us.chargen:
cp $(GENODE_DIR)/repos/os/src/server/input_filter/$@ $@

View File

@ -0,0 +1,240 @@
<config prio_levels="2">
<parent-provides>
<service name="ROM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="Timer"/>
<service name="Report"/>
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<default caps="100"/>
<service name="Framebuffer">
<default-policy> <child name="dynamic"/> </default-policy> </service>
<service name="Block">
<default-policy> <child name="dynamic"/> </default-policy> </service>
<service name="Usb">
<default-policy> <child name="usb_drv"/> </default-policy> </service>
<service name="Platform">
<default-policy> <child name="platform_drv"/> </default-policy> </service>
<service name="Input">
<default-policy> <child name="input_filter"/> </default-policy> </service>
<service name="File_system">
<default-policy> <child name="ram_fs" label="parent"/> </default-policy> </service>
<start name="ram_fs" priority="-1">
<resource name="RAM" quantum="4M"/>
<provides> <service name="File_system"/> </provides>
<config>
<policy label="fs_rom -> " root="/"/>
<policy label="fs_report -> " root="/" writeable="yes"/>
<policy label="parent" root="/"/>
<content>
<inline name="acpi"/>
<inline name="pci_devices"/>
<inline name="usb_devices"/>
<inline name="usb_active_config"/>
<inline name="usb_drv.config"/>
<dir name="dynamic">
<inline name="ahci_ports"/>
<inline name="config"/>
<inline name="state"/>
</dir>
</content>
</config>
<route>
<service name="LOG"> <parent/> </service>
<service name="PD"> <parent/> </service>
<service name="CPU"> <parent/> </service>
<service name="ROM"> <parent/> </service>
</route>
</start>
<start name="fs_report" priority="-1">
<resource name="RAM" quantum="2M"/>
<provides> <service name="Report"/> </provides>
<config> <vfs> <fs/> </vfs> </config>
<route>
<service name="File_system"> <child name="ram_fs"/> </service>
<service name="LOG"> <parent/> </service>
<service name="PD"> <parent/> </service>
<service name="CPU"> <parent/> </service>
<service name="ROM"> <parent/> </service>
</route>
</start>
<start name="fs_rom" priority="-1">
<resource name="RAM" quantum="1M"/>
<provides> <service name="ROM"/> </provides>
<config/>
<route>
<service name="File_system"> <child name="ram_fs"/> </service>
<service name="LOG"> <parent/> </service>
<service name="PD"> <parent/> </service>
<service name="CPU"> <parent/> </service>
<service name="ROM"> <parent/> </service>
</route>
</start>
<start name="acpi_drv" caps="300" priority="-1">
<resource name="RAM" quantum="2M"/>
<route>
<service name="Report" label="acpi"> <child name="fs_report" label="acpi"/> </service>
<service name="IO_MEM"> <parent/> </service>
<service name="LOG"> <parent/> </service>
<service name="PD"> <parent/> </service>
<service name="RM"> <parent/> </service>
<service name="CPU"> <parent/> </service>
<service name="ROM"> <parent/> </service>
</route>
</start>
<start name="platform_drv" caps="300">
<resource name="RAM" quantum="3M" constrain_phys="yes"/>
<provides>
<service name="Platform"/>
<service name="Acpi"/>
</provides>
<route>
<service name="ROM" label="system"> <child name="fs_rom"/> </service>
<service name="ROM" label="acpi"> <child name="fs_rom"/> </service>
<service name="Report" label="pci">
<child name="fs_report" label="pci_devices"/> </service>
<service name="IRQ"> <parent/> </service>
<service name="IO_MEM"> <parent/> </service>
<service name="IO_PORT"> <parent/> </service>
<service name="ROM"> <parent/> </service>
<service name="PD"> <parent/> </service>
<service name="CPU"> <parent/> </service>
<service name="LOG"> <parent/> </service>
<service name="Timer"> <parent/> </service>
</route>
<config>
<report pci="yes"/>
<policy label_prefix="ps2_drv"> <device name="PS2"/> </policy>
<policy label_prefix="dynamic -> vesa_fb_drv"> <pci class="VGA"/> </policy>
<policy label_prefix="dynamic -> ahci_drv"> <pci class="AHCI"/> </policy>
<policy label_prefix="usb_drv"> <pci class="USB"/> </policy>
<policy label_prefix="dynamic -> intel_fb_drv" irq_mode="nomsi">
<pci class="VGA"/>
<pci bus="0" device="0" function="0"/>
<pci class="ISABRIDGE"/>
</policy>
<policy label_suffix="-> wifi"> <pci class="WIFI"/> </policy>
</config>
</start>
<start name="usb_drv" caps="100" priority="-1">
<resource name="RAM" quantum="14M"/>
<provides> <service name="Input"/> <service name="Usb"/> </provides>
<route>
<service name="Platform"> <child name="platform_drv"/> </service>
<service name="ROM" label="config">
<child name="fs_rom" label="usb_drv.config"/> </service>
<service name="Report" label="devices">
<child name="fs_report" label="usb_devices"/> </service>
<service name="Report" label="config">
<child name="fs_report" label="usb_active_config"/> </service>
<service name="ROM"> <parent/> </service>
<service name="PD"> <parent/> </service>
<service name="RM"> <parent/> </service>
<service name="CPU"> <parent/> </service>
<service name="LOG"> <parent/> </service>
<service name="Timer"> <parent/> </service>
</route>
</start>
<start name="ps2_drv" priority="0">
<resource name="RAM" quantum="1M"/>
<provides> <service name="Input"/> </provides>
<route>
<service name="Platform"> <child name="platform_drv"/> </service>
<service name="ROM"> <parent/> </service>
<service name="PD"> <parent/> </service>
<service name="CPU"> <parent/> </service>
<service name="LOG"> <parent/> </service>
</route>
</start>
<start name="input_filter" caps="80" priority="-1">
<resource name="RAM" quantum="1M"/>
<provides> <service name="Input"/> </provides>
<route>
<service name="ROM" label="config"> <parent label="input_filter.config"/> </service>
<service name="ROM" label="en_us.chargen"> <parent label="en_us.chargen"/> </service>
<service name="Input" label="ps2"> <child name="ps2_drv"/> </service>
<service name="Input" label="usb"> <child name="usb_drv"/> </service>
<service name="ROM"> <parent/> </service>
<service name="PD"> <parent/> </service>
<service name="CPU"> <parent/> </service>
<service name="LOG"> <parent/> </service>
<service name="Timer"> <parent/> </service>
</route>
</start>
<start name="driver_manager" priority="-1">
<resource name="RAM" quantum="1M"/>
<route>
<service name="Report" label="init.config">
<child name="fs_report" label="dynamic -> config"/> </service>
<service name="Report" label="usb_drv.config">
<child name="fs_report" label="usb_drv.config"/> </service>
<service name="Report" label="block_devices">
<parent label="block_devices"/> </service>
<service name="ROM" label="init_state">
<child name="fs_rom" label="dynamic/state"/> </service>
<service name="ROM" label="usb_devices"> <child name="fs_rom"/> </service>
<service name="ROM" label="pci_devices"> <child name="fs_rom"/> </service>
<service name="ROM" label="usb_active_config"> <child name="fs_rom"/> </service>
<service name="ROM" label="ahci_ports">
<child name="fs_rom" label="dynamic/ahci_ports"/> </service>
<service name="ROM" label_prefix="dynamic/"> <child name="fs_rom"/> </service>
<service name="LOG"> <parent/> </service>
<service name="PD"> <parent/> </service>
<service name="CPU"> <parent/> </service>
<service name="ROM"> <parent/> </service>
</route>
</start>
<start name="dynamic" caps="800" priority="0">
<binary name="init"/>
<resource name="RAM" quantum="1G"/>
<provides>
<service name="Framebuffer"/>
<service name="Block"/>
</provides>
<route>
<service name="Platform"> <child name="platform_drv"/> </service>
<service name="Report" label="state">
<child name="fs_report" label="dynamic/state"/> </service>
<service name="Report"> <child name="fs_report"/> </service>
<service name="Usb"> <child name="usb_drv"/> </service>
<service name="ROM" label="config">
<child name="fs_rom" label="dynamic/config"/> </service>
<service name="LOG"> <parent/> </service>
<service name="PD"> <parent/> </service>
<service name="RM"> <parent/> </service>
<service name="CPU"> <parent/> </service>
<service name="ROM"> <parent/> </service>
<service name="IO_MEM"> <parent/> </service>
<service name="IO_PORT"> <parent/> </service>
<service name="Timer"> <parent/> </service>
</route>
</start>
</config>

View File

@ -0,0 +1 @@
2017-06-30 a5a5feaf6577dcf69602022f0a55078a039b7eda

View File

@ -0,0 +1,2 @@
SRC_DIR := src/app/driver_manager
include $(GENODE_DIR)/repos/base/recipes/src/content.inc

View File

@ -0,0 +1 @@
2017-09-07-a 6616814f9b594c0a130f086432b83a349ac5aa48

View File

@ -0,0 +1,8 @@
base
os
report_session
block_session
usb_session
framebuffer_session
timer_session
platform_session

View File

@ -0,0 +1,118 @@
if {![have_spec x86] || [have_spec linux]} {
puts "Platform is unsupported."
exit 0
}
build { app/driver_manager test/driver_manager lib/ld }
create_boot_directory
import_from_depot genodelabs/src/[base_src] \
genodelabs/pkg/drivers_managed-pc \
genodelabs/src/report_rom \
genodelabs/src/init
install_config {
<config prio_levels="2">
<parent-provides>
<service name="ROM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<default caps="100"/>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
</start>
<start name="report_rom">
<binary name="report_rom"/>
<resource name="RAM" quantum="1M"/>
<provides> <service name="Report"/> <service name="ROM"/> </provides>
<config verbose="yes">
<policy label="test-driver_manager -> block_devices" report="drivers -> block_devices"/>
</config>
</start>
<start name="drivers" caps="2500">
<resource name="RAM" quantum="64M"/>
<binary name="init"/>
<route>
<service name="ROM" label="config"> <parent label="drivers.config"/> </service>
<service name="Timer"> <child name="timer"/> </service>
<service name="Report" label="block_devices"> <child name="report_rom"/> </service>
<any-service> <parent/> </any-service>
</route>
<provides>
<service name="Input"/>
<service name="Framebuffer"/>
<service name="Block"/>
</provides>
</start>
<start name="test-driver_manager">
<resource name="RAM" quantum="1M"/>
<config>
<check_ahci_block_device label="ahci-0" block_count="65536" block_size="512"
model="QEMU HARDDISK"/>
<check_input/>
<check_framebuffer/>
</config>
<route>
<service name="ROM" label="block_devices"> <child name="report_rom"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
</config>}
set fd [open [run_dir]/genode/fb_drv.config "w"]
puts $fd {
<config width="1024" height="768" buffered="yes"> <!-- used by VESA driver -->
<report connectors="yes"/>
<connector name="eDP-36" width="1920" height="1080" enabled="true"/>
</config>}
close $fd
#
# Override 'drivers.config' as supplied with the 'drivers_managed-pc' pkg
# with the (possibly modified) version found in the source tree. This avoids
# the need to re-create the pkg while testing modifications of this file.
#
file copy -force [genode_dir]/repos/gems/recipes/raw/drivers_managed-pc/drivers.config \
[run_dir]/genode/drivers.config
build_boot_image { driver_manager test-driver_manager ld.lib.so }
#
# Build ext2 file-system images to be supplied to Qemu
#
if {[have_include "power_on/qemu"]} {
set mke2fs [check_installed mke2fs]
set dd [check_installed dd]
catch { exec $dd if=/dev/zero of=bin/hdd_disk.raw bs=1M count=32 }
catch { exec $mke2fs -F bin/hdd_disk.raw }
}
#
# Qemu opts for supplying hdd_disk.raw as AHCI disk
#
append qemu_args " -m 128 "
append qemu_args " -nographic "
append qemu_args " -device ahci,id=ahci "
append qemu_args " -drive id=hdd,file=bin/hdd_disk.raw,format=raw,if=none -device ide-hd,drive=hdd,bus=ahci.0 "
run_genode_until {.*all expected devices present and accessible.*\n} 120

View File

@ -0,0 +1,448 @@
/*
* \brief Driver manager
* \author Norman Feske
* \date 2017-06-13
*/
/*
* Copyright (C) 2017 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.
*/
/* Genode includes */
#include <base/component.h>
#include <base/registry.h>
#include <base/attached_rom_dataspace.h>
#include <os/reporter.h>
#include <block_session/block_session.h>
#include <rm_session/rm_session.h>
#include <framebuffer_session/framebuffer_session.h>
#include <io_mem_session/io_mem_session.h>
#include <io_port_session/io_port_session.h>
#include <timer_session/timer_session.h>
#include <log_session/log_session.h>
#include <usb_session/usb_session.h>
#include <platform_session/platform_session.h>
namespace Driver_manager {
using namespace Genode;
struct Main;
struct Block_devices_generator;
struct Device_driver;
struct Intel_fb_driver;
struct Vesa_fb_driver;
struct Ahci_driver;
struct Priority { int value; };
}
struct Driver_manager::Block_devices_generator
{
virtual void generate_block_devices() = 0;
};
class Driver_manager::Device_driver : Noncopyable
{
public:
typedef String<64> Name;
typedef String<100> Binary;
typedef String<32> Service;
protected:
static void _gen_common_start_node_content(Xml_generator &xml,
Name const &name,
Binary const &binary,
Ram_quota ram,
Cap_quota caps,
Priority priority)
{
xml.attribute("name", name);
xml.attribute("caps", String<64>(caps));
xml.attribute("priority", priority.value);
xml.node("binary", [&] () { xml.attribute("name", binary); });
xml.node("resource", [&] () {
xml.attribute("name", "RAM");
xml.attribute("quantum", String<64>(ram));
});
}
template <typename SESSION>
static void _gen_provides_node(Xml_generator &xml)
{
xml.node("provides", [&] () {
xml.node("service", [&] () {
xml.attribute("name", SESSION::service_name()); }); });
}
static void _gen_config_route(Xml_generator &xml, char const *config_name)
{
xml.node("service", [&] () {
xml.attribute("name", Rom_session::service_name());
xml.attribute("label", "config");
xml.node("parent", [&] () {
xml.attribute("label", config_name); });
});
}
static void _gen_default_parent_route(Xml_generator &xml)
{
xml.node("any-service", [&] () {
xml.node("parent", [&] () { }); });
}
template <typename SESSION>
static void _gen_forwarded_service(Xml_generator &xml,
Device_driver::Name const &name)
{
xml.node("service", [&] () {
xml.attribute("name", SESSION::service_name());
xml.node("default-policy", [&] () {
xml.node("child", [&] () {
xml.attribute("name", name);
});
});
});
};
virtual ~Device_driver() { }
public:
virtual void generate_start_node(Xml_generator &xml) const = 0;
};
struct Driver_manager::Intel_fb_driver : Device_driver
{
void generate_start_node(Xml_generator &xml) const override
{
xml.node("start", [&] () {
_gen_common_start_node_content(xml, "intel_fb_drv", "intel_fb_drv",
Ram_quota{20*1024*1024}, Cap_quota{100},
Priority{0});
_gen_provides_node<Framebuffer::Session>(xml);
xml.node("route", [&] () {
_gen_config_route(xml, "fb_drv.config");
_gen_default_parent_route(xml);
});
});
_gen_forwarded_service<Framebuffer::Session>(xml, "intel_fb_drv");
}
};
struct Driver_manager::Vesa_fb_driver : Device_driver
{
void generate_start_node(Xml_generator &xml) const override
{
xml.node("start", [&] () {
_gen_common_start_node_content(xml, "vesa_fb_drv", "fb_drv",
Ram_quota{8*1024*1024}, Cap_quota{100},
Priority{-1});
_gen_provides_node<Framebuffer::Session>(xml);
xml.node("route", [&] () {
_gen_config_route(xml, "fb_drv.config");
_gen_default_parent_route(xml);
});
});
_gen_forwarded_service<Framebuffer::Session>(xml, "vesa_fb_drv");
}
};
struct Driver_manager::Ahci_driver : Device_driver
{
void generate_start_node(Xml_generator &xml) const override
{
xml.node("start", [&] () {
_gen_common_start_node_content(xml, "ahci_drv", "ahci_drv",
Ram_quota{10*1024*1024}, Cap_quota{100},
Priority{-1});
_gen_provides_node<Block::Session>(xml);
xml.node("config", [&] () {
xml.node("report", [&] () { xml.attribute("ports", "yes"); });
for (unsigned i = 0; i < 6; i++) {
xml.node("policy", [&] () {
xml.attribute("label_suffix", String<64>(" ahci-", i));
xml.attribute("device", i);
xml.attribute("writeable", "yes");
});
}
});
xml.node("route", [&] () {
xml.node("service", [&] () {
xml.attribute("name", "Report");
xml.node("parent", [&] () { xml.attribute("label", "ahci_ports"); });
});
_gen_default_parent_route(xml);
});
});
}
void generate_block_service_forwarding_policy(Xml_generator &xml) const
{
for (unsigned i = 0; i < 6; i++) {
xml.node("policy", [&] () {
xml.attribute("label_suffix", String<64>(" ahci-", i));
xml.node("child", [&] () {
xml.attribute("name", "ahci_drv");
});
});
}
}
};
struct Driver_manager::Main : Block_devices_generator
{
Env &_env;
Attached_rom_dataspace _init_state { _env, "init_state" };
Attached_rom_dataspace _usb_devices { _env, "usb_devices" };
Attached_rom_dataspace _pci_devices { _env, "pci_devices" };
Attached_rom_dataspace _ahci_ports { _env, "ahci_ports" };
Reporter _init_config { _env, "config", "init.config" };
Reporter _usb_drv_config { _env, "config", "usb_drv.config" };
Reporter _block_devices { _env, "block_devices" };
Constructible<Intel_fb_driver> _intel_fb_driver;
Constructible<Vesa_fb_driver> _vesa_fb_driver;
Constructible<Ahci_driver> _ahci_driver;
void _handle_pci_devices_update();
Signal_handler<Main> _pci_devices_update_handler {
_env.ep(), *this, &Main::_handle_pci_devices_update };
void _handle_usb_devices_update();
Signal_handler<Main> _usb_devices_update_handler {
_env.ep(), *this, &Main::_handle_usb_devices_update };
void _handle_ahci_ports_update();
Signal_handler<Main> _ahci_ports_update_handler {
_env.ep(), *this, &Main::_handle_ahci_ports_update };
static void _gen_parent_service_xml(Xml_generator &xml, char const *name)
{
xml.node("service", [&] () { xml.attribute("name", name); });
};
void _generate_init_config (Reporter &) const;
void _generate_usb_drv_config (Reporter &, Xml_node) const;
void _generate_block_devices (Reporter &) const;
/**
* Block_devices_generator interface
*/
void generate_block_devices() override { _generate_block_devices(_block_devices); }
Main(Env &env) : _env(env)
{
_init_config.enabled(true);
_usb_drv_config.enabled(true);
_block_devices.enabled(true);
_pci_devices.sigh(_pci_devices_update_handler);
_usb_devices.sigh(_usb_devices_update_handler);
_ahci_ports .sigh(_ahci_ports_update_handler);
_generate_init_config(_init_config);
_generate_usb_drv_config(_usb_drv_config, Xml_node("<devices/>"));
_handle_pci_devices_update();
_handle_usb_devices_update();
_handle_ahci_ports_update();
}
};
void Driver_manager::Main::_handle_pci_devices_update()
{
_pci_devices.update();
bool has_vga = false;
bool has_intel_graphics = false;
bool has_ahci = false;
_pci_devices.xml().for_each_sub_node([&] (Xml_node device) {
uint16_t const vendor_id = device.attribute_value("vendor_id", 0UL);
uint16_t const class_code = device.attribute_value("class_code", 0UL) >> 8;
enum {
VENDOR_INTEL = 0x8086U,
CLASS_VGA = 0x300U,
CLASS_AHCI = 0x106U,
};
if (class_code == CLASS_VGA)
has_vga = true;
if (vendor_id == VENDOR_INTEL && class_code == CLASS_VGA)
has_intel_graphics = true;
if (vendor_id == VENDOR_INTEL && class_code == CLASS_AHCI)
has_ahci = true;
});
if (!_intel_fb_driver.constructed() && has_intel_graphics) {
_intel_fb_driver.construct();
_vesa_fb_driver.destruct();
_generate_init_config(_init_config);
}
if (!_vesa_fb_driver.constructed() && has_vga && !has_intel_graphics) {
_intel_fb_driver.destruct();
_vesa_fb_driver.construct();
_generate_init_config(_init_config);
}
if (!_ahci_driver.constructed() && has_ahci) {
_ahci_driver.construct();
_generate_init_config(_init_config);
}
}
void Driver_manager::Main::_handle_ahci_ports_update()
{
_ahci_ports.update();
_generate_block_devices(_block_devices);
}
void Driver_manager::Main::_handle_usb_devices_update()
{
_usb_devices.update();
_generate_usb_drv_config(_usb_drv_config, _usb_devices.xml());
}
void Driver_manager::Main::_generate_init_config(Reporter &init_config) const
{
Reporter::Xml_generator xml(init_config, [&] () {
xml.attribute("verbose", false);
xml.attribute("prio_levels", 2);
xml.node("report", [&] () { xml.attribute("child_ram", true); });
xml.node("parent-provides", [&] () {
_gen_parent_service_xml(xml, Rom_session::service_name());
_gen_parent_service_xml(xml, Io_mem_session::service_name());
_gen_parent_service_xml(xml, Io_port_session::service_name());
_gen_parent_service_xml(xml, Cpu_session::service_name());
_gen_parent_service_xml(xml, Pd_session::service_name());
_gen_parent_service_xml(xml, Rm_session::service_name());
_gen_parent_service_xml(xml, Log_session::service_name());
_gen_parent_service_xml(xml, Timer::Session::service_name());
_gen_parent_service_xml(xml, Platform::Session::service_name());
_gen_parent_service_xml(xml, Report::Session::service_name());
_gen_parent_service_xml(xml, Usb::Session::service_name());
});
if (_intel_fb_driver.constructed())
_intel_fb_driver->generate_start_node(xml);
if (_vesa_fb_driver.constructed())
_vesa_fb_driver->generate_start_node(xml);
if (_ahci_driver.constructed())
_ahci_driver->generate_start_node(xml);
/* block-service forwarding rules */
xml.node("service", [&] () {
xml.attribute("name", Block::Session::service_name());
if (_ahci_driver.constructed())
_ahci_driver->generate_block_service_forwarding_policy(xml);
});
});
}
void Driver_manager::Main::_generate_block_devices(Reporter &block_devices) const
{
Reporter::Xml_generator xml(block_devices, [&] () {
_ahci_ports.xml().for_each_sub_node([&] (Xml_node ahci_port) {
xml.node("device", [&] () {
unsigned long const
num = ahci_port.attribute_value("num", 0UL),
block_count = ahci_port.attribute_value("block_count", 0UL),
block_size = ahci_port.attribute_value("block_size", 0UL);
typedef String<80> Model;
Model const model = ahci_port.attribute_value("model", Model());
xml.attribute("label", String<64>("ahci-", num));
xml.attribute("block_count", block_count);
xml.attribute("block_size", block_size);
xml.attribute("model", model);
});
});
});
}
void Driver_manager::Main::_generate_usb_drv_config(Reporter &usb_drv_config,
Xml_node devices) const
{
Reporter::Xml_generator xml(usb_drv_config, [&] () {
xml.attribute("uhci", true);
xml.attribute("ehci", true);
xml.attribute("xhci", true);
xml.node("hid", [&] () { });
xml.node("raw", [&] () {
xml.node("report", [&] () { xml.attribute("devices", true); });
devices.for_each_sub_node("device", [&] (Xml_node device) {
typedef String<64> Label;
typedef String<32> Id;
Label const label = device.attribute_value("label", Label());
Id const vendor_id = device.attribute_value("vendor_id", Id());
Id const product_id = device.attribute_value("product_id", Id());
/*
* Limit USB sessions to storage in order to avoid conflicts with
* the USB driver's built-in HID drivers.
*/
unsigned long const class_code = device.attribute_value("class", 0UL);
enum { USB_CLASS_MASS_STORAGE = 8 };
bool const expose_as_usb_raw = (class_code == USB_CLASS_MASS_STORAGE);
if (!expose_as_usb_raw)
return;
xml.node("policy", [&] () {
xml.attribute("label_suffix", label);
xml.attribute("vendor_id", vendor_id);
xml.attribute("product_id", product_id);
/* annotate policy to make storage devices easy to spot */
if (class_code == USB_CLASS_MASS_STORAGE)
xml.attribute("class", "storage");
});
});
});
});
}
void Component::construct(Genode::Env &env) { static Driver_manager::Main main(env); }

View File

@ -0,0 +1,5 @@
TARGET = driver_manager
SRC_CC = main.cc
LIBS += base
REQUIRES = x86

View File

@ -0,0 +1,142 @@
/*
* \brief Test for validating the device detection of the driver manager
* \author Norman Feske
* \date 2017-06-30
*/
/*
* Copyright (C) 2017 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.
*/
/* Genode includes */
#include <base/component.h>
#include <base/attached_rom_dataspace.h>
#include <base/allocator_avl.h>
#include <base/heap.h>
#include <framebuffer_session/connection.h>
#include <input_session/connection.h>
#include <block_session/connection.h>
namespace Test {
using namespace Genode;
struct Main;
}
struct Test::Main
{
Env &_env;
Attached_rom_dataspace _config { _env, "config" };
Attached_rom_dataspace _block_devices { _env, "block_devices" };
static bool _attribute_matches(char const *attr, Xml_node expected, Xml_node checked)
{
typedef String<80> Value;
return !expected.has_attribute(attr)
|| (expected.attribute_value(attr, Value()) ==
checked .attribute_value(attr, Value()));
}
static bool _block_device_matches(Xml_node expect, Xml_node device)
{
return _attribute_matches("label", expect, device)
&& _attribute_matches("block_size", expect, device)
&& _attribute_matches("block_count", expect, device);
}
static bool _usb_block_device_matches(Xml_node expect, Xml_node device)
{
return _block_device_matches(expect, device)
&& _attribute_matches("vendor", expect, device)
&& _attribute_matches("product", expect, device);
}
static bool _ahci_block_device_matches(Xml_node expect, Xml_node device)
{
return _block_device_matches(expect, device)
&& _attribute_matches("model", expect, device)
&& _attribute_matches("serial", expect, device);
}
void _check_conditions()
{
_block_devices.update();
bool expected_devices_present = true;
log("-- check presence of expected block devices --");
_config.xml().for_each_sub_node([&] (Xml_node expect) {
/* skip nodes that are unrelated to block devices */
if (expect.type() != "check_usb_block_device"
&& expect.type() != "check_ahci_block_device")
return;
bool device_exists = false;
_block_devices.xml().for_each_sub_node("device", [&] (Xml_node device) {
if (expect.type() == "check_usb_block_device"
&& _usb_block_device_matches(expect, device))
device_exists = true;
if (expect.type() == "check_ahci_block_device"
&& _ahci_block_device_matches(expect, device))
device_exists = true;
});
log("block device '", expect.attribute_value("label", String<80>()), "' ",
device_exists ? "present" : "not present");
if (!device_exists)
expected_devices_present = false;
});
if (!expected_devices_present)
return;
/* attempt to create a session to each block device */
_block_devices.xml().for_each_sub_node("device", [&] (Xml_node device) {
typedef String<64> Label;
Label label = device.attribute_value("label", Label());
log("connect to block device '", label, "'");
Heap heap(_env.ram(), _env.rm());
Allocator_avl packet_alloc(&heap);
Block::Connection block(_env, &packet_alloc, 128*1024, label.string());
});
log("all expected devices present and accessible");
}
Signal_handler<Main> _block_devices_update_handler {
_env.ep(), *this, &Main::_check_conditions };
Main(Env &env) : _env(env)
{
if (_config.xml().has_sub_node("check_framebuffer")) {
log("connect to framebuffer driver");
Framebuffer::Mode mode(640, 480, Framebuffer::Mode::RGB565);
Framebuffer::Connection fb(_env, mode);
}
if (_config.xml().has_sub_node("check_input")) {
log("connect to input driver");
Input::Connection input(_env);
}
_block_devices.sigh(_block_devices_update_handler);
_check_conditions();
}
};
void Component::construct(Genode::Env &env) { static Test::Main main(env); }

View File

@ -0,0 +1,3 @@
TARGET = test-driver_manager
SRC_CC = main.cc
LIBS += base