Loading...
Searching...
No Matches
region_mapping_svr_2
// vi:set ft=cpp: -*- Mode: C++ -*-
/*
* (c) 2014 Alexander Warg <alexander.warg@kernkonzept.com>
*
* License: see LICENSE.spdx (in this directory or the directories above)
*/
#pragma once
#include <l4/sys/types.h>
#include <l4/re/rm>
#include <l4/re/util/region_mapping>
namespace L4Re { namespace Util {
template<typename DERIVED, typename Dbg>
struct Rm_server
{
private:
DERIVED *rm() { return static_cast<DERIVED*>(this); }
DERIVED const *rm() const { return static_cast<DERIVED const *>(this); }
public:
long op_attach(L4Re::Rm::Rights, l4_addr_t &_start,
unsigned long size, Rm::Flags flags,
L4::Ipc::Snd_fpage ds_cap, L4Re::Rm::Offset offs,
unsigned char align, l4_cap_idx_t client_cap_idx,
L4::Ipc::String<> name, L4Re::Rm::Offset backing_offset)
{
typename DERIVED::Dataspace ds;
if (!(flags & (Rm::F::Reserved | Rm::F::Kernel)))
{
if (long r = rm()->validate_ds
(static_cast<DERIVED*>(this)->server_iface(), ds_cap,
flags.region_flags(), &ds))
return r;
}
size = l4_round_page(size);
l4_addr_t start = l4_trunc_page(_start);
if (size < L4_PAGESIZE)
return -L4_EINVAL;
Rm::Region_flags r_flags = flags.region_flags();
Rm::Attach_flags a_flags = flags.attach_flags();
typename DERIVED::Region_handler handler(ds, client_cap_idx, offs, r_flags);
start = l4_addr_t(rm()->attach(reinterpret_cast<void*>(start), size,
handler, a_flags, align,
name.data, name.length, backing_offset));
if (start == L4_INVALID_ADDR)
return -L4_EADDRNOTAVAIL;
_start = start;
return L4_EOK;
}
long op_free_area(L4Re::Rm::Rights, l4_addr_t start)
{
if (!rm()->detach_area(start))
return -L4_ENOENT;
return L4_EOK;
}
long op_find(L4Re::Rm::Rights, l4_addr_t &addr, unsigned long &size,
L4Re::Rm::Flags &flags, L4Re::Rm::Offset &offset,
L4::Cap<L4Re::Dataspace> &m)
{
if (!DERIVED::Have_find)
return -L4_EPERM;
Rm::Flags flag_area { 0 };
typename DERIVED::Node r = rm()->find(Region(addr, addr + size -1));
if (!r)
{
r = rm()->area_find(Region(addr, addr + size - 1));
if (!r)
return -L4_ENOENT;
flag_area = Rm::F::In_area;
}
addr = r->first.start();
size = r->first.end() + 1 - addr;
flags = r->second.flags() | flag_area;
offset = r->second.offset();
m = L4::Cap<L4Re::Dataspace>(DERIVED::find_res(r->second.memory()));
return L4_EOK;
}
long op_detach(L4Re::Rm::Rights, l4_addr_t addr,
unsigned long size, unsigned flags,
l4_addr_t &start, l4_addr_t &rsize,
l4_cap_idx_t &mem_cap)
{
Region r;
typename DERIVED::Region_handler h;
int err = rm()->detach(reinterpret_cast<void*>(addr), size, flags, &r, &h);
if (err < 0)
{
start = rsize = 0;
mem_cap = L4_INVALID_CAP;
return err;
}
if (r.invalid())
{
start = rsize = 0;
mem_cap = L4_INVALID_CAP;
return -L4_ENOENT;
}
start = r.start();
rsize = r.size();
mem_cap = h.client_cap_idx();
return err;
}
long op_reserve_area(L4Re::Rm::Rights, l4_addr_t &start, unsigned long size,
L4Re::Rm::Flags flags, unsigned char align)
{
start = rm()->attach_area(start, size, flags, align);
if (start == L4_INVALID_ADDR)
return -L4_EADDRNOTAVAIL;
return L4_EOK;
}
long op_get_regions(L4Re::Rm::Rights, l4_addr_t addr,
L4::Ipc::Ret_array<L4Re::Rm::Region> regions)
{
typename DERIVED::Node r;
unsigned num = 0;
while ((r = rm()->lower_bound(Region(addr))))
{
Rm::Region &x = regions.value[num];
x.start = r->first.start();
x.end = r->first.end();
x.flags = r->second.flags();
if (++num >= regions.max)
break;
if (x.end >= rm()->max_addr())
break;
addr = x.end + 1;
}
return num;
}
long op_get_areas(L4Re::Rm::Rights, l4_addr_t addr,
L4::Ipc::Ret_array<L4Re::Rm::Area> areas)
{
typename DERIVED::Node r;
unsigned num = 0;
while ((r = rm()->lower_bound_area(Region(addr))))
{
Rm::Area &x = areas.value[num];
x.start = r->first.start();
x.end = r->first.end();
if (++num >= areas.max)
break;
if (x.end >= rm()->max_addr())
break;
addr = x.end + 1;
}
return num;
}
private:
static void pager_set_result(L4::Ipc::Opt<L4::Ipc::Snd_fpage> *fp,
L4::Ipc::Snd_fpage const &f)
{ *fp = f; }
static void pager_set_result(L4::Ipc::Opt<L4::Ipc::Snd_fpage> *, ...)
{}
public:
long op_io_page_fault(L4::Io_pager::Rights, l4_fpage_t, l4_umword_t,
L4::Ipc::Opt<L4::Ipc::Snd_fpage> &)
{
// generate exception
return -L4_ENOMEM;
}
long op_page_fault(L4::Pager::Rights, l4_umword_t addr, l4_umword_t pc,
L4::Ipc::Opt<L4::Ipc::Snd_fpage> &fp)
{
Dbg(Dbg::Server).printf("page fault: %lx pc=%lx\n", addr, pc);
bool need_w = addr & 2;
bool need_x = addr & 4;
typename DERIVED::Node n = rm()->find(addr);
if (!n || !n->second.memory())
{
Dbg(Dbg::Warn, "rm").printf("unhandled %s page fault at 0x%lx pc=0x%lx\n",
need_w ? "write" :
need_x ? "instruction" : "read", addr, pc);
// generate exception
return -L4_ENOMEM;
}
if (!(n->second.flags() & L4Re::Rm::F::W) && need_w)
{
Dbg(Dbg::Warn, "rm").printf("write page fault in readonly region at 0x%lx pc=0x%lx\n",
addr, pc);
// generate exception
return -L4_EACCESS;
}
if (!(n->second.flags() & L4Re::Rm::F::X) && need_x)
{
Dbg(Dbg::Warn, "rm").printf("instruction page fault in non-exec region at 0x%lx pc=0x%lx\n",
addr, pc);
// generate exception
return -L4_EACCESS;
}
// This check is optional but avoids doing a map operation that will not
// work. We shall never get here from a page-fault but only from
// artificial page handling.
if (n->second.flags() & (L4Re::Rm::F::Kernel | L4Re::Rm::F::Reserved))
{
Dbg(Dbg::Warn, "rm").printf("page fault handling in kernel-memory provided region or reserved region at 0x%lx pc=0x%lx\n",
addr, pc);
// generate exception
return -L4_ENODEV;
}
typename DERIVED::Region_handler::Ops::Map_result map_res;
if (int err = n->second.map(addr, n->first, need_w, &map_res))
{
Dbg(Dbg::Warn, "rm").printf("mapping for page fault failed with error %d at 0x%lx pc=0x%lx\n",
err, addr, pc);
// generate exception
return -L4_ENOMEM;
}
pager_set_result(&fp, map_res);
return L4_EOK;
}
long op_get_info(L4Re::Rm::Rights, l4_addr_t addr,
L4::Ipc::String<char> &name, L4Re::Rm::Offset &backing_offset)
{
#ifdef CONFIG_L4RE_REGION_INFO
typename DERIVED::Node r = rm()->find(Region(addr));
if (!r)
return -L4_ENOENT;
backing_offset = r->first.backing_offset();
unsigned long i;
char const *src = r->first.name();
unsigned src_len = r->first.name_len();
for (i = 0; i < src_len && i < name.length - 1; ++i)
name.data[i] = src[i];
name.length = i + 1;
name.data[i] = '\0';
return L4_EOK;
#else
(void)addr;
(void)name;
(void)backing_offset;
return -L4_ENOSYS;
#endif
}
};
}}
l4_umword_t
unsigned long l4_umword_t
Unsigned machine word.
Definition l4int.h:40
l4_addr_t
unsigned long l4_addr_t
Address type.
Definition l4int.h:34
l4_cap_idx_t
unsigned long l4_cap_idx_t
Capability selector type.
Definition types.h:336
L4_INVALID_CAP
@ L4_INVALID_CAP
Invalid capability selector.
Definition consts.h:153
L4_ENOENT
@ L4_ENOENT
No such entity.
Definition err.h:34
L4_ENOSYS
@ L4_ENOSYS
No sys.
Definition err.h:50
L4_EACCESS
@ L4_EACCESS
Permission denied.
Definition err.h:40
L4_EINVAL
@ L4_EINVAL
Invalid argument.
Definition err.h:46
L4_ENODEV
@ L4_ENODEV
No such thing.
Definition err.h:44
L4_EOK
@ L4_EOK
Ok.
Definition err.h:32
L4_EADDRNOTAVAIL
@ L4_EADDRNOTAVAIL
Address not available.
Definition err.h:52
L4_EPERM
@ L4_EPERM
No permission.
Definition err.h:33
L4_ENOMEM
@ L4_ENOMEM
No memory.
Definition err.h:39
l4_trunc_page
l4_addr_t l4_trunc_page(l4_addr_t address) L4_NOTHROW
Round an address down to the next lower page boundary.
Definition consts.h:448
l4_round_page
l4_addr_t l4_round_page(l4_addr_t address) L4_NOTHROW
Round address up to the next page.
Definition consts.h:473
L4_PAGESIZE
#define L4_PAGESIZE
Minimal page size (in bytes).
Definition consts.h:391
L4_INVALID_ADDR
@ L4_INVALID_ADDR
Invalid address.
Definition consts.h:505
types.h
Common L4 ABI Data Types.
L4Re::Util
Documentation of the L4 Runtime Environment utility functionality in C++.
Definition l4re.dox:21
L4Re
L4Re C++ Interfaces.
Definition cmd_control:14
region_mapping
Region handling.
rm
Region mapper interface.
L4Re::Rm::F::Reserved
@ Reserved
Region is reserved (blocked).
Definition rm:152
L4Re::Rm::F::X
@ X
Executable region.
Definition rm:137
L4Re::Rm::F::W
@ W
Writable region.
Definition rm:135
L4Re::Rm::F::Kernel
@ Kernel
Kernel-provided memory (KUMEM).
Definition rm:146
L4Re::Rm::F::In_area
@ In_area
Search only in area, or map into area.
Definition rm:116