os: introduce common platform driver for ARM

Ref #3299
This commit is contained in:
Stefan Kalkowski 2020-05-14 15:35:40 +02:00 committed by Christian Helmuth
parent 935dcf8b18
commit 1a80f166c5
22 changed files with 1589 additions and 8 deletions

View File

@ -1,5 +1,5 @@
/* /*
* \brief PCI device capability type * \brief Device capability type
* \author Norman Feske * \author Norman Feske
* \date 2008-08-16 * \date 2008-08-16
*/ */

View File

@ -0,0 +1,58 @@
/*
* \brief Client-side interface for ARM device
* \author Stefan Kalkowski
* \date 2020-04-15
*/
/*
* 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.
*/
#ifndef _INCLUDE__SPEC__ARM__PLATFORM_DEVICE__CLIENT_H_
#define _INCLUDE__SPEC__ARM__PLATFORM_DEVICE__CLIENT_H_
#include <platform_session/platform_session.h>
#include <platform_device/platform_device.h>
#include <base/rpc_client.h>
#include <io_mem_session/client.h>
namespace Platform { struct Device_client; }
struct Platform::Device_client : Genode::Rpc_client<Device>
{
Device_client(Device_capability device)
: Genode::Rpc_client<Device>(device) {}
Genode::Irq_session_capability irq(unsigned id = 0) override
{
return call<Rpc_irq>(id);
}
Genode::Io_mem_session_capability
io_mem(unsigned id = 0,
Genode::Cache_attribute caching =
Genode::Cache_attribute::UNCACHED) override
{
return call<Rpc_io_mem>(id, caching);
}
/***************************
** Convenience utilities **
***************************/
Genode::Io_mem_dataspace_capability
io_mem_dataspace(unsigned id = 0,
Genode::Cache_attribute caching =
Genode::Cache_attribute::UNCACHED)
{
Genode::Io_mem_session_client session(io_mem(id, caching));
return session.dataspace();
}
};
#endif /* _INCLUDE__SPEC__ARM__PLATFORM_DEVICE__CLIENT_H_ */

View File

@ -0,0 +1,56 @@
/*
* \brief ARM-device interface
* \author Stefan Kalkowski
* \date 2020-04-15
*/
/*
* 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.
*/
#ifndef _INCLUDE__SPEC__ARM__PLATFORM_DEVICE__PLATFORM_DEVICE_H_
#define _INCLUDE__SPEC__ARM__PLATFORM_DEVICE__PLATFORM_DEVICE_H_
#include <base/rpc.h>
#include <base/exception.h>
#include <io_mem_session/capability.h>
#include <irq_session/capability.h>
#include <util/string.h>
namespace Platform { struct Device; }
struct Platform::Device : Genode::Session
{
enum { DEVICE_NAME_LEN = 64 };
using Name = Genode::String<DEVICE_NAME_LEN>;
virtual ~Device() { }
/**
* Get IRQ session capability
*/
virtual Genode::Irq_session_capability irq(unsigned id) = 0;
/**
* Get IO mem session capability of specified resource id
*/
virtual Genode::Io_mem_session_capability
io_mem(unsigned id, Genode::Cache_attribute attr) = 0;
/*********************
** RPC declaration **
*********************/
GENODE_RPC(Rpc_irq, Genode::Irq_session_capability, irq, unsigned);
GENODE_RPC(Rpc_io_mem, Genode::Io_mem_session_capability, io_mem,
unsigned, Genode::Cache_attribute);
GENODE_RPC_INTERFACE(Rpc_irq, Rpc_io_mem);
};
#endif /* _INCLUDE__SPEC__ARM__PLATFORM_DEVICE__PLATFORM_DEVICE_H_ */

View File

@ -0,0 +1,52 @@
/*
* \brief Client-side Platform-session interface
* \author Stefan Kalkowski
* \date 2020-04-28
*/
/*
* 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.
*/
#ifndef _INCLUDE__SPEC__ARM__PLATFORM_SESSION__CLIENT_H_
#define _INCLUDE__SPEC__ARM__PLATFORM_SESSION__CLIENT_H_
#include <base/rpc_client.h>
#include <platform_device/client.h>
#include <platform_session/capability.h>
namespace Platform {
using namespace Genode;
struct Client;
}
struct Platform::Client : public Genode::Rpc_client<Session>
{
Client(Session_capability session)
: Rpc_client<Session>(session) { }
Rom_session_capability devices_rom() override {
return call<Rpc_devices_rom>(); }
Device_capability acquire_device(String const &device) override {
return call<Rpc_acquire_device>(device); }
void release_device(Device_capability device) override {
call<Rpc_release_device>(device); }
Ram_dataspace_capability alloc_dma_buffer(size_t size) override {
return call<Rpc_alloc_dma_buffer>(size); }
void free_dma_buffer(Ram_dataspace_capability cap) override {
call<Rpc_free_dma_buffer>(cap); }
addr_t bus_addr_dma_buffer(Ram_dataspace_capability cap) override {
return call<Rpc_bus_addr_dma_buffer>(cap); }
};
#endif /* _INCLUDE__SPEC__ARM__PLATFORM_SESSION__CLIENT_H_ */

View File

@ -0,0 +1,132 @@
/*
* \brief Connection to Platform service
* \author Stefan Kalkowski
* \date 2020-05-13
*/
/*
* 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.
*/
#ifndef _INCLUDE__SPEC__ARM__PLATFORM_SESSION__CONNECTION_H_
#define _INCLUDE__SPEC__ARM__PLATFORM_SESSION__CONNECTION_H_
#include <base/connection.h>
#include <base/env.h>
#include <platform_session/client.h>
#include <rom_session/client.h>
#include <util/xml_node.h>
namespace Platform { struct Connection; }
class Platform::Connection : public Genode::Connection<Session>,
public Client
{
private:
Region_map & _rm;
Rom_session_client _rom {devices_rom()};
Constructible<Attached_dataspace> _ds {};
void _try_attach()
{
_ds.destruct();
try { _ds.construct(_rm, _rom.dataspace()); }
catch (Attached_dataspace::Invalid_dataspace) {
warning("Invalid devices rom dataspace returned!");}
}
public:
Connection(Env &env)
: Genode::Connection<Session>(env, session(env.parent(),
"ram_quota=%u, cap_quota=%u",
RAM_QUOTA, CAP_QUOTA)),
Client(cap()),
_rm(env.rm()) { _try_attach(); }
Device_capability acquire_device(String const &device) override
{
return retry_with_upgrade(Ram_quota{6*1024}, Cap_quota{6}, [&] () {
return Client::acquire_device(device); });
}
Ram_dataspace_capability alloc_dma_buffer(size_t size) override
{
return retry_with_upgrade(Ram_quota{size}, Cap_quota{2}, [&] () {
return Client::alloc_dma_buffer(size); });
}
template <typename FN>
void with_xml(FN const & fn)
{
try {
if (_ds.constructed() && _ds->local_addr<void const>()) {
Xml_node xml(_ds->local_addr<char>(), _ds->size());
fn(xml);
}
} catch (Xml_node::Invalid_syntax) {
warning("Devices rom has invalid XML syntax"); }
}
Device_capability device_by_index(unsigned idx)
{
Device_capability cap;
with_xml([&] (Xml_node & xml) {
try {
Xml_node node = xml.sub_node(idx);
Device::Name name = node.attribute_value("name",
Device::Name());
cap = acquire_device(name.string());
} catch(Xml_node::Nonexistent_sub_node) {
error(__func__, ": invalid device index ", idx);
error("device ROM content: ", xml);
}
});
return cap;
}
Device_capability device_by_property(char const * property,
char const * value)
{
using String = Genode::String<64>;
Device_capability cap;
with_xml([&] (Xml_node & xml) {
xml.for_each_sub_node("device", [&] (Xml_node node) {
/* already found a device? */
if (cap.valid()) { return; }
bool found = false;
node.for_each_sub_node("property", [&] (Xml_node node) {
if ((node.attribute_value("name", String()) == property) &&
(node.attribute_value("value", String()) == value)) {
found = true;
}
});
if (found) {
Device::Name name = node.attribute_value("name",
Device::Name());
cap = acquire_device(name.string());
}
});
if (!cap.valid()) {
error(__func__, ": property=", property, " value=",
value, " not found!");
error("device ROM content: ", xml);
}
});
return cap;
}
};
#endif /* _INCLUDE__SPEC__ARM__PLATFORM_SESSION__CONNECTION_H_ */

View File

@ -0,0 +1,108 @@
/*
* \brief Platform session interface
* \author Stefan Kalkowski
* \date 2020-04-28
*/
/*
* 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.
*/
#ifndef _INCLUDE__SPEC__ARM__PLATFORM_SESSION__PLATFORM_SESSION_H_
#define _INCLUDE__SPEC__ARM__PLATFORM_SESSION__PLATFORM_SESSION_H_
#include <base/quota_guard.h>
#include <base/rpc_args.h>
#include <dataspace/capability.h>
#include <platform_device/capability.h>
#include <platform_device/platform_device.h>
#include <rom_session/capability.h>
#include <session/session.h>
namespace Platform {
using namespace Genode;
struct Session;
}
struct Platform::Session : Genode::Session
{
/*********************
** Exception types **
*********************/
class Fatal : public Out_of_ram { };
/**
* \noapi
*/
static const char *service_name() { return "Platform"; }
enum { RAM_QUOTA = 16 * 1024, CAP_QUOTA = 6 };
virtual ~Session() { }
using String = Rpc_in_buffer<Device::DEVICE_NAME_LEN>;
/**
* Request ROM session containing the information about available devices.
*
* \return capability to ROM dataspace
*/
virtual Rom_session_capability devices_rom() = 0;
/**
* Acquire device known by unique 'name'.
*/
virtual Device_capability acquire_device(String const &name) = 0;
/**
* Free server-internal data structures representing the device
*
* Use this method to relax the resource-allocation of the Platform session.
*/
virtual void release_device(Device_capability device) = 0;
/**
* Allocate memory suitable for DMA.
*/
virtual Ram_dataspace_capability alloc_dma_buffer(size_t) = 0;
/**
* Free previously allocated DMA memory
*/
virtual void free_dma_buffer(Ram_dataspace_capability) = 0;
/**
* Return the bus address of the previously allocated DMA memory
*/
virtual addr_t bus_addr_dma_buffer(Ram_dataspace_capability) = 0;
/*********************
** RPC declaration **
*********************/
GENODE_RPC(Rpc_devices_rom, Rom_session_capability, devices_rom);
GENODE_RPC_THROW(Rpc_acquire_device, Device_capability, acquire_device,
GENODE_TYPE_LIST(Out_of_ram, Out_of_caps),
String const &);
GENODE_RPC(Rpc_release_device, void, release_device, Device_capability);
GENODE_RPC_THROW(Rpc_alloc_dma_buffer, Ram_dataspace_capability,
alloc_dma_buffer,
GENODE_TYPE_LIST(Out_of_ram, Out_of_caps, Fatal), size_t);
GENODE_RPC(Rpc_free_dma_buffer, void, free_dma_buffer,
Ram_dataspace_capability);
GENODE_RPC(Rpc_bus_addr_dma_buffer, addr_t, bus_addr_dma_buffer,
Ram_dataspace_capability);
GENODE_RPC_INTERFACE(Rpc_devices_rom, Rpc_acquire_device, Rpc_release_device,
Rpc_alloc_dma_buffer, Rpc_free_dma_buffer,
Rpc_bus_addr_dma_buffer);
};
#endif /* _INCLUDE__SPEC__ARM__PLATFORM_SESSION__PLATFORM_SESSION_H_ */

View File

@ -0,0 +1,35 @@
/*
* \brief Connection to platform service
* \author Stefan Kalkowski
* \date 2013-04-29
*/
/*
* Copyright (C) 2013-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.
*/
#ifndef _INCLUDE__SPEC__IMX53__PLATFORM_SESSION__CONNECTION_H_
#define _INCLUDE__SPEC__IMX53__PLATFORM_SESSION__CONNECTION_H_
#include <platform_session/client.h>
#include <util/arg_string.h>
#include <base/connection.h>
namespace Platform { struct Connection; }
struct Platform::Connection : Genode::Connection<Session>, Client
{
/**
* Constructor
*/
Connection(Genode::Env &env)
: Genode::Connection<Session>(env, session(env.parent(),
"ram_quota=6K, cap_quota=%u", CAP_QUOTA)),
Client(cap()) { }
};
#endif /* _INCLUDE__SPEC__IMX53__PLATFORM_SESSION__CONNECTION_H_ */

View File

@ -11,14 +11,14 @@
* under the terms of the GNU Affero General Public License version 3. * under the terms of the GNU Affero General Public License version 3.
*/ */
#ifndef _INCLUDE__PLATFORM_SESSION__CONNECTION_H_ #ifndef _INCLUDE__SPEC__RPI__PLATFORM_SESSION__CONNECTION_H_
#define _INCLUDE__PLATFORM_SESSION__CONNECTION_H_ #define _INCLUDE__SPEC__RPI__PLATFORM_SESSION__CONNECTION_H_
#include <platform_session/client.h> #include <platform_session/client.h>
#include <util/arg_string.h> #include <util/arg_string.h>
#include <base/connection.h> #include <base/connection.h>
namespace Platform { class Connection; } namespace Platform { struct Connection; }
struct Platform::Connection : Genode::Connection<Session>, Client struct Platform::Connection : Genode::Connection<Session>, Client
@ -28,8 +28,8 @@ struct Platform::Connection : Genode::Connection<Session>, Client
*/ */
Connection(Genode::Env &env) Connection(Genode::Env &env)
: Genode::Connection<Session>(env, session(env.parent(), : Genode::Connection<Session>(env, session(env.parent(),
"ram_quota=6K, cap_quota=%ld", CAP_QUOTA)), "ram_quota=6K, cap_quota=%u", CAP_QUOTA)),
Client(cap()) { } Client(cap()) { }
}; };
#endif /* _INCLUDE__PLATFORM_SESSION__CONNECTION_H_ */ #endif /* _INCLUDE__SPEC__RPI__PLATFORM_SESSION__CONNECTION_H_ */

View File

@ -38,7 +38,7 @@ struct Platform::Session : Genode::Session
*/ */
static const char *service_name() { return "Platform"; } static const char *service_name() { return "Platform"; }
enum { CAP_QUOTA = 2 }; enum { RAM_QUOTA = 16 * 1024, CAP_QUOTA = 2 };
virtual ~Session() { } virtual ~Session() { }

View File

@ -1,9 +1,11 @@
INCLUDE_SUB_DIRS := platform_session \ INCLUDE_SUB_DIRS := platform_session \
platform_device \
spec/arm/platform_session \
spec/arm/platform_device \
spec/imx53/platform_session \ spec/imx53/platform_session \
spec/rpi/platform \ spec/rpi/platform \
spec/rpi/platform_session \ spec/rpi/platform_session \
spec/x86/platform_session \ spec/x86/platform_session \
platform_device \
spec/x86/platform_device spec/x86/platform_device
INCLUDE_DIRS := $(addprefix include/,$(INCLUDE_SUB_DIRS)) INCLUDE_DIRS := $(addprefix include/,$(INCLUDE_SUB_DIRS))

View File

@ -0,0 +1,162 @@
/*
* \brief Platform driver - Device abstraction
* \author Stefan Kalkowski
* \date 2020-04-30
*/
/*
* 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 <device.h>
#include <session_component.h>
Driver::Device::Name Driver::Device::name() const { return _name; }
bool Driver::Device::acquire(Session_component & sc)
{
using namespace Genode;
if (_session.valid() && _session != sc.label()) { return false; }
/**
* FIXME: By now, we cannot use the connection objects for IRQ and
* IOMEM and propagate missing resources when opening the
* sessions, because the combination of Genode::Env and
* Genode::Connection object transparently does quota upgrades.
* If we like to account those costs per client, we actually
* need to explicitely forward exceptions during session
* requests.
* For now, we try to measure the probable costs.
*/
Cap_quota_guard::Reservation caps(sc.cap_quota_guard(),
Cap_quota{_cap_quota_required()});
Ram_quota_guard::Reservation ram(sc.ram_quota_guard(),
Ram_quota{_ram_quota_required()});
_session = sc.label();
caps.acknowledge();
ram.acknowledge();
return true;
}
void Driver::Device::release(Session_component & sc)
{
if (_session != sc.label()) { return; }
sc.replenish(Genode::Cap_quota{_cap_quota_required()});
sc.replenish(Genode::Ram_quota{_ram_quota_required()});
_io_mem_list.for_each([&] (Io_mem & io_mem) {
if (io_mem.io_mem) {
Genode::destroy(sc.heap(), io_mem.io_mem);
}
});
_irq_list.for_each([&] (Irq & irq) {
if (irq.irq) {
Genode::destroy(sc.heap(), irq.irq);
}
});
_session = Platform::Session::Label();;
}
Genode::Irq_session_capability Driver::Device::irq(unsigned idx,
Session_component & sc)
{
Genode::Irq_session_capability cap;
if (_session != sc.label()) { return cap; }
unsigned i = 0;
_irq_list.for_each([&] (Irq & irq)
{
if (i++ != idx) return;
if (!irq.irq) {
irq.irq = new (sc.heap())
Genode::Irq_connection(sc.env(), irq.number);
}
cap = irq.irq->cap();
});
return cap;
}
Genode::Io_mem_session_capability
Driver::Device::io_mem(unsigned idx, Genode::Cache_attribute attr,
Session_component & sc)
{
Genode::Io_mem_session_capability cap;
if (_session != sc.label()) return cap;
unsigned i = 0;
_io_mem_list.for_each([&] (Io_mem & io_mem)
{
if (i++ != idx) return;
if (!io_mem.io_mem) {
io_mem.io_mem = new (sc.heap())
Genode::Io_mem_connection(sc.env(), io_mem.base, io_mem.size,
(attr == Genode::WRITE_COMBINED));
}
cap = io_mem.io_mem->cap();
});
return cap;
}
void Driver::Device::report(Genode::Xml_generator & xml)
{
xml.node("device", [&] () {
xml.attribute("name", name());
_property_list.for_each([&] (Property & p) {
xml.node("property", [&] () {
xml.attribute("name", p.name);
xml.attribute("value", p.value);
});
});
});
}
Genode::size_t Driver::Device::_cap_quota_required()
{
Genode::size_t total = 0;
_io_mem_list.for_each([&] (Io_mem &) {
total += Genode::Io_mem_session::CAP_QUOTA; });
return total;
}
Genode::size_t Driver::Device::_ram_quota_required()
{
Genode::size_t total = 0;
_io_mem_list.for_each([&] (Io_mem & io_mem) {
total += io_mem.size + 2*1024; });
return total;
}
Driver::Device::Device(Name name)
: _name(name) { }
Driver::Device::~Device()
{
if (_session.valid()) {
Genode::error("Device to be destroyed, still obtained by session ",
_session);
}
}

View File

@ -0,0 +1,144 @@
/*
* \brief Platform driver - Device abstraction
* \author Stefan Kalkowski
* \date 2020-04-30
*/
/*
* 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.
*/
#ifndef _SRC__DRIVERS__PLATFORM__SPEC__ARM__DEVICE_H_
#define _SRC__DRIVERS__PLATFORM__SPEC__ARM__DEVICE_H_
#include <base/allocator.h>
#include <io_mem_session/connection.h>
#include <irq_session/connection.h>
#include <platform_session/platform_session.h>
#include <util/list.h>
#include <util/list_model.h>
#include <util/reconstructible.h>
#include <util/xml_generator.h>
namespace Driver {
class Device;
struct Device_model;
class Session_component;
}
class Driver::Device : public Genode::List_model<Device>::Element
{
public:
struct Io_mem : Genode::List_model<Io_mem>::Element
{
Genode::addr_t base;
Genode::size_t size;
Genode::Io_mem_connection * io_mem { nullptr };
Io_mem(Genode::addr_t base, Genode::size_t size)
: base(base), size(size) {}
};
struct Irq : Genode::List_model<Irq>::Element
{
unsigned number;
Genode::Irq_connection * irq { nullptr };
Irq(unsigned number) : number(number) {}
};
struct Property : Genode::List_model<Property>::Element
{
using Name = Genode::String<64>;
using Value = Genode::String<64>;
Name name;
Value value;
Property(Name name, Value value)
: name(name), value(value) {}
};
using Name = Genode::String<64>;
Device(Name name);
~Device();
Name name() const;
bool acquire(Session_component &);
void release(Session_component &);
Genode::Irq_session_capability irq(unsigned idx,
Session_component & session);
Genode::Io_mem_session_capability io_mem(unsigned idx,
Genode::Cache_attribute,
Session_component & session);
void report(Genode::Xml_generator &);
private:
Genode::size_t _cap_quota_required();
Genode::size_t _ram_quota_required();
friend class Driver::Device_model;
Name _name;
Platform::Session::Label _session {};
Genode::List_model<Io_mem> _io_mem_list {};
Genode::List_model<Irq> _irq_list {};
Genode::List_model<Property> _property_list {};
/*
* Noncopyable
*/
Device(Device const &);
Device &operator = (Device const &);
};
class Driver::Device_model :
public Genode::List_model<Device>::Update_policy
{
private:
Genode::Allocator & _alloc;
Genode::List_model<Device> _model {};
public:
void update(Genode::Xml_node const & node) {
_model.update_from_xml(*this, node);
}
Device_model(Genode::Allocator & alloc,
Genode::Xml_node const & node)
: _alloc(alloc) { update(node); }
~Device_model() {
_model.destroy_all_elements(*this); }
template <typename FN>
void for_each(FN const & fn) { _model.for_each(fn); }
/***********************
** Update_policy API **
***********************/
void destroy_element(Device & device);
Device & create_element(Genode::Xml_node node);
void update_element(Device & device, Genode::Xml_node node);
static bool element_matches_xml_node(Device const &,
Genode::Xml_node);
static bool node_is_element(Genode::Xml_node);
};
#endif /* _SRC__DRIVERS__PLATFORM__SPEC__ARM__DEVICE_H_ */

View File

@ -0,0 +1,75 @@
/*
* \brief Platform driver for ARM device component
* \author Stefan Kalkowski
* \date 2020-04-20
*/
/*
* 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 <device.h>
#include <device_component.h>
#include <session_component.h>
using Driver::Device_component;
Driver::Device::Name Device_component::device() const { return _device; }
Driver::Session_component & Device_component::session() { return _session; }
bool Driver::Device_component::acquire()
{
bool acquired = false;
_session.devices().for_each([&] (Driver::Device & device) {
if (device.name() == _device) {
acquired = device.acquire(_session); }});
return acquired;
}
void Driver::Device_component::release()
{
_session.devices().for_each([&] (Driver::Device & device) {
if (device.name() == _device) { device.release(_session); }});
}
Genode::Io_mem_session_capability
Device_component::io_mem(unsigned idx, Genode::Cache_attribute attr)
{
Genode::Io_mem_session_capability cap;
_session.devices().for_each([&] (Driver::Device & device) {
if (device.name() == _device) {
cap = device.io_mem(idx, attr, _session); }});
return cap;
}
Genode::Irq_session_capability Device_component::irq(unsigned idx)
{
Genode::Irq_session_capability cap;
_session.devices().for_each([&] (Driver::Device & device) {
if (device.name() == _device) { cap = device.irq(idx, _session); }});
return cap;
}
void Driver::Device_component::report(Genode::Xml_generator & xml)
{
_session.devices().for_each([&] (Driver::Device & device) {
if (device.name() == _device) { device.report(xml); }});
}
Device_component::Device_component(Driver::Session_component & session,
Driver::Device::Name const device)
: _session(session), _device(device) { }
Device_component::~Device_component() { release(); }

View File

@ -0,0 +1,71 @@
/*
* \brief Platform driver for ARM device component
* \author Stefan Kalkowski
* \date 2020-04-20
*/
/*
* 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.
*/
#ifndef _SRC__DRIVERS__PLATFORM__SPEC__ARM__DEVICE_COMPONENT_H_
#define _SRC__DRIVERS__PLATFORM__SPEC__ARM__DEVICE_COMPONENT_H_
#include <base/rpc_server.h>
#include <platform_session/platform_session.h>
#include <platform_device/platform_device.h>
#include <device.h>
namespace Driver {
class Device_component;
class Session_component;
}
class Driver::Device_component : public Genode::Rpc_object<Platform::Device>
{
public:
Device_component(Session_component & session,
Driver::Device::Name const device);
~Device_component();
Driver::Device::Name device() const;
Session_component & session();
bool acquire();
void release();
void report(Genode::Xml_generator&);
/**************************
** Platform::Device API **
**************************/
Genode::Irq_session_capability irq(unsigned) override;
Genode::Io_mem_session_capability
io_mem(unsigned, Genode::Cache_attribute) override;
private:
friend class Session_component;
Session_component & _session;
Driver::Device::Name const _device;
Platform::Device_capability _cap {};
Genode::List_element<Device_component> _list_elem { this };
/*
* Noncopyable
*/
Device_component(Device_component const &);
Device_component &operator = (Device_component const &);
};
#endif /* _SRC__DRIVERS__PLATFORM__SPEC__ARM__DEVICE_COMPONENT_H_ */

View File

@ -0,0 +1,169 @@
/*
* \brief Platform driver - Device model policy
* \author Stefan Kalkowski
* \date 2020-05-13
*/
/*
* 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 <device.h>
using Driver::Device_model;
using Driver::Device;
struct Irq_update_policy : Genode::List_model<Device::Irq>::Update_policy
{
Genode::Allocator & alloc;
Irq_update_policy(Genode::Allocator & alloc) : alloc(alloc) {}
void destroy_element(Element & irq) {
Genode::destroy(alloc, &irq); }
Element & create_element(Genode::Xml_node node)
{
unsigned number = node.attribute_value<unsigned>("number", 0);
return *(new (alloc) Element(number));
}
void update_element(Element &, Genode::Xml_node) {}
static bool element_matches_xml_node(Element const & irq, Genode::Xml_node node)
{
unsigned number = node.attribute_value<unsigned>("number", 0);
return number == irq.number;
}
static bool node_is_element(Genode::Xml_node node)
{
using Name = Genode::String<16>;
return node.has_type("resource") &&
(node.attribute_value("name", Name()) == "IRQ");
}
};
struct Io_mem_update_policy : Genode::List_model<Device::Io_mem>::Update_policy
{
Genode::Allocator & alloc;
Io_mem_update_policy(Genode::Allocator & alloc) : alloc(alloc) {}
void destroy_element(Element & iomem) {
Genode::destroy(alloc, &iomem); }
Element & create_element(Genode::Xml_node node)
{
Genode::addr_t base = node.attribute_value<Genode::addr_t>("address", 0);
Genode::size_t size = node.attribute_value<Genode::size_t>("size", 0);
return *(new (alloc) Element(base, size));
}
void update_element(Element &, Genode::Xml_node) {}
static bool element_matches_xml_node(Element const & iomem, Genode::Xml_node node)
{
Genode::addr_t base = node.attribute_value<Genode::addr_t>("address", 0);
Genode::size_t size = node.attribute_value<Genode::size_t>("size", 0);
return (base == iomem.base) && (size == iomem.size);
}
static bool node_is_element(Genode::Xml_node node)
{
bool iomem = node.attribute_value("name", Genode::String<16>())
== "IO_MEM";
return node.has_type("resource") && iomem;
}
};
struct Property_update_policy : Genode::List_model<Device::Property>::Update_policy
{
Genode::Allocator & alloc;
Property_update_policy(Genode::Allocator & alloc) : alloc(alloc) {}
void destroy_element(Element & p) {
Genode::destroy(alloc, &p); }
Element & create_element(Genode::Xml_node node)
{
return *(new (alloc)
Element(node.attribute_value("name", Element::Name()),
node.attribute_value("value", Element::Value())));
}
void update_element(Element &, Genode::Xml_node) {}
static bool element_matches_xml_node(Element const & prop, Genode::Xml_node node)
{
Element::Name n = node.attribute_value("name", Element::Name());
Element::Value v = node.attribute_value("value", Element::Value());
return (n == prop.name) && (v == prop.value);
}
static bool node_is_element(Genode::Xml_node node) {
return node.has_type("property"); }
};
void Device_model::destroy_element(Device & device)
{
{
Irq_update_policy policy(_alloc);
device._irq_list.destroy_all_elements(policy);
}
{
Io_mem_update_policy policy(_alloc);
device._io_mem_list.destroy_all_elements(policy);
}
{
Property_update_policy policy(_alloc);
device._property_list.destroy_all_elements(policy);
}
Genode::destroy(_alloc, &device);
}
Device & Device_model::create_element(Genode::Xml_node node)
{
Device::Name name = node.attribute_value("name", Device::Name());
return *(new (_alloc) Device(name));
}
void Device_model::update_element(Device & device,
Genode::Xml_node node)
{
{
Irq_update_policy policy(_alloc);
device._irq_list.update_from_xml(policy, node);
}
{
Io_mem_update_policy policy(_alloc);
device._io_mem_list.update_from_xml(policy, node);
}
{
Property_update_policy policy(_alloc);
device._property_list.update_from_xml(policy, node);
}
}
bool Device_model::element_matches_xml_node(Device const & dev,
Genode::Xml_node n) {
return dev.name() == n.attribute_value("name", Device::Name()); }
bool Device_model::node_is_element(Genode::Xml_node node) {
return node.has_type("device"); }

View File

@ -0,0 +1,53 @@
/*
* \brief Platform driver for ARM
* \author Stefan Kalkowski
* \date 2020-04-12
*/
/*
* 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 <base/component.h>
#include <base/env.h>
#include <base/heap.h>
#include <root.h>
namespace Driver { struct Main; };
struct Driver::Main
{
void update_config();
Genode::Env & env;
Genode::Heap heap { env.ram(), env.rm() };
Genode::Sliced_heap sliced_heap { env.ram(), env.rm() };
Genode::Attached_rom_dataspace config { env, "config" };
Genode::Signal_handler<Main> config_handler { env.ep(), *this,
&Main::update_config };
Driver::Device_model devices { heap, config.xml() };
Driver::Root root { env, sliced_heap,
config, devices };
Main(Genode::Env &env)
: env(env)
{
config.sigh(config_handler);
env.parent().announce(env.ep().manage(root));
}
};
void Driver::Main::update_config()
{
config.update();
devices.update(config.xml());
root.update_policy();
}
void Component::construct(Genode::Env &env) {
static Driver::Main main(env); }

View File

@ -0,0 +1,89 @@
/*
* \brief Platform driver for ARM root component
* \author Stefan Kalkowski
* \date 2020-04-13
*/
/*
* 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 <root.h>
void Driver::Root::update_policy()
{
_sessions.for_each([&] (Session_component & sc) {
bool policy_changed = false;
unsigned device_count = 0;
try {
Genode::Session_policy const policy { sc._label, _config.xml() };
policy.for_each_sub_node("device", [&] (Genode::Xml_node node) {
device_count++;
if (!sc.has_device(node.attribute_value("name",
Device::Name()))) {
policy_changed = true; }
});
if (device_count != sc.devices_count()) { policy_changed = true; }
}
catch (Genode::Session_policy::No_policy_defined) {
policy_changed = true;
Genode::error("No matching policy for '", sc._label.string(),
"' anymore, will close the session!");
}
if (policy_changed) { close(sc.cap()); }
});
}
Driver::Session_component * Driver::Root::_create_session(const char *args)
{
using namespace Genode;
Session_component * sc = nullptr;
try {
sc = new (md_alloc()) Session_component(_env,
_devices,
_sessions,
session_label_from_args(args),
session_resources_from_args(args),
session_diag_from_args(args));
Session_policy const policy { sc->_label, _config.xml() };
policy.for_each_sub_node("device", [&] (Xml_node node) {
sc->add(node.attribute_value("name", Driver::Device::Name())); });
} catch (Session_policy::No_policy_defined) {
if (sc) { Genode::destroy(md_alloc(), sc); }
error("Invalid session request, no matching policy for ",
"'", Genode::label_from_args(args).string(), "'");
throw Service_denied();
} catch (...) {
if (sc) { Genode::destroy(md_alloc(), sc); }
throw;
}
return sc;
}
void Driver::Root::_upgrade_session(Session_component * sc, const char * args)
{
sc->upgrade(Genode::ram_quota_from_args(args));
sc->upgrade(Genode::cap_quota_from_args(args));
}
Driver::Root::Root(Genode::Env & env,
Genode::Allocator & alloc,
Genode::Attached_rom_dataspace & config,
Driver::Device_model & devices)
: Genode::Root_component<Session_component>(env.ep(), alloc),
_env(env), _config(config), _devices(devices) { }

View File

@ -0,0 +1,49 @@
/*
* \brief Platform driver for ARM root component
* \author Stefan Kalkowski
* \date 2020-04-13
*/
/*
* 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.
*/
#ifndef _SRC__DRIVERS__PLATFORM__SPEC__ARM__ROOT_H_
#define _SRC__DRIVERS__PLATFORM__SPEC__ARM__ROOT_H_
#include <base/attached_rom_dataspace.h>
#include <base/registry.h>
#include <root/component.h>
#include <session_component.h>
#include <device.h>
namespace Driver { class Root; }
class Driver::Root : public Genode::Root_component<Driver::Session_component>
{
public:
Root(Genode::Env & env,
Genode::Allocator & alloc,
Genode::Attached_rom_dataspace & config,
Device_model & devices);
void update_policy();
private:
Session_component * _create_session(const char * args) override;
void _upgrade_session(Session_component *, const char *) override;
Genode::Env & _env;
Genode::Attached_rom_dataspace & _config;
Driver::Device_model & _devices;
Genode::Registry<Session_component> _sessions {};
};
#endif /* _SRC__DRIVERS__PLATFORM__SPEC__ARM__ROOT_H_ */

View File

@ -0,0 +1,198 @@
/*
* \brief Platform driver - session component
* \author Stefan Kalkowski
* \date 2020-04-13
*/
/*
* 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 <dataspace/client.h>
#include <device.h>
#include <session_component.h>
using Driver::Session_component;
void Session_component::produce_xml(Genode::Xml_generator &xml)
{
for (Device_list_element * e = _device_list.first(); e; e = e->next()) {
e->object()->report(xml); }
}
Genode::Heap & Session_component::heap() { return _md_alloc; }
Genode::Env & Session_component::env() { return _env; }
Driver::Device_model & Session_component::devices() { return _device_model; }
void Session_component::add(Device::Name const & device)
{
if (has_device(device)) return;
Device_component * new_dc =
new (_md_alloc) Device_component(*this, device);
Device_list_element * last = nullptr;
for (last = _device_list.first(); last; last = last->next()) {
if (!last->next()) break; }
_device_list.insert(&new_dc->_list_elem, last);
}
bool Session_component::has_device(Device::Name const & device) const
{
for (Device_list_element const * e = _device_list.first(); e;
e = e->next()) {
if (e->object()->device() == device) { return true; }
}
return false;
}
unsigned Session_component::devices_count() const
{
unsigned counter = 0;
for (Device_list_element const * e = _device_list.first();
e; e = e->next()) { counter++; }
return counter;
}
Genode::Rom_session_capability Session_component::devices_rom() {
return _rom_session.cap(); }
Platform::Device_capability
Session_component::acquire_device(Platform::Session::String const &name)
{
for (Device_list_element * e = _device_list.first(); e; e = e->next()) {
if (e->object()->device() != name.string()) { continue; }
if (!e->object()->acquire()) {
Genode::error("Device ", e->object()->device(),
" already acquired!");
break;
}
/* account one device capability needed */
_cap_quota_guard().replenish(Genode::Cap_quota{1});
return _env.ep().rpc_ep().manage(e->object());
}
return Platform::Device_capability();
}
void Session_component::release_device(Platform::Device_capability device_cap)
{
_env.ep().rpc_ep().apply(device_cap, [&] (Device_component * dc) {
_env.ep().rpc_ep().dissolve(dc);
_cap_quota_guard().replenish(Genode::Cap_quota{1});
dc->release();
});
}
Genode::Ram_dataspace_capability
Session_component::alloc_dma_buffer(Genode::size_t const size)
{
Genode::Ram_dataspace_capability ram_cap =
_env_ram.alloc(size, Genode::UNCACHED);
if (!ram_cap.valid()) return ram_cap;
try {
_buffer_list.insert(new (_md_alloc) Dma_buffer(ram_cap));
} catch (Genode::Out_of_ram) {
_env_ram.free(ram_cap);
throw;
} catch (Genode::Out_of_caps) {
_env_ram.free(ram_cap);
throw;
}
return ram_cap;
}
void Session_component::free_dma_buffer(Genode::Ram_dataspace_capability ram_cap)
{
if (!ram_cap.valid()) { return; }
for (Dma_buffer * buf = _buffer_list.first(); buf; buf = buf->next()) {
if (buf->cap.local_name() != ram_cap.local_name()) continue;
_buffer_list.remove(buf);
destroy(_md_alloc, buf);
_env_ram.free(ram_cap);
return;
}
}
Genode::addr_t Session_component::bus_addr_dma_buffer(Ram_dataspace_capability ram_cap)
{
if (!ram_cap.valid()) { return 0; }
for (Dma_buffer * buf = _buffer_list.first(); buf; buf = buf->next()) {
if (buf->cap.local_name() != ram_cap.local_name()) continue;
Genode::Dataspace_client dsc(buf->cap);
return dsc.phys_addr();
}
return 0;
}
Session_component::Session_component(Genode::Env & env,
Device_model & devices,
Registry & registry,
Label const & label,
Resources const & resources,
Diag const & diag)
: Genode::Session_object<Platform::Session>(env.ep(), resources,
label, diag),
Registry::Element(registry, *this),
Genode::Dynamic_rom_session::Xml_producer("devices"),
_env(env),
_device_model(devices)
{
/*
* FIXME: As the ROM session does not propagate Out_of_*
* exceptions resp. does not account costs for the ROM
* dataspace to the client for the moment, we cannot do
* so in the dynamic rom session, and cannot use the
* constrained ram allocator within it. Therefore,
* we account the costs here until the ROM session interface
* changes.
*/
_cap_quota_guard().withdraw(Genode::Cap_quota{1});
_ram_quota_guard().withdraw(Genode::Ram_quota{5*1024});
}
Session_component::~Session_component()
{
while (_device_list.first()) {
Device_list_element * e = _device_list.first();
_device_list.remove(e);
destroy(_md_alloc, e->object());
}
/* replenish quota for rom sessions, see constructor for explanation */
_cap_quota_guard().replenish(Genode::Cap_quota{1});
_ram_quota_guard().replenish(Genode::Ram_quota{5*1024});
}

View File

@ -0,0 +1,123 @@
/*
* \brief Platform driver - session component
* \author Stefan Kalkowski
* \date 2020-04-13
*/
/*
* 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.
*/
#ifndef _SRC__DRIVERS__PLATFORM__SPEC__ARM__SESSION_COMPONENT_H_
#define _SRC__DRIVERS__PLATFORM__SPEC__ARM__SESSION_COMPONENT_H_
#include <base/env.h>
#include <base/heap.h>
#include <base/quota_guard.h>
#include <base/registry.h>
#include <base/session_object.h>
#include <os/dynamic_rom_session.h>
#include <os/session_policy.h>
#include <platform_session/platform_session.h>
#include <device_component.h>
namespace Driver {
class Session_component;
class Root;
}
class Driver::Session_component :
public Genode::Session_object<Platform::Session>,
private Genode::Registry<Driver::Session_component>::Element,
private Genode::Dynamic_rom_session::Xml_producer
{
public:
using Registry = Genode::Registry<Session_component>;
Session_component(Genode::Env & env,
Device_model & devices,
Registry & registry,
Label const & label,
Resources const & resources,
Diag const & diag);
~Session_component();
Genode::Heap & heap();
Genode::Env & env();
Device_model & devices();
void add(Device::Name const &);
bool has_device(Device::Name const &) const;
unsigned devices_count() const;
Genode::Ram_quota_guard &ram_quota_guard() {
return _ram_quota_guard(); }
Genode::Cap_quota_guard &cap_quota_guard() {
return _cap_quota_guard(); }
/**************************
** Platform Session API **
**************************/
using Rom_session_capability = Genode::Rom_session_capability;
using Device_capability = Platform::Device_capability;
using Ram_dataspace_capability = Genode::Ram_dataspace_capability;
using String = Platform::Session::String;
using size_t = Genode::size_t;
Rom_session_capability devices_rom() override;
Device_capability acquire_device(String const &) override;
void release_device(Device_capability) override;
Ram_dataspace_capability alloc_dma_buffer(size_t const) override;
void free_dma_buffer(Ram_dataspace_capability ram_cap) override;
Genode::addr_t bus_addr_dma_buffer(Ram_dataspace_capability) override;
private:
friend class Root;
struct Dma_buffer : Genode::List<Dma_buffer>::Element
{
Genode::Ram_dataspace_capability const cap;
Dma_buffer(Genode::Ram_dataspace_capability const cap)
: cap(cap) {}
};
using Device_list_element = Genode::List_element<Device_component>;
using Device_list = Genode::List<Device_list_element>;
Genode::Env & _env;
Genode::Constrained_ram_allocator _env_ram { _env.pd(),
_ram_quota_guard(),
_cap_quota_guard() };
Genode::Heap _md_alloc { _env_ram, _env.rm() };
Device_list _device_list { };
Genode::List<Dma_buffer> _buffer_list { };
Genode::Dynamic_rom_session _rom_session { _env.ep(), _env.ram(),
_env.rm(), *this };
Device_model & _device_model;
/*
* Noncopyable
*/
Session_component(Session_component const &);
Session_component &operator = (Session_component const &);
/*******************************************
** Dynamic_rom_session::Xml_producer API **
*******************************************/
void produce_xml(Genode::Xml_generator &xml) override;
};
#endif /* _SRC__DRIVERS__PLATFORM__SPEC__ARM__SESSION_COMPONENT_H_ */

View File

@ -0,0 +1,5 @@
TARGET = platform_drv
REQUIRES = arm
SRC_CC = device.cc device_component.cc device_model_policy.cc main.cc session_component.cc root.cc
INC_DIR = $(PRG_DIR)
LIBS = base