Merge branch 'master' into ealan to sync with upstream.

This commit is contained in:
Michael Mueller
2022-10-14 16:56:15 +02:00
1560 changed files with 27336 additions and 15652 deletions

View File

@@ -189,10 +189,10 @@ class Genode::Affinity
Affinity::Space space { };
Affinity::Location location { };
node.with_sub_node("affinity", [&] (Xml_node const &node) {
node.with_sub_node("space", [&] (Xml_node const &node) {
node.with_optional_sub_node("affinity", [&] (Xml_node const &node) {
node.with_optional_sub_node("space", [&] (Xml_node const &node) {
space = Space::from_xml(node); });
node.with_sub_node("location", [&] (Xml_node const &node) {
node.with_optional_sub_node("location", [&] (Xml_node const &node) {
location = Location::from_xml(space, node); });
});

View File

@@ -481,6 +481,17 @@ class Genode::Rpc_entrypoint : Thread, public Object_pool<Rpc_object_base>
* This method is solely needed on Linux.
*/
bool is_myself() const;
/**
* Check whether given stack info matches stack of the entrypoint.
*
* \noapi
*
*/
bool myself(addr_t const ptr) const
{
return addr_t(stack_base()) <= ptr && ptr <= addr_t(stack_top());
}
};

View File

@@ -257,6 +257,9 @@ class Genode::Trace::Simple_buffer
size_t length() const { return _entry->len; }
char const *data() const { return _entry->data; }
template <typename T>
T const &object() const { return *reinterpret_cast<const T*>(data()); }
/* return whether entry is valid, i.e. length field is present */
bool last() const { return _entry == 0; }

View File

@@ -25,6 +25,8 @@ namespace Genode { namespace Trace {
struct Rpc_reply;
struct Signal_submit;
struct Signal_received;
struct Checkpoint;
struct Ethernet_packet;
} }
@@ -121,4 +123,62 @@ struct Genode::Trace::Signal_received
};
struct Genode::Trace::Checkpoint
{
enum Type : unsigned char {
UNDEF = 0x0,
START = 0x1,
END = 0x2,
OBJ_NEW = 0x10,
OBJ_DEL = 0x11,
OBJ_STATE = 0x12,
EXCEPTION = 0xfe,
FAILURE = 0xff
};
char const *name;
unsigned long const data;
Type const type;
void *addr;
Checkpoint(char const *name, unsigned long data, void *addr, Type type=Type::UNDEF)
: name(name), data(data), type(type), addr(addr)
{
Thread::trace(this);
}
size_t generate(Policy_module &policy, char *dst) const {
return policy.checkpoint(dst, name, data, addr, type); }
};
struct Genode::Trace::Ethernet_packet
{
enum Direction : char {
RECV = 0x0,
SENT = 0x1
};
char const *name;
Direction direction;
char *data;
size_t length;
Ethernet_packet(char const *name, Direction direction, char *data, size_t len)
: name(name), direction(direction), data(data), length(len)
{
Thread::trace(this);
}
Ethernet_packet(char const *name, Direction direction, void *data, size_t len)
: name(name), direction(direction), data((char*)data), length(len)
{
Thread::trace(this);
}
size_t generate(Policy_module &policy, char *dst) const {
return policy.trace_eth_packet(dst, name, direction == Direction::SENT, data, length); }
};
#endif /* _INCLUDE__BASE__TRACE__EVENTS_H_ */

View File

@@ -31,14 +31,16 @@ namespace Genode {
*/
struct Genode::Trace::Policy_module
{
size_t (*max_event_size) ();
size_t (*log_output) (char *, char const *, size_t);
size_t (*rpc_call) (char *, char const *, Msgbuf_base const &);
size_t (*rpc_returned) (char *, char const *, Msgbuf_base const &);
size_t (*rpc_dispatch) (char *, char const *);
size_t (*rpc_reply) (char *, char const *);
size_t (*signal_submit) (char *, unsigned const);
size_t (*signal_received) (char *, Signal_context const &, unsigned const);
size_t (*max_event_size) ();
size_t (*trace_eth_packet) (char *, char const *, bool, char *, size_t);
size_t (*checkpoint) (char *, char const *, unsigned long, void *, unsigned char);
size_t (*log_output) (char *, char const *, size_t);
size_t (*rpc_call) (char *, char const *, Msgbuf_base const &);
size_t (*rpc_returned) (char *, char const *, Msgbuf_base const &);
size_t (*rpc_dispatch) (char *, char const *);
size_t (*rpc_reply) (char *, char const *);
size_t (*signal_submit) (char *, unsigned const);
size_t (*signal_received) (char *, Signal_context const &, unsigned const);
};
#endif /* _INCLUDE__BASE__TRACE__POLICY_H_ */

View File

@@ -42,6 +42,26 @@ struct Genode::Irq_connection : Connection<Irq_session>, Irq_session_client
irq, trigger, polarity, device_config_phys)),
Irq_session_client(cap())
{ }
/**
* Constructor for label-based configuration (used by pin driver)
*
* \param label session label
*/
Irq_connection(Env &env,
char const *label)
:
Connection<Irq_session>(env, session(env.parent(),
"ram_quota=%u, cap_quota=%u, "
"irq_number=%u, irq_trigger=%u, "
"irq_polarity=%u, device_config_phys=0x%lx, "
"label=\"%s\"",
RAM_QUOTA, CAP_QUOTA, 0,
Irq_session::TRIGGER_UNCHANGED,
Irq_session::POLARITY_UNCHANGED,
0, label)),
Irq_session_client(cap())
{ }
};
#endif /* _INCLUDE__IRQ_SESSION__CONNECTION_H_ */

View File

@@ -123,6 +123,8 @@ class Genode::Timeout : private Noncopyable,
void discard();
bool scheduled();
Microseconds deadline() const { return _deadline; }
};

View File

@@ -117,6 +117,8 @@ class Timer::One_shot_timeout : private Genode::Noncopyable,
void discard() { _timeout.discard(); }
bool scheduled() { return _timeout.scheduled(); }
Microseconds deadline() const { return _timeout.deadline(); }
};

View File

@@ -0,0 +1,85 @@
/*
* \brief Trace probes
* \author Johannes Schlatow
* \date 2021-12-01
*
* Convenience macros for creating user-defined trace checkpoints.
*/
/*
* Copyright (C) 2021 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__TRACE__PROBE_H_
#define _INCLUDE__TRACE__PROBE_H_
#include <base/trace/events.h>
namespace Genode { namespace Trace {
class Duration
{
private:
char const *_name;
unsigned long const _data;
Duration(Duration const &) = delete;
Duration & operator = (Duration const &) = delete;
public:
Duration(char const * name, unsigned long data)
: _name(name), _data(data)
{ Checkpoint(_name, _data, nullptr, Checkpoint::Type::START); }
~Duration()
{ Checkpoint(_name, _data, nullptr, Checkpoint::Type::END); }
};
} }
/**
* Trace a single checkpoint named after the current function.
*
* The argument 'data' specifies the payload as an unsigned value.
*/
#define GENODE_TRACE_CHECKPOINT(data) \
Genode::Trace::Checkpoint(__PRETTY_FUNCTION__, (unsigned long)data, nullptr);
/**
* Variant of 'GENODE_TRACE_CHECKPOINT' that accepts the name of the checkpoint as argument.
*
* The argument 'data' specifies the payload as an unsigned value.
* The argument 'name' specifies the name of the checkpoint.
*/
#define GENODE_TRACE_CHECKPOINT_NAMED(data, name) \
Genode::Trace::Checkpoint(name, (unsigned long)data, nullptr);
/**
* Trace a pair of checkpoints when entering and leaving the current scope.
*
* The argument 'data' specifies the payload as an unsigned value.
*/
#define GENODE_TRACE_DURATION(data) \
Genode::Trace::Duration duration(__PRETTY_FUNCTION__, (unsigned long)data);
/**
* Variant of 'GENODE_TRACE_DURATION' that accepts the name of the checkpoints as argument.
*
* The argument 'data' specifies the payload as an unsigned value.
* The argument 'name' specifies the names of the checkpoints
*/
#define GENODE_TRACE_DURATION_NAMED(data, name) \
Genode::Trace::Duration duration(name, (unsigned long)data);
#endif /* _INCLUDE__TRACE__PROBE_H_ */

View File

@@ -116,10 +116,6 @@ struct Genode::Trace::Session_client : Genode::Rpc_client<Genode::Trace::Session
void trace(Subject_id s, Policy_id p, size_t buffer_size) override {
call<Rpc_trace>(s, p, buffer_size); }
void rule(Session_label const &label, Thread_name const &thread,
Policy_id policy, size_t buffer_size) override {
call<Rpc_rule>(label, thread, policy, buffer_size); }
void pause(Subject_id subject) override {
call<Rpc_pause>(subject); }

View File

@@ -64,12 +64,6 @@ struct Genode::Trace::Session : Genode::Session
*/
virtual void trace(Subject_id, Policy_id, size_t buffer_size) = 0;
/**
* Install a matching rule for automatically tracing new threads
*/
virtual void rule(Session_label const &, Thread_name const &,
Policy_id, size_t buffer_size) = 0;
/**
* Pause generation of tracing data
*
@@ -124,10 +118,6 @@ struct Genode::Trace::Session : Genode::Session
Nonexistent_policy,
Traced_by_other_session),
Subject_id, Policy_id, size_t);
GENODE_RPC_THROW(Rpc_rule, void, rule,
GENODE_TYPE_LIST(Out_of_ram, Out_of_caps),
Session_label const &, Thread_name const &,
Policy_id, size_t);
GENODE_RPC_THROW(Rpc_pause, void, pause,
GENODE_TYPE_LIST(Nonexistent_subject), Subject_id);
GENODE_RPC_THROW(Rpc_resume, void, resume,
@@ -144,7 +134,7 @@ struct Genode::Trace::Session : Genode::Session
GENODE_TYPE_LIST(Nonexistent_subject), Subject_id);
GENODE_RPC_INTERFACE(Rpc_dataspace, Rpc_alloc_policy, Rpc_policy,
Rpc_unload_policy, Rpc_trace, Rpc_rule, Rpc_pause,
Rpc_unload_policy, Rpc_trace, Rpc_pause,
Rpc_resume, Rpc_subjects, Rpc_buffer,
Rpc_free, Rpc_subject_infos);
};

View File

@@ -0,0 +1,148 @@
/*
* \brief Utility for accessing objects by name
* \author Norman Feske
* \date 2022-09-14
*/
/*
* Copyright (C) 2022 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__UTIL__DICTIONARY_H_
#define _INCLUDE__UTIL__DICTIONARY_H_
#include <util/meta.h>
#include <util/string.h>
#include <util/avl_tree.h>
#include <util/noncopyable.h>
#include <base/log.h>
namespace Genode { template <typename, typename> class Dictionary; }
template <typename T, typename NAME>
class Genode::Dictionary : Noncopyable
{
private:
Avl_tree<T> _tree { };
public:
class Element : private Avl_node<T>
{
public:
NAME const name;
private:
using This = Dictionary<T, NAME>::Element;
Dictionary<T, NAME> &_dictionary;
bool higher(T const *other) const { return name > other->This::name; }
friend class Avl_tree<T>;
friend class Avl_node<T>;
friend class Dictionary<T, NAME>;
static T *_matching_sub_tree(T &curr, NAME const &name)
{
typename Avl_node<T>::Side side = (curr.This::name > name);
return curr.Avl_node<T>::child(side);
}
public:
Element(Dictionary &dictionary, NAME const &name)
:
name(name), _dictionary(dictionary)
{
if (_dictionary.exists(name))
warning("dictionary entry '", name, "' is not unique");
_dictionary._tree.insert(this);
}
~Element()
{
_dictionary._tree.remove(this);
}
};
/**
* Call 'match_fn' with named constant dictionary element
*
* The 'match_fn' functor is called with a const reference to the
* matching dictionary element. If no maching element exists,
* 'no_match_fn' is called without argument.
*/
template <typename FN1, typename FN2>
auto with_element(NAME const &name, FN1 const &match_fn, FN2 const &no_match_fn)
-> typename Trait::Functor<decltype(&FN1::operator())>::Return_type
{
T *curr_ptr = _tree.first();
for (;;) {
if (!curr_ptr)
break;
if (curr_ptr->Element::name == name) {
return match_fn(*curr_ptr);
}
curr_ptr = Element::_matching_sub_tree(*curr_ptr, name);
}
return no_match_fn();
}
/**
* Call 'match_fn' with named mutable dictionary element
*
* The 'match_fn' functor is called with a non-const reference to the
* matching dictionary element. If no maching element exists,
* 'no_match_fn' is called without argument.
*/
template <typename FN1, typename FN2>
auto with_element(NAME const &name, FN1 const &match_fn, FN2 const &no_match_fn) const
-> typename Trait::Functor<decltype(&FN1::operator())>::Return_type
{
auto const_match_fn = [&] (T const &e) { return match_fn(e); };
auto non_const_this = const_cast<Dictionary *>(this);
return non_const_this->with_element(name, const_match_fn, no_match_fn);
}
/**
* Call 'fn' with a non-const reference to any dictionary element
*
* \return true if 'fn' was called, or
* false if the dictionary is empty
*
* This method is intended for the orderly destruction of a dictionary.
* It allows for the consecutive destruction of all elements.
*/
template <typename FUNC>
bool with_any_element(FUNC const &fn)
{
T *curr_ptr = _tree.first();
if (!curr_ptr)
return false;
fn(*curr_ptr);
return true;
}
template <typename FN>
void for_each(FN const &fn) const { _tree.for_each(fn); }
bool exists(NAME const &name) const
{
return with_element(name, [] (T const &) { return true; },
[] { return false; });
}
};
#endif /* _INCLUDE__UTIL__DICTIONARY_H_ */

View File

@@ -459,20 +459,21 @@ namespace Genode {
/**
* Read signed long value from string
* Read signed value from string
*
* \return number of consumed characters
*/
inline size_t ascii_to(const char *s, long &result)
template <typename T>
inline size_t ascii_to_signed(const char *s, T &result)
{
int i = 0;
size_t i = 0;
/* read sign */
int sign = (*s == '-') ? -1 : 1;
if (*s == '-' || *s == '+') { s++; i++; }
unsigned long value = 0;
T value = 0;
size_t const j = ascii_to_unsigned(s, value, 0);
@@ -484,6 +485,28 @@ namespace Genode {
}
/**
* Read signed long value from string
*
* \return number of consumed characters
*/
inline size_t ascii_to(const char *s, long &result)
{
return ascii_to_signed<long>(s, result);
}
/**
* Read signed integer value from string
*
* \return number of consumed characters
*/
inline size_t ascii_to(const char *s, int &result)
{
return ascii_to_signed<int>(s, result);
}
/**
* Read 'Number_of_bytes' value from string and handle the size suffixes
*
@@ -785,6 +808,12 @@ class Genode::String
return strcmp(string(), other.string()) != 0;
}
template <size_t N>
bool operator > (String<N> const &other) const
{
return strcmp(string(), other.string()) > 0;
}
void print(Output &out) const { Genode::print(out, string()); }
};

View File

@@ -110,7 +110,7 @@ class Genode::Token
/**
* Access single characters of token
*/
char operator [] (int idx)
char operator [] (int idx) const
{
return ((idx >= 0) && ((unsigned)idx < _len)) ? _start[idx] : 0;
}

View File

@@ -55,17 +55,16 @@ class Genode::Xml_attribute
struct Tokens
{
Token name;
Token value;
Token equals { name .next().eat_whitespace() };
Token value { equals.next().eat_whitespace() };
Tokens(Token t)
: name(t.eat_whitespace()), value(name.next().next()) { };
Tokens(Token t) : name(t.eat_whitespace()) { };
bool valid() const
{
bool const tag_present = (name.type() == Token::IDENT);
bool const value_present = (name.next()[0] == '=' &&
value.type() == Token::STRING);
return tag_present && value_present;
return (name.type() == Token::IDENT)
&& (equals[0] == '=')
&& (value.type() == Token::STRING);
}
} _tokens;
@@ -103,7 +102,7 @@ class Genode::Xml_attribute
/**
* Return token following the attribute declaration
*/
Token _next_token() const { return _tokens.name.next().next().next(); }
Token _next_token() const { return _tokens.value.next(); }
public:
@@ -355,7 +354,7 @@ class Genode::Xml_node
}
/**
* Return true if tag as at least one attribute
* Return true if tag has at least one attribute
*/
bool has_attribute() const { return Xml_attribute::_valid(_name.next()); }
@@ -846,12 +845,27 @@ class Genode::Xml_node
* If no matching sub node exists, the functor is not called.
*/
template <typename FN>
void with_sub_node(char const *type, FN const &fn) const
void with_optional_sub_node(char const *type, FN const &fn) const
{
if (has_sub_node(type))
fn(sub_node(type));
}
/**
* Apply functor 'fn' to first sub node of specified type
*
* The functor is called with the sub node as argument.
* If no matching sub node exists, the functor 'fn_nexists' is called.
*/
template <typename FN, typename FN_NEXISTS>
void with_sub_node(char const *type, FN const &fn, FN_NEXISTS const &fn_nexists) const
{
if (has_sub_node(type))
fn(sub_node(type));
else
fn_nexists();
}
/**
* Execute functor 'fn' for each sub node of specified type
*/