/* * \brief Registry of ROM modules * \author Norman Feske * \date 2014-01-11 */ /* * Copyright (C) 2014-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 _ROM_REGISTRY_H_ #define _ROM_REGISTRY_H_ /* Genode includes */ #include #include namespace Rom { struct Registry; } struct Rom::Registry : Registry_for_reader, Registry_for_writer, Genode::Noncopyable { private: Genode::Allocator &_md_alloc; Genode::Ram_allocator &_ram; Genode::Region_map &_rm; Genode::Attached_rom_dataspace &_config_rom; Module_list _modules { }; struct Read_write_policy : Module::Read_policy, Module::Write_policy { bool read_permitted(Module const &, Writer const &, Reader const &) const override { /* * The access-control policy is applied at the ROM-session * construction time by applying the '_report_name' method * on the session label. Once connected to a ROM module, * the ROM client is always allowed to read the ROM content. */ return true; } bool write_permitted(Module const &, Writer const &) const override { /* * Because the report-session label is used as the module name * for the writer, each report session refers to a distinct * module. Report client can write to their respective modules * at any time. */ return true; } } _read_write_policy { }; Module &_lookup(Module::Name const name) { for (Module *m = _modules.first(); m; m = m->next()) if (m->_has_name(name)) return *m; /* module does not exist yet, create one */ /* XXX proper accounting for the used memory is missing */ /* XXX if we run out of memory, the server will abort */ Module * const module = new (&_md_alloc) Module(_ram, _rm, name, _read_write_policy, _read_write_policy); _modules.insert(module); return *module; } void _try_to_destroy(Module const &module) { if (module._in_use()) return; _modules.remove(&module); Genode::destroy(&_md_alloc, const_cast(&module)); } template Module &_lookup(USER &user, Module::Name const &name) { Module &module = _lookup(name); module._register(user); return module; } template void _release(USER &user, Module const &module) { /* * The '_release' function is called by both the report service * and the ROM service. The latter has merely a 'const' version * of the module because it is not supposed to modify it. However, * when closing a ROM session, we have to disassociate the ROM * session from the module. To do that, we need a non-const * reference to the module. */ const_cast(module)._unregister(user); _try_to_destroy(module); } /** * Return report name that corresponds to the given ROM session label * * \throw Registry_for_reader::Lookup_failed */ Module::Name _report_name(Module::Name const &rom_label) const { using namespace Genode; _config_rom.update(); try { Session_policy policy(rom_label, _config_rom.xml()); return policy.attribute_value("report", Module::Name()); } catch (Session_policy::No_policy_defined) { } warning("no valid policy for ROM request '", rom_label, "'"); throw Service_denied(); } public: Registry(Genode::Allocator &md_alloc, Genode::Ram_allocator &ram, Genode::Region_map &rm, Genode::Attached_rom_dataspace &config_rom) : _md_alloc(md_alloc), _ram(ram), _rm(rm), _config_rom(config_rom) { } Module &lookup(Writer &writer, Module::Name const &name) override { Module &module = _lookup(writer, name); /* * Enforce invariant that each module can have only one writer at a * time. */ if (module._num_writers() > 1) { release(writer, module); throw Genode::Service_denied(); } return module; } void release(Writer &writer, Module &module) override { return _release(writer, module); } Readable_module &lookup(Reader &reader, Module::Name const &rom_label) override { return _lookup(reader, _report_name(rom_label)); } void release(Reader &reader, Readable_module &module) override { return _release(reader, static_cast(module)); } }; #endif /* _ROM_REGISTRY_H_ */