mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-20 17:52:52 +00:00
parent
8763b6925a
commit
702646a4a3
137
repos/os/run/rom_filter.run
Normal file
137
repos/os/run/rom_filter.run
Normal file
@ -0,0 +1,137 @@
|
||||
#
|
||||
# Build
|
||||
#
|
||||
|
||||
set build_components {
|
||||
core init drivers/timer
|
||||
server/dynamic_rom server/rom_filter app/rom_logger
|
||||
}
|
||||
|
||||
build $build_components
|
||||
|
||||
create_boot_directory
|
||||
|
||||
#
|
||||
# Generate config
|
||||
#
|
||||
|
||||
append config {
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="ROM"/>
|
||||
<service name="RAM"/>
|
||||
<service name="RM"/>
|
||||
<service name="LOG"/>
|
||||
<service name="IRQ"/>
|
||||
<service name="IO_MEM"/>
|
||||
<service name="IO_PORT"/>
|
||||
<service name="CAP"/>
|
||||
<service name="SIGNAL"/>
|
||||
</parent-provides>
|
||||
|
||||
<default-route>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>
|
||||
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Timer"/></provides>
|
||||
</start>
|
||||
|
||||
<start name="dynamic_rom">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides><service name="ROM"/></provides>
|
||||
<config verbose="yes">
|
||||
<rom name="xray">
|
||||
<sleep milliseconds="1000" />
|
||||
<inline description="disable X-ray mode">
|
||||
<xray enabled="no"/>
|
||||
</inline>
|
||||
<sleep milliseconds="1000" />
|
||||
<inline description="enable X-ray mode">
|
||||
<xray enabled="yes"/>
|
||||
</inline>
|
||||
<sleep milliseconds="1000" />
|
||||
<inline description="leave X-ray mode undefined">
|
||||
<xray/> <!-- undefined -->
|
||||
</inline>
|
||||
<sleep milliseconds="1000" />
|
||||
<inline description="finished"/>
|
||||
</rom>
|
||||
</config>
|
||||
</start>
|
||||
|
||||
<start name="rom_filter">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides><service name="ROM"/></provides>
|
||||
<config verbose="no">
|
||||
|
||||
<input name="xray_enabled" rom="xray" node="xray">
|
||||
<attribute name="enabled" />
|
||||
</input>
|
||||
|
||||
<output node="config">
|
||||
<if>
|
||||
<has_value input="xray_enabled" value="no" />
|
||||
<then>
|
||||
<inline><!-- .. flat window decorations ... --></inline>
|
||||
</then>
|
||||
<else>
|
||||
<if>
|
||||
<has_value input="xray_enabled" value="yes" />
|
||||
<then>
|
||||
<inline><!-- ... colored window decorations ... --></inline>
|
||||
</then>
|
||||
<else>
|
||||
<inline><!-- ... fallback ... --></inline>
|
||||
</else>
|
||||
</if>
|
||||
</else>
|
||||
</if>
|
||||
</output>
|
||||
|
||||
</config>
|
||||
<route>
|
||||
<service name="ROM"> <child name="dynamic_rom"/> </service>
|
||||
<any-service> <parent/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
|
||||
<start name="rom_logger">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<config rom="generated" />
|
||||
<route>
|
||||
<service name="ROM"> <child name="rom_filter"/> </service>
|
||||
<any-service> <parent/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
</config>}
|
||||
|
||||
install_config $config
|
||||
|
||||
#
|
||||
# Boot modules
|
||||
#
|
||||
|
||||
set boot_modules { core init timer dynamic_rom rom_filter rom_logger }
|
||||
|
||||
build_boot_image $boot_modules
|
||||
|
||||
append qemu_args " -nographic "
|
||||
|
||||
run_genode_until {.*finished.*\n} 20
|
||||
|
||||
# pay only attention to the output of the rom_logger
|
||||
grep_output {^\[init -> rom_logger}
|
||||
|
||||
compare_output_to {
|
||||
[init -> rom_logger] ROM 'generated':
|
||||
[init -> rom_logger] <config><!-- ... fallback ... --></config>
|
||||
[init -> rom_logger] ROM 'generated':
|
||||
[init -> rom_logger] <config><!-- .. flat window decorations ... --></config>
|
||||
[init -> rom_logger] ROM 'generated':
|
||||
[init -> rom_logger] <config><!-- ... colored window decorations ... --></config>
|
||||
[init -> rom_logger] ROM 'generated':
|
||||
[init -> rom_logger] <config><!-- ... fallback ... --></config>
|
||||
}
|
||||
|
46
repos/os/src/server/rom_filter/README
Normal file
46
repos/os/src/server/rom_filter/README
Normal file
@ -0,0 +1,46 @@
|
||||
The ROM filter provides a ROM module that depends on the content
|
||||
of other ROM modules. Its designated use is the dynamic switching between
|
||||
configuration variants dependent on the state of the system. For example,
|
||||
the configuration of the window decorator may be toggled depending on whether
|
||||
nitpicker's X-ray mode is active or not.
|
||||
|
||||
|
||||
Configuration
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
The configuration consists of two parts. The first part is the declaration of
|
||||
input values that are taken into the account. The input values are obtained
|
||||
from ROM modules that contain XML-formatted data. Each input value is
|
||||
represented by an '<input>' node with a unique 'name' attribute. The 'rom'
|
||||
attribute specifies the ROM module to take the input from. If not specified,
|
||||
the 'name' is used as the ROM name. The type of the top-level XML node can be
|
||||
specified via the 'node' attribute. If not present, the top-level XML node is
|
||||
expected to correspond to the 'name' attribute.
|
||||
|
||||
The second part of the configuration defines the output via an '<output>' node.
|
||||
The type of the top-level XML node must be specified via the 'node' attribute.
|
||||
The '<output>' node can contain the following sub nodes:
|
||||
|
||||
:'<inline>':
|
||||
Contains content to be written to the output.
|
||||
|
||||
:'<if>':
|
||||
Produces output depending on a condition (see below). If the condition
|
||||
is satisfied, the '<then>' sub node is evaluated. Otherwise, the '<else>'
|
||||
sub node is evaluated. Each of those sub nodes can contain the same
|
||||
nodes as the '<output>' node.
|
||||
|
||||
|
||||
Conditions
|
||||
----------
|
||||
|
||||
The '<has_value>' condition compares an input value (specified as 'input'
|
||||
attribute) with a predefined value (specified as 'value' attribute). The
|
||||
condition is satisfied if both values are equal.
|
||||
|
||||
|
||||
Example
|
||||
~~~~~~~
|
||||
|
||||
For an example that illustrates the use of the component, please refer to the
|
||||
_os/run/conditional_rom.run_ script.
|
382
repos/os/src/server/rom_filter/input_rom_registry.h
Normal file
382
repos/os/src/server/rom_filter/input_rom_registry.h
Normal file
@ -0,0 +1,382 @@
|
||||
/*
|
||||
* \brief Registry of ROM modules used as input for the condition
|
||||
* \author Norman Feske
|
||||
* \date 2015-09-21
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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 _INPUT_ROM_REGISTRY_H_
|
||||
#define _INPUT_ROM_REGISTRY_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/xml_node.h>
|
||||
#include <os/attached_rom_dataspace.h>
|
||||
#include <os/config.h>
|
||||
#include <os/attached_ram_dataspace.h>
|
||||
#include <os/server.h>
|
||||
#include <base/allocator.h>
|
||||
|
||||
namespace Rom_filter {
|
||||
|
||||
class Input_rom_registry;
|
||||
|
||||
typedef Genode::String<100> Input_rom_name;
|
||||
typedef Genode::String<100> Input_name;
|
||||
typedef Genode::String<100> Input_value;
|
||||
|
||||
typedef Genode::String<80> Node_type_name;
|
||||
typedef Genode::String<80> Attribute_name;
|
||||
|
||||
|
||||
using Genode::env;
|
||||
using Genode::Signal_context_capability;
|
||||
using Genode::Signal_rpc_member;
|
||||
using Genode::Xml_node;
|
||||
}
|
||||
|
||||
|
||||
class Rom_filter::Input_rom_registry
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Callback type
|
||||
*/
|
||||
struct Input_rom_changed_fn
|
||||
{
|
||||
virtual void input_rom_changed() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Exception type
|
||||
*/
|
||||
class Nonexistent_input_value { };
|
||||
|
||||
private:
|
||||
|
||||
class Entry : public Genode::List<Entry>::Element
|
||||
{
|
||||
private:
|
||||
|
||||
Server::Entrypoint &_ep;
|
||||
|
||||
Input_rom_name _name;
|
||||
|
||||
Input_rom_changed_fn &_input_rom_changed_fn;
|
||||
|
||||
Genode::Attached_rom_dataspace _rom_ds { _name.string() };
|
||||
|
||||
Xml_node _top_level { "<empty/>" };
|
||||
|
||||
void _handle_rom_changed(unsigned)
|
||||
{
|
||||
_rom_ds.update();
|
||||
|
||||
try {
|
||||
_top_level = Xml_node(_rom_ds.local_addr<char>());
|
||||
} catch (...) {
|
||||
_top_level = Xml_node("<empty/>");
|
||||
}
|
||||
|
||||
/* trigger re-evaluation of the inputs */
|
||||
_input_rom_changed_fn.input_rom_changed();
|
||||
}
|
||||
|
||||
Genode::Signal_rpc_member<Entry> _rom_changed_dispatcher =
|
||||
{ _ep, *this, &Entry::_handle_rom_changed };
|
||||
|
||||
/**
|
||||
* Query value from XML-structured ROM content
|
||||
*
|
||||
* \param path XML node that defines the path to the value
|
||||
* \param content XML-structured content, to which the path
|
||||
* is applied
|
||||
*/
|
||||
Input_value _query_value(Xml_node path, Xml_node content) const
|
||||
{
|
||||
for (;;) {
|
||||
|
||||
/*
|
||||
* Take value of an attribute
|
||||
*/
|
||||
if (path.has_type("attribute")) {
|
||||
|
||||
Attribute_name const attr_name =
|
||||
path.attribute_value("name", Attribute_name(""));
|
||||
|
||||
if (!content.has_attribute(attr_name.string()))
|
||||
throw Nonexistent_input_value();
|
||||
|
||||
return content.attribute_value(attr_name.string(),
|
||||
Input_value(""));
|
||||
}
|
||||
|
||||
/*
|
||||
* Follow path node
|
||||
*/
|
||||
if (path.has_type("node")) {
|
||||
|
||||
Node_type_name const sub_node_type =
|
||||
path.attribute_value("type", Node_type_name(""));
|
||||
|
||||
content = content.sub_node(sub_node_type.string());
|
||||
path = path.sub_node();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
throw Nonexistent_input_value();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the expected top-level XML node type of a given input
|
||||
*/
|
||||
static Node_type_name _top_level_node_type(Xml_node input_node)
|
||||
{
|
||||
Node_type_name const undefined("");
|
||||
|
||||
if (input_node.has_attribute("node"))
|
||||
return input_node.attribute_value("node", undefined);
|
||||
|
||||
return input_node.attribute_value("name", undefined);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Entry(Input_rom_name const &name, Server::Entrypoint &ep,
|
||||
Input_rom_changed_fn &input_rom_changed_fn)
|
||||
:
|
||||
_ep(ep), _name(name),
|
||||
_input_rom_changed_fn(input_rom_changed_fn)
|
||||
{
|
||||
_rom_ds.sigh(_rom_changed_dispatcher);
|
||||
}
|
||||
|
||||
Input_rom_name name() const { return _name; }
|
||||
|
||||
/**
|
||||
* Query input value from ROM modules
|
||||
*
|
||||
* \param input_node XML that describes the path to the
|
||||
* input value
|
||||
*
|
||||
* \throw Nonexistent_input_value
|
||||
*/
|
||||
Input_value query_value(Xml_node input_node) const
|
||||
{
|
||||
try {
|
||||
/*
|
||||
* The creation of the XML node may fail with an
|
||||
* exception if the ROM module contains non-XML data.
|
||||
*/
|
||||
Xml_node content_node(_top_level);
|
||||
|
||||
/*
|
||||
* Check type of top-level node, query value of the
|
||||
* type name matches.
|
||||
*/
|
||||
Node_type_name expected = _top_level_node_type(input_node);
|
||||
if (content_node.has_type(expected.string()))
|
||||
return _query_value(input_node.sub_node(), content_node);
|
||||
else
|
||||
PWRN("top-level node <%s> missing in input ROM %s",
|
||||
expected.string(), name().string());
|
||||
|
||||
} catch (...) { }
|
||||
|
||||
throw Nonexistent_input_value();
|
||||
}
|
||||
};
|
||||
|
||||
Genode::Allocator &_alloc;
|
||||
|
||||
Server::Entrypoint &_ep;
|
||||
|
||||
Genode::List<Entry> _input_roms;
|
||||
|
||||
Input_rom_changed_fn &_input_rom_changed_fn;
|
||||
|
||||
/**
|
||||
* Apply functor for each input ROM
|
||||
*
|
||||
* The functor is called with 'Input &' as argument.
|
||||
*/
|
||||
template <typename FUNC>
|
||||
void _for_each_input_rom(FUNC const &func) const
|
||||
{
|
||||
Entry const *ir = _input_roms.first();
|
||||
Entry const *next = nullptr;
|
||||
for (; ir; ir = next) {
|
||||
|
||||
/*
|
||||
* Obtain next element prior calling the functor because
|
||||
* the functor may remove the current element from the list.
|
||||
*/
|
||||
next = ir->next();
|
||||
|
||||
func(*ir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return ROM name of specified XML node
|
||||
*/
|
||||
static inline Input_rom_name _input_rom_name(Xml_node input)
|
||||
{
|
||||
if (input.has_attribute("rom"))
|
||||
return input.attribute_value("rom", Input_rom_name(""));
|
||||
|
||||
/*
|
||||
* If no 'rom' attribute was specified, we fall back to use the
|
||||
* name of the input as ROM name.
|
||||
*/
|
||||
return input.attribute_value("name", Input_rom_name(""));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if ROM with specified name is known
|
||||
*/
|
||||
bool _input_rom_exists(Input_rom_name const &name) const
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
_for_each_input_rom([&] (Entry const &input_rom) {
|
||||
|
||||
if (input_rom.name() == name)
|
||||
result = true;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool _config_uses_input_rom(Xml_node config,
|
||||
Input_rom_name const &name)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
config.for_each_sub_node("input", [&] (Xml_node input) {
|
||||
|
||||
if (_input_rom_name(input) == name)
|
||||
result = true;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Entry const *_lookup_entry_by_name(Input_rom_name const &name) const
|
||||
{
|
||||
Entry const *entry = nullptr;
|
||||
|
||||
_for_each_input_rom([&] (Entry const &input_rom) {
|
||||
if (input_rom.name() == name)
|
||||
entry = &input_rom; });
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* \throw Nonexistent_input_value
|
||||
*/
|
||||
Input_value _query_value_in_roms(Xml_node input_node)
|
||||
{
|
||||
Entry const *entry =
|
||||
_lookup_entry_by_name(_input_rom_name(input_node));
|
||||
|
||||
try {
|
||||
if (entry)
|
||||
return entry->query_value(input_node);
|
||||
} catch (...) { }
|
||||
|
||||
throw Nonexistent_input_value();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param sigh signal context capability to install in ROM sessions
|
||||
* for the inputs
|
||||
*/
|
||||
Input_rom_registry(Genode::Allocator &alloc, Server::Entrypoint &ep,
|
||||
Input_rom_changed_fn &input_rom_changed_fn)
|
||||
:
|
||||
_alloc(alloc), _ep(ep), _input_rom_changed_fn(input_rom_changed_fn)
|
||||
{ }
|
||||
|
||||
void update_config(Xml_node config)
|
||||
{
|
||||
/*
|
||||
* Remove ROMs that are no longer present in the configuration.
|
||||
*/
|
||||
auto remove_stale_entry = [&] (Entry const &entry) {
|
||||
|
||||
if (_config_uses_input_rom(config, entry.name()))
|
||||
return;
|
||||
|
||||
_input_roms.remove(const_cast<Entry *>(&entry));
|
||||
Genode::destroy(_alloc, const_cast<Entry *>(&entry));
|
||||
};
|
||||
_for_each_input_rom(remove_stale_entry);
|
||||
|
||||
/*
|
||||
* Add new appearing ROMs.
|
||||
*/
|
||||
auto add_new_entry = [&] (Xml_node input) {
|
||||
|
||||
Input_rom_name name = _input_rom_name(input);
|
||||
|
||||
if (_input_rom_exists(name))
|
||||
return;
|
||||
|
||||
Entry *entry =
|
||||
new (_alloc) Entry(name, _ep, _input_rom_changed_fn);
|
||||
|
||||
_input_roms.insert(entry);
|
||||
};
|
||||
config.for_each_sub_node("input", add_new_entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup value of input with specified name
|
||||
*
|
||||
* \throw Nonexistent_input_value
|
||||
*/
|
||||
Input_value query_value(Xml_node config, Input_name const &input_name) const
|
||||
{
|
||||
Input_value input_value;
|
||||
bool input_value_defined = false;
|
||||
|
||||
auto handle_input_node = [&] (Xml_node input_node) {
|
||||
|
||||
if (input_node.attribute_value("name", Input_name("")) != input_name)
|
||||
return;
|
||||
|
||||
input_value = _query_value_in_roms(input_node);
|
||||
input_value_defined = true;
|
||||
};
|
||||
|
||||
try {
|
||||
config.for_each_sub_node("input", handle_input_node);
|
||||
} catch (...) {
|
||||
throw Nonexistent_input_value();
|
||||
}
|
||||
|
||||
if (!input_value_defined)
|
||||
throw Nonexistent_input_value();
|
||||
|
||||
return input_value;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _INPUT_ROM_REGISTRY_H_ */
|
344
repos/os/src/server/rom_filter/main.cc
Normal file
344
repos/os/src/server/rom_filter/main.cc
Normal file
@ -0,0 +1,344 @@
|
||||
/*
|
||||
* \brief ROM server that generates a ROM depending on other ROMs
|
||||
* \author Norman Feske
|
||||
* \date 2015-09-21
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/volatile_object.h>
|
||||
#include <util/arg_string.h>
|
||||
#include <util/xml_generator.h>
|
||||
#include <base/heap.h>
|
||||
#include <base/env.h>
|
||||
#include <root/component.h>
|
||||
|
||||
/* local includes */
|
||||
#include "input_rom_registry.h"
|
||||
|
||||
namespace Rom_filter {
|
||||
using Server::Entrypoint;
|
||||
using Genode::Rpc_object;
|
||||
using Genode::Sliced_heap;
|
||||
using Genode::env;
|
||||
using Genode::Lazy_volatile_object;
|
||||
using Genode::Xml_generator;
|
||||
using Genode::size_t;
|
||||
|
||||
class Output_buffer;
|
||||
class Session_component;
|
||||
class Root;
|
||||
struct Main;
|
||||
|
||||
typedef Genode::List<Session_component> Session_list;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Interface used by the sessions to obtain the XML output data
|
||||
*/
|
||||
struct Rom_filter::Output_buffer
|
||||
{
|
||||
virtual size_t content_size() const = 0;
|
||||
virtual size_t export_content(char *dst, size_t dst_len) const = 0;
|
||||
};
|
||||
|
||||
|
||||
class Rom_filter::Session_component : public Rpc_object<Genode::Rom_session>,
|
||||
public Session_list::Element
|
||||
{
|
||||
private:
|
||||
|
||||
Signal_context_capability _sigh;
|
||||
|
||||
Output_buffer const &_output_buffer;
|
||||
|
||||
Session_list &_sessions;
|
||||
|
||||
Lazy_volatile_object<Genode::Attached_ram_dataspace> _ram_ds;
|
||||
|
||||
public:
|
||||
|
||||
Session_component(Session_list &sessions, Output_buffer const &output_buffer)
|
||||
:
|
||||
_output_buffer(output_buffer), _sessions(sessions)
|
||||
{
|
||||
_sessions.insert(this);
|
||||
}
|
||||
|
||||
~Session_component() { _sessions.remove(this); }
|
||||
|
||||
void notify_client()
|
||||
{
|
||||
if (!_sigh.valid())
|
||||
return;
|
||||
|
||||
Genode::Signal_transmitter(_sigh).submit();
|
||||
}
|
||||
|
||||
Genode::Rom_dataspace_capability dataspace() override
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
/* replace dataspace by new one as needed */
|
||||
if (!_ram_ds.is_constructed()
|
||||
|| _output_buffer.content_size() > _ram_ds->size()) {
|
||||
|
||||
_ram_ds.construct(env()->ram_session(), _output_buffer.content_size());
|
||||
}
|
||||
|
||||
char *dst = _ram_ds->local_addr<char>();
|
||||
size_t const dst_size = _ram_ds->size();
|
||||
|
||||
/* fill with content of current evaluation result */
|
||||
size_t const copied_len = _output_buffer.export_content(dst, dst_size);
|
||||
|
||||
/* clear remainder of dataspace */
|
||||
Genode::memset(dst + copied_len, 0, dst_size - copied_len);
|
||||
|
||||
/* cast RAM into ROM dataspace capability */
|
||||
Dataspace_capability ds_cap = static_cap_cast<Dataspace>(_ram_ds->cap());
|
||||
return static_cap_cast<Rom_dataspace>(ds_cap);
|
||||
}
|
||||
|
||||
void sigh(Genode::Signal_context_capability sigh) override
|
||||
{
|
||||
_sigh = sigh;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Rom_filter::Root : public Genode::Root_component<Session_component>
|
||||
{
|
||||
private:
|
||||
|
||||
Output_buffer &_output_buffer;
|
||||
Session_list _sessions;
|
||||
|
||||
protected:
|
||||
|
||||
Session_component *_create_session(const char *args)
|
||||
{
|
||||
/*
|
||||
* We ignore the name of the ROM module requested
|
||||
*/
|
||||
return new (md_alloc()) Session_component(_sessions, _output_buffer);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Root(Entrypoint &ep, Output_buffer &output_buffer,
|
||||
Genode::Allocator &md_alloc)
|
||||
:
|
||||
Genode::Root_component<Session_component>(&ep.rpc_ep(), &md_alloc),
|
||||
_output_buffer(output_buffer)
|
||||
{ }
|
||||
|
||||
void notify_clients()
|
||||
{
|
||||
for (Session_component *s = _sessions.first(); s; s = s->next())
|
||||
s->notify_client();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Rom_filter::Main : Input_rom_registry::Input_rom_changed_fn,
|
||||
Output_buffer
|
||||
{
|
||||
Entrypoint &_ep;
|
||||
|
||||
Sliced_heap _sliced_heap = { env()->ram_session(), env()->rm_session() };
|
||||
|
||||
Input_rom_registry _input_rom_registry { *env()->heap(), _ep, *this };
|
||||
|
||||
Genode::Lazy_volatile_object<Genode::Attached_ram_dataspace> _xml_ds;
|
||||
|
||||
size_t _xml_output_len = 0;
|
||||
|
||||
void _evaluate_node(Xml_node node, Xml_generator &xml);
|
||||
void _evaluate();
|
||||
|
||||
Root _root = { _ep, *this, _sliced_heap };
|
||||
|
||||
Genode::Signal_rpc_member<Main> _config_dispatcher =
|
||||
{ _ep, *this, &Main::_handle_config };
|
||||
|
||||
void _handle_config(unsigned)
|
||||
{
|
||||
Genode::config()->reload();
|
||||
|
||||
/*
|
||||
* Create buffer for generated XML data
|
||||
*/
|
||||
Genode::Number_of_bytes xml_ds_size = 4096;
|
||||
|
||||
xml_ds_size = Genode::config()->xml_node().attribute_value("buffer", xml_ds_size);
|
||||
|
||||
if (!_xml_ds.is_constructed() || xml_ds_size != _xml_ds->size())
|
||||
_xml_ds.construct(env()->ram_session(), xml_ds_size);
|
||||
|
||||
/*
|
||||
* Obtain inputs
|
||||
*/
|
||||
try {
|
||||
_input_rom_registry.update_config(Genode::config()->xml_node());
|
||||
} catch (Xml_node::Nonexistent_sub_node) { }
|
||||
|
||||
/*
|
||||
* Generate output
|
||||
*/
|
||||
_evaluate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Input_rom_registry::Input_rom_changed_fn interface
|
||||
*
|
||||
* Called each time one of the input ROM modules changes.
|
||||
*/
|
||||
void input_rom_changed() override
|
||||
{
|
||||
_evaluate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Output_buffer interface
|
||||
*/
|
||||
size_t content_size() const override
|
||||
{
|
||||
return _xml_output_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output_buffer interface
|
||||
*/
|
||||
size_t export_content(char *dst, size_t dst_len) const
|
||||
{
|
||||
size_t const len = Genode::min(dst_len, _xml_output_len);
|
||||
Genode::memcpy(dst, _xml_ds->local_addr<char>(), len);
|
||||
return len;
|
||||
}
|
||||
|
||||
Main(Entrypoint &ep) : _ep(ep)
|
||||
{
|
||||
env()->parent()->announce(_ep.manage(_root));
|
||||
|
||||
_handle_config(0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void Rom_filter::Main::_evaluate_node(Xml_node node, Xml_generator &xml)
|
||||
{
|
||||
auto process_output_sub_node = [&] (Xml_node node) {
|
||||
|
||||
if (node.has_type("if")) {
|
||||
|
||||
/*
|
||||
* Check condition
|
||||
*/
|
||||
bool condition_satisfied = false;
|
||||
|
||||
if (node.has_sub_node("has_value")) {
|
||||
|
||||
Xml_node const has_value_node = node.sub_node("has_value");
|
||||
|
||||
Input_name const input_name =
|
||||
has_value_node.attribute_value("input", Input_name());
|
||||
|
||||
Input_value const expected_input_value =
|
||||
has_value_node.attribute_value("value", Input_value());
|
||||
|
||||
try {
|
||||
Xml_node config = Genode::config()->xml_node();
|
||||
|
||||
Input_value const input_value =
|
||||
_input_rom_registry.query_value(config, input_name);
|
||||
|
||||
if (input_value == expected_input_value)
|
||||
condition_satisfied = true;
|
||||
}
|
||||
catch (Input_rom_registry::Nonexistent_input_value) {
|
||||
PWRN("could not obtain input value for input %s", input_name.string());
|
||||
}
|
||||
}
|
||||
|
||||
if (condition_satisfied) {
|
||||
if (node.has_sub_node("then"))
|
||||
_evaluate_node(node.sub_node("then"), xml);
|
||||
} else {
|
||||
if (node.has_sub_node("else"))
|
||||
_evaluate_node(node.sub_node("else"), xml);
|
||||
}
|
||||
}
|
||||
|
||||
if (node.has_type("inline")) {
|
||||
char const *src = node.content_base();
|
||||
size_t src_len = node.content_size();
|
||||
|
||||
/*
|
||||
* The 'Xml_generator::append' method puts the content at a fresh
|
||||
* line, and also adds a newline before the closing tag. We strip
|
||||
* eventual newlines from the '<inline>' node content to avoid
|
||||
* double newlines in the output.
|
||||
*/
|
||||
|
||||
/* remove leading newline */
|
||||
if (src_len > 0 && src[0] == '\n') {
|
||||
src++;
|
||||
src_len--;
|
||||
}
|
||||
|
||||
/* remove trailing whilespace including newlines */
|
||||
for (; src_len > 0 && Genode::is_whitespace(src[src_len - 1]); src_len--);
|
||||
|
||||
xml.append(src, src_len);
|
||||
}
|
||||
};
|
||||
|
||||
node.for_each_sub_node(process_output_sub_node);
|
||||
}
|
||||
|
||||
|
||||
void Rom_filter::Main::_evaluate()
|
||||
{
|
||||
try {
|
||||
Xml_node output = Genode::config()->xml_node().sub_node("output");
|
||||
|
||||
if (!output.has_attribute("node")) {
|
||||
PERR("missing 'node' attribute in '<output>' node");
|
||||
return;
|
||||
}
|
||||
|
||||
Node_type_name const node_type =
|
||||
output.attribute_value("node", Node_type_name(""));
|
||||
|
||||
/* generate output */
|
||||
Xml_generator xml(_xml_ds->local_addr<char>(),
|
||||
_xml_ds->size(), node_type.string(),
|
||||
[&] () { _evaluate_node(output, xml); });
|
||||
|
||||
_xml_output_len = xml.used();
|
||||
|
||||
} catch (Xml_node::Nonexistent_sub_node) { }
|
||||
|
||||
_root.notify_clients();
|
||||
}
|
||||
|
||||
|
||||
namespace Server {
|
||||
|
||||
char const *name() { return "conditional_rom_ep"; }
|
||||
|
||||
size_t stack_size() { return 4*1024*sizeof(long); }
|
||||
|
||||
void construct(Entrypoint &ep)
|
||||
{
|
||||
static Rom_filter::Main main(ep);
|
||||
}
|
||||
}
|
3
repos/os/src/server/rom_filter/target.mk
Normal file
3
repos/os/src/server/rom_filter/target.mk
Normal file
@ -0,0 +1,3 @@
|
||||
TARGET = rom_filter
|
||||
SRC_CC = main.cc
|
||||
LIBS = base server config
|
Loading…
x
Reference in New Issue
Block a user