Loading...
Searching...
No Matches
name_space_svr
// vi:set ft=cpp: -*- Mode: C++ -*-
/*
* (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
* Alexander Warg <warg@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/cxx/avl_tree>
#include <l4/cxx/std_ops>
#include <l4/sys/cxx/ipc_epiface>
#include <l4/cxx/string>
#include <l4/re/util/debug>
#include <l4/sys/capability>
#include <l4/re/namespace>
#include <stddef.h>
#include <string.h>
namespace L4Re { namespace Util { namespace Names {
class Name : public cxx::String
{
public:
Name(const char *name = "") : String(name, __builtin_strlen(name)) {}
Name(const char *name, unsigned long len) : String(name, len) {}
Name(cxx::String const &n) : String(n) {}
char const *name() const { return start(); }
bool operator < (Name const &r) const
{
unsigned long l = cxx::min(len(), r.len());
int v = memcmp(start(), r.start(), l);
return v < 0 || (v == 0 && len() < r.len());
}
};
class Obj
{
protected:
unsigned _f;
union
{
l4_cap_idx_t _cap;
L4::Epiface *_obj;
};
public:
enum Flags
{
F_rw = L4Re::Namespace::Rw,
F_strong = L4Re::Namespace::Strong,
F_trusted = L4Re::Namespace::Trusted,
F_rights_mask = F_rw | F_strong | F_trusted,
F_cap = 0x100,
F_local = 0x200,
F_replacable = 0x400,
F_base_mask = 0xf00,
};
unsigned flags() const { return _f; }
void restrict_flags(unsigned max_rights)
{ _f &= (~F_rights_mask | (max_rights & F_rights_mask)); }
bool is_rw() const { return (_f & F_rw) == F_rw; }
bool is_strong() const { return _f & F_strong; }
bool is_valid() const { return _f & F_cap; }
bool is_complete() const { return is_valid(); }
bool is_local() const { return _f & F_local; }
bool is_replacable() const { return _f & F_replacable; }
bool is_trusted() const { return _f & F_trusted; }
L4::Epiface *obj() const { if (is_local()) return _obj; return 0; }
L4::Cap<void> cap() const
{
if (!is_local())
return L4::Cap<void>(_cap);
if (!_obj)
return L4::Cap<void>::Invalid;
return _obj->obj_cap();
}
void set(Obj const &o, unsigned flags)
{
*this = o;
restrict_flags(flags);
}
explicit Obj(unsigned flags = 0)
: _f(flags), _cap(L4_INVALID_CAP)
{}
Obj(unsigned f, L4::Cap<void> const &cap)
: _f((f & ~F_base_mask) | F_cap), _cap(cap.cap())
{}
Obj(unsigned f, L4::Epiface *o)
: _f((f & ~F_base_mask) | F_cap | F_local), _obj(o)
{}
void reset(unsigned flags)
{
_f = (_f & F_replacable) | (flags & ~(F_cap | F_local));
_cap = L4_INVALID_CAP;
}
};
class Entry : public cxx::Avl_tree_node
{
private:
friend class Name_space;
Name _n;
Obj _o;
bool _dynamic;
public:
Entry(Name const &n, Obj const &o, bool dynamic = false)
: _n(n), _o(o), _dynamic(dynamic) {}
Name const &name() const { return _n; }
Obj const *obj() const { return &_o; }
Obj *obj() { return &_o; }
void obj(Obj const &o) { _o = o; }
bool is_placeholder() const
{ return !obj()->is_complete(); }
bool is_dynamic() const { return _dynamic; }
void set(Obj const &o)
{
obj()->set(o, obj()->flags());
}
private:
void * operator new (size_t s);
void operator delete(void *b);
};
struct Names_get_key
{
typedef Name Key_type;
static Key_type const &key_of(Entry const *e)
{ return e->name(); }
};
class Name_space
{
friend class Entry;
private:
typedef cxx::Avl_tree<Entry, Names_get_key> Tree;
Tree _tree;
protected:
L4Re::Util::Dbg const &_dbg;
L4Re::Util::Err const &_err;
public:
typedef Tree::Const_iterator Const_iterator;
Const_iterator begin() const { return _tree.begin(); }
Const_iterator end() const { return _tree.end(); }
Name_space(L4Re::Util::Dbg const &dbg, L4Re::Util::Err const &err)
: _dbg(dbg), _err(err)
{}
virtual ~Name_space() {}
Entry *find(Name const &name) const { return _tree.find_node(name); }
Entry *remove(Name const &name) { return _tree.remove(name); }
Entry *find_iter(Name const &pname) const
{
Name name = pname;
_dbg.printf("resolve '%.*s': ", name.len(), name.start());
Name_space const *ns = this;
while (ns)
{
cxx::String::Index sep = name.find("/");
cxx::String part;
if (!name.eof(sep))
part = name.head(sep);
else
part = name;
_dbg.cprintf(" '%.*s'", part.len(), part.start());
Entry *o = ns->find(Name(part.start(), part.len()));
if (!o)
{
_dbg.cprintf(": resolution failed: '%.*s' remaining\n",
name.len(), name.start());
return 0;
}
auto const *obj = o->obj()->obj();
ns = dynamic_cast<Name_space const *>(obj);
if (ns)
{
if (!name.eof(sep))
{
name = name.substr(sep + 1);
continue;
}
}
_dbg.cprintf(": found object: %p (%s)\n",
obj, obj ? typeid(*obj).name() : "");
return o;
}
return 0;
}
bool insert(Entry *e) { return _tree.insert(e).second; }
void dump(bool rec = false, int indent = 0) const;
protected:
// server support --------------------------------------------
virtual Entry *alloc_dynamic_entry(Name const &n, unsigned flags) = 0;
virtual void free_dynamic_entry(Entry *e) = 0;
virtual int get_epiface(l4_umword_t data, bool is_local, L4::Epiface **lo) = 0;
virtual int copy_receive_cap(L4::Cap<void> *cap) = 0;
virtual void free_capability(L4::Cap<void> cap) = 0;
virtual void free_epiface(L4::Epiface *epiface) = 0;
int insert_entry(Name const &name, unsigned flags, Entry **e)
{
Entry *n = find(name);
if (n && n->obj()->is_valid())
{
if (!(flags & L4Re::Namespace::Overwrite)
&& n->obj()->cap().validate(L4_BASE_TASK_CAP).label() > 0)
return -L4_EEXIST;
if (n->obj()->is_local())
free_epiface(n->obj()->obj());
else
free_capability(n->obj()->cap());
if (n->is_dynamic())
{
remove(n->name());
free_dynamic_entry(n);
n = 0;
}
else
{
if (!n->obj()->is_replacable())
return -L4_EEXIST;
n->obj()->reset(Obj::F_rw);
}
}
flags &= L4Re::Namespace::Cap_flags;
if (!n)
{
if (!(n = alloc_dynamic_entry(name, flags)))
return -L4_ENOMEM;
else
{
if (!insert(n))
{
free_dynamic_entry(n);
return -L4_EEXIST;
}
}
}
*e = n;
return 0;
}
public:
// server interface ------------------------------------------
int op_query(L4Re::Namespace::Rights,
L4::Ipc::Array_in_buf<char, unsigned long> const &name,
L4::Ipc::Snd_fpage &snd_cap, L4::Ipc::Opt<L4::Opcode> &dummy,
L4::Ipc::Opt<L4::Ipc::Array_ref<char, unsigned long> > &out_name)
{
#if 1
_dbg.printf("query: [%ld] '%.*s'\n", name.length,
static_cast<int>(name.length), name.data);
#endif
char const *sep
= static_cast<char const*>(memchr(name.data, '/', name.length));
unsigned long part;
if (sep)
part = sep - name.data;
else
part = name.length;
Entry *n = find(Name(name.data, part));
if (!n)
return -L4_ENOENT;
else if (!n->obj()->is_valid())
return -L4_EAGAIN;
else
{
if (n->obj()->cap().validate(L4_BASE_TASK_CAP).label() <= 0)
{
if (n->obj()->is_local())
free_epiface(n->obj()->obj());
else
free_capability(n->obj()->cap());
if (n->is_dynamic())
{
remove(n->name());
free_dynamic_entry(n);
}
return -L4_ENOENT;
}
// make picky clients happy
dummy.set_valid();
// prevent warning about writing uninitialized data in IPC framework
dummy = 0;
l4_umword_t result = 0;
out_name.set_valid();
if (part < name.length)
{
result |= L4Re::Namespace::Partly_resolved;
memcpy(out_name->data, name.data + part + 1, name.length - part - 1);
out_name->length = name.length - part - 1;
}
else
out_name->length = 0;
unsigned flags = L4_CAP_FPAGE_R;
if (n->obj()->is_rw()) flags |= L4_CAP_FPAGE_W;
if (n->obj()->is_strong()) flags |= L4_CAP_FPAGE_S;
snd_cap = L4::Ipc::Snd_fpage(n->obj()->cap(), flags);
_dbg.printf(" result = %lx flgs=%x strg=%d\n",
result, flags, static_cast<int>(n->obj()->is_strong()));
return result;
}
}
int op_register_obj(L4Re::Namespace::Rights, unsigned flags,
L4::Ipc::Array_in_buf<char, unsigned long> const &name,
L4::Ipc::Snd_fpage &cap)
{
if (name.length == 0 || memchr(name.data, '/', name.length))
return -L4_EINVAL;
L4::Cap<void> reg_cap(L4_INVALID_CAP);
L4::Epiface *src_o = 0;
// Did we receive something we have handed out ourselves? If yes,
// register the object under the given name but do not allocate
// anything more.
if (cap.id_received() || cap.local_id_received())
{
if (int ret = get_epiface(cap.data(), cap.local_id_received(), &src_o))
return ret;
// Make sure rights are restricted to the mapped rights.
flags &= (cap.data() & 0x3UL) | ~0x3UL;
}
else if (cap.cap_received())
{
if (int ret = copy_receive_cap(&reg_cap))
return ret;
}
else if (!cap.is_valid())
{
reg_cap = L4::Cap<void>::Invalid;
}
else
return -L4_EINVAL;
// got a valid entry to register
_dbg.printf("register: '%.*s' flags=%x\n", static_cast<int>(name.length),
name.data, flags);
Name _name(name.data, name.length);
Entry *n;
if (int r = insert_entry(_name, flags, &n))
{
if (cap.cap_received())
free_capability(reg_cap);
if (src_o)
free_epiface(src_o);
return r;
}
if (src_o)
n->set(Names::Obj(flags & L4Re::Namespace::Cap_flags, src_o));
else if (reg_cap.is_valid())
n->set(Names::Obj(flags & L4Re::Namespace::Cap_flags, reg_cap));
return 0;
}
int op_unlink(L4Re::Namespace::Rights,
L4::Ipc::Array_in_buf<char, unsigned long> const &name)
{
#if 1
_dbg.printf("unlink: [%ld] '%.*s'\n", name.length,
static_cast<int>(name.length), name.data);
#endif
char const *sep
= static_cast<char const*>(memchr(name.data, '/', name.length));
unsigned long part;
if (sep)
part = sep - name.data;
else
part = name.length;
Entry *n = find(Name(name.data, part));
if (!n || !n->obj()->is_valid())
return -L4_ENOENT;
if (n->obj()->is_local())
free_epiface(n->obj()->obj());
else
free_capability(n->obj()->cap());
if (n->is_dynamic())
{
remove(n->name());
free_dynamic_entry(n);
}
else
return -L4_EACCESS;
return 0;
}
};
}}}
avl_tree
AVL tree.
capability
L4::Cap related definitions.
L4Re::Namespace::Partly_resolved
@ Partly_resolved
Name was only partly resolved.
Definition namespace:79
L4Re::Namespace::Trusted
@ Trusted
Obsolete, do not use.
Definition namespace:64
L4Re::Namespace::Overwrite
@ Overwrite
If entry already exists, overwrite it.
Definition namespace:69
L4Re::Namespace::Strong
@ Strong
Strong.
Definition namespace:63
L4Re::Namespace::Rw
@ Rw
Read-write.
Definition namespace:60
L4Re::Util::Names::Name_space::free_dynamic_entry
virtual void free_dynamic_entry(Entry *e)=0
Free an entry previously allocated with alloc_dynamic_entry().
L4Re::Util::Names::Name_space::get_epiface
virtual int get_epiface(l4_umword_t data, bool is_local, L4::Epiface **lo)=0
Return a pointer to the epiface assigned to a given label.
L4Re::Util::Names::Name_space::alloc_dynamic_entry
virtual Entry * alloc_dynamic_entry(Name const &n, unsigned flags)=0
Allocate a new entry for the given name.
L4Re::Util::Names::Name_space::copy_receive_cap
virtual int copy_receive_cap(L4::Cap< void > *cap)=0
Return the receive capability for permanent use.
L4Re::Util::Names::Name_space::~Name_space
virtual ~Name_space()
The destructor of the derived class is responsible for freeing resources.
Definition name_space_svr:206
L4Re::Util::Names::Name_space::free_capability
virtual void free_capability(L4::Cap< void > cap)=0
Free a capability previously acquired with copy_receive_cap().
L4Re::Util::Names::Name_space::free_epiface
virtual void free_epiface(L4::Epiface *epiface)=0
Free epiface previously acquired with get_epiface().
L4Re::Util::Names::Name
Name class.
Definition name_space_svr:29
L4::Cap_base::Invalid
@ Invalid
Invalid capability selector.
Definition capability.h:42
L4::Cap
C++ interface for capabilities.
Definition capability.h:224
L4::Ipc::Gen_fpage::data
l4_umword_t data() const noexcept
Return the raw flexpage descriptor.
Definition ipc_types:304
L4::Ipc::Snd_fpage
Send item or return item.
Definition ipc_types:324
L4::Ipc::Snd_fpage::id_received
bool id_received() const noexcept
(Defined for return items only.) Check if an IPC gate label has been received instead of a mapping.
Definition ipc_types:512
L4::Ipc::Snd_fpage::local_id_received
bool local_id_received() const noexcept
(Defined for return items only.) Check if a raw object flexpage has been received instead of a mappin...
Definition ipc_types:528
L4::Ipc::Snd_fpage::is_valid
bool is_valid() const noexcept
Check if the capability is valid.
Definition ipc_types:480
L4::Ipc::Snd_fpage::cap_received
bool cap_received() const noexcept
(Defined for return items only.) Check if at least one object capability has been mapped for this ite...
Definition ipc_types:496
cxx::Avl_tree
A generic AVL tree.
Definition avl_tree:101
cxx::Avl_tree::remove
Node * remove(Key_param_type key)
Remove the node with key from the tree.
Definition avl_tree:282
cxx::Avl_tree< Entry, Names_get_key >::Const_iterator
Bst::Const_iterator Const_iterator
Definition avl_tree:132
cxx::Bits::Bst::find_node
Node * find_node(Key_param_type key) const
find the node with the given key.
Definition bst.h:269
cxx::String
Allocation free string class with explicit length field.
Definition string:31
cxx::String::start
Index start() const
Pointer to first character.
Definition string:54
cxx::String::head
String head(Index end) const
Return prefix up to index.
Definition string:68
cxx::String::Index
char const * Index
Character index type.
Definition string:35
cxx::String::len
int len() const
Length.
Definition string:58
cxx::String::String
String()
Zero-initialize. Create an invalid string.
Definition string:51
l4_umword_t
unsigned long l4_umword_t
Unsigned machine word.
Definition l4int.h:40
l4_cap_idx_t
unsigned long l4_cap_idx_t
Capability selector type.
Definition types.h:336
L4_BASE_TASK_CAP
@ L4_BASE_TASK_CAP
Capability selector for the current task.
Definition consts.h:327
L4_INVALID_CAP
@ L4_INVALID_CAP
Invalid capability selector.
Definition consts.h:153
L4_EEXIST
@ L4_EEXIST
Already exists.
Definition err.h:43
L4_ENOENT
@ L4_ENOENT
No such entity.
Definition err.h:34
L4_EACCESS
@ L4_EACCESS
Permission denied.
Definition err.h:40
L4_EINVAL
@ L4_EINVAL
Invalid argument.
Definition err.h:46
L4_EAGAIN
@ L4_EAGAIN
Try again.
Definition err.h:38
L4_ENOMEM
@ L4_ENOMEM
No memory.
Definition err.h:39
L4_CAP_FPAGE_R
@ L4_CAP_FPAGE_R
Read right for capability flexpages.
Definition __l4_fpage.h:175
L4_CAP_FPAGE_W
@ L4_CAP_FPAGE_W
Interface specific 'W' right for capability flexpages.
Definition __l4_fpage.h:157
L4_CAP_FPAGE_S
@ L4_CAP_FPAGE_S
Interface specific 'S' right for capability flexpages.
Definition __l4_fpage.h:169
L4Re::Util
Documentation of the L4 Runtime Environment utility functionality in C++.
Definition l4re.dox:21
L4Re
L4Re C++ Interfaces.
Definition cmd_control:14
namespace
Namespace interface.
string.h
String.
L4::Epiface
Base class for interface implementations.
Definition ipc_epiface:146
L4::Ipc::Array_in_buf
Server-side copy in buffer for Array.
Definition ipc_array:127
L4::Ipc::Array_in_buf::length
LEN_TYPE length
The length of the array.
Definition ipc_array:134
L4::Ipc::Array_in_buf::data
ELEM_TYPE data[MAX]
The data elements.
Definition ipc_array:132
L4::Ipc::Array_ref
Array reference data type for arrays located in the message.
Definition ipc_array:29
L4::Ipc::Opt
Attribute for defining an optional RPC argument.
Definition ipc_types:137
L4::Ipc::Opt::set_valid
void set_valid(bool valid=true) noexcept
Set the argument to present or absent.
Definition ipc_types:156