/* * \brief ROM service * \author Norman Feske * \date 2014-01-11 */ /* * Copyright (C) 2014 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. */ #ifndef _INCLUDE__REPORT_ROM__ROM_SERVICE_H_ #define _INCLUDE__REPORT_ROM__ROM_SERVICE_H_ /* Genode includes */ #include #include #include #include #include #include namespace Rom { class Session_component; class Module_name_fn; class Root; using Genode::Xml_node; } class Rom::Session_component : public Genode::Rpc_object, public Reader { private: Registry_for_reader &_registry; Genode::Session_label const _label; Readable_module &_module; Readable_module &_init_module(Genode::Session_label const &label) { try { return _registry.lookup(*this, label.string()); } catch (Registry_for_reader::Lookup_failed) { throw Genode::Root::Invalid_args(); } } Lazy_volatile_object _ds; size_t _content_size = 0; /** * Keep state of valid content to notify the client only once when * the ROM module becomes invalid. */ bool _valid = false; Genode::Signal_context_capability _sigh; void _notify_client() { if (_sigh.valid()) Genode::Signal_transmitter(_sigh).submit(); } public: Session_component(Registry_for_reader ®istry, Genode::Session_label const &label) : _registry(registry), _label(label), _module(_init_module(label)) { } ~Session_component() { _registry.release(*this, _module); } Genode::Session_label label() const { return _label; } Genode::Rom_dataspace_capability dataspace() override { using namespace Genode; /* replace dataspace by new one */ /* XXX we could keep the old dataspace if the size fits */ _ds.construct(env()->ram_session(), _module.size()); /* fill dataspace content with report contained in module */ _content_size = _module.read_content(*this, _ds->local_addr(), _ds->size()); _valid = _content_size > 0; /* cast RAM into ROM dataspace capability */ Dataspace_capability ds_cap = static_cap_cast(_ds->cap()); return static_cap_cast(ds_cap); } bool update() override { if (!_ds.constructed() || _module.size() > _ds->size()) return false; size_t const new_content_size = _module.read_content(*this, _ds->local_addr(), _ds->size()); /* clear difference between old and new content */ if (new_content_size < _content_size) Genode::memset(_ds->local_addr() + new_content_size, 0, _content_size - new_content_size); _content_size = new_content_size; _valid = _content_size > 0; return true; } void sigh(Genode::Signal_context_capability sigh) override { _sigh = sigh; /* * Notify client initially to enforce a client-side ROM update. * Otherwise, a server-side ROM update between session creation and * signal-handler registration would go unnoticed. */ _notify_client(); } /** * Reader interface */ void notify_module_changed() override { _notify_client(); } /** * Reader interface */ void notify_module_invalidated() override { /* deliver a signal for an invalidated module only once */ if (!_valid) return; _valid = false; _notify_client(); } }; class Rom::Root : public Genode::Root_component { private: Registry_for_reader &_registry; protected: Session_component *_create_session(const char *args) override { using namespace Genode; return new (md_alloc()) Session_component(_registry, Session_label(args)); } public: Root(Server::Entrypoint &ep, Genode::Allocator &md_alloc, Registry_for_reader ®istry) : Genode::Root_component(&ep.rpc_ep(), &md_alloc), _registry(registry) { } }; #endif /* _INCLUDE__REPORT_ROM__ROM_SERVICE_H_ */