platform_drv(arm): robust re-configuration support

This change of the inner working of the platform driver for ARM allows
clients to have permanent open sessions, as long as a policy node matches
the client. If devices disappear from the policy resp. from the set of
available devices (hotplug), the devices ROM of the session gets updated,
and a corresponding device session gets closed. If the device remains
untouched in the configuration but other devices appeared/disappeared, the
device session is not affected.

Ref #4330
This commit is contained in:
Stefan Kalkowski 2021-11-30 16:12:03 +01:00 committed by Norman Feske
parent 6d231597b4
commit 132e4fe815
10 changed files with 401 additions and 365 deletions

View File

@ -34,21 +34,17 @@ unsigned Driver::Rpi_device::Power_domain::id()
};
bool Driver::Rpi_device::acquire(Driver::Session_component & sc)
void Driver::Rpi_device::acquire(Driver::Session_component & sc)
{
bool ret = Driver::Device::acquire(sc);
Driver::Device::acquire(sc);
if (ret) {
_power_domain_list.for_each([&] (Power_domain & p) {
auto & msg = sc.env().mbox.message<Property_message>();
msg.append_no_response<Property_command::Set_power_state>(p.id(),
true,
true);
sc.env().mbox.call<Property_message>();
});
}
return ret;
_power_domain_list.for_each([&] (Power_domain & p) {
auto & msg = sc.env().mbox.message<Property_message>();
msg.append_no_response<Property_command::Set_power_state>(p.id(),
true,
true);
sc.env().mbox.call<Property_message>();
});
}

View File

@ -39,7 +39,7 @@ class Driver::Rpi_device : public Driver::Device
unsigned id();
};
bool acquire(Session_component &) override;
void acquire(Session_component &) override;
void release(Session_component &) override;
Rpi_device(Device::Name name, Device::Type type)

View File

@ -12,114 +12,29 @@
*/
#include <device.h>
#include <device_component.h>
#include <session_component.h>
Driver::Device::Owner::Owner(Session_component & session)
: obj_id(reinterpret_cast<void*>(&session)) {}
Driver::Device::Name Driver::Device::name() const { return _name; }
Driver::Device::Type Driver::Device::type() const { return _type; }
bool Driver::Device::acquire(Session_component & sc)
{
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;
}
Driver::Device::Owner Driver::Device::owner() const { return _owner; }
void Driver::Device::release(Session_component & sc)
{
if (_session != sc.label()) { return; }
_io_mem_list.for_each([&] (Io_mem & io_mem) {
if (io_mem.io_mem) {
destroy(sc.heap(), io_mem.io_mem);
io_mem.io_mem = nullptr;
}
});
_irq_list.for_each([&] (Irq & irq) {
if (irq.irq) {
destroy(sc.heap(), irq.irq);
irq.irq = nullptr;
}
});
_session = Platform::Session::Label();;
sc.replenish(Cap_quota{_cap_quota_required()});
sc.replenish(Ram_quota{_ram_quota_required()});
}
void Driver::Device::acquire(Session_component & sc) {
if (!_owner.valid()) _owner = sc; }
Genode::Irq_session_capability Driver::Device::irq(unsigned idx,
Session_component & sc)
{
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())
Irq_connection(sc.env().env, irq.number);
}
cap = irq.irq->cap();
});
return cap;
}
Genode::Io_mem_session_capability
Driver::Device::io_mem(unsigned idx, Range &range, Cache cache, Session_component & sc)
{
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;
range = Range { .start = io_mem.base & 0xfff,
.size = io_mem.size };
if (!io_mem.io_mem) {
io_mem.io_mem = new (sc.heap())
Io_mem_connection(sc.env().env, io_mem.base, io_mem.size,
(cache == WRITE_COMBINED));
}
cap = io_mem.io_mem->cap();
});
return cap;
}
void Driver::Device::release(Session_component & sc) {
if (_owner == sc) _owner = Owner();; }
void Driver::Device::report(Xml_generator & xml, Session_component & sc)
@ -129,8 +44,8 @@ void Driver::Device::report(Xml_generator & xml, Session_component & sc)
xml.attribute("type", type());
_io_mem_list.for_each([&] (Io_mem & io_mem) {
xml.node("io_mem", [&] () {
xml.attribute("phys_addr", String<16>(Hex(io_mem.base)));
xml.attribute("size", String<16>(Hex(io_mem.size)));
xml.attribute("phys_addr", String<16>(Hex(io_mem.range.start)));
xml.attribute("size", String<16>(Hex(io_mem.range.size)));
});
});
_irq_list.for_each([&] (Irq & irq) {
@ -149,36 +64,12 @@ void Driver::Device::report(Xml_generator & xml, Session_component & sc)
}
Genode::size_t Driver::Device::_cap_quota_required()
{
/* one cap is needed for the device component itself */
size_t total = 1;
_io_mem_list.for_each([&] (Io_mem &) {
total += Io_mem_session::CAP_QUOTA; });
_irq_list.for_each([&] (Irq &) {
total += Irq_session::CAP_QUOTA; });
return total;
}
Genode::size_t Driver::Device::_ram_quota_required()
{
size_t total = 0;
_io_mem_list.for_each([&] (Io_mem &) {
total += Io_mem_session::RAM_QUOTA; });
_irq_list.for_each([&] (Irq &) {
total += Irq_session::RAM_QUOTA; });
return total;
}
Driver::Device::Device(Name name, Type type)
: _name(name), _type(type) { }
Driver::Device::~Device()
{
if (_session.valid()) {
error("Device to be destroyed, still obtained by session ",
_session); }
if (_owner.valid()) {
error("Device to be destroyed, still obtained by session"); }
}

View File

@ -15,8 +15,6 @@
#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/device.h>
#include <util/list.h>
#include <util/list_model.h>
@ -41,20 +39,34 @@ class Driver::Device : private List_model<Device>::Element
{
public:
using Name = Genode::String<64>;
using Type = Genode::String<64>;
using Range = Platform::Device_interface::Range;
struct Owner
{
void * obj_id;
Owner() : obj_id(nullptr) {}
Owner(Session_component & session);
bool operator == (Owner const & o) const {
return obj_id == o.obj_id; }
bool valid() const {
return obj_id != nullptr; }
};
struct Io_mem : List_model<Io_mem>::Element
{
addr_t base;
size_t size;
Io_mem_connection * io_mem { nullptr };
Range range;
Io_mem(addr_t base, size_t size)
: base(base), size(size) {}
Io_mem(Range range) : range(range) {}
};
struct Irq : List_model<Irq>::Element
{
unsigned number;
Irq_connection * irq { nullptr };
unsigned number;
Irq(unsigned number) : number(number) {}
};
@ -71,22 +83,29 @@ class Driver::Device : private List_model<Device>::Element
: name(name), value(value) {}
};
using Name = Genode::String<64>;
using Type = Genode::String<64>;
using Range = Platform::Device_interface::Range;
Device(Name name, Type type);
virtual ~Device();
Name name() const;
Type type() const;
Name name() const;
Type type() const;
Owner owner() const;
virtual bool acquire(Session_component &);
virtual void acquire(Session_component &);
virtual void release(Session_component &);
Irq_session_capability irq(unsigned idx, Session_component &);
Io_mem_session_capability io_mem(unsigned idx, Range &, Cache,
Session_component &);
template <typename FN> void for_each_irq(FN const & fn)
{
unsigned idx = 0;
_irq_list.for_each([&] (Irq const & irq) {
fn(idx++, irq.number); });
}
template <typename FN> void for_each_io_mem(FN const & fn)
{
unsigned idx = 0;
_io_mem_list.for_each([&] (Io_mem const & iomem) {
fn(idx++, iomem.range); });
}
void report(Xml_generator &, Session_component &);
@ -95,19 +114,16 @@ class Driver::Device : private List_model<Device>::Element
virtual void _report_platform_specifics(Xml_generator &,
Session_component &) {}
size_t _cap_quota_required();
size_t _ram_quota_required();
friend class Driver::Device_model;
friend class List_model<Device>;
friend class List<Device>;
Name _name;
Type _type;
Platform::Session::Label _session {};
List_model<Io_mem> _io_mem_list {};
List_model<Irq> _irq_list {};
List_model<Property> _property_list {};
Name _name;
Type _type;
Owner _owner {};
List_model<Io_mem> _io_mem_list {};
List_model<Irq> _irq_list {};
List_model<Property> _property_list {};
/*
* Noncopyable
@ -201,18 +217,18 @@ struct Driver::Io_mem_update_policy : Genode::List_model<Device::Io_mem>::Update
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));
Device::Range range { node.attribute_value<Genode::addr_t>("address", 0),
node.attribute_value<Genode::size_t>("size", 0) };
return *(new (alloc) Element(range));
}
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);
Device::Range range { node.attribute_value<Genode::addr_t>("address", 0),
node.attribute_value<Genode::size_t>("size", 0) };
return (range.start == iomem.range.start) && (range.size == iomem.range.size);
}
static bool node_is_element(Genode::Xml_node node)

View File

@ -17,36 +17,47 @@
using Driver::Device_component;
void Driver::Device_component::_release_resources()
{
_io_mem_registry.for_each([&] (Io_mem & iomem) {
destroy(_session.heap(), &iomem); });
_irq_registry.for_each([&] (Irq & irq) {
destroy(_session.heap(), &irq); });
_session.ram_quota_guard().replenish(Ram_quota{_ram_quota});
_session.cap_quota_guard().replenish(Cap_quota{_cap_quota});
}
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.env().devices.for_each([&] (Driver::Device & device) {
if (device.name() == _device) {
acquired = device.acquire(_session); }});
return acquired;
}
void Driver::Device_component::release()
{
_session.env().devices.for_each([&] (Driver::Device & device) {
if (device.name() == _device) { device.release(_session); }});
}
Genode::Io_mem_session_capability
Device_component::io_mem(unsigned idx, Range &range, Cache cache)
{
Io_mem_session_capability cap;
_session.env().devices.for_each([&] (Driver::Device & device) {
if (device.name() == _device) {
cap = device.io_mem(idx, range, cache, _session); }});
_io_mem_registry.for_each([&] (Io_mem & iomem)
{
if (iomem.idx != idx)
return;
if (!iomem.io_mem.constructed())
iomem.io_mem.construct(_session.env().env,
iomem.range.start,
iomem.range.size,
cache == WRITE_COMBINED);
range = iomem.range;
range.start &= 0xfff;
cap = iomem.io_mem->cap();
});
return cap;
}
@ -54,22 +65,64 @@ Device_component::io_mem(unsigned idx, Range &range, Cache cache)
Genode::Irq_session_capability Device_component::irq(unsigned idx)
{
Irq_session_capability cap;
_session.env().devices.for_each([&] (Driver::Device & device) {
if (device.name() == _device) { cap = device.irq(idx, _session); }});
_irq_registry.for_each([&] (Irq & irq)
{
if (irq.idx != idx)
return;
if (!irq.irq.constructed())
irq.irq.construct(_session.env().env, irq.number);
cap = irq.irq->cap();
});
return cap;
}
void Driver::Device_component::report(Xml_generator & xml)
Device_component::Device_component(Registry<Device_component> & registry,
Driver::Session_component & session,
Driver::Device & device)
: _session(session), _device(device.name()), _reg_elem(registry, *this)
{
_session.env().devices.for_each([&] (Driver::Device & device) {
if (device.name() == _device) { device.report(xml, _session); }});
session.cap_quota_guard().withdraw(Cap_quota{1});
_cap_quota += 1;
/**
* 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.
*/
try {
device.for_each_irq([&] (unsigned idx, unsigned nr)
{
session.ram_quota_guard().withdraw(Ram_quota{Irq_session::RAM_QUOTA});
_ram_quota += Irq_session::RAM_QUOTA;
session.cap_quota_guard().withdraw(Cap_quota{Irq_session::CAP_QUOTA});
_cap_quota += Irq_session::CAP_QUOTA;
new (session.heap()) Irq(_irq_registry, idx, nr);
});
device.for_each_io_mem([&] (unsigned idx, Range range)
{
session.ram_quota_guard().withdraw(Ram_quota{Io_mem_session::RAM_QUOTA});
_ram_quota += Io_mem_session::RAM_QUOTA;
session.cap_quota_guard().withdraw(Cap_quota{Io_mem_session::CAP_QUOTA});
_cap_quota += Io_mem_session::CAP_QUOTA;
new (session.heap()) Io_mem(_io_mem_registry, idx, range);
});
} catch(...) {
_release_resources();
throw;
}
}
Device_component::Device_component(Driver::Session_component & session,
Driver::Device::Name const device)
: _session(session), _device(device) { }
Device_component::~Device_component() { release(); }
Device_component::~Device_component() { _release_resources(); };

View File

@ -14,9 +14,13 @@
#ifndef _SRC__DRIVERS__PLATFORM__SPEC__ARM__DEVICE_COMPONENT_H_
#define _SRC__DRIVERS__PLATFORM__SPEC__ARM__DEVICE_COMPONENT_H_
#include <base/registry.h>
#include <base/rpc_server.h>
#include <platform_session/platform_session.h>
#include <io_mem_session/connection.h>
#include <irq_session/connection.h>
#include <platform_session/device.h>
#include <platform_session/platform_session.h>
#include <util/reconstructible.h>
#include <env.h>
#include <device.h>
@ -32,18 +36,42 @@ class Driver::Device_component : public Rpc_object<Platform::Device_interface,
{
public:
Device_component(Session_component & session,
Driver::Device::Name const device);
struct Irq : Registry<Irq>::Element
{
unsigned idx;
unsigned number;
Constructible<Irq_connection> irq {};
Irq(Registry<Irq> & registry,
unsigned idx,
unsigned number)
:
Registry<Irq>::Element(registry, *this),
idx(idx), number(number) {}
};
struct Io_mem : Registry<Io_mem>::Element
{
unsigned idx;
Range range;
Constructible<Io_mem_connection> io_mem {};
Io_mem(Registry<Io_mem> & registry,
unsigned idx,
Range range)
:
Registry<Io_mem>::Element(registry, *this),
idx(idx), range(range) {}
};
Device_component(Registry<Device_component> & registry,
Session_component & session,
Driver::Device & device);
~Device_component();
Driver::Device::Name device() const;
Session_component & session();
bool acquire();
void release();
void report(Xml_generator&);
/************************************
** Platform::Device RPC functions **
@ -54,12 +82,15 @@ class Driver::Device_component : public Rpc_object<Platform::Device_interface,
private:
friend class Session_component;
Session_component & _session;
Driver::Device::Name const _device;
size_t _cap_quota { 0 };
size_t _ram_quota { 0 };
Registry<Device_component>::Element _reg_elem;
Registry<Irq> _irq_registry {};
Registry<Io_mem> _io_mem_registry {};
Session_component & _session;
Driver::Device::Name const _device;
Capability<Platform::Device> _cap {};
List_element<Device_component> _list_elem { this };
void _release_resources();
/*
* Noncopyable

View File

@ -39,15 +39,8 @@ struct Driver::Main
void Driver::Main::update_config()
{
env.config.update();
/**
* We must perform the policy update before updating the devices since
* the former may need to release devices and its corresponding Io_mem
* and Irq connections when closing a session that is no longer supposed
* to exist. For doing so, it must access the old device model.
*/
root.update_policy();
env.devices.update(env.config.xml());
root.update_policy();
}
void Component::construct(Genode::Env &env) {

View File

@ -13,32 +13,22 @@
#include <root.h>
using Version = Driver::Session_component::Policy_version;
void Driver::Root::update_policy()
{
_sessions.for_each([&] (Session_component & sc) {
bool policy_changed = false;
unsigned device_count = 0;
_sessions.for_each([&] (Session_component & sc)
{
try {
Session_policy const policy { sc._label, _env.config.xml() };
policy.for_each_sub_node("device", [&] (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; }
sc.update_policy(policy.attribute_value("info", false),
policy.attribute_value("version", Version()));
}
catch (Session_policy::No_policy_defined) {
policy_changed = true;
error("No matching policy for '", sc._label.string(),
"' anymore, will close the session!");
close(sc.cap());
}
if (policy_changed) { close(sc.cap()); }
});
}
@ -55,10 +45,8 @@ Driver::Session_component * Driver::Root::_create_session(const char *args)
Session_component(_env, _sessions, label,
session_resources_from_args(args),
session_diag_from_args(args),
policy.attribute_value("info", false));
policy.for_each_sub_node("device", [&] (Xml_node node) {
sc->add(node.attribute_value("name", Driver::Device::Name())); });
policy.attribute_value("info", false),
policy.attribute_value("version", Version()));
} catch (Session_policy::No_policy_defined) {
error("Invalid session request, no matching policy for ",
"'", label_from_args(args).string(), "'");

View File

@ -18,11 +18,93 @@
using Driver::Session_component;
Genode::Capability<Platform::Device_interface>
Session_component::_acquire(Device & device)
{
Device_component * dc = new (heap())
Device_component(_device_registry, *this, device);
device.acquire(*this);
return _env.env.ep().rpc_ep().manage(dc);
};
void Session_component::_release_device(Device_component & dc)
{
Device::Name name = dc.device();
_env.env.ep().rpc_ep().dissolve(&dc);
destroy(heap(), &dc);
_env.devices.for_each([&] (Device & dev) {
if (name == dev.name()) dev.release(*this); });
}
void Session_component::_free_dma_buffer(Dma_buffer & buf)
{
Ram_dataspace_capability cap = buf.cap;
destroy(heap(), &buf);
_env_ram.free(cap);
}
bool Session_component::matches(Device & dev) const
{
bool ret = false;
try {
Session_policy const policy { label(), _env.config.xml() };
policy.for_each_sub_node("device", [&] (Xml_node node) {
if (dev.name() == node.attribute_value("name", Device::Name()))
ret = true;
});
} catch (Session_policy::No_policy_defined) { }
return ret;
};
void Session_component::update_policy(bool info, Policy_version version)
{
_info = info;
_version = version;
enum Device_state { AWAY, CHANGED, UNCHANGED };
_device_registry.for_each([&] (Device_component & dc) {
Device_state state = AWAY;
_env.devices.for_each([&] (Device & dev) {
if (dev.name() != dc.device())
return;
state = (dev.owner() == _owner_id) ? UNCHANGED : CHANGED;
});
if (state == UNCHANGED)
return;
if (state == AWAY)
warning("Device ", dc.device(),
" has changed, will close device session");
else
warning("Device ", dc.device(),
" unavailable, will close device session");
_release_device(dc);
});
update_devices_rom();
};
void Session_component::produce_xml(Xml_generator &xml)
{
if (!_info) { return; }
for (Device_list_element * e = _device_list.first(); e; e = e->next()) {
e->object()->report(xml); }
if (!_info)
return;
if (_version.valid())
xml.attribute("version", _version);
_env.devices.for_each([&] (Device & dev) {
if (matches(dev)) dev.report(xml, *this); });
}
@ -32,39 +114,6 @@ Genode::Heap & Session_component::heap() { return _md_alloc; }
Driver::Env & Session_component::env() { return _env; }
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;
}
void Session_component::update_devices_rom()
{
_rom_session.trigger_update();
@ -78,40 +127,59 @@ Genode::Rom_session_capability Session_component::devices_rom() {
Genode::Capability<Platform::Device_interface>
Session_component::acquire_device(Platform::Session::Device_name const &name)
{
for (Device_list_element * e = _device_list.first(); e; e = e->next()) {
if (e->object()->device() != name.string()) { continue; }
Capability<Platform::Device_interface> cap;
if (!e->object()->acquire()) {
error("Device ", e->object()->device(),
" already acquired!");
break;
}
/* Search for existing, aquired device session */
_device_registry.for_each([&] (Device_component & dc) {
if (dc.device() == name)
cap = dc.cap();
});
return _env.env.ep().rpc_ep().manage(e->object());
}
if (cap.valid())
return cap;
return Capability<Platform::Device_interface>();
_env.devices.for_each([&] (Device & dev)
{
if (dev.name() != name || !matches(dev))
return;
if (dev.owner().valid())
warning("Cannot aquire device ", name, " already in use");
else
cap = _acquire(dev);
});
return cap;
}
Genode::Capability<Platform::Device_interface>
Session_component::acquire_single_device()
{
Device_list_element * e = _device_list.first();
if (!e) { return Capability<Platform::Device_interface>(); }
Capability<Platform::Device_interface> cap;
return acquire_device(e->object()->device());
/* Search for existing, aquired device session */
_device_registry.for_each([&] (Device_component & dc) {
cap = dc.cap(); });
if (cap.valid())
return cap;
_env.devices.for_each([&] (Device & dev) {
if (matches(dev) && !dev.owner().valid())
cap = _acquire(dev); });
return cap;
}
void Session_component::release_device(Capability<Platform::Device_interface> device_cap)
{
_env.env.ep().rpc_ep().apply(device_cap, [&] (Device_component * dc) {
if (!dc)
return;
_env.env.ep().rpc_ep().dissolve(dc);
dc->release();
});
if (!device_cap.valid())
return;
_device_registry.for_each([&] (Device_component & dc) {
if (device_cap.local_name() == dc.cap().local_name())
_release_device(dc); });
}
@ -123,7 +191,7 @@ Session_component::alloc_dma_buffer(size_t const size, Cache cache)
if (!ram_cap.valid()) return ram_cap;
try {
_buffer_list.insert(new (_md_alloc) Dma_buffer(ram_cap));
new (heap()) Dma_buffer(_buffer_registry, ram_cap);
} catch (Out_of_ram) {
_env_ram.free(ram_cap);
throw;
@ -140,44 +208,41 @@ void Session_component::free_dma_buffer(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;
}
_buffer_registry.for_each([&] (Dma_buffer & buf) {
if (buf.cap.local_name() == ram_cap.local_name())
_free_dma_buffer(buf); });
}
Genode::addr_t Session_component::dma_addr(Ram_dataspace_capability ram_cap)
{
if (!ram_cap.valid()) { return 0; }
addr_t ret = 0;
for (Dma_buffer * buf = _buffer_list.first(); buf; buf = buf->next()) {
if (!ram_cap.valid())
return ret;
if (buf->cap.local_name() != ram_cap.local_name()) continue;
_buffer_registry.for_each([&] (Dma_buffer & buf) {
if (buf.cap.local_name() == ram_cap.local_name()) {
Dataspace_client dsc(buf.cap);
ret = dsc.phys_addr();
} });
Dataspace_client dsc(buf->cap);
return dsc.phys_addr();
}
return 0;
return ret;
}
Session_component::Session_component(Driver::Env & env,
Session_registry & registry,
Label const & label,
Resources const & resources,
Diag const & diag,
bool const info)
: Session_object<Platform::Session>(env.env.ep(), resources, label, diag),
Session_registry::Element(registry, *this),
Dynamic_rom_session::Xml_producer("devices"),
_env(env), _info(info)
Session_component::Session_component(Driver::Env & env,
Session_registry & registry,
Label const & label,
Resources const & resources,
Diag const & diag,
bool const info,
Policy_version const version)
:
Session_object<Platform::Session>(env.env.ep(), resources, label, diag),
Session_registry::Element(registry, *this),
Dynamic_rom_session::Xml_producer("devices"),
_env(env), _info(info), _version(version)
{
/*
* FIXME: As the ROM session does not propagate Out_of_*
@ -188,25 +253,21 @@ Session_component::Session_component(Driver::Env & env,
* we account the costs here until the ROM session interface
* changes.
*/
_cap_quota_guard().withdraw(Cap_quota{1});
_cap_quota_guard().withdraw(Cap_quota{Rom_session::CAP_QUOTA});
_ram_quota_guard().withdraw(Ram_quota{5*1024});
}
Session_component::~Session_component()
{
while (_device_list.first()) {
Device_list_element * e = _device_list.first();
release_device(e->object()->cap());
_device_list.remove(e);
destroy(_md_alloc, e->object());
}
_device_registry.for_each([&] (Device_component & dc) {
_release_device(dc); });
/* also free up dma buffers */
while (_buffer_list.first())
free_dma_buffer(_buffer_list.first()->cap);
/* free up dma buffers */
_buffer_registry.for_each([&] (Dma_buffer & buf) {
_free_dma_buffer(buf); });
/* replenish quota for rom sessions, see constructor for explanation */
_cap_quota_guard().replenish(Cap_quota{1});
_cap_quota_guard().replenish(Cap_quota{Rom_session::CAP_QUOTA});
_ram_quota_guard().replenish(Ram_quota{5*1024});
}

View File

@ -40,26 +40,29 @@ class Driver::Session_component
public:
using Session_registry = Registry<Session_component>;
using Policy_version = String<64>;
Session_component(Driver::Env & env,
Session_registry & registry,
Label const & label,
Resources const & resources,
Diag const & diag,
bool const info,
Policy_version const version);
Session_component(Driver::Env & env,
Session_registry & registry,
Label const & label,
Resources const & resources,
Diag const & diag,
bool const info);
~Session_component();
Heap & heap();
Driver::Env & env();
void add(Device::Name const &);
bool has_device(Device::Name const &) const;
unsigned devices_count() const;
void update_devices_rom();
bool matches(Device &) const;
void update_devices_rom();
Ram_quota_guard & ram_quota_guard() { return _ram_quota_guard(); }
Cap_quota_guard & cap_quota_guard() { return _cap_quota_guard(); }
void update_policy(bool info, Policy_version version);
/**************************
** Platform Session API **
@ -80,28 +83,32 @@ class Driver::Session_component
friend class Root;
struct Dma_buffer : List<Dma_buffer>::Element
struct Dma_buffer : Registry<Dma_buffer>::Element
{
Ram_dataspace_capability const cap;
Dma_buffer(Ram_dataspace_capability const cap)
: cap(cap) {}
Dma_buffer(Registry<Dma_buffer> & registry,
Ram_dataspace_capability const cap)
: Registry<Dma_buffer>::Element(registry, *this), cap(cap) {}
};
using Device_list_element = List_element<Device_component>;
using Device_list = List<Device_list_element>;
Driver::Env & _env;
Constrained_ram_allocator _env_ram { _env.env.pd(),
_ram_quota_guard(),
_cap_quota_guard() };
Heap _md_alloc { _env_ram, _env.env.rm() };
Device_list _device_list { };
List<Dma_buffer> _buffer_list { };
Dynamic_rom_session _rom_session { _env.env.ep(), _env.env.ram(),
_env.env.rm(), *this };
bool const _info;
Driver::Env & _env;
Device::Owner _owner_id { *this };
Constrained_ram_allocator _env_ram { _env.env.pd(),
_ram_quota_guard(),
_cap_quota_guard() };
Heap _md_alloc { _env_ram, _env.env.rm() };
Registry<Device_component> _device_registry { };
Registry<Dma_buffer> _buffer_registry { };
Dynamic_rom_session _rom_session { _env.env.ep(), _env.env.ram(),
_env.env.rm(), *this };
bool _info;
Policy_version _version;
Device_capability _acquire(Device & device);
void _release_device(Device_component & dc);
void _free_dma_buffer(Dma_buffer & buf);
/*
* Noncopyable
*/