L4Re – L4 Runtime Environment
region_mapping_svr_2
1 // vi:set ft=cpp: -*- Mode: C++ -*-
7 /*
8  * (c) 2014 Alexander Warg <alexander.warg@kernkonzept.com>
9  *
10  * This file is part of TUD:OS and distributed under the terms of the
11  * GNU General Public License 2.
12  * Please see the COPYING-GPL-2 file for details.
13  *
14  * As a special exception, you may use this file as part of a free software
15  * library without restriction. Specifically, if other files instantiate
16  * templates or use macros or inline functions from this file, or you compile
17  * this file and link it with other files to produce an executable, this
18  * file does not by itself cause the resulting executable to be covered by
19  * the GNU General Public License. This exception does not however
20  * invalidate any other reasons why the executable file might be covered by
21  * the GNU General Public License.
22  */
23 #pragma once
24 
25 #include <l4/sys/types.h>
26 #include <l4/re/rm>
28 
29 namespace L4Re { namespace Util {
30 
31 template<typename DERIVED, typename Dbg>
32 struct Rm_server
33 {
34 private:
35  DERIVED *rm() { return static_cast<DERIVED*>(this); }
36  DERIVED const *rm() const { return static_cast<DERIVED const *>(this); }
37 
38 public:
39 
43  long op_attach(L4Re::Rm::Rights, l4_addr_t &_start,
44  unsigned long size, Rm::Flags flags,
45  L4::Ipc::Snd_fpage ds_cap, L4Re::Rm::Offset offs,
46  unsigned char align, l4_cap_idx_t client_cap_idx)
47  {
48  typename DERIVED::Dataspace ds;
49 
50  if (!(flags & Rm::F::Reserved))
51  {
52  if (long r = rm()->validate_ds(static_cast<DERIVED*>(this)->server_iface(), ds_cap, flags.region_flags(), &ds))
53  return r;
54  }
55 
56  size = l4_round_page(size);
57  l4_addr_t start = l4_trunc_page(_start);
58 
59  if (size < L4_PAGESIZE)
60  return -L4_EINVAL;
61 
62  Rm::Region_flags r_flags = flags.region_flags();
63  Rm::Attach_flags a_flags = flags.attach_flags();
64 
65  start = l4_addr_t(rm()->attach((void*)start, size,
66  typename DERIVED::Region_handler(ds, client_cap_idx, offs, r_flags),
67  a_flags, align));
68 
69  if (start == L4_INVALID_ADDR)
70  return -L4_EADDRNOTAVAIL;
71 
72  _start = start;
73  return L4_EOK;
74  }
75 
79  long op_free_area(L4Re::Rm::Rights, l4_addr_t start)
80  {
81  if (!rm()->detach_area(start))
82  return -L4_ENOENT;
83 
84  return L4_EOK;
85  }
86 
90  long op_find(L4Re::Rm::Rights, l4_addr_t &addr, unsigned long &size,
91  L4Re::Rm::Flags &flags, L4Re::Rm::Offset &offset,
93  {
94  if (!DERIVED::Have_find)
95  return -L4_EPERM;
96 
97  Rm::Flags flag_area { 0 };
98 
99  typename DERIVED::Node r = rm()->find(Region(addr, addr + size -1));
100  if (!r)
101  {
102  r = rm()->area_find(Region(addr, addr + size - 1));
103  if (!r)
104  return -L4_ENOENT;
105  flag_area = Rm::F::In_area;
106  }
107 
108  addr = r->first.start();
109  size = r->first.end() + 1 - addr;
110 
111  flags = r->second.flags() | flag_area;
112  offset = r->second.offset();
113  m = L4::Cap<L4Re::Dataspace>(DERIVED::find_res(r->second.memory()));
114  return L4_EOK;
115  }
116 
120  long op_detach(L4Re::Rm::Rights, l4_addr_t addr,
121  unsigned long size, unsigned flags,
122  l4_addr_t &start, l4_addr_t &rsize,
123  l4_cap_idx_t &mem_cap)
124  {
125  Region r;
126  typename DERIVED::Region_handler h;
127  int err = rm()->detach((void*)addr, size, flags, &r, &h);
128  if (err < 0)
129  return err;
130 
131  if (r.invalid())
132  return -L4_ENOENT;
133 
134  start = r.start();
135  rsize = r.size();
136  mem_cap = h.client_cap_idx();
137  return err;
138  }
139 
143  long op_reserve_area(L4Re::Rm::Rights, l4_addr_t &start, unsigned long size,
144  L4Re::Rm::Flags flags, unsigned char align)
145  {
146  start = rm()->attach_area(start, size, flags, align);
147  if (start == L4_INVALID_ADDR)
148  return -L4_EADDRNOTAVAIL;
149  return L4_EOK;
150  }
151 
155  long op_get_regions(L4Re::Rm::Rights, l4_addr_t addr,
157  {
158  typename DERIVED::Node r;
159  unsigned num = 0;
160  while ((r = rm()->lower_bound(Region(addr))))
161  {
162  Rm::Region &x = regions.value[num];
163  x.start = r->first.start();
164  x.end = r->first.end();
165 
166  if (++num >= regions.max)
167  break;
168 
169  if (x.end >= rm()->max_addr())
170  break;
171  addr = x.end + 1;
172  }
173  return num;
174  }
175 
179  long op_get_areas(L4Re::Rm::Rights, l4_addr_t addr,
181  {
182  typename DERIVED::Node r;
183  unsigned num = 0;
184  while ((r = rm()->lower_bound_area(Region(addr))))
185  {
186  Rm::Area &x = areas.value[num];
187  x.start = r->first.start();
188  x.end = r->first.end();
189 
190  if (++num >= areas.max)
191  break;
192 
193  if (x.end >= rm()->max_addr())
194  break;
195 
196  addr = x.end + 1;
197  }
198  return num;
199  }
200 
201 private:
202  static void pager_set_result(L4::Ipc::Opt<L4::Ipc::Snd_fpage> *fp,
203  L4::Ipc::Snd_fpage const &f)
204  { *fp = f; }
205 
206  static void pager_set_result(L4::Ipc::Opt<L4::Ipc::Snd_fpage> *, ...)
207  {}
208 public:
209 
213  long op_io_page_fault(L4::Io_pager::Rights, l4_fpage_t, l4_umword_t,
215  {
216  // generate exception
217  return -L4_ENOMEM;
218  }
219 
220  long op_page_fault(L4::Pager::Rights, l4_umword_t addr, l4_umword_t pc,
222  {
223  Dbg(Dbg::Server).printf("page fault: %lx pc=%lx\n", addr, pc);
224 
225  bool need_w = addr & 2;
226  bool need_x = addr & 4;
227 
228  typename DERIVED::Node n = rm()->find(addr);
229 
230  if (!n || !n->second.memory())
231  {
232  Dbg(Dbg::Warn, "rm").printf("unhandled %s page fault at 0x%lx pc=0x%lx\n",
233  need_w ? "write" : "read", addr, pc);
234  // generate exception
235  return -L4_ENOMEM;
236  }
237 
238  if (!(n->second.flags() & L4Re::Rm::F::W) && need_w)
239  {
240  Dbg(Dbg::Warn, "rm").printf("write page fault in readonly region at 0x%lx pc=0x%lx\n",
241  addr, pc);
242  // generate exception
243  return -L4_EACCESS;
244  }
245 
246  if (!(n->second.flags() & L4Re::Rm::F::X) && need_x)
247  {
248  Dbg(Dbg::Warn, "rm").printf("instruction page fault in non-exec region at 0x%lx pc=0x%lx\n",
249  addr, pc);
250  // generate exception
251  return -L4_EACCESS;
252  }
253 
254  typename DERIVED::Region_handler::Ops::Map_result map_res;
255  if (int err = n->second.map(addr, n->first, need_w, &map_res))
256  {
257  Dbg(Dbg::Warn, "rm").printf("mapping for page fault failed with error %d at 0x%lx pc=0x%lx\n",
258  err, addr, pc);
259  // generate exception
260  return -L4_ENOMEM;
261  }
262 
263  pager_set_result(&fp, map_res);
264  return L4_EOK;
265  }
266 };
267 
268 }}
Range Area
An area is a range of virtual addresses which is reserved, see L4Re::Rm::reserve_area().
Definition: rm:592
Range Region
A region is a range of virtual addresses which is backed by a dataspace.
Definition: rm:584
Generic RPC wrapper for L4 flex-pages.
Definition: ipc_types:322
unsigned long l4_umword_t
Unsigned machine word.
Definition: l4int.h:51
unsigned long l4_addr_t
Address type.
Definition: l4int.h:45
unsigned long l4_cap_idx_t
L4 Capability selector Type.
Definition: types.h:342
@ L4_ENOENT
No such entity.
Definition: err.h:45
@ L4_EACCESS
Permission denied.
Definition: err.h:51
@ L4_EINVAL
Invalid argument.
Definition: err.h:56
@ L4_EOK
Ok.
Definition: err.h:43
@ L4_EADDRNOTAVAIL
Address not available.
Definition: err.h:62
@ L4_EPERM
No permission.
Definition: err.h:44
@ L4_ENOMEM
No memory.
Definition: err.h:50
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:364
l4_addr_t l4_round_page(l4_addr_t address) L4_NOTHROW
Round address up to the next page.
Definition: consts.h:389
#define L4_PAGESIZE
Minimal page size (in bytes).
Definition: consts.h:307
@ L4_INVALID_ADDR
Invalid address.
Definition: consts.h:421
Common L4 ABI Data Types.
L4Re C++ Interfaces.
Definition: cmd_control:15
Region handling.
Region mapper interface.
@ Reserved
Region is reserved (blocked)
Definition: rm:132
@ In_area
Search only in area, or map into area.
Definition: rm:107
Attribute for defining an optional RPC argument.
Definition: ipc_types:148
Dynamically sized output array of type T.
Definition: ipc_ret_array:35
L4 flexpage type.
Definition: __l4_fpage.h:83